Migrating from 0.13.3 to 0.14.0
Related PR: #1848
The previous()
and previousAttributes()
methods were changed so they are now more useful. Whenever a model is saved or destroyed the previous attributes are no longer reset back to the current attributes, meaning you can access the previous value of an attribute before the save or destroy operation.
However this is a breaking change, but since the old behavior wasn't very useful it's likely this won't cause issues for many people. In case you were using these methods previously and expect the previous attributes to equal the current attributes after a save()
or destroy()
call, just replace:
-
model.previousAttributes()
->model.attributes
-
model.previous('attributeName')
->model.get('attributeName')
Related PR: #1846
The .set()
method determines if a model is duplicate by its primary key. If there's already another model in the collection with the same primary key then the model being added is a duplicate.
Previously setting both the merge
and remove
options of collection.set()
to false
would just cause any duplicate models passed in to be ignored. Now the duplicate models will be present which is useful if you have models in your database with the same primary key but different columns otherwise.
You can't really get the old behavior back, because there was a bug in collection.set()
that caused duplicates to be present by default but each one had the exact same column values as the last one being added, even if they had different values in the database. However, if you pass the merge: true
option, the behavior should be very similar with the exception that there will be a single model with the values obtained by merging all duplicates.
Now, if you want to have duplicate models in your collection you have to pass merge: false, remove: false
to collection.set()
.
Related PR: #1839
This shouldn't cause many issues but now, when serializing a model with an empty hasOne
relation, the result will be null
for consistency with belongsTo
.
If you were using:
if (model.singleRelation && model.singeRelation.id) { ... }
before for checking if a hasOne
relation was set, this is no longer necessary, although it will continue working. That code can now be simplified as:
if (model.singleRelation) { ... }
If you were depending on the return value always being an object you'll have to adapt your code to handle the possibility of a null
relation in this case.
Related PR: #1824
Previously there was an error that was only thrown when the defined morph type couldn't be found in any of the possible target types, but the message was a bit ambiguous because it only said that the target model couldn't be found, which isn't very helpful.
Now when trying to eager load a row that doesn't have the type attribute set there will be a new error thrown:
The target polymorphic model could not be determined because it's missing the type attribute
For example, the above error will be shown if you have a model in your database like this:
const Photo = Bookshelf.Model.extend({
tableName: 'photos',
imageable() {
return this.morphTo('imageable', Site, [Author, 'profile_pic'])
}
})
new Photo({ name: 'something', imageable_id: 4, imageable_type: null }).save()
And you try to fetch it with its related imageable
:
Photo.fetchAll({withRelated: ['imageable']})
Additionally in the following situation of an unrecognized morph type:
new Photo({ name: 'something', imageable_id: 4, imageable_type: 'bad-type' }).save()
where bad-type
is not one of the types that the imageable
expects now the error message also clearly says so:
The target polymorphic type "bad-type" is not one of the defined target types
instead of the previous generic message:
The target polymorphic model was not found
In this case if you were doing checks based on the error message you'll have to update your logic to deal with these two cases.
Related PR: #1798
Previously when saving a model that had no changes it would still update the updated_at
column in case the model had the option hasTimestamps: true
. If you were using this to only update the updated_at
attribute of a model without doing any further changes you can now achieve the same thing by changing:
// Before
myModel.save() // updated_at got updated to the current date
// Now
myModel.save({updated_at: new Date()})