added include functionnality to abstract class and mysql

This commit is contained in:
Sébastien Drouyer 2012-12-16 18:05:36 +01:00
parent 24ccb0ffc2
commit c6bddf170a
2 changed files with 220 additions and 3 deletions

View File

@ -58,6 +58,10 @@ AbstractClass.prototype._initProperties = function (data, applySetters) {
value: {}
});
if (data['__cachedRelations']) {
this.__cachedRelations = data['__cachedRelations'];
}
for (var i in data) this.__data[i] = this.__dataWas[i] = data[i];
if (applySetters && ctor.setter) {
@ -384,6 +388,202 @@ AbstractClass.count = function (where, cb) {
this.schema.adapter.count(this.modelName, cb, where);
};
/**
*
*
* @param objects
* @param include
*/
AbstractClass.include = function (objects, include, callback, preprocessDataCallback) {
var self = this;
if ((include.constructor.name == 'Array' && include.length == 0) || (include.constructor.name == 'Object' && Object.keys(include).length == 0)) {
callback(null, objects);
return;
}
console.log('******************* OLD INCLUDE', include);
include = processIncludeJoin(include);
console.log('******************* NEW INCLUDE', include);
var keyVals = {};
var objsByKeys = {};
var nbCallbacks = 0;
for (var i = 0; i < include.length; i++) {
var cb = processIncludeItem(objects, include[i], keyVals, objsByKeys);
if (cb !== null) {
nbCallbacks++;
cb(function() {
nbCallbacks--;
if (nbCallbacks == 0) {
callback(null, objects);
}
});
}
}
/*
async.parallel(callbacks, function(err, results) {
callback(null, objs);
});
*/
function processIncludeJoin(ij) {
if (typeof ij === 'string') {
ij = [ij];
}
if (ij.constructor.name === 'Object') {
var newIj = [];
for (var key in ij) {
var obj = {};
obj[key] = ij[key];
newIj.push(obj);
}
return newIj;
}
return ij;
}
function processIncludeItem(objs, include, keyVals, objsByKeys) {
var relations = self.relations;
if (include.constructor.name === 'Object') {
var relationName = Object.keys(include)[0];
var subInclude = include[relationName];
} else {
var relationName = include;
var subInclude = [];
}
var relation = relations[relationName];
var req = {'where': {}};
var keysToBeProcessed = {};
if (!keyVals[relation.keyFrom]) {
objsByKeys[relation.keyFrom] = {};
for (var j = 0; j < objs.length; j++) {
keysToBeProcessed[objs[j][relation.keyFrom]] = true;
if (!objsByKeys[relation.keyFrom][objs[j][relation.keyFrom]]) {
objsByKeys[relation.keyFrom][objs[j][relation.keyFrom]] = [];
}
objsByKeys[relation.keyFrom][objs[j][relation.keyFrom]].push(objs[j]);
}
keyVals[relation.keyFrom] = Object.keys(objsByKeys[relation.keyFrom]);
}
if (keyVals[relation.keyFrom].length > 0) {
// deep clone is necessary since inq seems to change the processed array
var inValues = [];
for (var j = 0; j < keyVals[relation.keyFrom].length; j++) {
if (keyVals[relation.keyFrom][j] !== 'null') {
inValues.push(keyVals[relation.keyFrom][j]);
}
}
req['where'][relation.keyTo] = {inq: inValues};
req['include'] = subInclude;
return function(cb) {
relation.modelTo.all(req, function(err, dataIncluded) {
var objsIncluded = preprocessDataCallback(relation.modelTo.modelName, dataIncluded);
for (var i = 0; i < objsIncluded.length; i++) {
delete keysToBeProcessed[objsIncluded[i][relation.keyTo]];
var objectsFrom = objsByKeys[relation.keyFrom][objsIncluded[i][relation.keyTo]];
for (var j = 0; j < objectsFrom.length; j++) {
if (!objectsFrom[j].__cachedRelations) {
objectsFrom[j].__cachedRelations = {};
}
if (relation.multiple) {
if (!objectsFrom[j].__cachedRelations[relationName]) {
objectsFrom[j].__cachedRelations[relationName] = [];
}
objectsFrom[j].__cachedRelations[relationName].push(objsIncluded[i]);
} else {
objectsFrom[j].__cachedRelations[relationName] = objsIncluded[i];
}
}
}
// No relation have been found for these keys
for (var key in keysToBeProcessed) {
var objectsFrom = objsByKeys[relation.keyFrom][key];
for (var j = 0; j < objectsFrom.length; j++) {
if (!objectsFrom[j].__cachedRelations) {
objectsFrom[j].__cachedRelations = {};
}
objectsFrom[j].__cachedRelations[relationName] = relation.multiple ? [] : null;
}
}
cb(err, objsIncluded);
});
};
}
return null;
}
/*
function processIncludeItem(model, objs, include, keyVals, objsByKeys) {
var relations = model.relations;
if (include.constructor.name === 'Object') {
var relationName = Object.keys(include)[0];
var relation = relations[relationName];
var subInclude = include[relationName];
} else {
var relationName = include;
var relation = relations[relationName];
var subInclude = [];
}
var req = {'where': {}};
if (!keyVals[relation.keyFrom]) {
objsByKeys[relation.keyFrom] = {};
for (var j = 0; j < objs.length; j++) {
if (!objsByKeys[relation.keyFrom][objs[j][relation.keyFrom]]) {
objsByKeys[relation.keyFrom][objs[j][relation.keyFrom]] = [];
}
objsByKeys[relation.keyFrom][objs[j][relation.keyFrom]].push(objs[j]);
}
keyVals[relation.keyFrom] = Object.keys(objsByKeys[relation.keyFrom]);
}
req['where'][relation.keyTo] = {inq: keyVals[relation.keyFrom]};
req['include'] = subInclude;
return function(cb) {
relation.model.all(req, function(err, dataIncluded) {
var objsIncluded = dataIncluded.map(function (obj) {
return self.fromDatabase(relation.model.modelName, obj);
});
for (var i = 0; i < objsIncluded.length; i++) {
var objectsFrom = objsByKeys[relation.keyFrom][objsIncluded[i][relation.keyTo]];
for (var j = 0; j < objectsFrom.length; j++) {
if (!objectsFrom[j].__cache) {
objectsFrom[j].__cache = {};
}
if (relation.type == 'hasMany') {
if (!objectsFrom[j].__cache[relationName]) {
objectsFrom[j].__cache[relationName] = [];
}
objectsFrom[j].__cache[relationName].push(objsIncluded[i]);
} else {
objectsFrom[j].__cache[relationName] = objsIncluded[i];
}
}
}
cb(err, dataIncluded);
});
};
}
*/
}
/**
* Return string representation of class
*
@ -671,6 +871,7 @@ AbstractClass.hasMany = function hasMany(anotherClass, params) {
type: 'hasMany',
keyFrom: 'id',
keyTo: params['foreignKey'],
modelTo: anotherClass,
multiple: true
};
// each instance of this class should have method named
@ -744,6 +945,7 @@ AbstractClass.belongsTo = function (anotherClass, params) {
type: 'belongsTo',
keyFrom: params['foreignKey'],
keyTo: 'id',
modelTo: anotherClass,
multiple: false
};
@ -751,6 +953,10 @@ AbstractClass.belongsTo = function (anotherClass, params) {
this.prototype['__finders__'] = this.prototype['__finders__'] || {};
this.prototype['__finders__'][methodName] = function (id, cb) {
if (id === null) {
cb(null, null);
return;
}
anotherClass.find(id, function (err,inst) {
if (err) return cb(err);
if (!inst) return cb(null, null);

View File

@ -224,9 +224,20 @@ MySQL.prototype.all = function all(model, filter, callback) {
if (err) {
return callback(err, []);
}
callback(null, data.map(function (obj) {
return self.fromDatabase(model, obj);
}));
var preprocessDataCallback = function(model, data) {
data.map(function (obj) {
return self.fromDatabase(model, obj);
});
return data;
};
var objs = preprocessDataCallback(model, data);
if (filter && filter.include) {
this._models[model].model.include(objs, filter.include, callback, preprocessDataCallback);
} else {
callback(null, objs);
}
}.bind(this));
return sql;