Add ctx.isNewInstance for "save" hooks
"before save" hooks provide "ctx.isNewInstance" whenever "ctx.instance" is set. Possible values: - true for all CREATE operations - false for all UPDATE operations - undefined for "prototype.save" "after save" hooks provide "ctx.isNewInstance" whenever "ctx.instance" is set. Possible values: - true after all CREATE operations - false after all UPDATE operations - undefined after "updateOrCreate" and "save" Note: both "updateOrCreate" and "prototype.updateAttributes" don't provide `ctx.instance` to "before save" hooks, therefore `ctx.isNewInstance` it not provided either.
This commit is contained in:
parent
ae3dc3cec2
commit
ffcaa4e76e
|
@ -225,11 +225,13 @@ Memory.prototype.updateOrCreate = function (model, data, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.exists(model, self.getIdValue(model, data), function (err, exists) {
|
this.exists(model, self.getIdValue(model, data), function (err, exists) {
|
||||||
if (exists) {
|
if (exists) {
|
||||||
self.save(model, data, callback);
|
self.save(model, data, function(err, data) {
|
||||||
|
callback(err, data, { isNewInstance: false });
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
self.create(model, data, function (err, id) {
|
self.create(model, data, function (err, id) {
|
||||||
self.setIdValue(model, data, id);
|
self.setIdValue(model, data, id);
|
||||||
callback(err, data);
|
callback(err, data, { isNewInstance: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -244,7 +246,9 @@ Memory.prototype.save = function save(model, data, callback) {
|
||||||
data = merge(modelData, data);
|
data = merge(modelData, data);
|
||||||
}
|
}
|
||||||
this.collection(model)[id] = serialize(data);
|
this.collection(model)[id] = serialize(data);
|
||||||
this.saveToFile(data, callback);
|
this.saveToFile(data, function(err) {
|
||||||
|
callback(err, data, { isNewInstance: !modelData });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Memory.prototype.exists = function exists(model, id, callback) {
|
Memory.prototype.exists = function exists(model, id, callback) {
|
||||||
|
@ -462,12 +466,12 @@ function applyFilter(filter) {
|
||||||
if ('neq' in example) {
|
if ('neq' in example) {
|
||||||
return compare(example.neq, value) !== 0;
|
return compare(example.neq, value) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('between' in example ) {
|
if ('between' in example ) {
|
||||||
return ( testInEquality({gte:example.between[0]}, value) &&
|
return ( testInEquality({gte:example.between[0]}, value) &&
|
||||||
testInEquality({lte:example.between[1]}, value) );
|
testInEquality({lte:example.between[1]}, value) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (example.like || example.nlike) {
|
if (example.like || example.nlike) {
|
||||||
|
|
||||||
var like = example.like || example.nlike;
|
var like = example.like || example.nlike;
|
||||||
|
|
53
lib/dao.js
53
lib/dao.js
|
@ -231,7 +231,12 @@ DataAccessObject.create = function (data, options, cb) {
|
||||||
Model = this.lookupModel(data); // data-specific
|
Model = this.lookupModel(data); // data-specific
|
||||||
if (Model !== obj.constructor) obj = new Model(data);
|
if (Model !== obj.constructor) obj = new Model(data);
|
||||||
|
|
||||||
var context = { Model: Model, instance: obj, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: obj,
|
||||||
|
isNewInstance: true,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('before save', context, function(err) {
|
Model.notifyObserversOf('before save', context, function(err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
@ -270,7 +275,12 @@ DataAccessObject.create = function (data, options, cb) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return cb(err, obj);
|
return cb(err, obj);
|
||||||
}
|
}
|
||||||
var context = { Model: Model, instance: obj, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: obj,
|
||||||
|
isNewInstance: true,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('after save', context, function(err) {
|
Model.notifyObserversOf('after save', context, function(err) {
|
||||||
cb(err, obj);
|
cb(err, obj);
|
||||||
if(!err) Model.emit('changed', obj);
|
if(!err) Model.emit('changed', obj);
|
||||||
|
@ -390,7 +400,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
|
||||||
self.getDataSource().connector
|
self.getDataSource().connector
|
||||||
.updateOrCreate(Model.modelName, update, done);
|
.updateOrCreate(Model.modelName, update, done);
|
||||||
|
|
||||||
function done(err, data) {
|
function done(err, data, result) {
|
||||||
var obj;
|
var obj;
|
||||||
if (data && !(data instanceof Model)) {
|
if (data && !(data instanceof Model)) {
|
||||||
inst._initProperties(data, { persisted: true });
|
inst._initProperties(data, { persisted: true });
|
||||||
|
@ -404,7 +414,12 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
|
||||||
Model.emit('changed', inst);
|
Model.emit('changed', inst);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var context = { Model: Model, instance: obj, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: obj,
|
||||||
|
isNewInstance: result ? result.isNewInstance : undefined,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('after save', context, function(err) {
|
Model.notifyObserversOf('after save', context, function(err) {
|
||||||
cb(err, obj);
|
cb(err, obj);
|
||||||
if(!err) {
|
if(!err) {
|
||||||
|
@ -505,7 +520,12 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (created) {
|
if (created) {
|
||||||
var context = { Model: Model, instance: obj, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: obj,
|
||||||
|
isNewInstance: true,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('after save', context, function(err) {
|
Model.notifyObserversOf('after save', context, function(err) {
|
||||||
if (cb.promise) {
|
if (cb.promise) {
|
||||||
cb(err, [obj, created]);
|
cb(err, [obj, created]);
|
||||||
|
@ -551,7 +571,12 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
|
||||||
Model.applyProperties(enforced, obj);
|
Model.applyProperties(enforced, obj);
|
||||||
obj.setAttributes(enforced);
|
obj.setAttributes(enforced);
|
||||||
|
|
||||||
var context = { Model: Model, instance: obj, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: obj,
|
||||||
|
isNewInstance: true,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('before save', context, function(err, ctx) {
|
Model.notifyObserversOf('before save', context, function(err, ctx) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
@ -1562,12 +1587,17 @@ DataAccessObject.prototype.save = function (options, cb) {
|
||||||
inst.trigger('save', function (saveDone) {
|
inst.trigger('save', function (saveDone) {
|
||||||
inst.trigger('update', function (updateDone) {
|
inst.trigger('update', function (updateDone) {
|
||||||
data = removeUndefined(data);
|
data = removeUndefined(data);
|
||||||
inst._adapter().save(modelName, inst.constructor._forDB(data), function (err) {
|
inst._adapter().save(modelName, inst.constructor._forDB(data), function (err, data, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return cb(err, inst);
|
return cb(err, inst);
|
||||||
}
|
}
|
||||||
inst._initProperties(data, { persisted: true });
|
inst._initProperties(data, { persisted: true });
|
||||||
var context = { Model: Model, instance: inst, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: inst,
|
||||||
|
isNewInstance: result && result.isNewInstance,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('after save', context, function(err) {
|
Model.notifyObserversOf('after save', context, function(err) {
|
||||||
if (err) return cb(err, inst);
|
if (err) return cb(err, inst);
|
||||||
updateDone.call(inst, function () {
|
updateDone.call(inst, function () {
|
||||||
|
@ -1959,7 +1989,12 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
|
||||||
done.call(inst, function () {
|
done.call(inst, function () {
|
||||||
saveDone.call(inst, function () {
|
saveDone.call(inst, function () {
|
||||||
if (err) return cb(err, inst);
|
if (err) return cb(err, inst);
|
||||||
var context = { Model: Model, instance: inst, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: inst,
|
||||||
|
isNewInstance: false,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('after save', context, function(err) {
|
Model.notifyObserversOf('after save', context, function(err) {
|
||||||
if(!err) Model.emit('changed', inst);
|
if(!err) Model.emit('changed', inst);
|
||||||
cb(err, inst);
|
cb(err, inst);
|
||||||
|
|
|
@ -116,11 +116,14 @@ module.exports = function(dataSource, should) {
|
||||||
|
|
||||||
TestModel.create({ name: 'created' }, function(err, instance) {
|
TestModel.create({ name: 'created' }, function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: instance.id,
|
instance: {
|
||||||
name: 'created',
|
id: instance.id,
|
||||||
extra: undefined
|
name: 'created',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: true
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -161,10 +164,12 @@ module.exports = function(dataSource, should) {
|
||||||
});
|
});
|
||||||
observedContexts.should.eql([
|
observedContexts.should.eql([
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
instance: { id: list[0].id, name: '1', extra: undefined }
|
instance: { id: list[0].id, name: '1', extra: undefined },
|
||||||
|
isNewInstance: true
|
||||||
}),
|
}),
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
instance: { id: list[1].id, name: '2', extra: undefined }
|
instance: { id: list[1].id, name: '2', extra: undefined },
|
||||||
|
isNewInstance: true
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
done();
|
done();
|
||||||
|
@ -186,11 +191,14 @@ module.exports = function(dataSource, should) {
|
||||||
|
|
||||||
TestModel.create({ name: 'created' }, function(err, instance) {
|
TestModel.create({ name: 'created' }, function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: instance.id,
|
instance: {
|
||||||
name: 'created',
|
id: instance.id,
|
||||||
extra: undefined
|
name: 'created',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: true
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -231,10 +239,12 @@ module.exports = function(dataSource, should) {
|
||||||
});
|
});
|
||||||
observedContexts.should.eql([
|
observedContexts.should.eql([
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
instance: { id: list[0].id, name: '1', extra: undefined }
|
instance: { id: list[0].id, name: '1', extra: undefined },
|
||||||
|
isNewInstance: true
|
||||||
}),
|
}),
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
instance: { id: list[1].id, name: '2', extra: undefined }
|
instance: { id: list[1].id, name: '2', extra: undefined },
|
||||||
|
isNewInstance: true
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
done();
|
done();
|
||||||
|
@ -263,7 +273,8 @@ module.exports = function(dataSource, should) {
|
||||||
list.map(get('name')).should.eql(['ok', 'fail']);
|
list.map(get('name')).should.eql(['ok', 'fail']);
|
||||||
|
|
||||||
observedContexts.should.eql(aTestModelCtx({
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
instance: { id: list[0].id, name: 'ok', extra: undefined }
|
instance: { id: list[0].id, name: 'ok', extra: undefined },
|
||||||
|
isNewInstance: true
|
||||||
}));
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -299,11 +310,14 @@ module.exports = function(dataSource, should) {
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
record.id.should.eql(existingInstance.id);
|
record.id.should.eql(existingInstance.id);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: getLastGeneratedUid(),
|
instance: {
|
||||||
name: existingInstance.name,
|
id: getLastGeneratedUid(),
|
||||||
extra: undefined
|
name: existingInstance.name,
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: true
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -317,11 +331,14 @@ module.exports = function(dataSource, should) {
|
||||||
{ name: 'new-record' },
|
{ name: 'new-record' },
|
||||||
function(err, record, created) {
|
function(err, record, created) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: record.id,
|
instance: {
|
||||||
name: 'new-record',
|
id: record.id,
|
||||||
extra: undefined
|
name: 'new-record',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: true
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -393,11 +410,14 @@ module.exports = function(dataSource, should) {
|
||||||
{ name: 'new name' },
|
{ name: 'new name' },
|
||||||
function(err, instance) {
|
function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: instance.id,
|
instance: {
|
||||||
name: 'new name',
|
id: instance.id,
|
||||||
extra: undefined
|
name: 'new name',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: true
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -492,17 +512,38 @@ module.exports = function(dataSource, should) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('triggers `after save` hook', function(done) {
|
it('triggers `after save` hook on update', function(done) {
|
||||||
TestModel.observe('after save', pushContextAndNext());
|
TestModel.observe('after save', pushContextAndNext());
|
||||||
|
|
||||||
existingInstance.name = 'changed';
|
existingInstance.name = 'changed';
|
||||||
existingInstance.save(function(err, instance) {
|
existingInstance.save(function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: existingInstance.id,
|
instance: {
|
||||||
name: 'changed',
|
id: existingInstance.id,
|
||||||
extra: undefined
|
name: 'changed',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: false
|
||||||
|
}));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('triggers `after save` hook on create', function(done) {
|
||||||
|
TestModel.observe('after save', pushContextAndNext());
|
||||||
|
|
||||||
|
var instance = new TestModel({ name: 'created' });
|
||||||
|
instance.save(function(err, instance) {
|
||||||
|
if (err) return done(err);
|
||||||
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
|
instance: {
|
||||||
|
id: instance.id,
|
||||||
|
name: 'created',
|
||||||
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: true
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -597,11 +638,14 @@ module.exports = function(dataSource, should) {
|
||||||
existingInstance.name = 'changed';
|
existingInstance.name = 'changed';
|
||||||
existingInstance.updateAttributes({ name: 'changed' }, function(err) {
|
existingInstance.updateAttributes({ name: 'changed' }, function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: existingInstance.id,
|
instance: {
|
||||||
name: 'changed',
|
id: existingInstance.id,
|
||||||
extra: undefined
|
name: 'changed',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: false
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -781,7 +825,8 @@ module.exports = function(dataSource, should) {
|
||||||
// The default unoptimized implementation runs
|
// The default unoptimized implementation runs
|
||||||
// `instance.save` and thus a full instance is availalbe
|
// `instance.save` and thus a full instance is availalbe
|
||||||
observedContexts.should.eql(aTestModelCtx({
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
instance: { id: 'new-id', name: 'a name', extra: undefined }
|
instance: { id: 'new-id', name: 'a name', extra: undefined },
|
||||||
|
isNewInstance: true
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -859,11 +904,14 @@ module.exports = function(dataSource, should) {
|
||||||
{ id: existingInstance.id, name: 'updated name' },
|
{ id: existingInstance.id, name: 'updated name' },
|
||||||
function(err, instance) {
|
function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: existingInstance.id,
|
instance: {
|
||||||
name: 'updated name',
|
id: existingInstance.id,
|
||||||
extra: undefined
|
name: 'updated name',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: false
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -875,11 +923,14 @@ module.exports = function(dataSource, should) {
|
||||||
{ id: 'new-id', name: 'a name' },
|
{ id: 'new-id', name: 'a name' },
|
||||||
function(err, instance) {
|
function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({ instance: {
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
id: instance.id,
|
instance: {
|
||||||
name: 'a name',
|
id: instance.id,
|
||||||
extra: undefined
|
name: 'a name',
|
||||||
}}));
|
extra: undefined
|
||||||
|
},
|
||||||
|
isNewInstance: true
|
||||||
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1126,12 +1177,12 @@ module.exports = function(dataSource, should) {
|
||||||
existingInstance.delete(function(err) {
|
existingInstance.delete(function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql([
|
observedContexts.should.eql([
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
hookState: { foo: 'bar', test: true },
|
hookState: { foo: 'bar', test: true },
|
||||||
where: { id: '1' },
|
where: { id: '1' },
|
||||||
instance: existingInstance
|
instance: existingInstance
|
||||||
}),
|
}),
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
hookState: { foo: 'BAR', test: true },
|
hookState: { foo: 'BAR', test: true },
|
||||||
where: { id: '1' },
|
where: { id: '1' },
|
||||||
instance: existingInstance
|
instance: existingInstance
|
||||||
|
|
Loading…
Reference in New Issue