fetch(options) {
      return this._doFetch(this.attributes, options).tap(() => {
        this._previousAttributes = _.cloneDeep(this.attributes);
      });
    }
Fetches a {@link Model model} from the database, using any {@link
Model#attributes attributes} currently set on the model to constrain the
results.

A {@link Model#event:fetching "fetching"} event will be fired just before the
record is fetched; a good place to hook into for validation. {@link
Model#event:fetched "fetched"} event will be fired when a record is
successfully retrieved.

If you need to constrain the query performed by fetch, you can call
{@link Model#query query} or {@link Model#where where} before calling
fetch.

    // select * from `books` where `ISBN-13` = '9780440180296'
    new Book({'ISBN-13': '9780440180296'})
      .fetch()
      .then(function(model) {
        // outputs 'Slaughterhouse Five'
        console.log(model.get('title'));
      });

If you'd like to only fetch specific columns, you may specify a `columns`
property in the `options` for the fetch call, or use
{@link Model#query query}, tapping into the
{@link https://knexjs.org/#Builder-column|Knex column} method to specify
which columns will be fetched.

A single property, or an array of properties can be specified as a value for
the `withRelated` property. You can also execute callbacks on relations
queries (eg. for sorting a relation). The results of these relation queries
will be loaded into a {@link Model#relations relations} property on the
model, may be retrieved with the {@link Model#related related} method, and
will be serialized as properties on a {@link Model#toJSON toJSON} call
unless `{shallow: true}` is passed.

    let Book = bookshelf.model('Book', {
      tableName: 'books',
      editions: function() {
        return this.hasMany('Edition');
      },
      chapters: function() {
        return this.hasMany('Chapter');
      },
      genre: function() {
        return this.belongsTo('Genre');
      }
    })

    new Book({'ISBN-13': '9780440180296'}).fetch({
      withRelated: [
        'genre', 'editions',
        { chapters: function(query) { query.orderBy('chapter_number'); }}
      ]
    }).then(function(book) {
      console.log(book.related('genre').toJSON());
      console.log(book.related('editions').toJSON());
      console.log(book.toJSON());
    });

@method Model#fetch
@param {Object=} options Hash of options.
@param {Boolean=} [options.require=true]
  Whether or not to reject the returned response with a
  {@link Model.NotFoundError NotFoundError} if there are no results when
  fetching. If set to `false` it will resolve with `null` instead.
@param {string|string[]} [options.columns='*']
  Specify columns to be retrieved.
@param {Transaction} [options.transacting]
 Optionally run the query in a transaction.
@param {string} [options.lock]
 Type of row-level lock to use. Valid options are `forShare` and
 `forUpdate`. This only works in conjunction with the `transacting`
 option, and requires a database that supports it.
@param {string|Object|mixed[]} [options.withRelated]
 Relations to be retrieved with `Model` instance. Either one or more
 relation names or objects mapping relation names to query callbacks.
@param {boolean} [options.debug=false]
  Whether to enable debugging mode or not. When enabled will show information about the
  queries being run.
@fires Model#fetching
@fires Model#fetched
@throws {Model.NotFoundError}
@returns {Promise<Model|null>}
 A promise resolving to the fetched {@link Model model} or `null` if
 none exists and the `require: false` option is passed.