@depup/bookshelf 1.2.0-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ const _ = require('lodash');
2
+ const CollectionBase = require('./collection');
3
+ const extend = require('../extend');
4
+
5
+ /**
6
+ * @class
7
+ * @param {string} type
8
+ * The type of relation to create. Can be one of 'hasOne', 'hasMany', 'belongsTo',
9
+ * 'belongsToMany' or 'morphTo'.
10
+ * @param {Model|Collection|null} Target
11
+ * The target model or collection for this relation or `null` in case the target model will be
12
+ * determined at a later time, as is the case of `morphTo` relations.
13
+ * @param {object} options
14
+ * Additional properties to set on the relation object. These vary according to the type of
15
+ * relation.
16
+ */
17
+ function RelationBase(type, Target, options) {
18
+ if (Target) {
19
+ this.targetTableName = _.result(Target.prototype, 'tableName');
20
+ this.targetIdAttribute = _.result(Target.prototype, 'idAttribute');
21
+ }
22
+
23
+ Object.assign(this, {type, target: Target}, options);
24
+ }
25
+
26
+ /**
27
+ * Creates a new relation instance. Used by the `Eager` relation when dealing with `morphTo` cases,
28
+ * where the same relation is targeting multiple models. It uses the same argument parameters as the
29
+ * base constructor.
30
+ *
31
+ * @return {RelationBase}
32
+ */
33
+ RelationBase.prototype.instance = function instance(type, Target, options) {
34
+ return new this.constructor(type, Target, options);
35
+ };
36
+
37
+ /**
38
+ * Creates a new, unparsed model. Used internally in the eager fetch helper methods because parsing
39
+ * may mutate information necessary for eager pairing.
40
+ *
41
+ * @param {object} data Model attributes to set on the new model.
42
+ * @return {Model} The new model.
43
+ */
44
+ RelationBase.prototype.createModel = function createModel(data) {
45
+ if (this.target.prototype instanceof CollectionBase) {
46
+ return new this.target.prototype.model(data)._reset();
47
+ }
48
+ return new this.target(data)._reset();
49
+ };
50
+
51
+ /**
52
+ * Clones a relation. Required by {@link Model#fetchPage}.
53
+ *
54
+ * @todo Can probably be removed for a simpler approach, or just the `instance` method.
55
+ * @return {RelationBase}
56
+ */
57
+ RelationBase.prototype.clone = function clone() {
58
+ return new this.constructor(null, null, this);
59
+ };
60
+
61
+ /**
62
+ * Extends the Base Relation.
63
+ *
64
+ * @method
65
+ * @static
66
+ */
67
+ RelationBase.extend = extend;
68
+
69
+ module.exports = RelationBase;
@@ -0,0 +1,558 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+
5
+ // We've supplemented `Events` with a `triggerThen` method to allow for
6
+ // asynchronous event handling via promises. We also mix this into the
7
+ // prototypes of the main objects in the library.
8
+ const Events = require('./base/events');
9
+
10
+ // All core modules required for the bookshelf instance.
11
+ const BookshelfModel = require('./model');
12
+ const BookshelfCollection = require('./collection');
13
+ const BookshelfRelation = require('./relation');
14
+ const errors = require('./errors');
15
+
16
+ function preventOverwrite(store, name) {
17
+ if (store[name]) throw new Error(`${name} is already defined in the registry`);
18
+ }
19
+
20
+ /**
21
+ * @class
22
+ * @classdesc
23
+ *
24
+ * The Bookshelf library is initialized by passing an initialized Knex client
25
+ * instance. The knex documentation provides a number of examples for different
26
+ * databases.
27
+ *
28
+ * @constructor
29
+ * @param {Knex} knex Knex instance.
30
+ */
31
+ function Bookshelf(knex) {
32
+ if (!knex || knex.name !== 'knex') {
33
+ throw new Error('Invalid knex instance');
34
+ }
35
+
36
+ function resolveModel(input) {
37
+ if (typeof input !== 'string') return input;
38
+
39
+ return (
40
+ bookshelf.collection(input) ||
41
+ bookshelf.model(input) ||
42
+ (function() {
43
+ throw new errors.ModelNotResolvedError(`The model ${input} could not be resolved from the registry.`);
44
+ })()
45
+ );
46
+ }
47
+
48
+ /** @lends Bookshelf.prototype */
49
+ const bookshelf = {
50
+ registry: {
51
+ collections: {},
52
+ models: {}
53
+ },
54
+ VERSION: require('../package.json').version,
55
+
56
+ collection(name, Collection, staticProperties) {
57
+ if (Collection) {
58
+ preventOverwrite(this.registry.collections, name);
59
+
60
+ if (_.isPlainObject(Collection)) {
61
+ Collection = this.Collection.extend(Collection, staticProperties);
62
+ }
63
+
64
+ this.registry.collections[name] = Collection;
65
+ }
66
+
67
+ return this.registry.collections[name] || bookshelf.resolve(name);
68
+ },
69
+
70
+ /**
71
+ * Registers a model. Omit the second argument `Model` to return a previously registered model that matches the
72
+ * provided name.
73
+ *
74
+ * Note that when registering a model with this method it will also be available to all relation methods, allowing
75
+ * you to use a string name in that case. See the calls to `hasMany()` in the examples above.
76
+ *
77
+ * @example
78
+ * // Defining and registering a model
79
+ * module.exports = bookshelf.model('Customer', {
80
+ * tableName: 'customers',
81
+ * orders() {
82
+ * return this.hasMany('Order')
83
+ * }
84
+ * })
85
+ *
86
+ * // Retrieving a previously registered model
87
+ * const Customer = bookshelf.model('Customer')
88
+ *
89
+ * // Registering already defined models
90
+ * // file: customer.js
91
+ * const Customer = bookshelf.Model.extend({
92
+ * tableName: 'customers',
93
+ * orders() {
94
+ * return this.hasMany('Order')
95
+ * }
96
+ * })
97
+ * module.exports = bookshelf.model('Customer', Customer)
98
+ *
99
+ * // file: order.js
100
+ * const Order = bookshelf.Model.extend({
101
+ * tableName: 'orders',
102
+ * customer() {
103
+ * return this.belongsTo('Customer')
104
+ * }
105
+ * })
106
+ * module.exports = bookshelf.model('Order', Order)
107
+ *
108
+ * @param {string} name
109
+ * The name to save the model as, or the name of the model to retrieve if no further arguments are passed to this
110
+ * method.
111
+ * @param {Model|Object} [Model]
112
+ * The model to register. If a plain object is passed it will be converted to a {@link Model}. See example above.
113
+ * @param {Object} [staticProperties]
114
+ * If a plain object is passed as second argument, this can be used to specify additional static properties and
115
+ * methods for the new model that is created.
116
+ * @return {Model} The registered model.
117
+ */
118
+ model(name, Model, staticProperties) {
119
+ if (Model) {
120
+ preventOverwrite(this.registry.models, name);
121
+ if (_.isPlainObject(Model)) Model = this.Model.extend(Model, staticProperties);
122
+ this.registry.models[name] = Model;
123
+ }
124
+
125
+ return this.registry.models[name] || bookshelf.resolve(name);
126
+ },
127
+
128
+ /**
129
+ * Override this in your bookshelf instance to define a custom function that will resolve the location of a model or
130
+ * collection when using the {@link Bookshelf#model} method or when passing a string with a model name in any of the
131
+ * collection methods (e.g. {@link Model#hasOne}, {@link Model#hasMany}, etc.).
132
+ *
133
+ * This will only be used if the specified name cannot be found in the registry. Note that this function
134
+ * can return anything you'd like, so it's not restricted in functionality.
135
+ *
136
+ * @example
137
+ * const Customer = bookshelf.model('Customer', {
138
+ * tableName: 'customers'
139
+ * })
140
+ *
141
+ * bookshelf.resolve = (name) => {
142
+ * if (name === 'SpecialCustomer') return Customer;
143
+ * }
144
+ *
145
+ * @param {string} name The model name to resolve.
146
+ * @return {*} The return value will depend on what your re-implementation of this function does.
147
+ */
148
+ resolve(name) {}
149
+ };
150
+
151
+ const Model = (bookshelf.Model = BookshelfModel.extend(
152
+ {
153
+ _builder: builderFn,
154
+
155
+ // The `Model` constructor is referenced as a property on the `Bookshelf` instance, mixing in the correct
156
+ // `builder` method, as well as the `relation` method, passing in the correct `Model` & `Collection`
157
+ // constructors for later reference.
158
+ _relation(type, Target, options) {
159
+ Target = resolveModel(Target);
160
+
161
+ if (type !== 'morphTo' && !_.isFunction(Target)) {
162
+ throw new Error(
163
+ 'A valid target model must be defined for the ' + _.result(this, 'tableName') + ' ' + type + ' relation'
164
+ );
165
+ }
166
+ return new Relation(type, Target, options);
167
+ },
168
+
169
+ morphTo(relationName, ...args) {
170
+ let candidates = args;
171
+ let columnNames = null;
172
+
173
+ if (Array.isArray(args[0]) || args[0] === null || args[0] === undefined) {
174
+ candidates = args.slice(1);
175
+ columnNames = args[0];
176
+ }
177
+
178
+ if (Array.isArray(columnNames)) {
179
+ // Try to use the columnNames as target instead
180
+ try {
181
+ columnNames[0] = resolveModel(columnNames[0]);
182
+ } catch (error) {
183
+ // If it did not work, they were real columnNames
184
+ if (error instanceof errors.ModelNotResolvedError) throw error;
185
+ }
186
+ }
187
+
188
+ const models = candidates.map((candidate) => {
189
+ if (!Array.isArray(candidate)) return resolveModel(candidate);
190
+
191
+ const model = candidate[0];
192
+ const morphValue = candidate[1];
193
+
194
+ return [resolveModel(model), morphValue];
195
+ });
196
+
197
+ return BookshelfModel.prototype.morphTo.apply(this, [relationName, columnNames].concat(models));
198
+ },
199
+
200
+ through(Source, ...rest) {
201
+ return BookshelfModel.prototype.through.apply(this, [resolveModel(Source), ...rest]);
202
+ }
203
+ },
204
+ {
205
+ /**
206
+ * @method Model.forge
207
+ * @description
208
+ *
209
+ * A simple helper function to instantiate a new Model without needing `new`.
210
+ *
211
+ * @param {Object=} attributes Initial values for this model's attributes.
212
+ * @param {Object=} options Hash of options.
213
+ * @param {string=} options.tableName Initial value for {@linkcode Model#tableName tableName}.
214
+ * @param {Boolean=} [options.hasTimestamps=false]
215
+ *
216
+ * Initial value for {@linkcode Model#hasTimestamps hasTimestamps}.
217
+ *
218
+ * @param {Boolean} [options.parse=false]
219
+ *
220
+ * Convert attributes by {@linkcode Model#parse parse} before being
221
+ * {@linkcode Model#set set} on the `model`.
222
+ */
223
+ forge: function forge(attributes, options) {
224
+ return new this(attributes, options);
225
+ },
226
+
227
+ /**
228
+ * A simple static helper to instantiate a new {@link Collection}, setting the model it's
229
+ * called on as the collection's target model.
230
+ *
231
+ * @example
232
+ * Customer.collection().fetch().then((customers) => {
233
+ * // ...
234
+ * })
235
+ *
236
+ * @method Model.collection
237
+ * @param {Model[]} [models] Any models to be added to the collection.
238
+ * @param {Object} [options] Additional options to pass to the {@link Collection} constructor.
239
+ * @param {string|function} [options.comparator]
240
+ * If specified this is used to sort the collection. It can be a string representing the
241
+ * model attribute to sort by, or a custom function. Check the documentation for {@link
242
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
243
+ * Array.prototype.sort} for more info on how to use a custom comparator function. If this
244
+ * options is not specified the collection sort order depends on what the database returns.
245
+ * @returns {Collection}
246
+ * The newly created collection. It will be empty unless any models were passed as the first
247
+ * argument.
248
+ */
249
+ collection(models, options) {
250
+ return new bookshelf.Collection(models || [], _.extend({}, options, {model: this}));
251
+ },
252
+
253
+ /**
254
+ * Shortcut to a model's `count` method so you don't need to instantiate a new model to count
255
+ * the number of records.
256
+ *
257
+ * @example
258
+ * Duck.count().then((count) => {
259
+ * console.log('number of ducks', count)
260
+ * })
261
+ *
262
+ * @method Model.count
263
+ * @since 0.8.2
264
+ * @see Model#count
265
+ * @param {string} [column='*']
266
+ * Specify a column to count. Rows with `null` values in this column will be excluded.
267
+ * @param {Object} [options] Hash of options.
268
+ * @param {boolean} [options.debug=false]
269
+ * Whether to enable debugging mode or not. When enabled will show information about the
270
+ * queries being run.
271
+ * @returns {Promise<number|string>}
272
+ */
273
+ count(column, options) {
274
+ return this.forge().count(column, options);
275
+ },
276
+
277
+ /**
278
+ * @method Model.fetchAll
279
+ * @description
280
+ *
281
+ * Simple helper function for retrieving all instances of the given model.
282
+ *
283
+ * @see Model#fetchAll
284
+ * @returns {Promise<Collection>}
285
+ */
286
+ fetchAll(options) {
287
+ return this.forge().fetchAll(options);
288
+ }
289
+ }
290
+ ));
291
+
292
+ const Collection = (bookshelf.Collection = BookshelfCollection.extend(
293
+ {
294
+ _builder: builderFn,
295
+ through(Source, ...args) {
296
+ return BookshelfCollection.prototype.through.apply(this, [resolveModel(Source), ...args]);
297
+ }
298
+ },
299
+ {
300
+ /**
301
+ * @method Collection.forge
302
+ * @description
303
+ *
304
+ * A simple helper function to instantiate a new Collection without needing
305
+ * new.
306
+ *
307
+ * @param {(Object[]|Model[])=} [models]
308
+ * Set of models (or attribute hashes) with which to initialize the
309
+ * collection.
310
+ * @param {Object} options Hash of options.
311
+ *
312
+ * @example
313
+ *
314
+ * var Promise = require('bluebird');
315
+ * var Accounts = bookshelf.Collection.extend({
316
+ * model: Account
317
+ * });
318
+ *
319
+ * var accounts = Accounts.forge([
320
+ * {name: 'Person1'},
321
+ * {name: 'Person2'}
322
+ * ]);
323
+ *
324
+ * Promise.all(accounts.invokeMap('save')).then(function() {
325
+ * // collection models should now be saved...
326
+ * });
327
+ */
328
+ forge: function forge(models, options) {
329
+ return new this(models, options);
330
+ }
331
+ }
332
+ ));
333
+
334
+ // The collection also references the correct `Model`, specified above, for
335
+ // creating new `Model` instances in the collection.
336
+ Collection.prototype.model = Model;
337
+ Model.prototype.Collection = Collection;
338
+
339
+ const Relation = BookshelfRelation.extend({Model, Collection});
340
+
341
+ // A `Bookshelf` instance may be used as a top-level pub-sub bus, as it mixes
342
+ // in the `Events` object. It also contains the version number, and a
343
+ // `Transaction` method referencing the correct version of `knex` passed into
344
+ // the object.
345
+ _.extend(bookshelf, Events, errors, {
346
+ /**
347
+ * An alias to `{@link http://knexjs.org/#Transactions Knex#transaction}`. The `transaction`
348
+ * object must be passed along in the options of any relevant Bookshelf calls, to ensure all
349
+ * queries are on the same connection. The entire transaction block is wrapped around a Promise
350
+ * that will commit the transaction if it resolves successfully, or roll it back if the Promise
351
+ * is rejected.
352
+ *
353
+ * Note that there is no need to explicitly call `transaction.commit()` or
354
+ * `transaction.rollback()` since the entire transaction will be committed if there are no
355
+ * errors inside the transaction block.
356
+ *
357
+ * When fetching inside a transaction it's possible to specify a row-level lock by passing the
358
+ * wanted lock type in the `lock` option to {@linkcode Model#fetch fetch}. Available options are
359
+ * `lock: 'forUpdate'` and `lock: 'forShare'`.
360
+ *
361
+ * @example
362
+ * var Promise = require('bluebird')
363
+ *
364
+ * Bookshelf.transaction((t) => {
365
+ * return new Library({name: 'Old Books'})
366
+ * .save(null, {transacting: t})
367
+ * .tap(function(model) {
368
+ * return Promise.map([
369
+ * {title: 'Canterbury Tales'},
370
+ * {title: 'Moby Dick'},
371
+ * {title: 'Hamlet'}
372
+ * ], (info) => {
373
+ * return new Book(info).save({'shelf_id': model.id}, {transacting: t})
374
+ * })
375
+ * })
376
+ * }).then((library) => {
377
+ * console.log(library.related('books').pluck('title'))
378
+ * }).catch((err) => {
379
+ * console.error(err)
380
+ * })
381
+ *
382
+ * @method Bookshelf#transaction
383
+ * @param {Bookshelf~transactionCallback} transactionCallback
384
+ * Callback containing transaction logic. The callback should return a Promise.
385
+ * @returns {Promise}
386
+ * A promise resolving to the value returned from
387
+ * {@link Bookshelf~transactionCallback transactionCallback}.
388
+ */
389
+ transaction() {
390
+ return this.knex.transaction.apply(this.knex, arguments);
391
+ },
392
+
393
+ /**
394
+ * This is a transaction block to be provided to {@link Bookshelf#transaction}. All of the
395
+ * database operations inside it can be part of the same transaction by passing the
396
+ * `transacting: transaction` option to {@link Model#fetch fetch}, {@link Model#save save} or
397
+ * {@link Model#destroy destroy}.
398
+ *
399
+ * Note that unless you explicitly pass the `transaction` object along to any relevant model
400
+ * operations, those operations will not be part of the transaction, even though they may be
401
+ * inside the transaction callback.
402
+ *
403
+ * @callback Bookshelf~transactionCallback
404
+ * @see {@link http://knexjs.org/#Transactions Knex#transaction}
405
+ * @see Bookshelf#transaction
406
+ *
407
+ * @param {Transaction} transaction
408
+ * @returns {Promise}
409
+ * The Promise will resolve to the return value of the callback, or be rejected with an error
410
+ * thrown inside it. If it resolves, the entire transaction is committed, otherwise it is
411
+ * rolled back.
412
+ */
413
+
414
+ /**
415
+ * @method Bookshelf#plugin
416
+ * @memberOf Bookshelf
417
+ * @description
418
+ *
419
+ * This method provides a nice, tested, standardized way of adding plugins
420
+ * to a `Bookshelf` instance, injecting the current instance into the
421
+ * plugin, which should be a `module.exports`.
422
+ *
423
+ * You can add a plugin by specifying a string with the name of the plugin
424
+ * to load. In this case it will try to find a module. It will pass the
425
+ * string to `require()`, so you can either require a third-party dependency
426
+ * by name or one of your own modules by relative path:
427
+ *
428
+ * bookshelf.plugin('./bookshelf-plugins/my-favourite-plugin');
429
+ * bookshelf.plugin('plugin-from-npm');
430
+ *
431
+ * There are a few official plugins published in `npm`, along with many
432
+ * independently developed ones. See
433
+ * [the list of available plugins](index.html#official-plugins).
434
+ *
435
+ * You can also provide an array of strings or functions, which is the same
436
+ * as calling `bookshelf.plugin()` multiple times. In this case the same
437
+ * options object will be reused:
438
+ *
439
+ * bookshelf.plugin(['cool-plugin', './my-plugins/even-cooler-plugin']);
440
+ *
441
+ * Example plugin:
442
+ *
443
+ * // Converts all string values to lower case when setting attributes on a model
444
+ * module.exports = function(bookshelf) {
445
+ * bookshelf.Model = bookshelf.Model.extend({
446
+ * set(key, value, options) {
447
+ * if (!key) return this
448
+ * if (typeof value === 'string') value = value.toLowerCase()
449
+ * return bookshelf.Model.prototype.set.call(this, key, value, options)
450
+ * }
451
+ * })
452
+ * }
453
+ *
454
+ * @param {string|array|Function} plugin
455
+ * The plugin or plugins to load. If you provide a string it can
456
+ * represent an npm package or a file somewhere on your project. You can
457
+ * also pass a function as argument to add it as a plugin. Finally, it's
458
+ * also possible to pass an array of strings or functions to add them all
459
+ * at once.
460
+ * @param {mixed} options
461
+ * This can be anything you want and it will be passed directly to the
462
+ * plugin as the second argument when loading it.
463
+ * @return {Bookshelf} The bookshelf instance for chaining.
464
+ */
465
+ plugin(plugin, options) {
466
+ if (_.isString(plugin)) {
467
+ if (plugin === 'pagination') {
468
+ const message =
469
+ 'Pagination plugin was moved into core Bookshelf. You can now use `fetchPage()` without having to ' +
470
+ "call `.plugin('pagination')`. Remove any `.plugin('pagination')` calls to clear this message.";
471
+ return console.warn(message); // eslint-disable-line no-console
472
+ }
473
+
474
+ if (plugin === 'visibility') {
475
+ const message =
476
+ 'Visibility plugin was moved into core Bookshelf. You can now set the `hidden` and `visible` properties ' +
477
+ "without having to call `.plugin('visibility')`. Remove any `.plugin('visibility')` calls to clear this " +
478
+ 'message.';
479
+ return console.warn(message); // eslint-disable-line no-console
480
+ }
481
+
482
+ if (plugin === 'registry') {
483
+ const message =
484
+ 'Registry plugin was moved into core Bookshelf. You can now register models using `bookshelf.model()` ' +
485
+ "and collections using `bookshelf.collection()` without having to call `.plugin('registry')`. Remove " +
486
+ "any `.plugin('registry')` calls to clear this message.";
487
+ return console.warn(message); // eslint-disable-line no-console
488
+ }
489
+
490
+ if (plugin === 'processor') {
491
+ const message =
492
+ 'Processor plugin was removed from core Bookshelf. To migrate to the new standalone package follow the ' +
493
+ 'instructions in https://github.com/bookshelf/bookshelf/wiki/Migrating-from-0.15.1-to-1.0.0#processor-plugin';
494
+ return console.warn(message); // eslint-disable-line no-console
495
+ }
496
+
497
+ if (plugin === 'case-converter') {
498
+ const message =
499
+ 'Case converter plugin was removed from core Bookshelf. To migrate to the new standalone package follow ' +
500
+ 'the instructions in https://github.com/bookshelf/bookshelf/wiki/Migrating-from-0.15.1-to-1.0.0#case-converter-plugin';
501
+ return console.warn(message); // eslint-disable-line no-console
502
+ }
503
+
504
+ if (plugin === 'virtuals') {
505
+ const message =
506
+ 'Virtuals plugin was removed from core Bookshelf. To migrate to the new standalone package follow ' +
507
+ 'the instructions in https://github.com/bookshelf/bookshelf/wiki/Migrating-from-0.15.1-to-1.0.0#virtuals-plugin';
508
+ return console.warn(message); // eslint-disable-line no-console
509
+ }
510
+
511
+ require(plugin)(this, options);
512
+ } else if (Array.isArray(plugin)) {
513
+ plugin.forEach((p) => this.plugin(p, options));
514
+ } else {
515
+ plugin(this, options);
516
+ }
517
+
518
+ return this;
519
+ }
520
+ });
521
+
522
+ /**
523
+ * @member Bookshelf#knex
524
+ * @type {Knex}
525
+ * @description
526
+ * A reference to the {@link http://knexjs.org Knex.js} instance being used by Bookshelf.
527
+ */
528
+ bookshelf.knex = knex;
529
+
530
+ function builderFn(tableNameOrBuilder) {
531
+ let builder = null;
532
+
533
+ if (_.isString(tableNameOrBuilder)) {
534
+ builder = bookshelf.knex(tableNameOrBuilder);
535
+ } else if (tableNameOrBuilder == null) {
536
+ builder = bookshelf.knex.queryBuilder();
537
+ } else {
538
+ // Assuming here that `tableNameOrBuilder` is a QueryBuilder instance. Not
539
+ // aware of a way to check that this is the case (ie. using
540
+ // `Knex.isQueryBuilder` or equivalent).
541
+ builder = tableNameOrBuilder;
542
+ }
543
+
544
+ return builder.on('query', (data) => this.trigger('query', data));
545
+ }
546
+
547
+ // Attach `where`, `query`, and `fetchAll` as static methods.
548
+ ['where', 'query'].forEach((method) => {
549
+ Model[method] = Collection[method] = function() {
550
+ const model = this.forge();
551
+ return model[method].apply(model, arguments);
552
+ };
553
+ });
554
+
555
+ return bookshelf;
556
+ }
557
+
558
+ module.exports = Bookshelf;