# List of notable changes made between 2.x and 3.0 All breaking changes must be described here. When adding a new entry, always describe the impact on users and instructions for upgrading applications from 2.x to 3.0. See also https://github.com/strongloop/loopback/blob/master/3.0-DEVELOPING.md for more details. ## Always use bluebird as promise library In version 3.0, we always use bluebird as our promise library instead of `global.Promise`. We consider Bluebird API a part of LoopBack API from now on, you are welcome to use any Bluebird-specific methods in your applications. If you are using LoopBack with a custom promise implementation provided via `global.Promise`, you will have to check all places where you are using non-standard promise API and update them to use Bluebird API instead. See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/790) for more details. ## DAO.find provides ctx.data in "loaded" hook When implementing "loaded" hook for `DAO.find` method, we have mistakenly implemented a version that sets `ctx.instance` instead of `ctx.data`. This defeats the purpose of the "loaded" hook, which is to allow hooks to modify the raw data provided by the datasource before it's used to build a model instance. This has been fixed in 3.0 and the "loaded" hook now consistently provides `ctx.data` for all operations. If you have a "loaded" hook handler that checks `if (ctx.instance)` then you can remove this condition together with the branch that follows. See [related code change](https://github.com/strongloop/loopback-datasource-juggler/commit/30283291?w=1) for more details. ## DAO.create no longer returns the instance(s) created While implementing support for promises in `DAO.create`, we found that this method returns the instance object synchronously. This is inconsistent with the usual convention of accessing the result via callback/promise and it may not work correctly in cases where some fields like the `id` property are generated by the database. We have changed the API to be consistent with other DAO methods: when invoked with a callback argument, the method does not return anything. When invoked without any callback, a promise is returned. See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/918) for more details. ## Applying an undefined mixin to a LoopBack model throws an error When applying an undefined mixin to a LoopBack model, a warning message was logged regarding the invalid mixin, which needs to be addressed rather than silently ignored. This has been fixed in 3.0, therefore an undefined mixin applied to a LoopBack model will throw an error that needs to be handled. See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/944) for more details. ## Remove deprecated model hooks and model events The following deprecated model events are now removed. Please upgrade your code by using operation hooks in its place. Model events * changed * deletedAll * deleted See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/965) for more details. ## Model property names with dot(s) generates an error Instead of showing a deprecation warning for model property names with dots, for example, `customer.name: 'string'`, an error is thrown in 3.0 for enforcing use of valid model property names. See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/947) for more details. ## Remove wrapper `DataSource.registerType()` `DataSource.registerType() method is removed as it was a wrapper for `ModelBuilder.registerType()` and was deprecated. See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/976) for more details. ## Disallow array input for updateOrCreate function Allowing updateOrCreate to accept an array as input would only work when creating new model instances (not updating them), so this support has been removed. Please use `create` function instead (array inputs only worked to create new instances with this method before). If you would like to perform a bulk `updateOrCreate`, you could use `async.each` or `Promise.all` to repeatedly call `updateOfCreate` for each instance. See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/889) here. ## Removing strict: validate and strict: throw Given a user model definition as follow: ```js ds.define('User', { name: String, required: false, age: Number, required: false }) var johndoe = new User({ name: 'John doe', age: 15, gender: 'm'}); ``` - #### strict: false behavior will remain the same and unknown properties will be saved along with other properties ```js //johndoe would be created as { id: 1, name: 'John doe', age: 15, geneder: 'm' } ``` - #### strict: `'validate'` and strict: `'throw'` are removed in favor of `strict: true`, and because non-empty string resolves as true, they will share the same behavior as `strict: true` - #### strict: `true`'s behavior change: **Previously:** (2.x) `strict:true` would silently removing unknown properties, and User instance will be created with unknown properties discarded ```js johndoe.isValid(); //true //johndoe would be created as { id: 1, name: 'John doe', age: 15 } ``` **New Behavior:** (3.x) ```js johndoe.isValid(); //false //johndoe would NOT be created and will result in the following error //ValidationError: The User instance is not valid. Details: gender is not defined in the model (value: 'm'). ``` See [related code change](https://github.com/strongloop/loopback-datasource-juggler/pull/1084) here. ## Users cannot provide a custom id value when id is auto-generated For security reason, the default value of config variable `forceId` is set to `true` if a model uses auto-generated id. It means creating/updating instance with a given id will return an error message like: ``` Unhandled rejection ValidationError: The `MyModel` instance is not valid. Details: `id` can't be set (value: 1). ``` You can change `forceId: false` in model.json file to disable the check, eg: Change config in `common/models/MyModel.json`: ```json { "name": "Product", "forceId": false } ``` Then create a new instance with given id: ```js MyModel.create({ id: 1, name: 'test', }).then(function(modelInstance) { // Get the modelInstance with id = 1. }); ```