1 | ;
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 |
|
7 | var _lodash = require('lodash');
|
8 |
|
9 | var _helpers = require('./helpers');
|
10 |
|
11 | var _helpers2 = _interopRequireDefault(_helpers);
|
12 |
|
13 | var _events = require('./base/events');
|
14 |
|
15 | var _events2 = _interopRequireDefault(_events);
|
16 |
|
17 | var _model = require('./model');
|
18 |
|
19 | var _model2 = _interopRequireDefault(_model);
|
20 |
|
21 | var _collection = require('./collection');
|
22 |
|
23 | var _collection2 = _interopRequireDefault(_collection);
|
24 |
|
25 | var _relation2 = require('./relation');
|
26 |
|
27 | var _relation3 = _interopRequireDefault(_relation2);
|
28 |
|
29 | var _errors = require('./errors');
|
30 |
|
31 | var _errors2 = _interopRequireDefault(_errors);
|
32 |
|
33 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
34 |
|
35 | /**
|
36 | * @class Bookshelf
|
37 | * @classdesc
|
38 | *
|
39 | * The Bookshelf library is initialized by passing an initialized Knex client
|
40 | * instance. The knex documentation provides a number of examples for different
|
41 | * databases.
|
42 | *
|
43 | * @constructor
|
44 | * @param {Knex} knex Knex instance.
|
45 | */
|
46 |
|
47 |
|
48 | // All core modules required for the bookshelf instance.
|
49 | function Bookshelf(knex) {
|
50 | if (!knex || knex.name !== 'knex') {
|
51 | throw new Error('Invalid knex instance');
|
52 | }
|
53 | var bookshelf = {
|
54 | VERSION: require('../package.json').version
|
55 | };
|
56 |
|
57 | var Model = bookshelf.Model = _model2.default.extend({
|
58 | _builder: builderFn,
|
59 |
|
60 | // The `Model` constructor is referenced as a property on the `Bookshelf`
|
61 | // instance, mixing in the correct `builder` method, as well as the
|
62 | // `relation` method, passing in the correct `Model` & `Collection`
|
63 | // constructors for later reference.
|
64 | _relation: function _relation(type, Target, options) {
|
65 | if (type !== 'morphTo' && !(0, _lodash.isFunction)(Target)) {
|
66 | throw new Error('A valid target model must be defined for the ' + (0, _lodash.result)(this, 'tableName') + ' ' + type + ' relation');
|
67 | }
|
68 | return new Relation(type, Target, options);
|
69 | }
|
70 | }, {
|
71 |
|
72 | /**
|
73 | * @method Model.forge
|
74 | * @belongsTo Model
|
75 | * @description
|
76 | *
|
77 | * A simple helper function to instantiate a new Model without needing `new`.
|
78 | *
|
79 | * @param {Object=} attributes Initial values for this model's attributes.
|
80 | * @param {Object=} options Hash of options.
|
81 | * @param {string=} options.tableName Initial value for {@linkcode Model#tableName tableName}.
|
82 | * @param {Boolean=} [options.hasTimestamps=false]
|
83 | *
|
84 | * Initial value for {@linkcode Model#hasTimestamps hasTimestamps}.
|
85 | *
|
86 | * @param {Boolean} [options.parse=false]
|
87 | *
|
88 | * Convert attributes by {@linkcode Model#parse parse} before being
|
89 | * {@linkcode Model#set set} on the `model`.
|
90 | */
|
91 | forge: forge,
|
92 |
|
93 | /**
|
94 | * @method Model.collection
|
95 | * @belongsTo Model
|
96 | * @description
|
97 | *
|
98 | * A simple static helper to instantiate a new {@link Collection}, setting
|
99 | * the current `model` as the collection's target.
|
100 | *
|
101 | * @example
|
102 | *
|
103 | * Customer.collection().fetch().then(function(collection) {
|
104 | * // ...
|
105 | * });
|
106 | *
|
107 | * @param {(Model[])=} models
|
108 | * @param {Object=} options
|
109 | * @returns {Collection}
|
110 | */
|
111 | collection: function collection(models, options) {
|
112 | return new bookshelf.Collection(models || [], (0, _lodash.extend)({}, options, { model: this }));
|
113 | },
|
114 |
|
115 |
|
116 | /**
|
117 | * @method Model.count
|
118 | * @belongsTo Model
|
119 | * @since 0.8.2
|
120 | * @description
|
121 | *
|
122 | * Gets the number of matching records in the database, respecting any
|
123 | * previous calls to {@link Model#query query}. If a `column` is provided,
|
124 | * records with a null value in that column will be excluded from the count.
|
125 | *
|
126 | * @param {string} [column='*']
|
127 | * Specify a column to count - rows with null values in this column will be excluded.
|
128 | * @param {Object=} options
|
129 | * Hash of options.
|
130 | * @returns {Promise<Number>}
|
131 | * A promise resolving to the number of matching rows.
|
132 | */
|
133 | count: function count(column, options) {
|
134 | return this.forge().count(column, options);
|
135 | },
|
136 |
|
137 |
|
138 | /**
|
139 | * @method Model.fetchAll
|
140 | * @belongsTo Model
|
141 | * @description
|
142 | *
|
143 | * Simple helper function for retrieving all instances of the given model.
|
144 | *
|
145 | * @see Model#fetchAll
|
146 | * @returns {Promise<Collection>}
|
147 | */
|
148 | fetchAll: function fetchAll(options) {
|
149 | return this.forge().fetchAll(options);
|
150 | }
|
151 | });
|
152 |
|
153 | var Collection = bookshelf.Collection = _collection2.default.extend({
|
154 |
|
155 | _builder: builderFn
|
156 |
|
157 | }, {
|
158 |
|
159 | /**
|
160 | * @method Collection.forge
|
161 | * @belongsTo Collection
|
162 | * @description
|
163 | *
|
164 | * A simple helper function to instantiate a new Collection without needing
|
165 | * new.
|
166 | *
|
167 | * @param {(Object[]|Model[])=} [models]
|
168 | * Set of models (or attribute hashes) with which to initialize the
|
169 | * collection.
|
170 | * @param {Object} options Hash of options.
|
171 | *
|
172 | * @example
|
173 | *
|
174 | * var Promise = require('bluebird');
|
175 | * var Accounts = bookshelf.Collection.extend({
|
176 | * model: Account
|
177 | * });
|
178 | *
|
179 | * var accounts = Accounts.forge([
|
180 | * {name: 'Person1'},
|
181 | * {name: 'Person2'}
|
182 | * ]);
|
183 | *
|
184 | * Promise.all(accounts.invokeMap('save')).then(function() {
|
185 | * // collection models should now be saved...
|
186 | * });
|
187 | */
|
188 | forge: forge
|
189 |
|
190 | });
|
191 |
|
192 | // The collection also references the correct `Model`, specified above, for
|
193 | // creating new `Model` instances in the collection.
|
194 | Collection.prototype.model = Model;
|
195 | Model.prototype.Collection = Collection;
|
196 |
|
197 | var Relation = _relation3.default.extend({
|
198 | Model: Model, Collection: Collection
|
199 | });
|
200 |
|
201 | // A `Bookshelf` instance may be used as a top-level pub-sub bus, as it mixes
|
202 | // in the `Events` object. It also contains the version number, and a
|
203 | // `Transaction` method referencing the correct version of `knex` passed into
|
204 | // the object.
|
205 | (0, _lodash.extend)(bookshelf, _events2.default, _errors2.default, {
|
206 |
|
207 | /**
|
208 | * @method Bookshelf#transaction
|
209 | * @memberOf Bookshelf
|
210 | * @description
|
211 | *
|
212 | * An alias to `{@link http://knexjs.org/#Transactions
|
213 | * Knex#transaction}`, the `transaction` object must be passed along in the
|
214 | * options of any relevant Bookshelf calls, to ensure all queries are on the
|
215 | * same connection. The entire transaction block is a promise that will
|
216 | * resolve when the transaction is committed, or fail if the transaction is
|
217 | * rolled back.
|
218 | *
|
219 | * var Promise = require('bluebird');
|
220 | *
|
221 | * Bookshelf.transaction(function(t) {
|
222 | * return new Library({name: 'Old Books'})
|
223 | * .save(null, {transacting: t})
|
224 | * .tap(function(model) {
|
225 | * return Promise.map([
|
226 | * {title: 'Canterbury Tales'},
|
227 | * {title: 'Moby Dick'},
|
228 | * {title: 'Hamlet'}
|
229 | * ], function(info) {
|
230 | * // Some validation could take place here.
|
231 | * return new Book(info).save({'shelf_id': model.id}, {transacting: t});
|
232 | * });
|
233 | * });
|
234 | * }).then(function(library) {
|
235 | * console.log(library.related('books').pluck('title'));
|
236 | * }).catch(function(err) {
|
237 | * console.error(err);
|
238 | * });
|
239 | *
|
240 | * @param {Bookshelf~transactionCallback} transactionCallback
|
241 | * Callback containing transaction logic. The callback should return a
|
242 | * promise.
|
243 | *
|
244 | * @returns {Promise<mixed>}
|
245 | * A promise resolving to the value returned from {@link
|
246 | * Bookshelf~transactionCallback transactionCallback}.
|
247 | */
|
248 | transaction: function transaction() {
|
249 | return this.knex.transaction.apply(this, arguments);
|
250 | },
|
251 |
|
252 |
|
253 | /**
|
254 | * @callback Bookshelf~transactionCallback
|
255 | * @description
|
256 | *
|
257 | * A transaction block to be provided to {@link Bookshelf#transaction}.
|
258 | *
|
259 | * @see {@link http://knexjs.org/#Transactions Knex#transaction}
|
260 | * @see Bookshelf#transaction
|
261 | *
|
262 | * @param {Transaction} transaction
|
263 | * @returns {Promise<mixed>}
|
264 | */
|
265 |
|
266 | /**
|
267 | * @method Bookshelf#plugin
|
268 | * @memberOf Bookshelf
|
269 | * @description
|
270 | *
|
271 | * This method provides a nice, tested, standardized way of adding plugins
|
272 | * to a `Bookshelf` instance, injecting the current instance into the
|
273 | * plugin, which should be a `module.exports`.
|
274 | *
|
275 | * You can add a plugin by specifying a string with the name of the plugin
|
276 | * to load. In this case it will try to find a module. It will first check
|
277 | * for a match within the `bookshelf/plugins` directory. If nothing is
|
278 | * found it will pass the string to `require()`, so you can either require
|
279 | * an npm dependency by name or one of your own modules by relative path:
|
280 | *
|
281 | * bookshelf.plugin('./bookshelf-plugins/my-favourite-plugin');
|
282 | * bookshelf.plugin('plugin-from-npm');
|
283 | *
|
284 | * There are a few built-in plugins already, along with many independently
|
285 | * developed ones. See [the list of available plugins](#plugins).
|
286 | *
|
287 | * You can also provide an array of strings or functions, which is the same
|
288 | * as calling `bookshelf.plugin()` multiple times. In this case the same
|
289 | * options object will be reused:
|
290 | *
|
291 | * bookshelf.plugin(['registry', './my-plugins/special-parse-format']);
|
292 | *
|
293 | * Example plugin:
|
294 | *
|
295 | * // Converts all string values to lower case when setting attributes on a model
|
296 | * module.exports = function(bookshelf) {
|
297 | * bookshelf.Model = bookshelf.Model.extend({
|
298 | * set: function(key, value, options) {
|
299 | * if (!key) return this;
|
300 | * if (typeof value === 'string') value = value.toLowerCase();
|
301 | * return bookshelf.Model.prototype.set.call(this, key, value, options);
|
302 | * }
|
303 | * });
|
304 | * }
|
305 | *
|
306 | * @param {string|array|Function} plugin
|
307 | * The plugin or plugins to add. If you provide a string it can
|
308 | * represent a built-in plugin, an npm package or a file somewhere on
|
309 | * your project. You can also pass a function as argument to add it as a
|
310 | * plugin. Finally, it's also possible to pass an array of strings or
|
311 | * functions to add them all at once.
|
312 | * @param {mixed} options
|
313 | * This can be anything you want and it will be passed directly to the
|
314 | * plugin as the second argument when loading it.
|
315 | */
|
316 | plugin: function plugin(_plugin, options) {
|
317 | var _this = this;
|
318 |
|
319 | if ((0, _lodash.isString)(_plugin)) {
|
320 | try {
|
321 | require('./plugins/' + _plugin)(this, options);
|
322 | } catch (e) {
|
323 | if (e.code !== 'MODULE_NOT_FOUND') {
|
324 | throw e;
|
325 | }
|
326 | if (!process.browser) {
|
327 | require(_plugin)(this, options);
|
328 | }
|
329 | }
|
330 | } else if ((0, _lodash.isArray)(_plugin)) {
|
331 | (0, _lodash.each)(_plugin, function (p) {
|
332 | _this.plugin(p, options);
|
333 | });
|
334 | } else {
|
335 | _plugin(this, options);
|
336 | }
|
337 | return this;
|
338 | }
|
339 | });
|
340 |
|
341 | /**
|
342 | * @member Bookshelf#knex
|
343 | * @memberOf Bookshelf
|
344 | * @type {Knex}
|
345 | * @description
|
346 | * A reference to the {@link http://knexjs.org Knex.js} instance being used by Bookshelf.
|
347 | */
|
348 | bookshelf.knex = knex;
|
349 |
|
350 | // The `forge` function properly instantiates a new Model or Collection
|
351 | // without needing the `new` operator... to make object creation cleaner
|
352 | // and more chainable.
|
353 | function forge() {
|
354 | return new (Function.prototype.bind.apply(this, [null].concat(Array.prototype.slice.call(arguments))))();
|
355 | }
|
356 |
|
357 | function builderFn(tableNameOrBuilder) {
|
358 | var _this2 = this;
|
359 |
|
360 | var builder = null;
|
361 |
|
362 | if ((0, _lodash.isString)(tableNameOrBuilder)) {
|
363 | builder = bookshelf.knex(tableNameOrBuilder);
|
364 | } else if (tableNameOrBuilder == null) {
|
365 | builder = bookshelf.knex.queryBuilder();
|
366 | } else {
|
367 | // Assuming here that `tableNameOrBuilder` is a QueryBuilder instance. Not
|
368 | // aware of a way to check that this is the case (ie. using
|
369 | // `Knex.isQueryBuilder` or equivalent).
|
370 | builder = tableNameOrBuilder;
|
371 | }
|
372 |
|
373 | return builder.on('query', function (data) {
|
374 | return _this2.trigger('query', data);
|
375 | });
|
376 | }
|
377 |
|
378 | // Attach `where`, `query`, and `fetchAll` as static methods.
|
379 | ['where', 'query'].forEach(function (method) {
|
380 | Model[method] = Collection[method] = function () {
|
381 | var model = this.forge();
|
382 | return model[method].apply(model, arguments);
|
383 | };
|
384 | });
|
385 |
|
386 | return bookshelf;
|
387 | }
|
388 |
|
389 | // Constructor for a new `Bookshelf` object, it accepts an active `knex`
|
390 | // instance and initializes the appropriate `Model` and `Collection`
|
391 | // constructors for use in the current instance.
|
392 |
|
393 |
|
394 | // We've supplemented `Events` with a `triggerThen` method to allow for
|
395 | // asynchronous event handling via promises. We also mix this into the
|
396 | // prototypes of the main objects in the library.
|
397 | Bookshelf.initialize = function (knex) {
|
398 | _helpers2.default.warn("Bookshelf.initialize is deprecated, pass knex directly: require('bookshelf')(knex)");
|
399 | return new Bookshelf(knex);
|
400 | };
|
401 |
|
402 | // Finally, export `Bookshelf` to the world.
|
403 | exports.default = Bookshelf; |
\ | No newline at end of file |