Skip to content

Migrating from 0.15.1 to 1.0.0

Ricardo Graça edited this page Sep 3, 2019 · 15 revisions

Default to {require: true} on Model#fetch and Collection#fetchOne

Related PR: #2006

The default was changed to {require: true} on the following fetch operations:

  • Model#fetch
  • Collection#fetchOne

Note that a new model option was also added to help you define this behavior on a per-model basis: Model#requireFetch.

This change in behavior means that the fetch operations mentioned will be rejected with an error if there are no results. You'll have to adapt your fetch code to deal with these errors if you'd like to adopt the new defaults.

If you prefer the previous behavior of returning null in this situation you'll have to either pass the require: false option to all affected fetch calls, or add the requireFetch: false option to your model definitions.

// Before
new MyModel({id: 1}).fetch(model => {
  if (!model) // Do something if there are no results
})

// Now
new MyModel({id: 1}).fetch(model => {
  // A model is guaranteed to exist
}).catch(MyModel.NotFoundError => {
  // Do something if there are no results 
})

// Keeping the same behavior as Bookshelf versions prior to 1.0.0  
const MyModel = bookshelf.model('MyModel', {
  tableName: 'my_models',
  requireFetch: false
})

new MyModel({id: 1}).fetch(model => {
  if (!model) // Do something if there are no results
})

Different arguments on after save event listeners (saved, created and updated)

Related PR: #2012

The event signatures have changed by removing the second argument that was being passed to the event listeners of:

Model#event:created

