Synchronize with cachedRelations
This commit is contained in:
parent
a3b178cbea
commit
332579ec87
|
@ -60,10 +60,10 @@ function RelationDefinition(definition) {
|
||||||
this.type = normalizeType(definition.type);
|
this.type = normalizeType(definition.type);
|
||||||
assert(this.type, 'Invalid relation type: ' + definition.type);
|
assert(this.type, 'Invalid relation type: ' + definition.type);
|
||||||
this.modelFrom = definition.modelFrom;
|
this.modelFrom = definition.modelFrom;
|
||||||
assert(this.modelFrom);
|
assert(this.modelFrom, 'Source model is required');
|
||||||
this.keyFrom = definition.keyFrom;
|
this.keyFrom = definition.keyFrom;
|
||||||
this.modelTo = definition.modelTo;
|
this.modelTo = definition.modelTo;
|
||||||
assert(this.modelTo);
|
assert(this.modelTo, 'Target model is required');
|
||||||
this.keyTo = definition.keyTo;
|
this.keyTo = definition.keyTo;
|
||||||
this.modelThrough = definition.modelThrough;
|
this.modelThrough = definition.modelThrough;
|
||||||
this.keyThrough = definition.keyThrough;
|
this.keyThrough = definition.keyThrough;
|
||||||
|
@ -106,6 +106,15 @@ function Relation(definition, modelInstance) {
|
||||||
this.modelInstance = modelInstance;
|
this.modelInstance = modelInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Relation.prototype.resetCache = function (cache) {
|
||||||
|
cache = cache || undefined;
|
||||||
|
this.modelInstance.__cachedRelations[this.definition.name] = cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
Relation.prototype.getCache = function () {
|
||||||
|
return this.modelInstance.__cachedRelations[this.definition.name];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasMany subclass
|
* HasMany subclass
|
||||||
* @param {RelationDefinition|Object} definition
|
* @param {RelationDefinition|Object} definition
|
||||||
|
@ -124,6 +133,39 @@ function HasMany(definition, modelInstance) {
|
||||||
|
|
||||||
util.inherits(HasMany, Relation);
|
util.inherits(HasMany, Relation);
|
||||||
|
|
||||||
|
HasMany.prototype.removeFromCache = function (id) {
|
||||||
|
var cache = this.modelInstance.__cachedRelations[this.definition.name];
|
||||||
|
var idName = this.definition.modelTo.definition.idName();
|
||||||
|
if (Array.isArray(cache)) {
|
||||||
|
for (var i = 0, n = cache.length; i < n; i++) {
|
||||||
|
if (cache[i][idName] === id) {
|
||||||
|
return cache.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
HasMany.prototype.addToCache = function (inst) {
|
||||||
|
if (!inst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var cache = this.modelInstance.__cachedRelations[this.definition.name];
|
||||||
|
if (cache === undefined) {
|
||||||
|
cache = this.modelInstance.__cachedRelations[this.definition.name] = [];
|
||||||
|
}
|
||||||
|
var idName = this.definition.modelTo.definition.idName();
|
||||||
|
if (Array.isArray(cache)) {
|
||||||
|
for (var i = 0, n = cache.length; i < n; i++) {
|
||||||
|
if (cache[i][idName] === inst[idName]) {
|
||||||
|
cache[i] = inst;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache.push(inst);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasManyThrough subclass
|
* HasManyThrough subclass
|
||||||
* @param {RelationDefinition|Object} definition
|
* @param {RelationDefinition|Object} definition
|
||||||
|
@ -210,7 +252,7 @@ function findBelongsTo(modelFrom, modelTo, keyTo) {
|
||||||
var rel = relations[keys[k]];
|
var rel = relations[keys[k]];
|
||||||
if (rel.type === RelationTypes.belongsTo &&
|
if (rel.type === RelationTypes.belongsTo &&
|
||||||
rel.modelTo === modelTo &&
|
rel.modelTo === modelTo &&
|
||||||
rel.keyTo === keyTo) {
|
(keyTo === undefined || rel.keyTo === keyTo)) {
|
||||||
return rel.keyFrom;
|
return rel.keyFrom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,6 +398,7 @@ HasMany.prototype.findById = function (id, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
HasMany.prototype.destroyById = function (id, cb) {
|
HasMany.prototype.destroyById = function (id, cb) {
|
||||||
|
var self = this;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var fk = this.definition.keyTo;
|
var fk = this.definition.keyTo;
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyFrom;
|
||||||
|
@ -369,6 +412,7 @@ HasMany.prototype.destroyById = function (id, cb) {
|
||||||
}
|
}
|
||||||
// Check if the foreign key matches the primary key
|
// Check if the foreign key matches the primary key
|
||||||
if (inst[fk] && inst[fk].toString() === modelInstance[pk].toString()) {
|
if (inst[fk] && inst[fk].toString() === modelInstance[pk].toString()) {
|
||||||
|
self.removeFromCache(inst[fk]);
|
||||||
inst.destroy(cb);
|
inst.destroy(cb);
|
||||||
} else {
|
} else {
|
||||||
cb(new Error('Permission denied: foreign key does not match the primary key'));
|
cb(new Error('Permission denied: foreign key does not match the primary key'));
|
||||||
|
@ -379,6 +423,7 @@ HasMany.prototype.destroyById = function (id, cb) {
|
||||||
// Create an instance of the target model and connect it to the instance of
|
// Create an instance of the target model and connect it to the instance of
|
||||||
// the source model by creating an instance of the through model
|
// the source model by creating an instance of the through model
|
||||||
HasManyThrough.prototype.create = function create(data, done) {
|
HasManyThrough.prototype.create = function create(data, done) {
|
||||||
|
var self = this;
|
||||||
var definition = this.definition;
|
var definition = this.definition;
|
||||||
var modelTo = definition.modelTo;
|
var modelTo = definition.modelTo;
|
||||||
var modelThrough = definition.modelThrough;
|
var modelThrough = definition.modelThrough;
|
||||||
|
@ -391,27 +436,28 @@ HasManyThrough.prototype.create = function create(data, done) {
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
|
||||||
// First create the target model
|
// First create the target model
|
||||||
modelTo.create(data, function (err, ac) {
|
modelTo.create(data, function (err, to) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done && done(err, ac);
|
return done && done(err, to);
|
||||||
}
|
}
|
||||||
// The primary key for the target model
|
// The primary key for the target model
|
||||||
var pk2 = modelTo.dataSource.idName(modelTo.modelName) || 'id';
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
||||||
definition.keyFrom);
|
definition.keyFrom);
|
||||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
||||||
var d = {};
|
var d = {};
|
||||||
d[fk1] = modelInstance[definition.keyFrom];
|
d[fk1] = modelInstance[definition.keyFrom];
|
||||||
d[fk2] = ac[pk2];
|
d[fk2] = to[pk2];
|
||||||
// Then create the through model
|
// Then create the through model
|
||||||
modelThrough.create(d, function (e) {
|
modelThrough.create(d, function (e, through) {
|
||||||
if (e) {
|
if (e) {
|
||||||
// Undo creation of the target model
|
// Undo creation of the target model
|
||||||
ac.destroy(function () {
|
to.destroy(function () {
|
||||||
done && done(e);
|
done && done(e);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
done && done(err, ac);
|
self.addToCache(to);
|
||||||
|
done && done(err, to);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -422,9 +468,9 @@ HasManyThrough.prototype.create = function create(data, done) {
|
||||||
* @param {Object|ID} acInst The actual instance or id value
|
* @param {Object|ID} acInst The actual instance or id value
|
||||||
*/
|
*/
|
||||||
HasManyThrough.prototype.add = function (acInst, done) {
|
HasManyThrough.prototype.add = function (acInst, done) {
|
||||||
|
var self = this;
|
||||||
var definition = this.definition;
|
var definition = this.definition;
|
||||||
var modelThrough = definition.modelThrough;
|
var modelThrough = definition.modelThrough;
|
||||||
var modelTo = definition.modelTo;
|
|
||||||
var pk1 = definition.keyFrom;
|
var pk1 = definition.keyFrom;
|
||||||
|
|
||||||
var data = {};
|
var data = {};
|
||||||
|
@ -434,7 +480,7 @@ HasManyThrough.prototype.add = function (acInst, done) {
|
||||||
definition.keyFrom);
|
definition.keyFrom);
|
||||||
|
|
||||||
// The primary key for the target model
|
// The primary key for the target model
|
||||||
var pk2 = modelTo.dataSource.idName(modelTo.modelName) || 'id';
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
|
|
||||||
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
||||||
|
|
||||||
|
@ -445,7 +491,14 @@ HasManyThrough.prototype.add = function (acInst, done) {
|
||||||
data[fk2] = acInst[pk2] || acInst;
|
data[fk2] = acInst[pk2] || acInst;
|
||||||
|
|
||||||
// Create an instance of the through model
|
// Create an instance of the through model
|
||||||
modelThrough.findOrCreate({where: query}, data, done);
|
modelThrough.findOrCreate({where: query}, data, function(err, ac) {
|
||||||
|
if(!err) {
|
||||||
|
if (acInst instanceof definition.modelTo) {
|
||||||
|
self.addToCache(acInst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done(err, ac);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -453,13 +506,30 @@ HasManyThrough.prototype.add = function (acInst, done) {
|
||||||
* @param {Object|ID) acInst The actual instance or id value
|
* @param {Object|ID) acInst The actual instance or id value
|
||||||
*/
|
*/
|
||||||
HasManyThrough.prototype.remove = function (acInst, done) {
|
HasManyThrough.prototype.remove = function (acInst, done) {
|
||||||
var modelThrough = this.definition.modelThrough;
|
var self = this;
|
||||||
var fk2 = this.definition.keyThrough;
|
var definition = this.definition;
|
||||||
var pk = this.definition.keyFrom;
|
var modelThrough = definition.modelThrough;
|
||||||
|
var pk1 = definition.keyFrom;
|
||||||
|
|
||||||
var q = {};
|
var query = {};
|
||||||
q[fk2] = acInst[pk] || acInst;
|
|
||||||
modelThrough.deleteAll(q, done );
|
var fk1 = findBelongsTo(modelThrough, definition.modelFrom,
|
||||||
|
definition.keyFrom);
|
||||||
|
|
||||||
|
// The primary key for the target model
|
||||||
|
var pk2 = definition.modelTo.definition.idName();
|
||||||
|
|
||||||
|
var fk2 = findBelongsTo(modelThrough, definition.modelTo, pk2);
|
||||||
|
|
||||||
|
query[fk1] = this.modelInstance[pk1];
|
||||||
|
query[fk2] = acInst[pk2] || acInst;
|
||||||
|
|
||||||
|
modelThrough.deleteAll(query, function (err) {
|
||||||
|
if (!err) {
|
||||||
|
self.removeFromCache(query[fk2]);
|
||||||
|
}
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -547,6 +617,7 @@ RelationDefinition.belongsTo = function (modelFrom, modelTo, params) {
|
||||||
};
|
};
|
||||||
|
|
||||||
BelongsTo.prototype.create = function(targetModelData, cb) {
|
BelongsTo.prototype.create = function(targetModelData, cb) {
|
||||||
|
var self = this;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var fk = this.definition.keyTo;
|
var fk = this.definition.keyTo;
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyFrom;
|
||||||
|
@ -555,6 +626,7 @@ BelongsTo.prototype.create = function(targetModelData, cb) {
|
||||||
modelTo.create(targetModelData, function(err, targetModel) {
|
modelTo.create(targetModelData, function(err, targetModel) {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
modelInstance[fk] = targetModel[pk];
|
modelInstance[fk] = targetModel[pk];
|
||||||
|
self.resetCache(targetModel);
|
||||||
cb && cb(err, targetModel);
|
cb && cb(err, targetModel);
|
||||||
} else {
|
} else {
|
||||||
cb && cb(err);
|
cb && cb(err);
|
||||||
|
@ -579,11 +651,11 @@ BelongsTo.prototype.build = function(targetModelData) {
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
BelongsTo.prototype.related = function (refresh, params) {
|
BelongsTo.prototype.related = function (refresh, params) {
|
||||||
|
var self = this;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var pk = this.definition.keyTo;
|
var pk = this.definition.keyTo;
|
||||||
var fk = this.definition.keyFrom;
|
var fk = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
var relationName = this.definition.name;
|
|
||||||
|
|
||||||
if (arguments.length === 1) {
|
if (arguments.length === 1) {
|
||||||
params = refresh;
|
params = refresh;
|
||||||
|
@ -593,13 +665,12 @@ BelongsTo.prototype.related = function (refresh, params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var cachedValue;
|
var cachedValue;
|
||||||
if (!refresh && modelInstance.__cachedRelations
|
if (!refresh) {
|
||||||
&& (modelInstance.__cachedRelations[relationName] !== undefined)) {
|
cachedValue = self.getCache();
|
||||||
cachedValue = modelInstance.__cachedRelations[relationName];
|
|
||||||
}
|
}
|
||||||
if (params instanceof ModelBaseClass) { // acts as setter
|
if (params instanceof ModelBaseClass) { // acts as setter
|
||||||
modelInstance[fk] = params[pk];
|
modelInstance[fk] = params[pk];
|
||||||
modelInstance.__cachedRelations[relationName] = params;
|
self.resetCache(params);
|
||||||
} else if (typeof params === 'function') { // acts as async getter
|
} else if (typeof params === 'function') { // acts as async getter
|
||||||
var cb = params;
|
var cb = params;
|
||||||
if (cachedValue === undefined) {
|
if (cachedValue === undefined) {
|
||||||
|
@ -612,9 +683,10 @@ BelongsTo.prototype.related = function (refresh, params) {
|
||||||
}
|
}
|
||||||
// Check if the foreign key matches the primary key
|
// Check if the foreign key matches the primary key
|
||||||
if (inst[pk] === modelInstance[fk]) {
|
if (inst[pk] === modelInstance[fk]) {
|
||||||
|
self.resetCache(inst);
|
||||||
cb(null, inst);
|
cb(null, inst);
|
||||||
} else {
|
} else {
|
||||||
cb(new Error('Permission denied'));
|
cb(new Error('Permission denied: foreign key does not match the primary key'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return modelInstance[fk];
|
return modelInstance[fk];
|
||||||
|
@ -626,7 +698,7 @@ BelongsTo.prototype.related = function (refresh, params) {
|
||||||
return modelInstance[fk];
|
return modelInstance[fk];
|
||||||
} else { // setter
|
} else { // setter
|
||||||
modelInstance[fk] = params;
|
modelInstance[fk] = params;
|
||||||
delete modelInstance.__cachedRelations[relationName];
|
self.resetCache();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -742,15 +814,19 @@ RelationDefinition.hasOne = function (modelFrom, modelTo, params) {
|
||||||
* @param {Object} The newly created target model instance
|
* @param {Object} The newly created target model instance
|
||||||
*/
|
*/
|
||||||
HasOne.prototype.create = function(targetModelData, cb) {
|
HasOne.prototype.create = function(targetModelData, cb) {
|
||||||
|
var self = this;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var fk = this.definition.keyTo;
|
var fk = this.definition.keyTo;
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyFrom;
|
||||||
var modelInstance = this.modelInstance;
|
var modelInstance = this.modelInstance;
|
||||||
|
var relationName = this.definition.name
|
||||||
|
|
||||||
targetModelData = targetModelData || {};
|
targetModelData = targetModelData || {};
|
||||||
targetModelData[fk] = modelInstance[pk];
|
targetModelData[fk] = modelInstance[pk];
|
||||||
modelTo.create(targetModelData, function(err, targetModel) {
|
modelTo.create(targetModelData, function(err, targetModel) {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
|
// Refresh the cache
|
||||||
|
self.resetCache(targetModel);
|
||||||
cb && cb(err, targetModel);
|
cb && cb(err, targetModel);
|
||||||
} else {
|
} else {
|
||||||
cb && cb(err);
|
cb && cb(err);
|
||||||
|
@ -784,6 +860,7 @@ HasOne.prototype.build = function(targetModelData) {
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
*/
|
*/
|
||||||
HasOne.prototype.related = function (refresh, params) {
|
HasOne.prototype.related = function (refresh, params) {
|
||||||
|
var self = this;
|
||||||
var modelTo = this.definition.modelTo;
|
var modelTo = this.definition.modelTo;
|
||||||
var fk = this.definition.keyTo;
|
var fk = this.definition.keyTo;
|
||||||
var pk = this.definition.keyFrom;
|
var pk = this.definition.keyFrom;
|
||||||
|
@ -798,13 +875,12 @@ HasOne.prototype.related = function (refresh, params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var cachedValue;
|
var cachedValue;
|
||||||
if (!refresh && modelInstance.__cachedRelations
|
if (!refresh) {
|
||||||
&& (modelInstance.__cachedRelations[relationName] !== undefined)) {
|
cachedValue = self.getCache();
|
||||||
cachedValue = modelInstance.__cachedRelations[relationName];
|
|
||||||
}
|
}
|
||||||
if (params instanceof ModelBaseClass) { // acts as setter
|
if (params instanceof ModelBaseClass) { // acts as setter
|
||||||
params[fk] = modelInstance[pk];
|
params[fk] = modelInstance[pk];
|
||||||
modelInstance.__cachedRelations[relationName] = params;
|
self.resetCache(params);
|
||||||
} else if (typeof params === 'function') { // acts as async getter
|
} else if (typeof params === 'function') { // acts as async getter
|
||||||
var cb = params;
|
var cb = params;
|
||||||
if (cachedValue === undefined) {
|
if (cachedValue === undefined) {
|
||||||
|
@ -819,6 +895,7 @@ HasOne.prototype.related = function (refresh, params) {
|
||||||
}
|
}
|
||||||
// Check if the foreign key matches the primary key
|
// Check if the foreign key matches the primary key
|
||||||
if (inst[fk] === modelInstance[pk]) {
|
if (inst[fk] === modelInstance[pk]) {
|
||||||
|
self.resetCache(inst);
|
||||||
cb(null, inst);
|
cb(null, inst);
|
||||||
} else {
|
} else {
|
||||||
cb(new Error('Permission denied'));
|
cb(new Error('Permission denied'));
|
||||||
|
@ -833,6 +910,6 @@ HasOne.prototype.related = function (refresh, params) {
|
||||||
return modelInstance[pk];
|
return modelInstance[pk];
|
||||||
} else { // setter
|
} else { // setter
|
||||||
params[fk] = modelInstance[pk];
|
params[fk] = modelInstance[pk];
|
||||||
delete modelInstance.__cachedRelations[relationName];
|
self.resetCache();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue