2016-04-01 22:25:16 +00:00
|
|
|
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
|
|
|
|
// Node module: loopback-datasource-juggler
|
|
|
|
// This file is licensed under the MIT License.
|
|
|
|
// License text available at https://opensource.org/licenses/MIT
|
|
|
|
|
2013-04-06 10:57:12 +00:00
|
|
|
// This test written in mocha+should.js
|
2016-08-22 19:55:22 +00:00
|
|
|
'use strict';
|
2016-12-05 14:14:09 +00:00
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
/* global getSchema:false, connectorCapabilities:false */
|
2018-12-07 14:54:29 +00:00
|
|
|
const async = require('async');
|
|
|
|
const bdd = require('./helpers/bdd-if');
|
|
|
|
const should = require('./init.js');
|
|
|
|
const uid = require('./helpers/uid-generator');
|
2013-04-06 10:57:12 +00:00
|
|
|
|
2018-12-07 14:54:29 +00:00
|
|
|
let db, Person;
|
|
|
|
const ValidationError = require('..').ValidationError;
|
2013-03-26 19:33:11 +00:00
|
|
|
|
2018-12-07 14:54:29 +00:00
|
|
|
const UUID_REGEXP = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
2015-02-20 10:18:47 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
describe('manipulation', function() {
|
|
|
|
before(function(done) {
|
2014-01-24 17:09:53 +00:00
|
|
|
db = getSchema();
|
|
|
|
|
|
|
|
Person = db.define('Person', {
|
|
|
|
name: String,
|
|
|
|
gender: String,
|
|
|
|
married: Boolean,
|
2016-08-19 17:46:59 +00:00
|
|
|
age: {type: Number, index: true},
|
2014-01-24 17:09:53 +00:00
|
|
|
dob: Date,
|
2016-08-19 17:46:59 +00:00
|
|
|
createdAt: {type: Date, default: Date},
|
|
|
|
}, {forceId: true, strict: true});
|
2013-03-26 19:33:11 +00:00
|
|
|
|
2015-08-27 22:59:58 +00:00
|
|
|
db.automigrate(['Person'], done);
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
|
2015-01-30 10:01:48 +00:00
|
|
|
// A simplified implementation of LoopBack's User model
|
|
|
|
// to reproduce problems related to properties with dynamic setters
|
|
|
|
// For the purpose of the tests, we use a counter instead of a hash fn.
|
2018-12-07 14:54:29 +00:00
|
|
|
let StubUser;
|
|
|
|
let stubPasswordCounter;
|
2016-08-22 19:55:22 +00:00
|
|
|
|
2015-01-30 10:01:48 +00:00
|
|
|
before(function setupStubUserModel(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
StubUser = db.createModel('StubUser', {password: String}, {forceId: true});
|
2015-01-30 10:01:48 +00:00
|
|
|
StubUser.setter.password = function(plain) {
|
2017-07-24 04:58:35 +00:00
|
|
|
if (plain.length === 0) throw new Error('password cannot be empty');
|
2018-12-07 14:54:29 +00:00
|
|
|
let hashed = false;
|
2016-04-06 17:14:56 +00:00
|
|
|
if (!plain) return;
|
2018-12-07 14:54:29 +00:00
|
|
|
const pos = plain.indexOf('-');
|
2016-04-06 17:14:56 +00:00
|
|
|
if (pos !== -1) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const head = plain.substr(0, pos);
|
|
|
|
const tail = plain.substr(pos + 1, plain.length);
|
2016-04-06 17:14:56 +00:00
|
|
|
hashed = head.toUpperCase() === tail;
|
|
|
|
}
|
|
|
|
if (hashed) return;
|
2015-02-21 00:10:25 +00:00
|
|
|
this.$password = plain + '-' + plain.toUpperCase();
|
2015-01-30 10:01:48 +00:00
|
|
|
};
|
|
|
|
db.automigrate('StubUser', done);
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function resetStubPasswordCounter() {
|
|
|
|
stubPasswordCounter = 0;
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
describe('create', function() {
|
|
|
|
before(function(done) {
|
2014-01-24 17:09:53 +00:00
|
|
|
Person.destroyAll(done);
|
|
|
|
});
|
2013-03-30 17:06:09 +00:00
|
|
|
|
2016-06-17 22:17:20 +00:00
|
|
|
describe('forceId', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let TestForceId;
|
2016-06-17 22:17:20 +00:00
|
|
|
before(function(done) {
|
|
|
|
TestForceId = db.define('TestForceId');
|
|
|
|
db.automigrate('TestForceId', done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('it defaults to forceId:true for generated id property', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
TestForceId.create({id: 1}, function(err, t) {
|
2016-06-17 22:17:20 +00:00
|
|
|
should.exist(err);
|
|
|
|
err.message.should.match(/can\'t be set/);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should create instance', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.create({name: 'Anatoliy'}, function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
should.exist(p);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.name.should.equal('Anatoliy');
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.findById(p.id, function(err, person) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2015-02-04 18:20:56 +00:00
|
|
|
person.id.should.eql(p.id);
|
2014-01-24 17:09:53 +00:00
|
|
|
person.name.should.equal('Anatoliy');
|
|
|
|
done();
|
2013-03-26 19:33:11 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
|
|
|
});
|
2015-01-30 10:01:48 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should create instance (promise variant)', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.create({name: 'Anatoliy'})
|
2017-01-06 12:33:54 +00:00
|
|
|
.then(function(p) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
p.name.should.equal('Anatoliy');
|
|
|
|
should.exist(p);
|
|
|
|
return Person.findById(p.id)
|
2017-01-06 12:33:54 +00:00
|
|
|
.then(function(person) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
person.id.should.eql(p.id);
|
|
|
|
person.name.should.equal('Anatoliy');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should instantiate an object', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = new Person({name: 'Anatoliy'});
|
2014-09-05 15:09:23 +00:00
|
|
|
p.name.should.equal('Anatoliy');
|
|
|
|
p.isNewRecord().should.be.true;
|
|
|
|
p.save(function(err, inst) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-09-05 15:09:23 +00:00
|
|
|
inst.isNewRecord().should.be.false;
|
|
|
|
inst.should.equal(p);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should instantiate an object (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = new Person({name: 'Anatoliy'});
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
p.name.should.equal('Anatoliy');
|
|
|
|
p.isNewRecord().should.be.true;
|
|
|
|
p.save()
|
2017-01-06 12:33:54 +00:00
|
|
|
.then(function(inst) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
inst.isNewRecord().should.be.false;
|
|
|
|
inst.should.equal(p);
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2016-04-29 07:08:15 +00:00
|
|
|
it('should not return instance of object', function(done) {
|
2018-12-07 15:22:36 +00:00
|
|
|
const person = Person.create(function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-04-29 07:08:15 +00:00
|
|
|
should.exist(p.id);
|
|
|
|
if (person) person.should.not.be.an.instanceOf(Person);
|
2014-01-24 17:09:53 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-01-30 10:01:48 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should not allow user-defined value for the id of object - create', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.create({id: 123456}, function(err, p) {
|
2014-09-05 14:35:01 +00:00
|
|
|
err.should.be.instanceof(ValidationError);
|
|
|
|
err.statusCode.should.equal(422);
|
2015-01-12 13:52:54 +00:00
|
|
|
err.details.messages.id.should.eql(['can\'t be set']);
|
2014-09-05 14:35:01 +00:00
|
|
|
p.should.be.instanceof(Person);
|
2014-09-05 15:09:23 +00:00
|
|
|
p.isNewRecord().should.be.true;
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-01-30 10:01:48 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should not allow user-defined value for the id of object - create (promise variant)', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.create({id: 123456})
|
2017-01-06 12:33:54 +00:00
|
|
|
.then(function(p) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
done(new Error('Person.create should have failed.'));
|
2016-04-01 11:48:17 +00:00
|
|
|
}, function(err) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
err.should.be.instanceof(ValidationError);
|
|
|
|
err.statusCode.should.equal(422);
|
|
|
|
err.details.messages.id.should.eql(['can\'t be set']);
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should not allow user-defined value for the id of object - save', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = new Person({id: 123456});
|
2014-09-05 15:09:23 +00:00
|
|
|
p.isNewRecord().should.be.true;
|
|
|
|
p.save(function(err, inst) {
|
|
|
|
err.should.be.instanceof(ValidationError);
|
|
|
|
err.statusCode.should.equal(422);
|
2015-01-12 13:52:54 +00:00
|
|
|
err.details.messages.id.should.eql(['can\'t be set']);
|
2014-09-05 15:09:23 +00:00
|
|
|
inst.isNewRecord().should.be.true;
|
2014-09-05 14:35:01 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should not allow user-defined value for the id of object - save (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = new Person({id: 123456});
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
p.isNewRecord().should.be.true;
|
|
|
|
p.save()
|
2017-01-06 12:33:54 +00:00
|
|
|
.then(function(inst) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
done(new Error('save should have failed.'));
|
2016-04-01 11:48:17 +00:00
|
|
|
}, function(err) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
err.should.be.instanceof(ValidationError);
|
|
|
|
err.statusCode.should.equal(422);
|
|
|
|
err.details.messages.id.should.eql(['can\'t be set']);
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should work when called without callback', function(done) {
|
|
|
|
Person.afterCreate = function(next) {
|
2014-01-24 17:09:53 +00:00
|
|
|
this.should.be.an.instanceOf(Person);
|
|
|
|
this.name.should.equal('Nickolay');
|
|
|
|
should.exist(this.id);
|
|
|
|
Person.afterCreate = null;
|
|
|
|
next();
|
|
|
|
setTimeout(done, 10);
|
|
|
|
};
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.create({name: 'Nickolay'});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-31 09:40:37 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should create instance with blank data', function(done) {
|
|
|
|
Person.create(function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
should.exist(p);
|
|
|
|
should.not.exists(p.name);
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.findById(p.id, function(err, person) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2015-02-04 18:20:56 +00:00
|
|
|
person.id.should.eql(p.id);
|
2014-01-24 17:09:53 +00:00
|
|
|
should.not.exists(person.name);
|
|
|
|
done();
|
2013-03-31 09:40:37 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should create instance with blank data (promise variant)', function(done) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
Person.create()
|
2017-01-06 12:33:54 +00:00
|
|
|
.then(function(p) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
should.exist(p);
|
|
|
|
should.not.exists(p.name);
|
|
|
|
return Person.findById(p.id)
|
2018-06-12 07:13:32 +00:00
|
|
|
.then(function(person) {
|
|
|
|
person.id.should.eql(p.id);
|
|
|
|
should.not.exists(person.name);
|
|
|
|
done();
|
|
|
|
});
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
}).catch(done);
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should work when called with no data and callback', function(done) {
|
|
|
|
Person.afterCreate = function(next) {
|
2014-01-24 17:09:53 +00:00
|
|
|
this.should.be.an.instanceOf(Person);
|
|
|
|
should.not.exist(this.name);
|
|
|
|
should.exist(this.id);
|
|
|
|
Person.afterCreate = null;
|
|
|
|
next();
|
|
|
|
setTimeout(done, 30);
|
|
|
|
};
|
|
|
|
Person.create();
|
|
|
|
});
|
2013-03-28 11:27:27 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should create batch of objects', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const batch = [
|
2016-08-19 17:46:59 +00:00
|
|
|
{name: 'Shaltay'},
|
|
|
|
{name: 'Boltay'},
|
2016-04-01 11:48:17 +00:00
|
|
|
{},
|
2014-01-24 17:09:53 +00:00
|
|
|
];
|
2018-12-07 15:22:36 +00:00
|
|
|
const res = Person.create(batch, function(e, ps) {
|
2016-04-29 07:08:15 +00:00
|
|
|
if (res) res.should.not.be.instanceOf(Array);
|
2014-01-24 17:09:53 +00:00
|
|
|
should.not.exist(e);
|
|
|
|
should.exist(ps);
|
|
|
|
ps.should.be.instanceOf(Array);
|
|
|
|
ps.should.have.lengthOf(batch.length);
|
|
|
|
|
|
|
|
Person.validatesPresenceOf('name');
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.create(batch, function(errors, persons) {
|
2014-08-26 15:51:01 +00:00
|
|
|
delete Person.validations;
|
2014-01-24 17:09:53 +00:00
|
|
|
should.exist(errors);
|
|
|
|
errors.should.have.lengthOf(batch.length);
|
|
|
|
should.not.exist(errors[0]);
|
2017-05-19 23:16:52 +00:00
|
|
|
should.not.exist(errors[1]);
|
|
|
|
should.exist(errors[2]);
|
|
|
|
|
|
|
|
should.exist(persons);
|
|
|
|
persons.should.have.lengthOf(batch.length);
|
|
|
|
persons[0].errors.should.be.false;
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should create batch of objects (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const batch = [
|
2017-05-19 23:16:52 +00:00
|
|
|
{name: 'ShaltayPromise'},
|
|
|
|
{name: 'BoltayPromise'},
|
|
|
|
{},
|
|
|
|
];
|
|
|
|
Person.create(batch).then(function(ps) {
|
|
|
|
should.exist(ps);
|
|
|
|
ps.should.be.instanceOf(Array);
|
|
|
|
ps.should.have.lengthOf(batch.length);
|
|
|
|
|
|
|
|
Person.validatesPresenceOf('name');
|
|
|
|
Person.create(batch, function(errors, persons) {
|
|
|
|
delete Person.validations;
|
|
|
|
should.exist(errors);
|
|
|
|
errors.should.have.lengthOf(batch.length);
|
|
|
|
should.not.exist(errors[0]);
|
2014-01-24 17:09:53 +00:00
|
|
|
should.not.exist(errors[1]);
|
|
|
|
should.exist(errors[2]);
|
|
|
|
|
|
|
|
should.exist(persons);
|
|
|
|
persons.should.have.lengthOf(batch.length);
|
|
|
|
persons[0].errors.should.be.false;
|
|
|
|
done();
|
2016-04-29 07:08:15 +00:00
|
|
|
});
|
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2015-01-29 19:52:39 +00:00
|
|
|
|
|
|
|
it('should create batch of objects with beforeCreate', function(done) {
|
|
|
|
Person.beforeCreate = function(next, data) {
|
|
|
|
if (data && data.name === 'A') {
|
2016-08-19 17:46:59 +00:00
|
|
|
return next(null, {id: 'a', name: 'A'});
|
2015-01-29 19:52:39 +00:00
|
|
|
} else {
|
|
|
|
return next();
|
|
|
|
}
|
|
|
|
};
|
2018-12-07 14:54:29 +00:00
|
|
|
const batch = [
|
2016-08-19 17:46:59 +00:00
|
|
|
{name: 'A'},
|
|
|
|
{name: 'B'},
|
2016-04-01 11:48:17 +00:00
|
|
|
undefined,
|
2015-01-29 19:52:39 +00:00
|
|
|
];
|
|
|
|
Person.create(batch, function(e, ps) {
|
|
|
|
should.not.exist(e);
|
|
|
|
should.exist(ps);
|
|
|
|
ps.should.be.instanceOf(Array);
|
|
|
|
ps.should.have.lengthOf(batch.length);
|
2016-08-19 17:46:59 +00:00
|
|
|
ps[0].should.be.eql({id: 'a', name: 'A'});
|
2015-01-29 19:52:39 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-02-04 08:08:28 +00:00
|
|
|
|
|
|
|
it('should preserve properties with "undefined" value', function(done) {
|
|
|
|
Person.create(
|
2016-08-19 17:46:59 +00:00
|
|
|
{name: 'a-name', gender: undefined},
|
2015-02-04 08:08:28 +00:00
|
|
|
function(err, created) {
|
|
|
|
if (err) return done(err);
|
|
|
|
created.toObject().should.have.properties({
|
|
|
|
id: created.id,
|
|
|
|
name: 'a-name',
|
2016-04-01 11:48:17 +00:00
|
|
|
gender: undefined,
|
2015-02-04 08:08:28 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
Person.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
2018-12-07 14:54:29 +00:00
|
|
|
const result = found.toObject();
|
2017-04-06 20:04:16 +00:00
|
|
|
result.should.containEql({
|
2015-02-04 08:08:28 +00:00
|
|
|
id: created.id,
|
2016-04-01 11:48:17 +00:00
|
|
|
name: 'a-name',
|
2015-02-04 08:08:28 +00:00
|
|
|
});
|
2015-02-20 17:55:09 +00:00
|
|
|
// The gender can be null from a RDB
|
|
|
|
should.equal(result.gender, null);
|
2015-02-04 08:08:28 +00:00
|
|
|
done();
|
|
|
|
});
|
2018-07-16 06:46:25 +00:00
|
|
|
}
|
|
|
|
);
|
2015-02-04 08:08:28 +00:00
|
|
|
});
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
bdd.itIf(connectorCapabilities.refuseDuplicateInsert !== false, 'should refuse to create ' +
|
|
|
|
'object with duplicate id', function(done) {
|
2015-03-16 10:26:57 +00:00
|
|
|
// NOTE(bajtos) We cannot reuse Person model here,
|
|
|
|
// `settings.forceId` aborts the CREATE request at the validation step.
|
2018-12-07 14:54:29 +00:00
|
|
|
const Product = db.define('ProductTest', {name: String}, {forceId: false});
|
2015-08-27 22:59:58 +00:00
|
|
|
db.automigrate('ProductTest', function(err) {
|
2015-03-16 10:26:57 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
Product.create({name: 'a-name'}, function(err, p) {
|
2015-03-16 10:26:57 +00:00
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
Product.create({id: p.id, name: 'duplicate'}, function(err, result) {
|
2015-03-16 10:26:57 +00:00
|
|
|
if (!err) {
|
|
|
|
return done(new Error('Create should have rejected duplicate id.'));
|
|
|
|
}
|
|
|
|
err.message.should.match(/duplicate/i);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-28 11:27:27 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
describe('save', function() {
|
|
|
|
it('should save new object', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = new Person;
|
2017-04-06 20:04:16 +00:00
|
|
|
should.not.exist(p.id);
|
2016-04-01 11:48:17 +00:00
|
|
|
p.save(function(err) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
should.exist(p.id);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2013-03-28 11:27:27 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should save new object (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = new Person;
|
2017-04-06 20:04:16 +00:00
|
|
|
should.not.exist(p.id);
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
p.save()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function() {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
should.exist(p.id);
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2017-07-18 19:20:21 +00:00
|
|
|
bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
|
|
|
'should save existing object', function(done) {
|
2017-07-11 18:56:39 +00:00
|
|
|
// Cloudant could not guarantee findOne always return the same item
|
2017-07-18 19:20:21 +00:00
|
|
|
Person.findOne(function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2017-07-18 19:20:21 +00:00
|
|
|
p.name = 'Hans';
|
|
|
|
p.save(function(err) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
p.name.should.equal('Hans');
|
2017-07-18 19:20:21 +00:00
|
|
|
Person.findOne(function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.name.should.equal('Hans');
|
|
|
|
done();
|
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-28 11:27:27 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-28 11:27:27 +00:00
|
|
|
|
2017-07-18 19:20:21 +00:00
|
|
|
bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
|
|
|
'should save existing object (promise variant)', function(done) {
|
2017-07-11 18:56:39 +00:00
|
|
|
// Cloudant could not guarantee findOne always return the same item
|
2017-07-18 19:20:21 +00:00
|
|
|
Person.findOne()
|
|
|
|
.then(function(p) {
|
|
|
|
p.name = 'Fritz';
|
|
|
|
return p.save()
|
|
|
|
.then(function() {
|
|
|
|
return Person.findOne()
|
|
|
|
.then(function(p) {
|
|
|
|
p.name.should.equal('Fritz');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should save invalid object (skipping validation)', function(done) {
|
|
|
|
Person.findOne(function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-04-01 11:48:17 +00:00
|
|
|
p.isValid = function(done) {
|
2014-01-24 17:09:53 +00:00
|
|
|
process.nextTick(done);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
p.name = 'Nana';
|
2016-04-01 11:48:17 +00:00
|
|
|
p.save(function(err) {
|
2014-01-24 17:09:53 +00:00
|
|
|
should.exist(err);
|
2016-08-19 17:46:59 +00:00
|
|
|
p.save({validate: false}, function(err) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
done();
|
|
|
|
});
|
2013-03-28 11:27:27 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
|
|
|
});
|
2013-03-30 17:07:16 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should save invalid object (skipping validation - promise variant)', function(done) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
Person.findOne()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
|
|
|
p.isValid = function(done) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
process.nextTick(done);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
p.name = 'Nana';
|
|
|
|
return p.save()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(d) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
done(new Error('save should have failed.'));
|
2016-04-01 11:48:17 +00:00
|
|
|
}, function(err) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
should.exist(err);
|
2016-08-19 17:46:59 +00:00
|
|
|
p.save({validate: false})
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(d) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
should.exist(d);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2016-12-05 14:14:09 +00:00
|
|
|
it('should save throw error on validation', function(done) {
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.findOne(function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-04-01 11:48:17 +00:00
|
|
|
p.isValid = function(cb) {
|
2014-01-24 17:09:53 +00:00
|
|
|
cb(false);
|
|
|
|
return false;
|
|
|
|
};
|
2016-04-01 11:48:17 +00:00
|
|
|
(function() {
|
2014-01-24 17:09:53 +00:00
|
|
|
p.save({
|
2016-04-01 11:48:17 +00:00
|
|
|
'throws': true,
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
|
|
|
}).should.throw(ValidationError);
|
2016-12-05 14:14:09 +00:00
|
|
|
done();
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-30 17:07:16 +00:00
|
|
|
});
|
|
|
|
|
2015-01-30 10:01:48 +00:00
|
|
|
it('should preserve properties with dynamic setters', function(done) {
|
|
|
|
// This test reproduces a problem discovered by LoopBack unit-test
|
|
|
|
// "User.hasPassword() should match a password after it is changed"
|
2016-08-19 17:46:59 +00:00
|
|
|
StubUser.create({password: 'foo'}, function(err, created) {
|
2015-01-30 10:01:48 +00:00
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
created.password.should.equal('foo-FOO');
|
2015-01-30 10:01:48 +00:00
|
|
|
created.password = 'bar';
|
|
|
|
created.save(function(err, saved) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
created.id.should.eql(saved.id);
|
2015-02-21 00:10:25 +00:00
|
|
|
saved.password.should.equal('bar-BAR');
|
2015-01-30 10:01:48 +00:00
|
|
|
StubUser.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
created.id.should.eql(found.id);
|
2015-02-21 00:10:25 +00:00
|
|
|
found.password.should.equal('bar-BAR');
|
2015-01-30 10:01:48 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-30 17:07:16 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
describe('updateAttributes', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let person;
|
2013-03-30 17:07:16 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
before(function(done) {
|
2017-04-06 20:04:16 +00:00
|
|
|
Person.destroyAll(function(err) {
|
|
|
|
if (err) return done(err);
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.create({name: 'Mary', age: 15}, function(err, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (err) return done(err);
|
2015-03-16 16:25:38 +00:00
|
|
|
person = p;
|
|
|
|
done();
|
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
});
|
|
|
|
|
2016-04-06 17:14:56 +00:00
|
|
|
it('should have updated password hashed with updateAttribute',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
StubUser.create({password: 'foo'}, function(err, created) {
|
2016-04-06 17:14:56 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
created.updateAttribute('password', 'test', function(err, created) {
|
2016-04-06 17:14:56 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
created.password.should.equal('test-TEST');
|
|
|
|
StubUser.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
|
|
|
found.password.should.equal('test-TEST');
|
|
|
|
done();
|
|
|
|
});
|
2016-04-06 17:14:56 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-07-24 04:58:35 +00:00
|
|
|
it('should reject created StubUser with empty password', function(done) {
|
|
|
|
StubUser.create({email: 'b@example.com', password: ''}, function(err, createdUser) {
|
|
|
|
(err.message).should.match(/password cannot be empty/);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should reject updated empty password with updateAttribute', function(done) {
|
|
|
|
StubUser.create({password: 'abc123'}, function(err, createdUser) {
|
|
|
|
if (err) return done(err);
|
|
|
|
createdUser.updateAttribute('password', '', function(err, updatedUser) {
|
|
|
|
(err.message).should.match(/password cannot be empty/);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2017-08-16 21:00:41 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should update one attribute', function(done) {
|
|
|
|
person.updateAttribute('name', 'Paul Graham', function(err, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (err) return done(err);
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.all(function(e, ps) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (e) return done(e);
|
2014-01-24 17:09:53 +00:00
|
|
|
ps.should.have.lengthOf(1);
|
|
|
|
ps.pop().name.should.equal('Paul Graham');
|
|
|
|
done();
|
2013-03-27 00:51:00 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
|
|
|
});
|
2015-01-30 07:26:11 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should update one attribute (promise variant)', function(done) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
person.updateAttribute('name', 'Teddy Graham')
|
2018-06-12 07:13:32 +00:00
|
|
|
.then(function(p) {
|
|
|
|
return Person.all()
|
|
|
|
.then(function(ps) {
|
|
|
|
ps.should.have.lengthOf(1);
|
|
|
|
ps.pop().name.should.equal('Teddy Graham');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
}).catch(done);
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
});
|
|
|
|
|
2015-01-30 07:26:11 +00:00
|
|
|
it('should ignore undefined values on updateAttributes', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
person.updateAttributes({'name': 'John', age: undefined},
|
2015-01-30 07:26:11 +00:00
|
|
|
function(err, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (err) return done(err);
|
2015-01-30 07:26:11 +00:00
|
|
|
Person.findById(p.id, function(e, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (e) return done(e);
|
2015-01-30 07:26:11 +00:00
|
|
|
p.name.should.equal('John');
|
|
|
|
p.age.should.equal(15);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-03-20 16:49:32 +00:00
|
|
|
|
2017-07-18 19:20:21 +00:00
|
|
|
bdd.itIf(connectorCapabilities.cloudantCompatible !== false,
|
|
|
|
'should discard undefined values before strict validation',
|
2016-09-07 18:24:48 +00:00
|
|
|
function(done) {
|
|
|
|
Person.definition.settings.strict = true;
|
|
|
|
Person.findById(person.id, function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-09-07 18:24:48 +00:00
|
|
|
p.updateAttributes({name: 'John', unknownVar: undefined},
|
|
|
|
function(err, p) {
|
|
|
|
// if uknownVar was defined, it would return validationError
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
person.id.should.eql(p.id);
|
2016-09-07 18:24:48 +00:00
|
|
|
Person.findById(p.id, function(e, p) {
|
|
|
|
if (e) return done(e);
|
|
|
|
p.name.should.equal('John');
|
|
|
|
p.should.not.have.property('unknownVar');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-07-20 09:59:07 +00:00
|
|
|
});
|
2016-09-07 18:24:48 +00:00
|
|
|
});
|
2015-03-20 16:49:32 +00:00
|
|
|
|
2016-09-07 18:24:48 +00:00
|
|
|
it('should allow unknown attributes when strict: false',
|
|
|
|
function(done) {
|
|
|
|
Person.definition.settings.strict = false;
|
|
|
|
Person.findById(person.id, function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-09-07 18:24:48 +00:00
|
|
|
p.updateAttributes({name: 'John', foo: 'bar'},
|
|
|
|
function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.should.have.property('foo');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-08-30 02:57:37 +00:00
|
|
|
it('should remove unknown attributes when strict: filter',
|
|
|
|
function(done) {
|
|
|
|
Person.definition.settings.strict = 'filter';
|
|
|
|
Person.findById(person.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.updateAttributes({name: 'John', foo: 'bar'},
|
|
|
|
function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.should.not.have.property('foo');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-09-07 18:24:48 +00:00
|
|
|
// Prior to version 3.0 `strict: true` used to silently remove unknown properties,
|
|
|
|
// now return validationError upon unknown properties
|
|
|
|
it('should return error on unknown attributes when strict: true',
|
|
|
|
function(done) {
|
|
|
|
// Using {foo: 'bar'} only causes dependent test failures due to the
|
|
|
|
// stripping of object properties when in strict mode (ie. {foo: 'bar'}
|
|
|
|
// changes to '{}' and breaks other tests
|
|
|
|
Person.definition.settings.strict = true;
|
|
|
|
Person.findById(person.id, function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-09-07 18:24:48 +00:00
|
|
|
p.updateAttributes({name: 'John', foo: 'bar'},
|
|
|
|
function(err, p) {
|
|
|
|
should.exist(err);
|
|
|
|
err.name.should.equal('ValidationError');
|
|
|
|
err.message.should.containEql('`foo` is not defined in the model');
|
|
|
|
p.should.not.have.property('foo');
|
|
|
|
Person.findById(p.id, function(e, p) {
|
|
|
|
if (e) return done(e);
|
|
|
|
p.should.not.have.property('foo');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// strict: throw is deprecated, use strict: true instead
|
|
|
|
// which returns Validation Error for unknown properties
|
|
|
|
it('should fallback to strict:true when using strict: throw', function(done) {
|
2015-07-21 11:33:42 +00:00
|
|
|
Person.definition.settings.strict = 'throw';
|
|
|
|
Person.findById(person.id, function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-08-19 17:46:59 +00:00
|
|
|
p.updateAttributes({foo: 'bar'},
|
2015-07-21 11:33:42 +00:00
|
|
|
function(err, p) {
|
|
|
|
should.exist(err);
|
2016-09-07 18:24:48 +00:00
|
|
|
err.name.should.equal('ValidationError');
|
|
|
|
err.message.should.containEql('`foo` is not defined in the model');
|
2015-07-21 11:33:42 +00:00
|
|
|
Person.findById(person.id, function(e, p) {
|
|
|
|
if (e) return done(e);
|
2016-09-07 18:24:48 +00:00
|
|
|
p.should.not.have.property('foo');
|
2015-07-21 11:33:42 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-03-20 16:49:32 +00:00
|
|
|
|
2016-09-07 18:24:48 +00:00
|
|
|
// strict: validate is deprecated, use strict: true instead
|
|
|
|
// behavior remains the same as before, because validate is now default behavior
|
|
|
|
it('should fallback to strict:true when using strict:validate', function(done) {
|
2015-07-21 11:33:42 +00:00
|
|
|
Person.definition.settings.strict = 'validate';
|
|
|
|
Person.findById(person.id, function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-08-19 17:46:59 +00:00
|
|
|
p.updateAttributes({foo: 'bar'},
|
2015-07-21 11:33:42 +00:00
|
|
|
function(err, p) {
|
|
|
|
should.exist(err);
|
|
|
|
err.name.should.equal('ValidationError');
|
|
|
|
err.message.should.containEql('`foo` is not defined in the model');
|
|
|
|
Person.findById(person.id, function(e, p) {
|
|
|
|
if (e) return done(e);
|
2016-09-07 18:24:48 +00:00
|
|
|
p.should.not.have.property('foo');
|
2015-07-21 11:33:42 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-01-30 07:26:11 +00:00
|
|
|
|
2015-03-16 16:25:38 +00:00
|
|
|
it('should allow same id value on updateAttributes', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
person.updateAttributes({id: person.id, name: 'John'},
|
2015-03-16 16:25:38 +00:00
|
|
|
function(err, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (err) return done(err);
|
2015-03-16 16:25:38 +00:00
|
|
|
Person.findById(p.id, function(e, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (e) return done(e);
|
2015-03-16 16:25:38 +00:00
|
|
|
p.name.should.equal('John');
|
|
|
|
p.age.should.equal(15);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-03-20 18:06:24 +00:00
|
|
|
it('should allow same stringified id value on updateAttributes',
|
|
|
|
function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
let pid = person.id;
|
2015-03-20 18:06:24 +00:00
|
|
|
if (typeof person.id === 'object' || typeof person.id === 'number') {
|
|
|
|
// For example MongoDB ObjectId
|
|
|
|
pid = person.id.toString();
|
|
|
|
}
|
2016-08-19 17:46:59 +00:00
|
|
|
person.updateAttributes({id: pid, name: 'John'},
|
2015-03-20 18:06:24 +00:00
|
|
|
function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
Person.findById(p.id, function(e, p) {
|
|
|
|
if (e) return done(e);
|
|
|
|
p.name.should.equal('John');
|
|
|
|
p.age.should.equal(15);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-03-16 16:25:38 +00:00
|
|
|
it('should fail if an id value is to be changed on updateAttributes',
|
|
|
|
function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
person.updateAttributes({id: person.id + 1, name: 'John'},
|
2018-06-12 07:13:32 +00:00
|
|
|
function(err, p) {
|
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2015-03-16 16:25:38 +00:00
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
it('has an alias "patchAttributes"', function(done) {
|
|
|
|
person.updateAttributes.should.equal(person.patchAttributes);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
|
2015-07-20 09:59:07 +00:00
|
|
|
it('should allow model instance on updateAttributes', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
person.updateAttributes(new Person({'name': 'John', age: undefined}),
|
2015-01-30 07:26:11 +00:00
|
|
|
function(err, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (err) return done(err);
|
2015-01-30 07:26:11 +00:00
|
|
|
Person.findById(p.id, function(e, p) {
|
2015-03-20 18:06:24 +00:00
|
|
|
if (e) return done(e);
|
2015-01-30 07:26:11 +00:00
|
|
|
p.name.should.equal('John');
|
|
|
|
p.age.should.equal(15);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-07-20 09:59:07 +00:00
|
|
|
it('should allow model instance on updateAttributes (promise variant)', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
person.updateAttributes(new Person({'name': 'Jane', age: undefined}))
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
.then(function(p) {
|
|
|
|
return Person.findById(p.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.name.should.equal('Jane');
|
|
|
|
p.age.should.equal(15);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2015-11-17 19:02:43 +00:00
|
|
|
it('should raises on connector error', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const fakeConnector = {
|
2016-04-01 11:48:17 +00:00
|
|
|
updateAttributes: function(model, id, data, options, cb) {
|
2015-11-17 19:02:43 +00:00
|
|
|
cb(new Error('Database Error'));
|
2016-04-01 11:48:17 +00:00
|
|
|
},
|
2015-11-17 19:02:43 +00:00
|
|
|
};
|
2016-04-01 11:48:17 +00:00
|
|
|
person.getConnector = function() { return fakeConnector; };
|
2016-08-19 17:46:59 +00:00
|
|
|
person.updateAttributes({name: 'John'}, function(err, p) {
|
2015-11-17 19:02:43 +00:00
|
|
|
should.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
|
|
|
|
2015-01-30 10:01:48 +00:00
|
|
|
describe('updateOrCreate', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let Post, Todo;
|
2016-07-01 12:25:45 +00:00
|
|
|
|
2016-04-05 04:55:15 +00:00
|
|
|
before('prepare "Post" and "Todo" models', function(done) {
|
|
|
|
Post = db.define('Post', {
|
2016-08-19 17:46:59 +00:00
|
|
|
title: {type: String, id: true},
|
|
|
|
content: {type: String},
|
2016-07-01 12:25:45 +00:00
|
|
|
});
|
2016-04-05 04:55:15 +00:00
|
|
|
Todo = db.define('Todo', {
|
|
|
|
content: String,
|
|
|
|
});
|
2017-04-03 20:00:31 +00:00
|
|
|
// Here `Person` model overrides the one outside 'updataOrCreate'
|
|
|
|
// with forceId: false. Related test cleanup see issue:
|
|
|
|
// https://github.com/strongloop/loopback-datasource-juggler/issues/1317
|
|
|
|
Person = db.define('Person', {
|
|
|
|
name: String,
|
|
|
|
gender: String,
|
|
|
|
married: Boolean,
|
|
|
|
age: {type: Number, index: true},
|
|
|
|
dob: Date,
|
|
|
|
createdAt: {type: Date, default: Date},
|
|
|
|
}, {forceId: false});
|
|
|
|
db.automigrate(['Post', 'Todo', 'Person'], done);
|
2016-04-05 04:55:15 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function deleteModelsInstances(done) {
|
|
|
|
Todo.deleteAll(done);
|
2016-07-01 12:25:45 +00:00
|
|
|
});
|
|
|
|
|
2016-04-02 16:20:51 +00:00
|
|
|
it('has an alias "patchOrCreate"', function() {
|
|
|
|
StubUser.updateOrCreate.should.equal(StubUser.patchOrCreate);
|
|
|
|
});
|
|
|
|
|
2016-04-05 04:55:15 +00:00
|
|
|
it('creates a model when one does not exist', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Todo.updateOrCreate({content: 'a'}, function(err, data) {
|
2016-04-05 04:55:15 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
|
|
|
|
Todo.findById(data.id, function(err, todo) {
|
|
|
|
should.exist(todo);
|
|
|
|
should.exist(todo.content);
|
|
|
|
todo.content.should.equal('a');
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('updates a model if it exists', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Todo.create({content: 'a'}, function(err, todo) {
|
|
|
|
Todo.updateOrCreate({id: todo.id, content: 'b'}, function(err, data) {
|
2016-04-05 04:55:15 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
|
|
|
|
should.exist(data);
|
|
|
|
should.exist(data.id);
|
2017-04-06 20:04:16 +00:00
|
|
|
data.id.should.eql(todo.id);
|
2016-04-05 04:55:15 +00:00
|
|
|
should.exist(data.content);
|
|
|
|
data.content.should.equal('b');
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-08-16 21:00:41 +00:00
|
|
|
it('should reject updated empty password with updateOrCreate', function(done) {
|
|
|
|
StubUser.create({password: 'abc123'}, function(err, createdUser) {
|
|
|
|
if (err) return done(err);
|
|
|
|
StubUser.updateOrCreate({id: createdUser.id, 'password': ''}, function(err, updatedUser) {
|
|
|
|
(err.message).should.match(/password cannot be empty/);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-05 04:55:15 +00:00
|
|
|
it('throws error for queries with array input', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Todo.updateOrCreate([{content: 'a'}], function(err, data) {
|
2016-04-05 04:55:15 +00:00
|
|
|
should.exist(err);
|
|
|
|
err.message.should.containEql('bulk');
|
|
|
|
should.not.exist(data);
|
|
|
|
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-01-30 10:01:48 +00:00
|
|
|
it('should preserve properties with dynamic setters on create', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
StubUser.updateOrCreate({password: 'foo'}, function(err, created) {
|
2015-01-30 10:01:48 +00:00
|
|
|
if (err) return done(err);
|
2015-02-21 00:10:25 +00:00
|
|
|
created.password.should.equal('foo-FOO');
|
2015-01-30 10:01:48 +00:00
|
|
|
StubUser.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
2015-02-21 00:10:25 +00:00
|
|
|
found.password.should.equal('foo-FOO');
|
2015-01-30 10:01:48 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should preserve properties with dynamic setters on update', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
StubUser.create({password: 'foo'}, function(err, created) {
|
2015-01-30 10:01:48 +00:00
|
|
|
if (err) return done(err);
|
2018-12-07 14:54:29 +00:00
|
|
|
const data = {id: created.id, password: 'bar'};
|
2015-01-30 10:01:48 +00:00
|
|
|
StubUser.updateOrCreate(data, function(err, updated) {
|
|
|
|
if (err) return done(err);
|
2015-02-21 00:10:25 +00:00
|
|
|
updated.password.should.equal('bar-BAR');
|
2015-01-30 10:01:48 +00:00
|
|
|
StubUser.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
2015-02-21 00:10:25 +00:00
|
|
|
found.password.should.equal('bar-BAR');
|
2015-01-30 10:01:48 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-02-04 08:08:28 +00:00
|
|
|
|
|
|
|
it('should preserve properties with "undefined" value', function(done) {
|
|
|
|
Person.create(
|
2016-08-19 17:46:59 +00:00
|
|
|
{name: 'a-name', gender: undefined},
|
2015-02-04 08:08:28 +00:00
|
|
|
function(err, instance) {
|
|
|
|
if (err) return done(err);
|
2018-12-07 14:54:29 +00:00
|
|
|
const result = instance.toObject();
|
2017-04-06 20:04:16 +00:00
|
|
|
result.id.should.eql(instance.id);
|
|
|
|
should.equal(result.name, 'a-name');
|
|
|
|
should.equal(result.gender, undefined);
|
2015-02-04 08:08:28 +00:00
|
|
|
|
|
|
|
Person.updateOrCreate(
|
2016-08-19 17:46:59 +00:00
|
|
|
{id: instance.id, name: 'updated name'},
|
2015-02-04 08:08:28 +00:00
|
|
|
function(err, updated) {
|
|
|
|
if (err) return done(err);
|
2018-12-07 14:54:29 +00:00
|
|
|
const result = updated.toObject();
|
2017-04-06 20:04:16 +00:00
|
|
|
result.id.should.eql(instance.id);
|
|
|
|
should.equal(result.name, 'updated name');
|
2015-02-21 00:10:25 +00:00
|
|
|
should.equal(result.gender, null);
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2015-02-04 08:08:28 +00:00
|
|
|
done();
|
2018-07-16 06:46:25 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
2015-02-04 08:08:28 +00:00
|
|
|
});
|
2016-07-01 12:25:45 +00:00
|
|
|
|
2017-04-05 18:09:10 +00:00
|
|
|
it('updates specific instances when PK is not an auto-generated id', function(done) {
|
|
|
|
// skip the test if the connector is mssql
|
|
|
|
// https://github.com/strongloop/loopback-connector-mssql/pull/92#r72853474
|
2018-12-07 14:54:29 +00:00
|
|
|
const dsName = Post.dataSource.name;
|
2017-04-05 18:09:10 +00:00
|
|
|
if (dsName === 'mssql') return done();
|
|
|
|
|
2016-07-01 12:25:45 +00:00
|
|
|
Post.create([
|
2016-08-19 17:46:59 +00:00
|
|
|
{title: 'postA', content: 'contentA'},
|
|
|
|
{title: 'postB', content: 'contentB'},
|
2016-07-01 12:25:45 +00:00
|
|
|
], function(err, instance) {
|
|
|
|
if (err) return done(err);
|
|
|
|
|
|
|
|
Post.updateOrCreate({
|
|
|
|
title: 'postA', content: 'newContent',
|
|
|
|
}, function(err, instance) {
|
|
|
|
if (err) return done(err);
|
|
|
|
|
2018-12-07 14:54:29 +00:00
|
|
|
const result = instance.toObject();
|
2016-07-01 12:25:45 +00:00
|
|
|
result.should.have.properties({
|
|
|
|
title: 'postA',
|
|
|
|
content: 'newContent',
|
|
|
|
});
|
|
|
|
Post.find(function(err, posts) {
|
|
|
|
if (err) return done(err);
|
|
|
|
|
|
|
|
posts.should.have.length(2);
|
|
|
|
posts[0].title.should.equal('postA');
|
|
|
|
posts[0].content.should.equal('newContent');
|
|
|
|
posts[1].title.should.equal('postB');
|
|
|
|
posts[1].content.should.equal('contentB');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-03-16 11:36:54 +00:00
|
|
|
|
|
|
|
it('should allow save() of the created instance', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 999;
|
2015-03-16 11:36:54 +00:00
|
|
|
Person.updateOrCreate(
|
2017-04-06 20:04:16 +00:00
|
|
|
{id: unknownId, name: 'a-name'},
|
2015-03-16 11:36:54 +00:00
|
|
|
function(err, inst) {
|
|
|
|
if (err) return done(err);
|
|
|
|
inst.save(done);
|
2018-07-16 06:46:25 +00:00
|
|
|
}
|
|
|
|
);
|
2015-03-16 11:36:54 +00:00
|
|
|
});
|
2019-04-01 11:18:05 +00:00
|
|
|
|
|
|
|
it('preserves empty values from the database', async () => {
|
|
|
|
// https://github.com/strongloop/loopback-datasource-juggler/issues/1692
|
|
|
|
|
|
|
|
// Initially, all Products were always active, no property was needed
|
|
|
|
const Product = db.define('Product', {name: String});
|
|
|
|
|
|
|
|
await db.automigrate('Product');
|
|
|
|
const created = await Product.create({name: 'Pen'});
|
|
|
|
|
|
|
|
// Later on, we decide to introduce `active` property
|
|
|
|
Product.defineProperty('active', {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
// And updateOrCreate an existing record
|
|
|
|
const found = await Product.updateOrCreate({id: created.id, name: 'updated'});
|
|
|
|
found.toObject().should.eql({
|
|
|
|
id: created.id,
|
|
|
|
name: 'updated',
|
|
|
|
active: undefined,
|
|
|
|
});
|
|
|
|
});
|
2015-01-30 10:01:48 +00:00
|
|
|
});
|
|
|
|
|
2017-04-17 22:18:20 +00:00
|
|
|
bdd.describeIf(connectorCapabilities.supportForceId !== false,
|
|
|
|
'updateOrCreate when forceId is true', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let Post;
|
2017-04-17 22:18:20 +00:00
|
|
|
before(function definePostModel(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const ds = getSchema();
|
2017-04-17 22:18:20 +00:00
|
|
|
Post = ds.define('Post', {
|
|
|
|
title: {type: String, length: 255},
|
|
|
|
content: {type: String},
|
|
|
|
}, {forceId: true});
|
|
|
|
ds.automigrate('Post', done);
|
|
|
|
});
|
2017-04-03 20:00:31 +00:00
|
|
|
|
2017-04-17 22:18:20 +00:00
|
|
|
it('fails when id does not exist in db & validate is true', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 123;
|
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2017-04-17 22:18:20 +00:00
|
|
|
Post.updateOrCreate(post, {validate: true}, (err) => {
|
2017-05-01 04:24:15 +00:00
|
|
|
should(err).have.property('statusCode', 404);
|
2017-04-17 22:18:20 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('fails when id does not exist in db & validate is false', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 123;
|
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2017-04-17 22:18:20 +00:00
|
|
|
Post.updateOrCreate(post, {validate: false}, (err) => {
|
2017-05-01 04:24:15 +00:00
|
|
|
should(err).have.property('statusCode', 404);
|
2017-04-17 22:18:20 +00:00
|
|
|
done();
|
|
|
|
});
|
2017-04-03 20:00:31 +00:00
|
|
|
});
|
|
|
|
|
2017-04-17 22:18:20 +00:00
|
|
|
it('fails when id does not exist in db & validate is false when using updateAttributes',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 123;
|
|
|
|
const post = new Post({id: unknownId});
|
2018-06-12 07:13:32 +00:00
|
|
|
post.updateAttributes({title: 'updated title', content: 'AAA'}, {validate: false}, (err) => {
|
|
|
|
should(err).have.property('statusCode', 404);
|
|
|
|
done();
|
|
|
|
});
|
2017-05-01 04:24:15 +00:00
|
|
|
});
|
2017-04-03 20:00:31 +00:00
|
|
|
|
2017-04-17 22:18:20 +00:00
|
|
|
it('works on create if the request does not include an id', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {title: 'a', content: 'AAA'};
|
2017-04-17 22:18:20 +00:00
|
|
|
Post.updateOrCreate(post, (err, p) => {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
|
|
|
done();
|
|
|
|
});
|
2017-04-03 20:00:31 +00:00
|
|
|
});
|
|
|
|
|
2017-04-17 22:18:20 +00:00
|
|
|
it('works on update if the request includes an existing id in db', function(done) {
|
|
|
|
Post.create({title: 'a', content: 'AAA'}, (err, post) => {
|
2017-04-03 20:00:31 +00:00
|
|
|
if (err) return done(err);
|
2017-04-17 22:18:20 +00:00
|
|
|
post = post.toObject();
|
|
|
|
delete post.content;
|
|
|
|
post.title = 'b';
|
|
|
|
Post.updateOrCreate(post, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.id.should.equal(post.id);
|
|
|
|
p.title.should.equal('b');
|
|
|
|
done();
|
|
|
|
});
|
2017-04-03 20:00:31 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-12-07 14:54:29 +00:00
|
|
|
const hasReplaceById = connectorCapabilities.cloudantCompatible !== false &&
|
2017-07-18 19:20:21 +00:00
|
|
|
!!getSchema().connector.replaceById;
|
|
|
|
|
|
|
|
if (!hasReplaceById) {
|
2016-04-01 11:48:17 +00:00
|
|
|
describe.skip('replaceById - not implemented', function() {});
|
2015-12-04 18:49:00 +00:00
|
|
|
} else {
|
|
|
|
describe('replaceOrCreate', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let Post, unknownId;
|
2016-03-29 16:21:10 +00:00
|
|
|
before(function(done) {
|
2017-04-06 20:04:16 +00:00
|
|
|
db = getSchema();
|
|
|
|
unknownId = uid.fromConnector(db) || 123;
|
|
|
|
Post = db.define('Post', {
|
2016-08-19 17:46:59 +00:00
|
|
|
title: {type: String, length: 255, index: true},
|
|
|
|
content: {type: String},
|
2016-04-01 11:48:17 +00:00
|
|
|
comments: [String],
|
2016-08-19 17:46:59 +00:00
|
|
|
}, {forceId: false});
|
2017-04-06 20:04:16 +00:00
|
|
|
db.automigrate('Post', done);
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('works without options on create (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.replaceOrCreate(post)
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
2018-06-12 07:13:32 +00:00
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Post);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2018-06-12 07:13:32 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
|
|
|
return Post.findById(p.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.id.should.eql(post.id);
|
|
|
|
p.id.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(p.title);
|
|
|
|
p.content.should.equal(p.content);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('works with options on create (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2016-08-19 17:46:59 +00:00
|
|
|
Post.replaceOrCreate(post, {validate: false})
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
2018-06-12 07:13:32 +00:00
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Post);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2018-06-12 07:13:32 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
|
|
|
return Post.findById(p.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.id.should.eql(post.id);
|
|
|
|
p.id.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(p.title);
|
|
|
|
p.content.should.equal(p.content);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('works without options on update (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {title: 'a', content: 'AAA', comments: ['Comment1']};
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.create(post)
|
|
|
|
.then(function(created) {
|
|
|
|
created = created.toObject();
|
|
|
|
delete created.comments;
|
|
|
|
delete created.content;
|
|
|
|
created.title = 'b';
|
|
|
|
return Post.replaceOrCreate(created)
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
2018-06-12 07:13:32 +00:00
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Post);
|
|
|
|
p.id.should.eql(created.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
|
|
|
p.should.have.property('comments').be.oneOf(null, undefined);
|
2018-06-12 07:13:32 +00:00
|
|
|
|
|
|
|
return Post.findById(created.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
|
|
|
should.not.exist(p.content);
|
|
|
|
should.not.exist(p.comments);
|
|
|
|
done();
|
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
|
|
|
})
|
2018-06-12 07:13:32 +00:00
|
|
|
.catch(done);
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('works with options on update (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {title: 'a', content: 'AAA', comments: ['Comment1']};
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.create(post)
|
|
|
|
.then(function(created) {
|
|
|
|
created = created.toObject();
|
|
|
|
delete created.comments;
|
|
|
|
delete created.content;
|
|
|
|
created.title = 'b';
|
2016-08-19 17:46:59 +00:00
|
|
|
return Post.replaceOrCreate(created, {validate: false})
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
2018-06-12 07:13:32 +00:00
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Post);
|
|
|
|
p.id.should.eql(created.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
|
|
|
p.should.have.property('comments').be.oneOf(null, undefined);
|
2018-06-12 07:13:32 +00:00
|
|
|
|
|
|
|
return Post.findById(created.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
|
|
|
should.not.exist(p.content);
|
|
|
|
should.not.exist(p.comments);
|
|
|
|
done();
|
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
|
|
|
})
|
2018-06-12 07:13:32 +00:00
|
|
|
.catch(done);
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('works without options on update (callback variant)', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Post.create({title: 'a', content: 'AAA', comments: ['Comment1']},
|
2015-12-04 18:49:00 +00:00
|
|
|
function(err, post) {
|
|
|
|
if (err) return done(err);
|
|
|
|
post = post.toObject();
|
|
|
|
delete post.comments;
|
|
|
|
delete post.content;
|
|
|
|
post.title = 'b';
|
|
|
|
Post.replaceOrCreate(post, function(err, p) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
|
|
|
p.should.have.property('comments').be.oneOf(null, undefined);
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.findById(post.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.id.should.eql(post.id);
|
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
2016-03-09 01:39:25 +00:00
|
|
|
should.not.exist(p.content);
|
|
|
|
should.not.exist(p.comments);
|
2015-12-04 18:49:00 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('works with options on update (callback variant)', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Post.create({title: 'a', content: 'AAA', comments: ['Comment1']},
|
|
|
|
{validate: false},
|
2015-12-04 18:49:00 +00:00
|
|
|
function(err, post) {
|
|
|
|
if (err) return done(err);
|
|
|
|
post = post.toObject();
|
|
|
|
delete post.comments;
|
|
|
|
delete post.content;
|
|
|
|
post.title = 'b';
|
|
|
|
Post.replaceOrCreate(post, function(err, p) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
|
|
|
p.should.have.property('comments').be.oneOf(null, undefined);
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.findById(post.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.id.should.eql(post.id);
|
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal('b');
|
2016-03-09 01:39:25 +00:00
|
|
|
should.not.exist(p.content);
|
|
|
|
should.not.exist(p.comments);
|
2015-12-04 18:49:00 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('works without options on create (callback variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.replaceOrCreate(post, function(err, p) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.findById(p.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('works with options on create (callback variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2016-08-19 17:46:59 +00:00
|
|
|
Post.replaceOrCreate(post, {validate: false}, function(err, p) {
|
2015-12-04 18:49:00 +00:00
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2015-12-04 18:49:00 +00:00
|
|
|
Post.findById(p.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(post.id);
|
2015-12-04 18:49:00 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
bdd.describeIf(hasReplaceById && connectorCapabilities.supportForceId !== false, 'replaceOrCreate ' +
|
|
|
|
'when forceId is true', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let Post, unknownId;
|
2017-01-04 16:33:49 +00:00
|
|
|
before(function(done) {
|
2017-04-06 20:04:16 +00:00
|
|
|
db = getSchema();
|
|
|
|
unknownId = uid.fromConnector(db) || 123;
|
|
|
|
Post = db.define('Post', {
|
2017-01-04 16:33:49 +00:00
|
|
|
title: {type: String, length: 255},
|
|
|
|
content: {type: String},
|
|
|
|
}, {forceId: true});
|
2017-04-06 20:04:16 +00:00
|
|
|
db.automigrate('Post', done);
|
2017-01-04 16:33:49 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('fails when id does not exist in db', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2017-01-04 16:33:49 +00:00
|
|
|
Post.replaceOrCreate(post, function(err, p) {
|
|
|
|
err.statusCode.should.equal(404);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
// eslint-disable-next-line mocha/no-identical-title
|
2017-01-04 16:33:49 +00:00
|
|
|
it('works on create if the request does not include an id', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const post = {title: 'a', content: 'AAA'};
|
2017-01-04 16:33:49 +00:00
|
|
|
Post.replaceOrCreate(post, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p.title.should.equal(post.title);
|
|
|
|
p.content.should.equal(post.content);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
// eslint-disable-next-line mocha/no-identical-title
|
2017-01-04 16:33:49 +00:00
|
|
|
it('works on update if the request includes an existing id in db', function(done) {
|
|
|
|
Post.create({title: 'a', content: 'AAA'},
|
2018-06-12 07:13:32 +00:00
|
|
|
function(err, post) {
|
|
|
|
if (err) return done(err);
|
|
|
|
post = post.toObject();
|
|
|
|
delete post.content;
|
|
|
|
post.title = 'b';
|
|
|
|
Post.replaceOrCreate(post, function(err, p) {
|
2017-04-06 20:04:16 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
p.id.should.eql(post.id);
|
|
|
|
done();
|
2017-04-06 20:04:16 +00:00
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2017-01-04 16:33:49 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-07-18 19:20:21 +00:00
|
|
|
if (!hasReplaceById) {
|
2016-04-01 11:48:17 +00:00
|
|
|
describe.skip('replaceAttributes/replaceById - not implemented', function() {});
|
2015-12-04 18:49:00 +00:00
|
|
|
} else {
|
|
|
|
describe('replaceAttributes', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let postInstance;
|
|
|
|
let Post;
|
|
|
|
const ds = getSchema();
|
2016-04-01 11:48:17 +00:00
|
|
|
before(function(done) {
|
2015-12-04 18:49:00 +00:00
|
|
|
Post = ds.define('Post', {
|
2016-08-19 17:46:59 +00:00
|
|
|
title: {type: String, length: 255, index: true},
|
|
|
|
content: {type: String},
|
2016-04-01 11:48:17 +00:00
|
|
|
comments: [String],
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
2016-03-29 16:21:10 +00:00
|
|
|
ds.automigrate('Post', done);
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
beforeEach(function(done) {
|
2016-06-17 22:17:20 +00:00
|
|
|
// TODO(bajtos) add API to lib/observer - remove observers for all hooks
|
|
|
|
Post._observers = {};
|
2016-04-01 11:48:17 +00:00
|
|
|
Post.destroyAll(function() {
|
2016-08-19 17:46:59 +00:00
|
|
|
Post.create({title: 'a', content: 'AAA'}, function(err, p) {
|
2015-12-04 18:49:00 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
postInstance = p;
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-06 17:14:56 +00:00
|
|
|
it('should have updated password hashed with replaceAttributes',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
StubUser.create({password: 'foo'}, function(err, created) {
|
2016-04-06 17:14:56 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
created.replaceAttributes({password: 'test'}, function(err, created) {
|
2016-04-06 17:14:56 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
created.password.should.equal('test-TEST');
|
|
|
|
StubUser.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
|
|
|
found.password.should.equal('test-TEST');
|
|
|
|
done();
|
|
|
|
});
|
2016-04-06 17:14:56 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-08-16 21:00:41 +00:00
|
|
|
it('should reject updated empty password with replaceAttributes', function(done) {
|
|
|
|
StubUser.create({password: 'abc123'}, function(err, createdUser) {
|
|
|
|
if (err) return done(err);
|
|
|
|
createdUser.replaceAttributes({'password': ''}, function(err, updatedUser) {
|
|
|
|
(err.message).should.match(/password cannot be empty/);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-05-31 22:10:44 +00:00
|
|
|
it('should ignore PK if it is set for `instance`' +
|
|
|
|
'in `before save` operation hook', function(done) {
|
|
|
|
Post.findById(postInstance.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
changePostIdInHook('before save');
|
2016-08-19 17:46:59 +00:00
|
|
|
p.replaceAttributes({title: 'b'}, function(err, data) {
|
2016-05-31 22:10:44 +00:00
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
data.id.should.eql(postInstance.id);
|
2016-05-31 22:10:44 +00:00
|
|
|
Post.find(function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p[0].id.should.eql(postInstance.id);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set cannotOverwritePKInBeforeSaveHook flag, if `instance` in' +
|
|
|
|
'`before save` operation hook is set, so we report a warning just once',
|
|
|
|
function(done) {
|
|
|
|
Post.findById(postInstance.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
changePostIdInHook('before save');
|
2016-08-19 17:46:59 +00:00
|
|
|
p.replaceAttributes({title: 'b'}, function(err, data) {
|
2016-05-31 22:10:44 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
Post._warned.cannotOverwritePKInBeforeSaveHook.should.equal(true);
|
2016-09-08 20:05:48 +00:00
|
|
|
data.id.should.eql(postInstance.id);
|
2016-05-31 22:10:44 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should ignore PK if it is set for `data`' +
|
|
|
|
'in `loaded` operation hook', function(done) {
|
|
|
|
Post.findById(postInstance.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
changePostIdInHook('loaded');
|
2016-08-19 17:46:59 +00:00
|
|
|
p.replaceAttributes({title: 'b'}, function(err, data) {
|
2016-05-31 22:10:44 +00:00
|
|
|
data.id.should.eql(postInstance.id);
|
|
|
|
if (err) return done(err);
|
|
|
|
// clear observers to make sure `loaded`
|
|
|
|
// hook does not affect `find()` method
|
|
|
|
Post.clearObservers('loaded');
|
|
|
|
Post.find(function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
p[0].id.should.eql(postInstance.id);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set cannotOverwritePKInLoadedHook flag, if `instance` in' +
|
|
|
|
'`before save` operation hook is set, so we report a warning just once',
|
|
|
|
function(done) {
|
|
|
|
Post.findById(postInstance.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
|
|
|
changePostIdInHook('loaded');
|
2016-08-19 17:46:59 +00:00
|
|
|
p.replaceAttributes({title: 'b'}, function(err, data) {
|
2016-05-31 22:10:44 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
Post._warned.cannotOverwritePKInLoadedHook.should.equal(true);
|
2016-09-08 20:05:48 +00:00
|
|
|
data.id.should.eql(postInstance.id);
|
2016-05-31 22:10:44 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('works without options(promise variant)', function(done) {
|
2016-04-01 13:23:42 +00:00
|
|
|
Post.findById(postInstance.id)
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
2018-06-12 07:13:32 +00:00
|
|
|
p.replaceAttributes({title: 'b'})
|
|
|
|
.then(function(p) {
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Post);
|
|
|
|
p.title.should.equal('b');
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
2018-06-12 07:13:32 +00:00
|
|
|
return Post.findById(postInstance.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.title.should.equal('b');
|
|
|
|
should.not.exist(p.content);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
2016-04-01 13:23:42 +00:00
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('works with options(promise variant)', function(done) {
|
2016-04-01 13:23:42 +00:00
|
|
|
Post.findById(postInstance.id)
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
2018-06-12 07:13:32 +00:00
|
|
|
p.replaceAttributes({title: 'b'}, {validate: false})
|
|
|
|
.then(function(p) {
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Post);
|
|
|
|
p.title.should.equal('b');
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
2018-06-12 07:13:32 +00:00
|
|
|
return Post.findById(postInstance.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.title.should.equal('b');
|
|
|
|
should.not.exist(p.content);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
2016-04-01 13:23:42 +00:00
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
|
2016-05-31 23:31:13 +00:00
|
|
|
it('should fail when changing id', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 999;
|
2016-05-31 23:31:13 +00:00
|
|
|
Post.findById(postInstance.id, function(err, p) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.replaceAttributes({title: 'b', id: unknownId}, function(err, p) {
|
2016-05-31 23:31:13 +00:00
|
|
|
should.exist(err);
|
2018-12-07 14:54:29 +00:00
|
|
|
const expectedErrMsg = 'id property (id) cannot be updated from ' +
|
2017-04-06 20:04:16 +00:00
|
|
|
postInstance.id + ' to ' + unknownId;
|
2016-05-31 23:31:13 +00:00
|
|
|
err.message.should.equal(expectedErrMsg);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('works without options(callback variant)', function(done) {
|
2016-04-01 13:23:42 +00:00
|
|
|
Post.findById(postInstance.id, function(err, p) {
|
2015-12-04 18:49:00 +00:00
|
|
|
if (err) return done(err);
|
2016-08-19 17:46:59 +00:00
|
|
|
p.replaceAttributes({title: 'b'}, function(err, p) {
|
2016-04-01 13:23:42 +00:00
|
|
|
if (err) return done(err);
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
2016-04-01 13:23:42 +00:00
|
|
|
p.title.should.equal('b');
|
|
|
|
done();
|
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('works with options(callback variant)', function(done) {
|
2016-04-01 13:23:42 +00:00
|
|
|
Post.findById(postInstance.id, function(err, p) {
|
2015-12-04 18:49:00 +00:00
|
|
|
if (err) return done(err);
|
2016-08-19 17:46:59 +00:00
|
|
|
p.replaceAttributes({title: 'b'}, {validate: false}, function(err, p) {
|
2016-04-01 13:23:42 +00:00
|
|
|
if (err) return done(err);
|
2018-07-08 15:24:07 +00:00
|
|
|
p.should.have.property('content').be.oneOf(null, undefined);
|
2016-04-01 13:23:42 +00:00
|
|
|
p.title.should.equal('b');
|
|
|
|
done();
|
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2016-05-31 22:10:44 +00:00
|
|
|
|
|
|
|
function changePostIdInHook(operationHook) {
|
|
|
|
Post.observe(operationHook, function(ctx, next) {
|
|
|
|
(ctx.data || ctx.instance).id = 99;
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
}
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2015-12-04 18:49:00 +00:00
|
|
|
}
|
|
|
|
|
2017-01-27 19:08:53 +00:00
|
|
|
bdd.describeIf(hasReplaceById, 'replaceById', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let Post;
|
2017-01-27 19:08:53 +00:00
|
|
|
before(function(done) {
|
2017-04-06 20:04:16 +00:00
|
|
|
db = getSchema();
|
|
|
|
Post = db.define('Post', {
|
2017-01-27 19:08:53 +00:00
|
|
|
title: {type: String, length: 255},
|
|
|
|
content: {type: String},
|
|
|
|
}, {forceId: true});
|
2017-04-06 20:04:16 +00:00
|
|
|
db.automigrate('Post', done);
|
2017-01-27 19:08:53 +00:00
|
|
|
});
|
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
bdd.itIf(connectorCapabilities.supportForceId !== false, 'fails when id does not exist in db ' +
|
|
|
|
'using replaceById', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 123;
|
|
|
|
const post = {id: unknownId, title: 'a', content: 'AAA'};
|
2017-01-27 19:08:53 +00:00
|
|
|
Post.replaceById(post.id, post, function(err, p) {
|
|
|
|
err.statusCode.should.equal(404);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
describe('findOrCreate', function() {
|
|
|
|
it('should create a record with if new', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.findOrCreate({name: 'Zed', gender: 'male'},
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
function(err, p, created) {
|
|
|
|
if (err) return done(err);
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Person);
|
|
|
|
p.name.should.equal('Zed');
|
|
|
|
p.gender.should.equal('male');
|
|
|
|
created.should.equal(true);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should find a record if exists', function(done) {
|
|
|
|
Person.findOrCreate(
|
2016-08-19 17:46:59 +00:00
|
|
|
{where: {name: 'Zed'}},
|
|
|
|
{name: 'Zed', gender: 'male'},
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
function(err, p, created) {
|
|
|
|
if (err) return done(err);
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Person);
|
|
|
|
p.name.should.equal('Zed');
|
|
|
|
p.gender.should.equal('male');
|
|
|
|
created.should.equal(false);
|
|
|
|
done();
|
2018-07-16 06:46:25 +00:00
|
|
|
}
|
|
|
|
);
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should create a record with if new (promise variant)', function(done) {
|
2016-08-19 17:46:59 +00:00
|
|
|
Person.findOrCreate({name: 'Jed', gender: 'male'})
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
.then(function(res) {
|
|
|
|
should.exist(res);
|
|
|
|
res.should.be.instanceOf(Array);
|
|
|
|
res.should.have.lengthOf(2);
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = res[0];
|
|
|
|
const created = res[1];
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
p.should.be.instanceOf(Person);
|
|
|
|
p.name.should.equal('Jed');
|
|
|
|
p.gender.should.equal('male');
|
|
|
|
created.should.equal(true);
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should find a record if exists (promise variant)', function(done) {
|
|
|
|
Person.findOrCreate(
|
2016-08-19 17:46:59 +00:00
|
|
|
{where: {name: 'Jed'}},
|
2018-07-16 06:46:25 +00:00
|
|
|
{name: 'Jed', gender: 'male'}
|
|
|
|
)
|
2018-06-12 07:13:32 +00:00
|
|
|
.then(function(res) {
|
|
|
|
res.should.be.instanceOf(Array);
|
|
|
|
res.should.have.lengthOf(2);
|
2018-12-07 14:54:29 +00:00
|
|
|
const p = res[0];
|
|
|
|
const created = res[1];
|
2018-06-12 07:13:32 +00:00
|
|
|
p.should.be.instanceOf(Person);
|
|
|
|
p.name.should.equal('Jed');
|
|
|
|
p.gender.should.equal('male');
|
|
|
|
created.should.equal(false);
|
|
|
|
done();
|
|
|
|
})
|
|
|
|
.catch(done);
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
});
|
2019-04-01 11:18:05 +00:00
|
|
|
|
|
|
|
it('preserves empty values from the database', async () => {
|
|
|
|
// https://github.com/strongloop/loopback-datasource-juggler/issues/1692
|
|
|
|
|
|
|
|
// Initially, all Products were always active, no property was needed
|
|
|
|
const Product = db.define('Product', {name: String});
|
|
|
|
|
|
|
|
await db.automigrate('Product');
|
|
|
|
const created = await Product.create({name: 'Pen'});
|
|
|
|
|
|
|
|
// Later on, we decide to introduce `active` property
|
|
|
|
Product.defineProperty('active', {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
});
|
|
|
|
|
|
|
|
// And findOrCreate an existing record
|
|
|
|
const [found] = await Product.findOrCreate({id: created.id}, {name: 'updated'});
|
|
|
|
found.toObject().should.eql({
|
|
|
|
id: created.id,
|
|
|
|
name: 'Pen',
|
|
|
|
active: undefined,
|
|
|
|
});
|
|
|
|
});
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
describe('destroy', function() {
|
|
|
|
it('should destroy record', function(done) {
|
|
|
|
Person.create(function(err, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-04-01 11:48:17 +00:00
|
|
|
p.destroy(function(err) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.exists(p.id, function(err, ex) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
ex.should.not.be.ok;
|
|
|
|
done();
|
|
|
|
});
|
2013-03-27 00:51:00 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should destroy record (promise variant)', function(done) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
Person.create()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(p) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
return p.destroy()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function() {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
return Person.exists(p.id)
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(ex) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
ex.should.not.be.ok;
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should destroy all records', function(done) {
|
|
|
|
Person.destroyAll(function(err) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.all(function(err, posts) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
posts.should.have.lengthOf(0);
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.count(function(err, count) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (err) return done(err);
|
2014-01-24 17:09:53 +00:00
|
|
|
count.should.eql(0);
|
|
|
|
done();
|
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
});
|
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should destroy all records (promise variant)', function(done) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
Person.create()
|
|
|
|
.then(function() {
|
|
|
|
return Person.destroyAll()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function() {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
return Person.all()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(ps) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
ps.should.have.lengthOf(0);
|
|
|
|
return Person.count()
|
2016-04-01 11:48:17 +00:00
|
|
|
.then(function(count) {
|
Add Promises to DAO
When a callback is omitted from a DAO method, return a Promise that
resolves to the value normally passed to the callback of that method.
If a callback is provided, behave normally.
This API will use native ES6 promises if available. If not available,
or to force the use of another Promise library, you must assign the
global.Promise object.
e.g.:
global.Promise = require('bluebird')
Class methods affected:
- create
- updateOrCreate / upsert
- findOrCreate
- exists
- find
- findOne
- findById
- findByIds
- remove / deleteAll / destroyAll
- removeById / deleteById / destroyById
- count
- update / updateAll
Prototype methods affected:
- save
- delete / remove / destroy
- updateAttribute
- updateAttributes
- reload
Exceptions / edge cases:
- create() used to return the data object that was passed in, even if
no callback was provided. Now, if a callback is provided, it will
return the data object, otherwise it will return a Promise.
- If create() is provided an array of data objects for creation, it
will continue to always return the array. This batch creation mode
does not support promises.
- findOrCreate() has a callback of the form: cb(err, instance, created),
with the extra parameter indicating whether the instance was created
or not. When called with its promise variant, the resolver will
receive a single array parameter: [instance, created]
2015-02-18 04:55:03 +00:00
|
|
|
count.should.eql(0);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
2014-01-24 17:09:53 +00:00
|
|
|
// TODO: implement destroy with filtered set
|
|
|
|
it('should destroy filtered set of records');
|
|
|
|
});
|
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
bdd.describeIf(connectorCapabilities.reportDeletedCount !== false &&
|
|
|
|
connectorCapabilities.deleteWithOtherThanId !== false, 'deleteAll/destroyAll', function() {
|
2015-03-25 04:30:40 +00:00
|
|
|
beforeEach(function clearOldData(done) {
|
|
|
|
Person.deleteAll(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function createTestData(done) {
|
|
|
|
Person.create([{
|
2016-04-01 11:48:17 +00:00
|
|
|
name: 'John',
|
2015-03-25 04:30:40 +00:00
|
|
|
}, {
|
2016-04-01 11:48:17 +00:00
|
|
|
name: 'Jane',
|
2017-04-06 20:04:16 +00:00
|
|
|
}], function(err, data) {
|
|
|
|
should.not.exist(err);
|
|
|
|
done();
|
|
|
|
});
|
2015-03-25 04:30:40 +00:00
|
|
|
});
|
|
|
|
|
2015-03-23 21:40:53 +00:00
|
|
|
it('should be defined as function', function() {
|
|
|
|
Person.deleteAll.should.be.a.Function;
|
|
|
|
Person.destroyAll.should.be.a.Function;
|
2015-03-18 09:18:03 +00:00
|
|
|
});
|
|
|
|
|
2015-03-25 04:30:40 +00:00
|
|
|
it('should only delete instances that satisfy the where condition',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
Person.deleteAll({name: 'John'}, function(err, info) {
|
|
|
|
if (err) return done(err);
|
|
|
|
info.should.have.property('count', 1);
|
|
|
|
Person.find({where: {name: 'John'}}, function(err, data) {
|
2015-03-18 09:18:03 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
data.should.have.length(0);
|
|
|
|
Person.find({where: {name: 'Jane'}}, function(err, data) {
|
2016-04-01 13:23:42 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
data.should.have.length(1);
|
|
|
|
done();
|
2016-04-01 13:23:42 +00:00
|
|
|
});
|
2015-03-18 09:18:03 +00:00
|
|
|
});
|
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2015-03-18 09:18:03 +00:00
|
|
|
|
2015-03-25 04:30:40 +00:00
|
|
|
it('should report zero deleted instances when no matches are found',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
Person.deleteAll({name: 'does-not-match'}, function(err, info) {
|
|
|
|
if (err) return done(err);
|
|
|
|
info.should.have.property('count', 0);
|
|
|
|
Person.count(function(err, count) {
|
2016-04-01 13:23:42 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
count.should.equal(2);
|
|
|
|
done();
|
2016-04-01 13:23:42 +00:00
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2015-03-18 09:18:03 +00:00
|
|
|
|
2015-03-25 04:30:40 +00:00
|
|
|
it('should delete all instances when the where condition is not provided',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
Person.deleteAll(function(err, info) {
|
|
|
|
if (err) return done(err);
|
|
|
|
info.should.have.property('count', 2);
|
|
|
|
Person.count(function(err, count) {
|
2016-04-01 13:23:42 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
count.should.equal(0);
|
|
|
|
done();
|
2016-04-01 13:23:42 +00:00
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2015-03-18 09:18:03 +00:00
|
|
|
});
|
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
bdd.describeIf(connectorCapabilities.reportDeletedCount === false &&
|
|
|
|
connectorCapabilities.deleteWithOtherThanId === false, 'deleteAll/destroyAll case 2', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let idJohn, idJane;
|
2017-04-06 20:04:16 +00:00
|
|
|
beforeEach(function clearOldData(done) {
|
|
|
|
Person.deleteAll(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function createTestData(done) {
|
|
|
|
Person.create([{
|
|
|
|
name: 'John',
|
|
|
|
}, {
|
|
|
|
name: 'Jane',
|
|
|
|
}], function(err, data) {
|
|
|
|
should.not.exist(err);
|
|
|
|
data.forEach(function(person) {
|
|
|
|
if (person.name === 'John') idJohn = person.id;
|
|
|
|
if (person.name === 'Jane') idJane = person.id;
|
|
|
|
});
|
|
|
|
should.exist(idJohn);
|
|
|
|
should.exist(idJane);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
// eslint-disable-next-line mocha/no-identical-title
|
2017-04-06 20:04:16 +00:00
|
|
|
it('should be defined as function', function() {
|
|
|
|
Person.deleteAll.should.be.a.Function;
|
|
|
|
Person.destroyAll.should.be.a.Function;
|
|
|
|
});
|
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
// eslint-disable-next-line mocha/no-identical-title
|
2017-04-06 20:04:16 +00:00
|
|
|
it('should only delete instances that satisfy the where condition',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
Person.deleteAll({id: idJohn}, function(err, info) {
|
|
|
|
if (err) return done(err);
|
|
|
|
should.not.exist(info.count);
|
|
|
|
Person.find({where: {name: 'John'}}, function(err, data) {
|
2017-04-06 20:04:16 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
should.not.exist(data.count);
|
|
|
|
data.should.have.length(0);
|
|
|
|
Person.find({where: {name: 'Jane'}}, function(err, data) {
|
2017-04-06 20:04:16 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
data.should.have.length(1);
|
|
|
|
done();
|
2017-04-06 20:04:16 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
// eslint-disable-next-line mocha/no-identical-title
|
2017-04-06 20:04:16 +00:00
|
|
|
it('should report zero deleted instances when no matches are found',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 1234567890;
|
2018-06-12 07:13:32 +00:00
|
|
|
Person.deleteAll({id: unknownId}, function(err, info) {
|
|
|
|
if (err) return done(err);
|
|
|
|
should.not.exist(info.count);
|
|
|
|
Person.count(function(err, count) {
|
2017-04-06 20:04:16 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
count.should.equal(2);
|
|
|
|
done();
|
2017-04-06 20:04:16 +00:00
|
|
|
});
|
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
// eslint-disable-next-line mocha/no-identical-title
|
2017-04-06 20:04:16 +00:00
|
|
|
it('should delete all instances when the where condition is not provided',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
Person.deleteAll(function(err, info) {
|
|
|
|
if (err) return done(err);
|
|
|
|
should.not.exist(info.count);
|
|
|
|
Person.count(function(err, count) {
|
2017-04-06 20:04:16 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
count.should.equal(0);
|
|
|
|
done();
|
2017-04-06 20:04:16 +00:00
|
|
|
});
|
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2017-04-06 20:04:16 +00:00
|
|
|
});
|
|
|
|
|
2015-03-20 16:49:32 +00:00
|
|
|
describe('deleteById', function() {
|
|
|
|
beforeEach(givenSomePeople);
|
|
|
|
afterEach(function() {
|
|
|
|
Person.settings.strictDelete = false;
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should allow deleteById(id) - success', function(done) {
|
|
|
|
Person.findOne(function(e, p) {
|
2015-03-20 16:49:32 +00:00
|
|
|
Person.deleteById(p.id, function(err, info) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
if (connectorCapabilities.reportDeletedCount !== false) {
|
|
|
|
info.should.have.property('count', 1);
|
|
|
|
} else {
|
|
|
|
should.not.exist(info.count);
|
|
|
|
}
|
2015-03-20 16:49:32 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should allow deleteById(id) - fail', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 9999;
|
2015-03-20 16:49:32 +00:00
|
|
|
Person.settings.strictDelete = false;
|
2017-04-06 20:04:16 +00:00
|
|
|
Person.deleteById(unknownId, function(err, info) {
|
2015-03-20 16:49:32 +00:00
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
if (connectorCapabilities.reportDeletedCount !== false) {
|
|
|
|
info.should.have.property('count', 0);
|
|
|
|
} else {
|
|
|
|
should.not.exist(info.count);
|
|
|
|
}
|
2015-03-20 16:49:32 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should allow deleteById(id) - fail with error', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const unknownId = uid.fromConnector(db) || 9999;
|
|
|
|
const errMsg = 'No instance with id ' + unknownId.toString() + ' found for Person';
|
2015-03-20 16:49:32 +00:00
|
|
|
Person.settings.strictDelete = true;
|
2017-04-06 20:04:16 +00:00
|
|
|
Person.deleteById(unknownId, function(err) {
|
2015-03-20 16:49:32 +00:00
|
|
|
should.exist(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
err.message.should.equal(errMsg);
|
2015-03-20 16:49:32 +00:00
|
|
|
err.should.have.property('code', 'NOT_FOUND');
|
|
|
|
err.should.have.property('statusCode', 404);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('prototype.delete', function() {
|
|
|
|
beforeEach(givenSomePeople);
|
|
|
|
afterEach(function() {
|
|
|
|
Person.settings.strictDelete = false;
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should allow delete(id) - success', function(done) {
|
|
|
|
Person.findOne(function(e, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (e) return done(e);
|
2015-03-20 16:49:32 +00:00
|
|
|
p.delete(function(err, info) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
if (connectorCapabilities.reportDeletedCount !== false) {
|
|
|
|
info.should.have.property('count', 1);
|
|
|
|
} else {
|
|
|
|
should.not.exist(info.count);
|
|
|
|
}
|
2015-03-20 16:49:32 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
it('should allow delete(id) - fail', function(done) {
|
2015-03-20 16:49:32 +00:00
|
|
|
Person.settings.strictDelete = false;
|
2016-04-01 11:48:17 +00:00
|
|
|
Person.findOne(function(e, p) {
|
2016-11-28 22:18:55 +00:00
|
|
|
if (e) return done(e);
|
2015-03-20 16:49:32 +00:00
|
|
|
p.delete(function(err, info) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
if (connectorCapabilities.reportDeletedCount !== false) {
|
|
|
|
info.should.have.property('count', 1);
|
|
|
|
} else {
|
|
|
|
should.not.exist(info.count);
|
|
|
|
}
|
2015-03-20 16:49:32 +00:00
|
|
|
p.delete(function(err, info) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
if (connectorCapabilities.reportDeletedCount !== false) {
|
|
|
|
info.should.have.property('count', 0);
|
|
|
|
} else {
|
|
|
|
should.not.exist(info.count);
|
|
|
|
}
|
2015-03-20 16:49:32 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
bdd.itIf(connectorCapabilities.supportStrictDelete !== false, 'should allow delete(id) - ' +
|
2017-07-18 19:20:21 +00:00
|
|
|
'fail with error', function(done) {
|
2018-06-12 07:13:32 +00:00
|
|
|
Person.settings.strictDelete = true;
|
|
|
|
Person.findOne(function(err, u) {
|
|
|
|
if (err) return done(err);
|
|
|
|
u.delete(function(err, info) {
|
2015-03-20 16:49:32 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
info.should.have.property('count', 1);
|
|
|
|
u.delete(function(err) {
|
|
|
|
should.exist(err);
|
|
|
|
err.message.should.equal('No instance with id ' + u.id + ' found for Person');
|
|
|
|
err.should.have.property('code', 'NOT_FOUND');
|
|
|
|
err.should.have.property('statusCode', 404);
|
|
|
|
done();
|
2015-03-20 16:49:32 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2015-03-20 16:49:32 +00:00
|
|
|
});
|
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
describe('initialize', function() {
|
|
|
|
it('should initialize object properly', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
const hw = 'Hello word',
|
2014-01-24 17:09:53 +00:00
|
|
|
now = Date.now(),
|
2016-08-19 17:46:59 +00:00
|
|
|
person = new Person({name: hw});
|
2014-01-24 17:09:53 +00:00
|
|
|
|
|
|
|
person.name.should.equal(hw);
|
|
|
|
person.name = 'Goodbye, Lenin';
|
|
|
|
(person.createdAt >= now).should.be.true;
|
|
|
|
person.isNewRecord().should.be.true;
|
2013-03-26 19:33:11 +00:00
|
|
|
});
|
2014-01-24 17:09:53 +00:00
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
describe('Date $now function (type: Date)', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let CustomModel;
|
2015-02-21 05:44:49 +00:00
|
|
|
|
|
|
|
before(function(done) {
|
|
|
|
CustomModel = db.define('CustomModel1', {
|
2016-08-19 17:46:59 +00:00
|
|
|
createdAt: {type: Date, default: '$now'},
|
2015-02-13 13:00:36 +00:00
|
|
|
});
|
2015-02-21 05:44:49 +00:00
|
|
|
db.automigrate('CustomModel1', done);
|
|
|
|
});
|
2015-02-13 13:00:36 +00:00
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
it('should report current date as default value for date property',
|
|
|
|
function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const now = Date.now();
|
2015-02-13 13:00:36 +00:00
|
|
|
|
2016-11-28 22:18:55 +00:00
|
|
|
CustomModel.create(function(err, model) {
|
2015-02-21 05:44:49 +00:00
|
|
|
should.not.exists(err);
|
2016-11-28 22:18:55 +00:00
|
|
|
model.createdAt.should.be.instanceOf(Date);
|
|
|
|
(model.createdAt >= now).should.be.true;
|
2015-02-21 05:44:49 +00:00
|
|
|
});
|
2015-02-13 13:00:36 +00:00
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
done();
|
|
|
|
});
|
2015-02-13 13:00:36 +00:00
|
|
|
});
|
|
|
|
|
2018-06-12 07:13:32 +00:00
|
|
|
describe('Date $now function (type: String)', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let CustomModel;
|
2015-02-21 05:44:49 +00:00
|
|
|
|
|
|
|
before(function(done) {
|
|
|
|
CustomModel = db.define('CustomModel2', {
|
2016-08-19 17:46:59 +00:00
|
|
|
now: {type: String, default: '$now'},
|
2015-02-13 13:00:36 +00:00
|
|
|
});
|
2015-02-21 05:44:49 +00:00
|
|
|
db.automigrate('CustomModel2', done);
|
|
|
|
});
|
2015-02-13 13:00:36 +00:00
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
it('should report \'$now\' as default value for string property',
|
|
|
|
function(done) {
|
2016-11-28 22:18:55 +00:00
|
|
|
CustomModel.create(function(err, model) {
|
|
|
|
if (err) return done(err);
|
|
|
|
model.now.should.be.instanceOf(String);
|
|
|
|
model.now.should.equal('$now');
|
2015-02-21 05:44:49 +00:00
|
|
|
});
|
2015-02-13 13:00:36 +00:00
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
done();
|
|
|
|
});
|
2015-02-13 13:00:36 +00:00
|
|
|
});
|
2015-02-20 10:18:47 +00:00
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
describe('now defaultFn', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let CustomModel;
|
2015-02-20 10:18:47 +00:00
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
before(function(done) {
|
|
|
|
CustomModel = db.define('CustomModel3', {
|
2016-08-19 17:46:59 +00:00
|
|
|
now: {type: Date, defaultFn: 'now'},
|
2015-02-21 05:44:49 +00:00
|
|
|
});
|
|
|
|
db.automigrate('CustomModel3', done);
|
2015-02-20 10:18:47 +00:00
|
|
|
});
|
2015-02-21 05:44:49 +00:00
|
|
|
|
|
|
|
it('should generate current time when "defaultFn" is "now"',
|
|
|
|
function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const now = Date.now();
|
2016-11-28 22:18:55 +00:00
|
|
|
CustomModel.create(function(err, model) {
|
|
|
|
if (err) return done(err);
|
|
|
|
model.now.should.be.instanceOf(Date);
|
|
|
|
model.now.should.be.within(now, now + 200);
|
2015-02-21 05:44:49 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-02-20 10:18:47 +00:00
|
|
|
});
|
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
describe('guid defaultFn', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let CustomModel;
|
2015-02-21 05:44:49 +00:00
|
|
|
|
|
|
|
before(function(done) {
|
|
|
|
CustomModel = db.define('CustomModel4', {
|
2016-08-19 17:46:59 +00:00
|
|
|
guid: {type: String, defaultFn: 'guid'},
|
2015-02-21 05:44:49 +00:00
|
|
|
});
|
|
|
|
db.automigrate('CustomModel4', done);
|
2015-02-20 10:18:47 +00:00
|
|
|
});
|
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
it('should generate a new id when "defaultFn" is "guid"', function(done) {
|
2016-11-28 22:18:55 +00:00
|
|
|
CustomModel.create(function(err, model) {
|
|
|
|
if (err) return done(err);
|
|
|
|
model.guid.should.match(UUID_REGEXP);
|
2015-02-21 05:44:49 +00:00
|
|
|
done();
|
|
|
|
});
|
2015-02-20 10:18:47 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-02-21 05:44:49 +00:00
|
|
|
describe('uuid defaultFn', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let CustomModel;
|
2015-02-21 05:44:49 +00:00
|
|
|
|
|
|
|
before(function(done) {
|
|
|
|
CustomModel = db.define('CustomModel5', {
|
2016-08-19 17:46:59 +00:00
|
|
|
guid: {type: String, defaultFn: 'uuid'},
|
2015-02-21 05:44:49 +00:00
|
|
|
});
|
|
|
|
db.automigrate('CustomModel5', done);
|
2015-02-20 10:18:47 +00:00
|
|
|
});
|
|
|
|
|
2016-09-22 23:13:11 +00:00
|
|
|
it('should generate a new id when "defaultfn" is "uuid"', function(done) {
|
2016-11-28 22:18:55 +00:00
|
|
|
CustomModel.create(function(err, model) {
|
|
|
|
if (err) return done(err);
|
|
|
|
model.guid.should.match(UUID_REGEXP);
|
2015-09-02 14:39:00 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('uuidv4 defaultFn', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let CustomModel;
|
2015-09-02 14:39:00 +00:00
|
|
|
|
|
|
|
before(function(done) {
|
|
|
|
CustomModel = db.define('CustomModel5', {
|
2016-08-19 17:46:59 +00:00
|
|
|
guid: {type: String, defaultFn: 'uuidv4'},
|
2015-09-02 14:39:00 +00:00
|
|
|
});
|
|
|
|
db.automigrate('CustomModel5', done);
|
|
|
|
});
|
|
|
|
|
2016-09-22 23:13:11 +00:00
|
|
|
it('should generate a new id when "defaultfn" is "uuidv4"', function(done) {
|
2016-11-28 22:18:55 +00:00
|
|
|
CustomModel.create(function(err, model) {
|
2015-09-02 14:39:00 +00:00
|
|
|
should.not.exists(err);
|
2016-11-28 22:18:55 +00:00
|
|
|
model.guid.should.match(UUID_REGEXP);
|
2015-02-21 05:44:49 +00:00
|
|
|
done();
|
|
|
|
});
|
2015-02-20 10:18:47 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-09-20 09:16:00 +00:00
|
|
|
describe('shortid defaultFn', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let ModelWithShortId;
|
2016-09-22 23:13:11 +00:00
|
|
|
before(createModelWithShortId);
|
2016-09-20 09:16:00 +00:00
|
|
|
|
|
|
|
it('should generate a new id when "defaultFn" is "shortid"', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const SHORTID_REGEXP = /^[0-9a-z_\-]{7,14}$/i;
|
2016-09-22 23:13:11 +00:00
|
|
|
ModelWithShortId.create(function(err, modelWithShortId) {
|
2016-09-21 10:48:02 +00:00
|
|
|
if (err) return done(err);
|
2016-09-22 23:13:11 +00:00
|
|
|
modelWithShortId.shortid.should.match(SHORTID_REGEXP);
|
2016-09-20 09:16:00 +00:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2016-09-22 23:13:11 +00:00
|
|
|
|
|
|
|
function createModelWithShortId(cb) {
|
|
|
|
ModelWithShortId = db.define('ModelWithShortId', {
|
|
|
|
shortid: {type: String, defaultFn: 'shortid'},
|
|
|
|
});
|
|
|
|
db.automigrate('ModelWithShortId', cb);
|
|
|
|
}
|
2016-09-20 09:16:00 +00:00
|
|
|
});
|
|
|
|
|
2014-01-24 17:09:53 +00:00
|
|
|
// it('should work when constructor called as function', function() {
|
|
|
|
// var p = Person({name: 'John Resig'});
|
|
|
|
// p.should.be.an.instanceOf(Person);
|
|
|
|
// p.name.should.equal('John Resig');
|
|
|
|
// });
|
|
|
|
});
|
2015-02-08 18:54:42 +00:00
|
|
|
|
2016-04-01 11:48:17 +00:00
|
|
|
describe('property value coercion', function() {
|
2015-02-08 18:54:42 +00:00
|
|
|
it('should coerce boolean types properly', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let p1 = new Person({name: 'John', married: 'false'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(false);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: 'true'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(true);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: '1'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(true);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: '0'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(false);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: true});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(true);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: false});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(false);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: 'null'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(true);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: ''});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(false);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: 'X'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(true);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: 0});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(false);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: 1});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.married.should.equal(true);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: null});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.should.have.property('married', null);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', married: undefined});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.should.have.property('married', undefined);
|
|
|
|
});
|
|
|
|
|
2016-07-24 12:38:37 +00:00
|
|
|
it('should coerce date types properly', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let p1 = new Person({name: 'John', dob: '2/1/2015'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.dob.should.eql(new Date('2/1/2015'));
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', dob: '2/1/2015'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.dob.should.eql(new Date('2/1/2015'));
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', dob: '12'});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.dob.should.eql(new Date('12'));
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', dob: 12});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.dob.should.eql(new Date(12));
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', dob: null});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.should.have.property('dob', null);
|
|
|
|
|
2016-08-19 17:46:59 +00:00
|
|
|
p1 = new Person({name: 'John', dob: undefined});
|
2015-02-08 18:54:42 +00:00
|
|
|
p1.should.have.property('dob', undefined);
|
|
|
|
|
2017-04-21 18:12:04 +00:00
|
|
|
p1 = new Person({name: 'John', dob: 'X'});
|
|
|
|
p1.should.have.property('dob');
|
|
|
|
p1.dob.toString().should.be.eql('Invalid Date');
|
2015-02-08 18:54:42 +00:00
|
|
|
});
|
2015-03-12 04:10:30 +00:00
|
|
|
});
|
|
|
|
|
2015-03-24 19:15:35 +00:00
|
|
|
describe('update/updateAll', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let idBrett, idCarla, idDonna, idFrank, idGrace, idHarry;
|
|
|
|
let filterBrett, filterHarry;
|
2017-04-06 20:04:16 +00:00
|
|
|
|
2015-03-25 04:30:40 +00:00
|
|
|
beforeEach(function clearOldData(done) {
|
2017-04-06 20:04:16 +00:00
|
|
|
db = getSchema();
|
2015-03-25 04:30:40 +00:00
|
|
|
Person.destroyAll(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function createTestData(done) {
|
|
|
|
Person.create([{
|
|
|
|
name: 'Brett Boe',
|
2016-04-01 11:48:17 +00:00
|
|
|
age: 19,
|
2015-03-25 04:30:40 +00:00
|
|
|
}, {
|
|
|
|
name: 'Carla Coe',
|
2016-04-01 11:48:17 +00:00
|
|
|
age: 20,
|
2015-03-25 04:30:40 +00:00
|
|
|
}, {
|
|
|
|
name: 'Donna Doe',
|
2016-04-01 11:48:17 +00:00
|
|
|
age: 21,
|
2015-03-25 04:30:40 +00:00
|
|
|
}, {
|
|
|
|
name: 'Frank Foe',
|
2016-04-01 11:48:17 +00:00
|
|
|
age: 22,
|
2015-03-25 04:30:40 +00:00
|
|
|
}, {
|
|
|
|
name: 'Grace Goe',
|
2016-04-01 11:48:17 +00:00
|
|
|
age: 23,
|
2017-04-06 20:04:16 +00:00
|
|
|
}], function(err, data) {
|
|
|
|
should.not.exist(err);
|
|
|
|
data.forEach(function(person) {
|
|
|
|
if (person.name === 'Brett Boe') idBrett = person.id;
|
|
|
|
if (person.name === 'Carla Coe') idCarla = person.id;
|
|
|
|
if (person.name === 'Donna Doe') idDonna = person.id;
|
|
|
|
if (person.name === 'Frank Foe') idFrank = person.id;
|
|
|
|
if (person.name === 'Grace Goe') idGrace = person.id;
|
|
|
|
});
|
|
|
|
should.exist(idBrett);
|
|
|
|
should.exist(idCarla);
|
|
|
|
should.exist(idDonna);
|
|
|
|
should.exist(idFrank);
|
|
|
|
should.exist(idGrace);
|
|
|
|
done();
|
|
|
|
});
|
2015-03-25 04:30:40 +00:00
|
|
|
});
|
|
|
|
|
2015-03-23 21:40:53 +00:00
|
|
|
it('should be defined as a function', function() {
|
2015-03-12 04:10:30 +00:00
|
|
|
Person.update.should.be.a.Function;
|
|
|
|
Person.updateAll.should.be.a.Function;
|
|
|
|
});
|
|
|
|
|
2015-03-25 04:30:40 +00:00
|
|
|
it('should not update instances that do not satisfy the where condition',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
|
|
|
idHarry = uid.fromConnector(db) || undefined;
|
2018-12-07 14:54:29 +00:00
|
|
|
const filter = connectorCapabilities.updateWithOtherThanId === false ?
|
2018-06-12 07:13:32 +00:00
|
|
|
{id: idHarry} : {name: 'Harry Hoe'};
|
|
|
|
Person.update(filter, {name: 'Marta Moe'}, function(err,
|
2015-03-25 04:30:40 +00:00
|
|
|
info) {
|
2018-06-12 07:13:32 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
if (connectorCapabilities.reportDeletedCount !== false) {
|
|
|
|
info.should.have.property('count', 0);
|
|
|
|
} else {
|
|
|
|
should.not.exist(info.count);
|
|
|
|
}
|
|
|
|
Person.find({where: {name: 'Harry Hoe'}}, function(err, people) {
|
2016-04-01 13:23:42 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
people.should.be.empty;
|
|
|
|
done();
|
2016-04-01 13:23:42 +00:00
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2015-02-08 18:54:42 +00:00
|
|
|
|
2015-03-25 04:30:40 +00:00
|
|
|
it('should only update instances that satisfy the where condition',
|
2018-06-12 07:13:32 +00:00
|
|
|
function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const filter = connectorCapabilities.deleteWithOtherThanId === false ?
|
2018-06-12 07:13:32 +00:00
|
|
|
{id: idBrett} : {name: 'Brett Boe'};
|
|
|
|
Person.update(filter, {name: 'Harry Hoe'}, function(err,
|
2015-03-25 04:30:40 +00:00
|
|
|
info) {
|
2018-06-12 07:13:32 +00:00
|
|
|
if (err) return done(err);
|
|
|
|
if (connectorCapabilities.reportDeletedCount !== false) {
|
|
|
|
info.should.have.property('count', 1);
|
|
|
|
} else {
|
|
|
|
should.not.exist(info.count);
|
|
|
|
}
|
|
|
|
Person.find({where: {age: 19}}, function(err, people) {
|
2016-04-01 13:23:42 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
people.should.have.length(1);
|
|
|
|
people[0].name.should.equal('Harry Hoe');
|
|
|
|
done();
|
2016-04-01 13:23:42 +00:00
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
});
|
2015-03-12 04:10:30 +00:00
|
|
|
|
2017-08-16 21:00:41 +00:00
|
|
|
it('should reject updated empty password with updateAll', function(done) {
|
|
|
|
StubUser.create({password: 'abc123'}, function(err, createdUser) {
|
|
|
|
if (err) return done(err);
|
|
|
|
StubUser.updateAll({where: {id: createdUser.id}}, {'password': ''}, function(err, updatedUser) {
|
|
|
|
(err.message).should.match(/password cannot be empty/);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-07-18 19:20:21 +00:00
|
|
|
bdd.itIf(connectorCapabilities.updateWithoutId !== false,
|
|
|
|
'should update all instances when the where condition is not provided', function(done) {
|
|
|
|
filterHarry = connectorCapabilities.deleteWithOtherThanId === false ?
|
|
|
|
{id: idHarry} : {name: 'Harry Hoe'};
|
|
|
|
filterBrett = connectorCapabilities.deleteWithOtherThanId === false ?
|
|
|
|
{id: idBrett} : {name: 'Brett Boe'};
|
|
|
|
Person.update(filterHarry, function(err, info) {
|
2017-04-06 20:04:16 +00:00
|
|
|
if (err) return done(err);
|
2017-07-18 19:20:21 +00:00
|
|
|
info.should.have.property('count', 5);
|
|
|
|
Person.find({where: filterBrett}, function(err, people) {
|
2015-03-23 21:40:53 +00:00
|
|
|
if (err) return done(err);
|
2017-07-18 19:20:21 +00:00
|
|
|
people.should.be.empty();
|
|
|
|
Person.find({where: filterHarry}, function(err, people) {
|
|
|
|
if (err) return done(err);
|
|
|
|
people.should.have.length(5);
|
|
|
|
done();
|
|
|
|
});
|
2015-03-23 21:40:53 +00:00
|
|
|
});
|
|
|
|
});
|
2017-04-06 20:04:16 +00:00
|
|
|
});
|
2015-03-23 21:40:53 +00:00
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
bdd.itIf(connectorCapabilities.ignoreUndefinedConditionValue !== false, 'should ignore where ' +
|
|
|
|
'conditions with undefined values', function(done) {
|
|
|
|
Person.update(filterBrett, {name: undefined, gender: 'male'},
|
2018-06-12 07:13:32 +00:00
|
|
|
function(err, info) {
|
2017-04-06 20:04:16 +00:00
|
|
|
if (err) return done(err);
|
2018-06-12 07:13:32 +00:00
|
|
|
info.should.have.property('count', 1);
|
|
|
|
Person.find({where: filterBrett}, function(err, people) {
|
|
|
|
if (err) return done(err);
|
|
|
|
people.should.have.length(1);
|
|
|
|
people[0].name.should.equal('Brett Boe');
|
|
|
|
done();
|
|
|
|
});
|
2016-04-01 11:48:17 +00:00
|
|
|
});
|
2017-04-06 20:04:16 +00:00
|
|
|
});
|
2015-03-23 21:40:53 +00:00
|
|
|
|
2017-04-06 20:04:16 +00:00
|
|
|
it('should not coerce invalid values provided in where conditions', function(done) {
|
|
|
|
Person.update({name: 'Brett Boe'}, {dob: 'notadate'}, function(err) {
|
|
|
|
should.exist(err);
|
|
|
|
err.message.should.equal('Invalid date: notadate');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-02-08 18:54:42 +00:00
|
|
|
});
|
2016-08-24 18:10:47 +00:00
|
|
|
|
|
|
|
describe('upsertWithWhere', function() {
|
2018-12-07 14:54:29 +00:00
|
|
|
let ds, Person;
|
2016-08-24 18:10:47 +00:00
|
|
|
before('prepare "Person" model', function(done) {
|
2017-07-18 19:20:21 +00:00
|
|
|
ds = getSchema();
|
2016-08-24 18:10:47 +00:00
|
|
|
Person = ds.define('Person', {
|
|
|
|
id: {type: Number, id: true},
|
|
|
|
name: {type: String},
|
|
|
|
city: {type: String},
|
|
|
|
});
|
|
|
|
ds.automigrate('Person', done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('has an alias "patchOrCreateWithWhere"', function() {
|
|
|
|
StubUser.upsertWithWhere.should.equal(StubUser.patchOrCreateWithWhere);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should preserve properties with dynamic setters on create', function(done) {
|
|
|
|
StubUser.upsertWithWhere({password: 'foo'}, {password: 'foo'}, function(err, created) {
|
|
|
|
if (err) return done(err);
|
|
|
|
created.password.should.equal('foo-FOO');
|
|
|
|
StubUser.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
|
|
|
found.password.should.equal('foo-FOO');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should preserve properties with dynamic setters on update', function(done) {
|
|
|
|
StubUser.create({password: 'foo'}, function(err, created) {
|
|
|
|
if (err) return done(err);
|
2018-12-07 14:54:29 +00:00
|
|
|
const data = {password: 'bar'};
|
2016-08-24 18:10:47 +00:00
|
|
|
StubUser.upsertWithWhere({id: created.id}, data, function(err, updated) {
|
|
|
|
if (err) return done(err);
|
|
|
|
updated.password.should.equal('bar-BAR');
|
|
|
|
StubUser.findById(created.id, function(err, found) {
|
|
|
|
if (err) return done(err);
|
|
|
|
found.password.should.equal('bar-BAR');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should preserve properties with "undefined" value', function(done) {
|
|
|
|
Person.create(
|
|
|
|
{id: 10, name: 'Ritz', city: undefined},
|
|
|
|
function(err, instance) {
|
|
|
|
if (err) return done(err);
|
|
|
|
instance.toObject().should.have.properties({
|
|
|
|
id: 10,
|
|
|
|
name: 'Ritz',
|
|
|
|
city: undefined,
|
|
|
|
});
|
|
|
|
|
|
|
|
Person.upsertWithWhere({id: 10},
|
|
|
|
{name: 'updated name'},
|
2018-06-12 07:13:32 +00:00
|
|
|
function(err, updated) {
|
|
|
|
if (err) return done(err);
|
2018-12-07 14:54:29 +00:00
|
|
|
const result = updated.toObject();
|
2018-06-12 07:13:32 +00:00
|
|
|
result.should.have.properties({
|
|
|
|
id: instance.id,
|
|
|
|
name: 'updated name',
|
2016-08-24 18:10:47 +00:00
|
|
|
});
|
2018-06-12 07:13:32 +00:00
|
|
|
should.equal(result.city, null);
|
|
|
|
done();
|
|
|
|
});
|
2018-07-16 06:46:25 +00:00
|
|
|
}
|
|
|
|
);
|
2016-08-24 18:10:47 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should allow save() of the created instance', function(done) {
|
|
|
|
Person.upsertWithWhere({id: 999},
|
|
|
|
// Todo @mountain: This seems a bug why in data object still I need to pass id?
|
|
|
|
{id: 999, name: 'a-name'},
|
|
|
|
function(err, inst) {
|
|
|
|
if (err) return done(err);
|
|
|
|
inst.save(done);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('works without options on create (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const person = {id: 123, name: 'a', city: 'city a'};
|
2016-08-24 18:10:47 +00:00
|
|
|
Person.upsertWithWhere({id: 123}, person)
|
|
|
|
.then(function(p) {
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Person);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(person.id);
|
2016-08-24 18:10:47 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.name.should.equal(person.name);
|
|
|
|
p.city.should.equal(person.city);
|
|
|
|
return Person.findById(p.id)
|
|
|
|
.then(function(p) {
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(person.id);
|
2016-08-24 18:10:47 +00:00
|
|
|
p.id.should.not.have.property('_id');
|
|
|
|
p.name.should.equal(person.name);
|
|
|
|
p.city.should.equal(person.city);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('works with options on create (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const person = {id: 234, name: 'b', city: 'city b'};
|
2016-08-24 18:10:47 +00:00
|
|
|
Person.upsertWithWhere({id: 234}, person, {validate: false})
|
|
|
|
.then(function(p) {
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Person);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(person.id);
|
2016-08-24 18:10:47 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.name.should.equal(person.name);
|
|
|
|
p.city.should.equal(person.city);
|
|
|
|
return Person.findById(p.id)
|
|
|
|
.then(function(p) {
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(person.id);
|
2016-08-24 18:10:47 +00:00
|
|
|
p.id.should.not.have.property('_id');
|
|
|
|
p.name.should.equal(person.name);
|
|
|
|
p.city.should.equal(person.city);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('works without options on update (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const person = {id: 456, name: 'AAA', city: 'city AAA'};
|
2016-08-24 18:10:47 +00:00
|
|
|
Person.create(person)
|
|
|
|
.then(function(created) {
|
|
|
|
created = created.toObject();
|
|
|
|
delete created.city;
|
|
|
|
created.name = 'BBB';
|
|
|
|
return Person.upsertWithWhere({id: 456}, created)
|
|
|
|
.then(function(p) {
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Person);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(created.id);
|
2016-08-24 18:10:47 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.name.should.equal('BBB');
|
|
|
|
p.should.have.property('city', 'city AAA');
|
|
|
|
return Person.findById(created.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.name.should.equal('BBB');
|
|
|
|
p.city.should.equal('city AAA');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('works with options on update (promise variant)', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const person = {id: 789, name: 'CCC', city: 'city CCC'};
|
2016-08-24 18:10:47 +00:00
|
|
|
Person.create(person)
|
|
|
|
.then(function(created) {
|
|
|
|
created = created.toObject();
|
|
|
|
delete created.city;
|
|
|
|
created.name = 'Carlton';
|
|
|
|
return Person.upsertWithWhere({id: 789}, created, {validate: false})
|
|
|
|
.then(function(p) {
|
|
|
|
should.exist(p);
|
|
|
|
p.should.be.instanceOf(Person);
|
2017-04-06 20:04:16 +00:00
|
|
|
p.id.should.eql(created.id);
|
2016-08-24 18:10:47 +00:00
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.name.should.equal('Carlton');
|
|
|
|
p.should.have.property('city', 'city CCC');
|
|
|
|
return Person.findById(created.id)
|
|
|
|
.then(function(p) {
|
|
|
|
p.should.not.have.property('_id');
|
|
|
|
p.name.should.equal('Carlton');
|
|
|
|
p.city.should.equal('city CCC');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(done);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('fails the upsertWithWhere operation when data object is empty', function(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const options = {};
|
2016-08-24 18:10:47 +00:00
|
|
|
Person.upsertWithWhere({name: 'John Lennon'}, {}, options,
|
|
|
|
function(err) {
|
|
|
|
err.message.should.equal('data object cannot be empty!');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('creates a new record when no matching instance is found', function(done) {
|
|
|
|
Person.upsertWithWhere({city: 'Florida'}, {name: 'Nick Carter', id: 1, city: 'Florida'},
|
|
|
|
function(err, created) {
|
|
|
|
if (err) return done(err);
|
|
|
|
Person.findById(1, function(err, data) {
|
|
|
|
if (err) return done(err);
|
|
|
|
data.id.should.equal(1);
|
|
|
|
data.name.should.equal('Nick Carter');
|
|
|
|
data.city.should.equal('Florida');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('fails the upsertWithWhere operation when multiple instances are ' +
|
|
|
|
'retrieved based on the filter criteria', function(done) {
|
|
|
|
Person.create([
|
|
|
|
{id: '2', name: 'Howie', city: 'Florida'},
|
|
|
|
{id: '3', name: 'Kevin', city: 'Florida'},
|
|
|
|
], function(err, instance) {
|
|
|
|
if (err) return done(err);
|
|
|
|
Person.upsertWithWhere({city: 'Florida'}, {
|
|
|
|
id: '4', name: 'Brian',
|
|
|
|
}, function(err) {
|
|
|
|
err.message.should.equal('There are multiple instances found.' +
|
|
|
|
'Upsert Operation will not be performed!');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('updates the record when one matching instance is found ' +
|
|
|
|
'based on the filter criteria', function(done) {
|
|
|
|
Person.create([
|
|
|
|
{id: '5', name: 'Howie', city: 'Kentucky'},
|
|
|
|
], function(err, instance) {
|
|
|
|
if (err) return done(err);
|
|
|
|
Person.upsertWithWhere({city: 'Kentucky'}, {
|
|
|
|
name: 'Brian',
|
|
|
|
}, {validate: false}, function(err, instance) {
|
|
|
|
if (err) return done(err);
|
|
|
|
Person.findById(5, function(err, data) {
|
|
|
|
if (err) return done(err);
|
2017-04-06 20:04:16 +00:00
|
|
|
should.equal(data.id, 5);
|
2016-08-24 18:10:47 +00:00
|
|
|
data.name.should.equal('Brian');
|
|
|
|
data.city.should.equal('Kentucky');
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2019-04-01 11:18:05 +00:00
|
|
|
|
|
|
|
it('preserves empty values from the database', async () => {
|
|
|
|
// https://github.com/strongloop/loopback-datasource-juggler/issues/1692
|
|
|
|
|
2019-04-09 13:54:52 +00:00
|
|
|
// Initially, all Players were always active, no property was needed
|
|
|
|
const Player = db.define('Player', {name: String});
|
2019-04-01 11:18:05 +00:00
|
|
|
|
2019-04-09 13:54:52 +00:00
|
|
|
await db.automigrate('Player');
|
|
|
|
const created = await Player.create({name: 'Pen'});
|
2019-04-01 11:18:05 +00:00
|
|
|
|
|
|
|
// Later on, we decide to introduce `active` property
|
2019-04-09 13:54:52 +00:00
|
|
|
Player.defineProperty('active', {
|
2019-04-01 11:18:05 +00:00
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
});
|
2019-04-09 13:54:52 +00:00
|
|
|
await db.autoupdate('Player');
|
2019-04-01 11:18:05 +00:00
|
|
|
|
|
|
|
// And upsertWithWhere an existing record
|
2019-04-09 13:54:52 +00:00
|
|
|
const found = await Player.upsertWithWhere({id: created.id}, {name: 'updated'});
|
|
|
|
should(found.toObject().active).be.oneOf([
|
|
|
|
undefined, // databases supporting `undefined` value
|
|
|
|
null, // databases representing `undefined` as `null` (e.g. SQL)
|
|
|
|
]);
|
2019-04-01 11:18:05 +00:00
|
|
|
});
|
2016-08-24 18:10:47 +00:00
|
|
|
});
|
2013-03-26 19:33:11 +00:00
|
|
|
});
|
2015-03-20 16:49:32 +00:00
|
|
|
|
|
|
|
function givenSomePeople(done) {
|
2018-12-07 14:54:29 +00:00
|
|
|
const beatles = [
|
2016-08-19 17:46:59 +00:00
|
|
|
{name: 'John Lennon', gender: 'male'},
|
|
|
|
{name: 'Paul McCartney', gender: 'male'},
|
|
|
|
{name: 'George Harrison', gender: 'male'},
|
|
|
|
{name: 'Ringo Starr', gender: 'male'},
|
|
|
|
{name: 'Pete Best', gender: 'male'},
|
|
|
|
{name: 'Stuart Sutcliffe', gender: 'male'},
|
2015-03-20 16:49:32 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
async.series([
|
|
|
|
Person.destroyAll.bind(Person),
|
|
|
|
function(cb) {
|
|
|
|
async.each(beatles, Person.create.bind(Person), cb);
|
2016-04-01 11:48:17 +00:00
|
|
|
},
|
2015-03-20 16:49:32 +00:00
|
|
|
], done);
|
|
|
|
}
|