Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions lib/dao.js
Original file line number Diff line number Diff line change
Expand Up @@ -1065,8 +1065,15 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
var obj, Model = self.lookupModel(data);

if (data) {
obj = new Model(data, {fields: query.fields, applySetters: false,
persisted: true});
var ctorOpts = {
fields: query.fields,
applySetters: false,
persisted: true,
};
if (Model.settings.applyDefaultsOnReads === false) {
ctorOpts.applyDefaultValues = false;
}
obj = new Model(data, ctorOpts);
}

if (created) {
Expand Down Expand Up @@ -1936,7 +1943,15 @@ DataAccessObject.find = function find(query, options, cb) {
if (!err && Array.isArray(data)) {
async.map(data, function(item, next) {
var Model = self.lookupModel(item);
var obj = new Model(item, {fields: query.fields, applySetters: false, persisted: true});
var ctorOpts = {
fields: query.fields,
applySetters: false,
persisted: true,
};
if (Model.settings.applyDefaultsOnReads === false) {
ctorOpts.applyDefaultValues = false;
}
var obj = new Model(item, ctorOpts);

if (query && query.include) {
if (query.collect) {
Expand Down
69 changes: 69 additions & 0 deletions test/basic-querying.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,75 @@ describe('basic-querying', function() {
sample(['id']).expect(['id']);
sample(['email']).expect(['email']);
});

it('applies default values by default', function() {
// Backwards compatibility, see
// https://github.com/strongloop/loopback-datasource-juggler/issues/1692

// Initially, all Players were always active, no property was needed
var Player = db.define('Player', {name: String});
var created;
return db.automigrate('Player')
.then(function() { return Player.create({name: 'Pen'}); })
.then(function(result) {
created = result;

// Later on, we decide to introduce `active` property
Player.defineProperty('active', {
type: Boolean,
default: false,
});
return db.autoupdate('Player');
})
.then(function() {
// And query existing data
return Player.findOne();
})
.then(function(found) {
should(found.toObject().active).be.oneOf([
// For databases supporting `undefined` value,
// we convert `undefined` to property default.
false,
// For databases representing `undefined` as `null` (e.g. SQL),
// we treat `null` as a defined value and don't apply defaults.
null,
]);
});
});

it('preserves empty values from the database when "applyDefaultsOnReads" is false', function() {
// https://github.com/strongloop/loopback-datasource-juggler/issues/1692

// Initially, all Players were always active, no property was needed
var Player = db.define(
'Player',
{name: String},
{applyDefaultsOnReads: false}
);
var created;
return db.automigrate('Player')
.then(function() { return Player.create({name: 'Pen'}); })
.then(function(result) {
created = result;

// Later on, we decide to introduce `active` property
Player.defineProperty('active', {
type: Boolean,
default: false,
});
return db.autoupdate('Player');
})
.then(function() {
// And query existing data
return Player.findOne();
})
.then(function(found) {
should(found.toObject().active).be.oneOf([
undefined, // databases supporting `undefined` value
null, // databases representing `undefined` as `null`
]);
});
});
});

describe('count', function() {
Expand Down
76 changes: 76 additions & 0 deletions test/manipulation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,82 @@ describe('manipulation', function() {
})
.catch(done);
});

it('applies default values on returned data', function() {
// Backwards compatibility, see
// https://github.com/strongloop/loopback-datasource-juggler/issues/1692

// Initially, all Players were always active, no property was needed
var Player = db.define('Player', {name: String});
var created;
return db.automigrate('Player')
.then(function() { return Player.create({name: 'Pen'}); })
.then(function(result) {
created = result;

// Later on, we decide to introduce `active` property
Player.defineProperty('active', {
type: Boolean,
default: false,
});
return db.autoupdate('Player');
})
.then(function() {
// and findOrCreate an existing record
return Player.findOrCreate({id: created.id}, {name: 'updated'});
})
.then(function(result) {
var found = result[0];

// Backwards-compatibility
// When Pen does not have "active" flag set, we change it to default
should(found.toObject().active).be.oneOf([
// For databases supporting `undefined` value,
// we convert `undefined` to property default.
false,
// For databases representing `undefined` as `null` (e.g. SQL),
// we treat `null` as a defined value and don't apply defaults.
null,
]);
});
});

it('preserves empty values from the database when "applyDefaultsOnReads" is false', function() {
// https://github.com/strongloop/loopback-datasource-juggler/issues/1692

// Initially, all Players were always active, no property was needed
var Player = db.define(
'Player',
{name: String},
{applyDefaultsOnReads: false}
);
var created;

return db.automigrate('Player')
.then(function() { return Player.create({name: 'Pen'}); })
.then(function(result) {
created = result;

// Later on, we decide to introduce `active` property
Player.defineProperty('active', {
type: Boolean,
default: false,
});
return db.autoupdate('Player');
})
.then(function() {
// And findOrCreate an existing record
return Player.findOrCreate({id: created.id}, {name: 'updated'});
})
.then(function(result) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I like the spread() function used in the original PR #1705, any reason switched back to then()?

Not a blocker for merging, just curious.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In LB 3.x, we are using Bluebird as the promise library, therefore .spread() is available on all Promise instances.

In LB 2.x, we use the native Promise library if it's provided (Node.js 4.0 an higher), and require users to set global.Promise to any compatible Promise implementation on Node.js versions 0.10 & 0.12. The native Promise does not provide .spread() API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I see. makes sense thanks!.

var found = result[0];

should(found.toObject().active).be.oneOf([
undefined, // databases supporting `undefined` value
null, // databases representing `undefined` as `null`
]);
});
});
});

describe('destroy', function() {
Expand Down