Merge branch 'asteroid-0.7'

Conflicts:
	lib/datasource.js
This commit is contained in:
Ritchie 2013-06-13 16:27:31 -07:00
commit b78050410d
4 changed files with 171 additions and 13 deletions

View File

@ -191,10 +191,18 @@ function applyFilter(filter) {
}
return false;
}
if(isNum(example.gt) && example.gt < value) return true;
if(isNum(example.gte) && example.gte <= value) return true;
if(isNum(example.lt) && example.lt > value) return true;
if(isNum(example.lte) && example.lte >= value) return true;
}
// not strict equality
return (example !== null ? example.toString() : example) == (value !== null ? value.toString() : value);
}
function isNum(n) {
return typeof n === 'number';
}
}
Memory.prototype.destroyAll = function destroyAll(model, callback) {
@ -209,15 +217,11 @@ Memory.prototype.count = function count(model, callback, where) {
var cache = this.cache[model];
var data = Object.keys(cache)
if (where) {
data = data.filter(function (id) {
var ok = true;
Object.keys(where).forEach(function (key) {
if (JSON.parse(cache[id])[key] != where[key]) {
ok = false;
}
});
return ok;
});
var filter = {where: where};
data = data.map(function (id) {
return this.fromDb(model, cache[id]);
}.bind(this));
data = data.filter(applyFilter(filter));
}
process.nextTick(function () {
callback(null, data.length);

View File

@ -157,6 +157,10 @@ DataAccessObject.create = function (data, callback) {
return obj;
};
DataAccessObject.create.shared = true;
DataAccessObject.create.accepts = {arg: 'data', type: 'object'};
DataAccessObject.create.returns = {arg: 'data', type: 'object'};
function stillConnecting(schema, obj, args) {
if (schema.connected) return false; // Connected
@ -358,6 +362,10 @@ DataAccessObject.findOne = function findOne(params, cb) {
});
};
DataAccessObject.findOne.shared = true;
DataAccessObject.findOne.accepts = {arg: 'filter', type: 'object'};
DataAccessObject.findOne.returns = {arg: 'data', type: 'object'};
/**
* Destroy all records
* @param {Function} cb - callback called with (err)
@ -529,6 +537,13 @@ DataAccessObject.prototype.updateAttribute = function updateAttribute(name, valu
this.updateAttributes(data, callback);
};
DataAccessObject.prototype.updateAttribute.shared = true;
DataAccessObject.prototype.updateAttribute.accepts = [
{arg: 'name', type: 'string', required: true},
{arg: 'value', type: 'any', required: true}
];
DataAccessObject.prototype.updateAttribute.returns = {arg: 'data', type: 'object'};
/**
* Update set of attributes
*
@ -609,6 +624,9 @@ DataAccessObject.prototype.reload = function reload(callback) {
this.constructor.find(this.id, callback);
};
DataAccessObject.prototype.reload.shared = true;
DataAccessObject.prototype.reload.returns = {arg: 'data', type: 'object'};
/**
* Define readonly property on object
*

View File

@ -1,6 +1,7 @@
/**
* Module dependencies
*/
var ModelBuilder = require('./model-builder.js').ModelBuilder;
var jutil = require('./jutil');
var ModelBaseClass = require('./model.js');
@ -57,9 +58,48 @@ function DataSource(name, settings) {
ModelBuilder.call(this, arguments);
this.setup(name, settings);
// default DataAccessObject
this.DataAccessObject = this.constructor.DataAccessObject;
// connector
var connector = this.connector();
// DataAccessObject - connector defined or supply the default
this.DataAccessObject = connector.DataAccessObject || this.constructor.DataAccessObject;
this.DataAccessObject.call(this, arguments);
// operation metadata
this._operations = {};
// define DataAccessObject methods
Object.keys(this.DataAccessObject).forEach(function (name) {
var fn = this.DataAccessObject[name];
if(typeof fn === 'function') {
this.defineOperation(name, {
accepts: fn.accepts,
returns: fn.returns,
http: fn.http,
remoteEnabled: fn.shared ? true : false,
scope: this.DataAccessObject,
fnName: name
});
}
}.bind(this));
// define DataAccessObject.prototype methods
Object.keys(this.DataAccessObject.prototype).forEach(function (name) {
var fn = this.DataAccessObject.prototype[name];
if(typeof fn === 'function') {
this.defineOperation(name, {
prototype: true,
accepts: fn.accepts,
returns: fn.returns,
http: fn.http,
remoteEnabled: fn.shared ? true : false,
scope: this.DataAccessObject.prototype,
fnName: name
});
}
}.bind(this));
};
util.inherits(DataSource, ModelBuilder);
@ -225,10 +265,40 @@ DataSource.prototype.define = function defineClass(className, properties, settin
*/
DataSource.prototype.mixin = function (ModelCtor) {
var ops = this.operations();
var self = this;
var DAO = this.DataAccessObject;
// inherit DataAccessObject methods
jutil.mixin(ModelCtor, this.DataAccessObject);
// mixin DAO
jutil.mixin(ModelCtor, DAO);
// decorate operations as alias functions
Object.keys(ops).forEach(function (name) {
var op = ops[name];
var fn = op.scope[op.fnName];
var scope;
if(op.enabled) {
scope = op.prototype ? ModelCtor.prototype : ModelCtor;
// var sfn = scope[name] = function () {
// op.scope[op.fnName].apply(self, arguments);
// }
Object.keys(op)
.filter(function (key) {
// filter out the following keys
return ~ [
'scope',
'fnName',
'prototype'
].indexOf(key)
})
.forEach(function (key) {
if(typeof op[key] !== 'undefined') {
op.scope[op.fnName][key] = op[key];
}
});
}
});
}
/**
@ -253,6 +323,7 @@ DataSource.prototype.attach = function (ModelCtor) {
// redefine the schema
hiddenProperty(ModelCtor, 'schema', this);
ModelCtor.dataSource = this;
// add to def
this.definitions[className] = {
@ -1072,6 +1143,67 @@ DataSource.prototype.transaction = function() {
return transaction;
};
/**
* Enable a data source operation remotely.
*/
DataSource.prototype.enableRemote = function (operation) {
var op = this.getOperation(operation);
if(op) {
op.remoteEnabled = true;
} else {
throw new Error(operation + ' is not provided by the attached connector');
}
}
/**
* Disable a data source operation remotely.
*/
DataSource.prototype.disableRemote = function (operation) {
var op = this.getOperation(operation);
if(op) {
op.remoteEnabled = false;
} else {
throw new Error(operation + ' is not provided by the attached connector');
}
}
/**
* Get an operation's metadata.
*/
DataSource.prototype.getOperation = function (operation) {
var ops = this.operations();
var opKeys = Object.keys(ops);
for(var i = 0; i < opKeys.length; i++) {
var op = ops[opKeys[i]];
if(op.name === operation) {
return op;
}
}
}
/**
* Get all operations.
*/
DataSource.prototype.operations = function () {
return this._operations;
}
/**
* Define an operation.
*/
DataSource.prototype.defineOperation = function (name, options, fn) {
options.fn = fn;
options.name = name;
this._operations[name] = options;
}
/**
* Define hidden property
*/

View File

@ -167,6 +167,10 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
Object.keys(properties).forEach(cb);
};
ModelClass.attachTo = function (dataSource) {
dataSource.attach(this);
}
ModelClass.registerProperty = function (attr) {
var DataType = properties[attr].type;
if(!DataType) {