// Before
bookshelf.model('MyModel', {
  initialize() {
    this.on('created', (model, newId, options) => {
      // ...
    })
  }
}

// After
bookshelf.model('MyModel', {
  initialize() {
    this.on('created', (model, options) => {
      const newId = model.id
      // ...
    })
  }
}

Model#event:updated

// Before
bookshelf.model('MyModel', {
  initialize() {
    this.on('updated', (model, numberOfAffectedRows, options) => {
      // ...
    })
  }
}

// After
bookshelf.model('MyModel', {
  initialize() {
    this.on('updated', (model, options) => {
      const numberOfAffectedRows = 1
      // ...
    })
  }
}

Model#event:saved

// Before
bookshelf.model('MyModel', {
  initialize() {
    this.on('saved', (model, differentThings, options) => {
      // differentThings can be either the number of affected rows (always 1) or
      // an array containing the id of the inserted model
      // ...
    })
  }
}

// After
bookshelf.model('MyModel', {
  initialize() {
    this.on('saved', (model, options) => {
      const modelId = model.id
      const numberOfAffectedRows = 1
      // ...
    })
  }
}

Processor plugin

Related PR: #2000

The processor plugin was removed from core Bookshelf and moved to its own separate package and repository. You can find it in bookshelf/processor-plugin.

To migrate to the new package install it with:

npm install bookshelf-processor-plugin

and then:

// Replace this
bookshelf.plugin('processor')

// With this
bookshelf.plugin('bookshelf-processor-plugin')

Case Converter plugin

Related PR: #2000

The case-converter plugin was removed from core Bookshelf and moved to its own separate package and repository. You can find it in bookshelf/case-converter-plugin.

To migrate to the new package install it with:

npm install bookshelf-case-converter-plugin

and then:

// Replace this
bookshelf.plugin('case-converter')

// With this
bookshelf.plugin('bookshelf-case-converter-plugin')

Virtuals plugin

Related PR: #2000

The virtuals plugin was removed from core Bookshelf and moved to its own separate package and repository. You can find it in bookshelf/virtuals-plugin.

To migrate to the new package install it with:

npm install bookshelf-virtuals-plugin

and then:

// Replace this
bookshelf.plugin('virtuals')

// With this
bookshelf.plugin('bookshelf-virtuals-plugin')

Collection#where()

Related PR: #2001

This method was changed so that instead of simply filtering the existing models already loaded in the collection it will constrain any subsequent fetch queries. This makes it behave like Model#where() and the method signature is exactly the same.

If you were relying on the previous behavior you can achieve the same results with:

// Before
const someModels = myCollection.where({ name: 'Bob' })
const otherModels = myCollection.where({ name: 'Bob', age: 35 })

// After
const someModels = myCollection.filter(model => model.get('name') === 'Bob')
const someModels = myCollection.filter(model => {
  return model.get('name') === 'Bob' && model.get('age') === 35
})

Collection#findWhere()

Related PR: #2001

This method was removed. If you were relying on it you can achieve the same results with:

// Before
const someModels = myCollection.findWhere({ name: 'Bob' })

// After
const someModels = myCollection.find(model => model.get('name') === 'Bob')

Model lodash methods invert, keys, toPairs, values

Related PR: #2005

These methods were removed. If you relied on them you'll have to adapt your code like so:

/** Model#invert **/

// before
const invertedModel = model.invert()
// after
const _ = require('lodash')
const invertedModel = _.invert(model.attributes)
/** Model#keys **/

// before
const keys = model.keys()
// after
const keys = Object.keys(model.attributes)
// or
const _ = require('lodash')
const keys = _.keys(model.attributes)
/** Model#toPairs **/

// before
const pairs = model.toPairs()
// after
const pairs = Object.entries(model.attributes)
// or
const _ = require('lodash')
const pairs = _.pairs(model.attributes)
/** Model#values **/

// before
const values = model.values()
// after
const values = Object.values(model.attributes)
// or
const _ = require('lodash')
const values = _.values(model.attributes)

Collection lodash methods chain, difference, drop, each, head, indexOf, initial, lastIndexOf, max, maxBy, min, minBy, shuffle, size, tail, take, without

Related PR: #2005

These methods were removed. If you relied on them you'll have to adapt your code like so:

/** Collection#chain **/

// before
const value = collection.chain().moreLodashMethods().value()
// after
const _ = require('lodash')
const value = _.chain(collection.models).moreLodashMethods().value()
/** Collection#difference **/

// before
const diff = collection.difference(otherCollection.models)
// after
const _ = require('lodash')
const diff = _.difference(collection.models, otherCollection.models)
/** Collection#drop **/

// before
const smallerCollection = collection.drop(2)
// after
const _ = require('lodash')
const smallerCollection = _.drop(collection.models, 2)
/** Collection#each **/

// before
collection.each(model => console.log(model.get('name')))
// after
collection.forEach(model => console.log(model.get('name')))
// or
collection.models.forEach(model => console.log(model.get('name')))
// or
const _ = require('lodash')
_.each(collection.models, model => console.log(model.get('name')))
/** Collection#head **/

// before
const head = collection.head()
// after
const head = collection.first()
// or
const head = collection.at(0)
/** Collection#indexOf **/

// before
const modelIndex = collection.indexOf(model)
// after
const modelIndex = collection.models.indexOf(model)
// or
const _ = require('lodash')
const modelIndex = _.indexOf(collection.models, model)
/** Collection#initial **/

// before
const smallerCollection = collection.initial()
// after
const smallerCollection = collection.slice(0, -1)
// or
const _ = require('lodash')
const smallerCollection = _.initial(collection.models)
/** Collection#lastIndexOf **/

// before
const modelIndex = collection.lastIndexOf(model)
// after
const modelIndex = collection.models.lastIndexOf(model)
// or
const _ = require('lodash')
const modelIndex = _.lastIndexOf(collection.models, model)
/** Collection#max **/

// before
const model = collection.max()
// after
const _ = require('lodash')
const model = _.max(collection.models)
/** Collection#maxBy **/

// before
const model = collection.maxBy(model => model.get('age'))
// after
const _ = require('lodash')
const model = _.maxBy(collection.models, model => model.get('age'))
/** Collection#min **/

// before
const model = collection.min()
// after
const _ = require('lodash')
const model = _.min(collection.models)
/** Collection#minBy **/

// before
const model = collection.minBy(model => model.get('age'))
// after
const _ = require('lodash')
const model = _.minBy(collection.models, model => model.get('age'))
/** Collection#shuffle **/

// before
const shuffledCollection = collection.shuffle()
// after
const _ = require('lodash')
const shuffledCollection = _.shuffle(collection.models)
/** Collection#size **/

// before
const size = collection.size()
// after
const size = collection.length
/** Collection#tail **/

// before
const smallerCollection = collection.tail()
// after
const smallerCollection = collection.slice(1)
// or
const _ = require('lodash')
const smallerCollection = _.tail(collection.models)
/** Collection#take **/

// before
const smallerCollection = collection.take(2)
// after
const smallerCollection = collection.slice(0, 2)
// or
const _ = require('lodash')
const smallerCollection = _.take(collection.models, 2)
/** Collection#without **/

// before
const smallerCollection = collection.without(model)
// after
const _ = require('lodash')
const smallerCollection = _.without(collection.models, model)