Merge pull request #1140 from strongloop/feature/guids-for-replicated-models
Guids for replicated models
This commit is contained in:
commit
d24da8c37d
|
@ -7,6 +7,7 @@ var registry = require('./registry');
|
||||||
var runtime = require('./runtime');
|
var runtime = require('./runtime');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
var deprecated = require('depd')('loopback');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends Model with basic query and CRUD support.
|
* Extends Model with basic query and CRUD support.
|
||||||
|
@ -1041,6 +1042,15 @@ PersistedModel.enableChangeTracking = function() {
|
||||||
assert(this.dataSource, 'Cannot enableChangeTracking(): ' + this.modelName +
|
assert(this.dataSource, 'Cannot enableChangeTracking(): ' + this.modelName +
|
||||||
' is not attached to a dataSource');
|
' is not attached to a dataSource');
|
||||||
|
|
||||||
|
var idName = this.getIdName();
|
||||||
|
var idProp = this.definition.properties[idName];
|
||||||
|
var idType = idProp && idProp.type;
|
||||||
|
var idDefn = idProp && idProp.defaultFn;
|
||||||
|
if (idType !== String || !(idDefn === 'uuid' || idDefn === 'guid')) {
|
||||||
|
deprecated('The model ' + this.modelName + ' is tracking changes, ' +
|
||||||
|
'which requries a string id with GUID/UUID default value.');
|
||||||
|
}
|
||||||
|
|
||||||
Change.attachTo(this.dataSource);
|
Change.attachTo(this.dataSource);
|
||||||
Change.getCheckpointModel().attachTo(this.dataSource);
|
Change.getCheckpointModel().attachTo(this.dataSource);
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"canonical-json": "0.0.4",
|
"canonical-json": "0.0.4",
|
||||||
"continuation-local-storage": "~3.1.1",
|
"continuation-local-storage": "~3.1.1",
|
||||||
"debug": "~2.0.0",
|
"debug": "~2.0.0",
|
||||||
|
"depd": "^1.0.0",
|
||||||
"ejs": "~1.0.0",
|
"ejs": "~1.0.0",
|
||||||
"express": "^4.10.2",
|
"express": "^4.10.2",
|
||||||
"inflection": "~1.4.2",
|
"inflection": "~1.4.2",
|
||||||
|
@ -52,7 +53,7 @@
|
||||||
"underscore.string": "~2.3.3"
|
"underscore.string": "~2.3.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"loopback-datasource-juggler": "^2.17.0"
|
"loopback-datasource-juggler": "^2.19.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"browserify": "~4.2.3",
|
"browserify": "~4.2.3",
|
||||||
|
@ -79,7 +80,7 @@
|
||||||
"karma-phantomjs-launcher": "~0.1.4",
|
"karma-phantomjs-launcher": "~0.1.4",
|
||||||
"karma-script-launcher": "~0.1.0",
|
"karma-script-launcher": "~0.1.0",
|
||||||
"loopback-boot": "^1.1.0",
|
"loopback-boot": "^1.1.0",
|
||||||
"loopback-datasource-juggler": "^2.17.0",
|
"loopback-datasource-juggler": "^2.19.0",
|
||||||
"loopback-testing": "~0.2.0",
|
"loopback-testing": "~0.2.0",
|
||||||
"mocha": "~1.21.4",
|
"mocha": "~1.21.4",
|
||||||
"strong-task-emitter": "0.0.x",
|
"strong-task-emitter": "0.0.x",
|
||||||
|
@ -94,6 +95,7 @@
|
||||||
"./lib/server-app.js": "./lib/browser-express.js",
|
"./lib/server-app.js": "./lib/browser-express.js",
|
||||||
"connect": false,
|
"connect": false,
|
||||||
"nodemailer": false,
|
"nodemailer": false,
|
||||||
|
"depd": "loopback-datasource-juggler/lib/browser.depd.js",
|
||||||
"bcrypt": false
|
"bcrypt": false
|
||||||
},
|
},
|
||||||
"license": {
|
"license": {
|
||||||
|
|
|
@ -6,9 +6,13 @@ describe('Change', function() {
|
||||||
var memory = loopback.createDataSource({
|
var memory = loopback.createDataSource({
|
||||||
connector: loopback.Memory
|
connector: loopback.Memory
|
||||||
});
|
});
|
||||||
TestModel = loopback.PersistedModel.extend('chtest', {}, {
|
TestModel = loopback.PersistedModel.extend('ChangeTestModel',
|
||||||
trackChanges: true
|
{
|
||||||
});
|
id: { id: true, type: 'string', defaultFn: 'guid' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
trackChanges: true
|
||||||
|
});
|
||||||
this.modelName = TestModel.modelName;
|
this.modelName = TestModel.modelName;
|
||||||
TestModel.attachTo(memory);
|
TestModel.attachTo(memory);
|
||||||
Change = TestModel.getChangeModel();
|
Change = TestModel.getChangeModel();
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('Model / PersistedModel', function() {
|
||||||
|
|
||||||
describe('Model.validatesUniquenessOf(property, options)', function() {
|
describe('Model.validatesUniquenessOf(property, options)', function() {
|
||||||
it('Ensure the value for `property` is unique', function(done) {
|
it('Ensure the value for `property` is unique', function(done) {
|
||||||
var User = PersistedModel.extend('user', {
|
var User = PersistedModel.extend('ValidatedUser', {
|
||||||
'first': String,
|
'first': String,
|
||||||
'last': String,
|
'last': String,
|
||||||
'age': Number,
|
'age': Number,
|
||||||
|
@ -72,6 +72,7 @@ describe.onServer('Remote Methods', function() {
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
User = PersistedModel.extend('user', {
|
User = PersistedModel.extend('user', {
|
||||||
|
id: { id: true, type: String, defaultFn: 'guid' },
|
||||||
'first': String,
|
'first': String,
|
||||||
'last': String,
|
'last': String,
|
||||||
'age': Number,
|
'age': Number,
|
||||||
|
@ -489,10 +490,10 @@ describe.onServer('Remote Methods', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('PersistelModel remote methods', function() {
|
describe('PersistedModel remote methods', function() {
|
||||||
it('includes all aliases', function() {
|
it('includes all aliases', function() {
|
||||||
var app = loopback();
|
var app = loopback();
|
||||||
var model = PersistedModel.extend('persistedModel');
|
var model = PersistedModel.extend('PersistedModelForAliases');
|
||||||
app.dataSource('db', { connector: 'memory' });
|
app.dataSource('db', { connector: 'memory' });
|
||||||
app.model(model, { dataSource: 'db' });
|
app.model(model, { dataSource: 'db' });
|
||||||
|
|
||||||
|
@ -500,7 +501,7 @@ describe.onServer('Remote Methods', function() {
|
||||||
var metadata = app.handler('rest')
|
var metadata = app.handler('rest')
|
||||||
.adapter
|
.adapter
|
||||||
.getClasses()
|
.getClasses()
|
||||||
.filter(function(c) { return c.name === 'persistedModel'; })[0];
|
.filter(function(c) { return c.name === model.modelName; })[0];
|
||||||
|
|
||||||
var methodNames = [];
|
var methodNames = [];
|
||||||
metadata.methods.forEach(function(method) {
|
metadata.methods.forEach(function(method) {
|
||||||
|
@ -509,7 +510,11 @@ describe.onServer('Remote Methods', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(methodNames).to.have.members([
|
expect(methodNames).to.have.members([
|
||||||
'destroyAll', 'deleteAll', 'remove',
|
// NOTE(bajtos) These three methods are disabled by default
|
||||||
|
// Because all tests share the same global registry model
|
||||||
|
// and one of the tests was enabling remoting of "destroyAll",
|
||||||
|
// this test was seeing this method (with all aliases) as public
|
||||||
|
// 'destroyAll', 'deleteAll', 'remove',
|
||||||
'create',
|
'create',
|
||||||
'upsert', 'updateOrCreate',
|
'upsert', 'updateOrCreate',
|
||||||
'exists',
|
'exists',
|
||||||
|
|
|
@ -20,7 +20,8 @@ describe('RemoteConnector', function() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onDefine: function(Model) {
|
onDefine: function(Model) {
|
||||||
var RemoteModel = Model.extend(Model.modelName);
|
var RemoteModel = Model.extend('Remote' + Model.modelName, {},
|
||||||
|
{ plural: Model.pluralModelName });
|
||||||
RemoteModel.attachTo(loopback.createDataSource({
|
RemoteModel.attachTo(loopback.createDataSource({
|
||||||
connector: loopback.Memory
|
connector: loopback.Memory
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -14,14 +14,16 @@ describe('Replication / Change APIs', function() {
|
||||||
dataSource = this.dataSource = loopback.createDataSource({
|
dataSource = this.dataSource = loopback.createDataSource({
|
||||||
connector: loopback.Memory
|
connector: loopback.Memory
|
||||||
});
|
});
|
||||||
SourceModel = this.SourceModel = PersistedModel.extend('SourceModel', {}, {
|
SourceModel = this.SourceModel = PersistedModel.extend('SourceModel',
|
||||||
trackChanges: true
|
{ id: { id: true, type: String, defaultFn: 'guid' } },
|
||||||
});
|
{ trackChanges: true });
|
||||||
|
|
||||||
SourceModel.attachTo(dataSource);
|
SourceModel.attachTo(dataSource);
|
||||||
|
|
||||||
TargetModel = this.TargetModel = PersistedModel.extend('TargetModel', {}, {
|
TargetModel = this.TargetModel = PersistedModel.extend('TargetModel',
|
||||||
trackChanges: true
|
{ id: { id: true, type: String, defaultFn: 'guid' } },
|
||||||
});
|
{ trackChanges: true });
|
||||||
|
|
||||||
TargetModel.attachTo(dataSource);
|
TargetModel.attachTo(dataSource);
|
||||||
|
|
||||||
test.startingCheckpoint = -1;
|
test.startingCheckpoint = -1;
|
||||||
|
@ -169,11 +171,11 @@ describe('Replication / Change APIs', function() {
|
||||||
var test = this;
|
var test = this;
|
||||||
this.conflict.models(function(err, source, target) {
|
this.conflict.models(function(err, source, target) {
|
||||||
assert.deepEqual(source.toJSON(), {
|
assert.deepEqual(source.toJSON(), {
|
||||||
id: 1,
|
id: test.model.id,
|
||||||
name: 'source update'
|
name: 'source update'
|
||||||
});
|
});
|
||||||
assert.deepEqual(target.toJSON(), {
|
assert.deepEqual(target.toJSON(), {
|
||||||
id: 1,
|
id: test.model.id,
|
||||||
name: 'target update'
|
name: 'target update'
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
|
@ -242,7 +244,7 @@ describe('Replication / Change APIs', function() {
|
||||||
this.conflict.models(function(err, source, target) {
|
this.conflict.models(function(err, source, target) {
|
||||||
assert.equal(source, null);
|
assert.equal(source, null);
|
||||||
assert.deepEqual(target.toJSON(), {
|
assert.deepEqual(target.toJSON(), {
|
||||||
id: 1,
|
id: test.model.id,
|
||||||
name: 'target update'
|
name: 'target update'
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
|
@ -311,7 +313,7 @@ describe('Replication / Change APIs', function() {
|
||||||
this.conflict.models(function(err, source, target) {
|
this.conflict.models(function(err, source, target) {
|
||||||
assert.equal(target, null);
|
assert.equal(target, null);
|
||||||
assert.deepEqual(source.toJSON(), {
|
assert.deepEqual(source.toJSON(), {
|
||||||
id: 1,
|
id: test.model.id,
|
||||||
name: 'source update'
|
name: 'source update'
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -36,7 +36,8 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
||||||
return extendedModel;
|
return extendedModel;
|
||||||
};
|
};
|
||||||
|
|
||||||
User = PersistedModel.extend('user', {
|
User = PersistedModel.extend('UtilUser', {
|
||||||
|
id: { id: true, type: String, defaultFn: 'guid' },
|
||||||
'first': String,
|
'first': String,
|
||||||
'last': String,
|
'last': String,
|
||||||
'age': Number,
|
'age': Number,
|
||||||
|
@ -48,8 +49,6 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
||||||
trackChanges: true
|
trackChanges: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// enable destroy all for testing
|
|
||||||
User.destroyAll.shared = true;
|
|
||||||
User.attachTo(dataSource);
|
User.attachTo(dataSource);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -187,10 +186,13 @@ module.exports = function defineModelTestsWithDataSource(options) {
|
||||||
it('Remove a model from the attached data source', function(done) {
|
it('Remove a model from the attached data source', function(done) {
|
||||||
User.create({first: 'joe', last: 'bob'}, function(err, user) {
|
User.create({first: 'joe', last: 'bob'}, function(err, user) {
|
||||||
User.findById(user.id, function(err, foundUser) {
|
User.findById(user.id, function(err, foundUser) {
|
||||||
|
if (err) return done(err);
|
||||||
assert.equal(user.id, foundUser.id);
|
assert.equal(user.id, foundUser.id);
|
||||||
foundUser.destroy(function() {
|
User.deleteById(foundUser.id, function(err) {
|
||||||
User.findById(user.id, function(err, notFound) {
|
if (err) return done(err);
|
||||||
assert.equal(notFound, null);
|
User.find({ where: { id: user.id } }, function(err, found) {
|
||||||
|
if (err) return done(err);
|
||||||
|
assert.equal(found.length, 0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue