Fix coercion of PK value in `replaceById` method

Before this change, when both the PK value (`id`) and the `data` object
were provided as plain-data values (e.g. as received in a JSON request),
and the connector was using a complex PK type (e.g. `ObjectID`
in MongoDB), then `replaceById` operation was printing confusing
warnings:

    WARNING: id property cannot be changed from 5d39775a59f5f541513c5e05
        to 5d39775a59f5f541513c5e05 for model:Post
        in 'before save' operation hook

    WARNING: id property cannot be changed from 5d39775a59f5f541513c5e05
        to 5d39775a59f5f541513c5e05 for model:Post
        in 'loaded' operation hook

This commit fixes the problem by applying the same type coercion on the
PK value (`id`) as has been applied by the model constructor on the PK
property (`data.id`).

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
This commit is contained in:
Miroslav Bajtoš 2019-07-25 11:33:59 +02:00
parent dd7167b533
commit f1fa976f50
No known key found for this signature in database
GPG Key ID: 6F2304BA9361C7E3
2 changed files with 32 additions and 0 deletions

View File

@ -2609,6 +2609,11 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
err.statusCode = 400;
process.nextTick(function() { cb(err); });
return cb.promise;
} else {
// Ensure any type conversion applied by the instance constructor
// on `data.id` is applied on the `id` value too.
// Typically, MongoDB converts PK value from a string to an ObjectID.
id = inst[pkName];
}
let context = {

View File

@ -1576,6 +1576,33 @@ describe('manipulation', function() {
done();
});
});
it('correctly coerces the PK value', async () => {
const created = await Post.create({
title: 'a title',
content: 'a content',
});
// Emulate what happens when model instance is received by REST API clients
const data = JSON.parse(JSON.stringify(created));
// Modify some of the data
data.title = 'Draft';
// Call replaceById to modify the database record
await Post.replaceById(data.id, data);
// Verify what has been stored
const found = await Post.findById(data.id);
found.toObject().should.eql({
id: created.id,
title: 'Draft',
content: 'a content',
});
// Verify that no warnings were triggered
Object.keys(Post._warned).should.be.empty();
});
});
describe('findOrCreate', function() {