@vsaas/loopback-datasource-juggler 10.0.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.
Files changed (63) hide show
  1. package/LICENSE +25 -0
  2. package/NOTICE +23 -0
  3. package/README.md +74 -0
  4. package/dist/_virtual/_rolldown/runtime.js +4 -0
  5. package/dist/index.js +26 -0
  6. package/dist/lib/browser.depd.js +13 -0
  7. package/dist/lib/case-utils.js +21 -0
  8. package/dist/lib/connectors/kv-memory.js +158 -0
  9. package/dist/lib/connectors/memory.js +810 -0
  10. package/dist/lib/connectors/transient.js +126 -0
  11. package/dist/lib/dao.js +2445 -0
  12. package/dist/lib/datasource.js +2215 -0
  13. package/dist/lib/date-string.js +87 -0
  14. package/dist/lib/geo.js +244 -0
  15. package/dist/lib/globalize.js +33 -0
  16. package/dist/lib/hooks.js +79 -0
  17. package/dist/lib/id-utils.js +66 -0
  18. package/dist/lib/include.js +795 -0
  19. package/dist/lib/include_utils.js +104 -0
  20. package/dist/lib/introspection.js +37 -0
  21. package/dist/lib/jutil.js +65 -0
  22. package/dist/lib/kvao/delete-all.js +57 -0
  23. package/dist/lib/kvao/delete.js +43 -0
  24. package/dist/lib/kvao/expire.js +35 -0
  25. package/dist/lib/kvao/get.js +34 -0
  26. package/dist/lib/kvao/index.js +28 -0
  27. package/dist/lib/kvao/iterate-keys.js +38 -0
  28. package/dist/lib/kvao/keys.js +55 -0
  29. package/dist/lib/kvao/set.js +39 -0
  30. package/dist/lib/kvao/ttl.js +35 -0
  31. package/dist/lib/list.js +101 -0
  32. package/dist/lib/mixins.js +58 -0
  33. package/dist/lib/model-builder.js +608 -0
  34. package/dist/lib/model-definition.js +231 -0
  35. package/dist/lib/model-utils.js +368 -0
  36. package/dist/lib/model.js +586 -0
  37. package/dist/lib/observer.js +235 -0
  38. package/dist/lib/relation-definition.js +2604 -0
  39. package/dist/lib/relations.js +587 -0
  40. package/dist/lib/scope.js +392 -0
  41. package/dist/lib/transaction.js +183 -0
  42. package/dist/lib/types.js +58 -0
  43. package/dist/lib/utils.js +625 -0
  44. package/dist/lib/validations.js +742 -0
  45. package/dist/package.js +93 -0
  46. package/package.json +85 -0
  47. package/types/common.d.ts +28 -0
  48. package/types/connector.d.ts +52 -0
  49. package/types/datasource.d.ts +324 -0
  50. package/types/date-string.d.ts +21 -0
  51. package/types/inclusion-mixin.d.ts +44 -0
  52. package/types/index.d.ts +36 -0
  53. package/types/kv-model.d.ts +201 -0
  54. package/types/model.d.ts +368 -0
  55. package/types/observer-mixin.d.ts +174 -0
  56. package/types/persisted-model.d.ts +505 -0
  57. package/types/query.d.ts +108 -0
  58. package/types/relation-mixin.d.ts +577 -0
  59. package/types/relation.d.ts +301 -0
  60. package/types/scope.d.ts +92 -0
  61. package/types/transaction-mixin.d.ts +47 -0
  62. package/types/types.d.ts +65 -0
  63. package/types/validation-mixin.d.ts +287 -0
@@ -0,0 +1,2445 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.js");
2
+ const require_lib_globalize = require("./globalize.js");
3
+ const require_lib_jutil = require("./jutil.js");
4
+ const require_lib_geo = require("./geo.js");
5
+ const require_lib_utils = require("./utils.js");
6
+ const require_lib_list = require("./list.js");
7
+ require("./model-utils.js");
8
+ const require_lib_validations = require("./validations.js");
9
+ require("./model.js");
10
+ const require_lib_scope = require("./scope.js");
11
+ const require_lib_connectors_memory = require("./connectors/memory.js");
12
+ const require_lib_relations = require("./relations.js");
13
+ const require_lib_include = require("./include.js");
14
+ const require_lib_transaction = require("./transaction.js");
15
+ //#region src/lib/dao.ts
16
+ var require_dao = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
17
+ /*!
18
+ * Module exports class Model
19
+ */
20
+ module.exports = DataAccessObject;
21
+ /*!
22
+ * Module dependencies
23
+ */
24
+ const g = require_lib_globalize();
25
+ const jutil = require_lib_jutil;
26
+ const ValidationError = require_lib_validations.ValidationError;
27
+ const Relation = require_lib_relations;
28
+ const Inclusion = require_lib_include;
29
+ const List = require_lib_list;
30
+ const geo = require_lib_geo;
31
+ const Memory = require_lib_connectors_memory.Memory;
32
+ const utils = require_lib_utils;
33
+ utils.fieldsToArray;
34
+ utils.sanitizeQuery;
35
+ const setScopeValuesFromWhere = utils.setScopeValuesFromWhere;
36
+ const idEquals = utils.idEquals;
37
+ const mergeQuery = utils.mergeQuery;
38
+ const assert = require("assert");
39
+ require("debug")("loopback:dao");
40
+ /**
41
+ * Base class for all persistent objects.
42
+ * Provides a common API to access any database connector.
43
+ * This class describes only abstract behavior. Refer to the specific connector for additional details.
44
+ *
45
+ * `DataAccessObject` mixes `Inclusion` classes methods.
46
+ * @class DataAccessObject
47
+ */
48
+ function DataAccessObject() {
49
+ if (DataAccessObject._mixins) {
50
+ const self = this;
51
+ const args = arguments;
52
+ DataAccessObject._mixins.forEach(function(m) {
53
+ m.call(self, args);
54
+ });
55
+ }
56
+ }
57
+ function idName(m) {
58
+ return m.definition.idName() || "id";
59
+ }
60
+ function getIdValue(m, data) {
61
+ return data && data[idName(m)];
62
+ }
63
+ function copyData(from, to) {
64
+ for (const key in from) to[key] = from[key];
65
+ }
66
+ function once(fn) {
67
+ let called = false;
68
+ return function() {
69
+ if (called) return;
70
+ called = true;
71
+ fn.apply(this, arguments);
72
+ };
73
+ }
74
+ function mapParallel(items, iterator, callback) {
75
+ if (!items || items.length === 0) return callback(null, []);
76
+ const results = Array.from({ length: items.length });
77
+ let pending = items.length;
78
+ let finished = false;
79
+ for (let i = 0; i < items.length; i++) {
80
+ const item = items[i];
81
+ const index = i;
82
+ const done = once(function(err, result) {
83
+ if (finished) return;
84
+ if (err) {
85
+ finished = true;
86
+ return callback(err);
87
+ }
88
+ results[index] = result;
89
+ pending--;
90
+ if (pending === 0) callback(null, results);
91
+ });
92
+ try {
93
+ iterator(item, done);
94
+ } catch (err) {
95
+ done(err);
96
+ }
97
+ }
98
+ }
99
+ function convertSubsetOfPropertiesByType(inst, data) {
100
+ const typedData = {};
101
+ for (const key in data) {
102
+ typedData[key] = inst[key];
103
+ if (typeof typedData[key] === "object" && typedData[key] !== null && typeof typedData[key].toObject === "function") typedData[key] = typedData[key].toObject();
104
+ }
105
+ return typedData;
106
+ }
107
+ /**
108
+ * Apply strict check for model's data.
109
+ * Notice: Please note this method modifies `inst` when `strict` is `validate`.
110
+ */
111
+ function applyStrictCheck(model, strict, data, inst, cb) {
112
+ const props = model.definition.properties;
113
+ const keys = Object.keys(data);
114
+ const result = {};
115
+ for (let i = 0; i < keys.length; i++) {
116
+ const key = keys[i];
117
+ if (props[key]) result[key] = data[key];
118
+ else if (strict && strict !== "filter") inst.__unknownProperties.push(key);
119
+ }
120
+ cb(null, result);
121
+ }
122
+ function byIdQuery(m, id) {
123
+ const pk = idName(m);
124
+ const query = { where: {} };
125
+ query.where[pk] = id;
126
+ return query;
127
+ }
128
+ function isWhereByGivenId(Model, where, idValue) {
129
+ const keys = Object.keys(where);
130
+ if (keys.length != 1) return false;
131
+ const pk = idName(Model);
132
+ if (keys[0] !== pk) return false;
133
+ return where[pk] === idValue;
134
+ }
135
+ function errorModelNotFound(idValue) {
136
+ const msg = g.f("Could not update attributes. {{Object}} with {{id}} %s does not exist!", idValue);
137
+ const error = new Error(msg);
138
+ error.statusCode = error.status = 404;
139
+ return error;
140
+ }
141
+ function invokeConnectorMethod(connector, method, Model, args, options, cb) {
142
+ const dataSource = Model.getDataSource();
143
+ const opts = dataSource.isTransaction && !options.transaction ? Object.assign(options, { transaction: dataSource.currentTransaction }) : options;
144
+ const optionsSupported = connector[method].length >= args.length + 3;
145
+ const transaction = opts.transaction;
146
+ if (transaction) {
147
+ if (!optionsSupported) return process.nextTick(function() {
148
+ cb(new Error(g.f("The connector does not support {{method}} within a transaction", method)));
149
+ });
150
+ if (transaction.ensureActive && !transaction.ensureActive(cb)) return;
151
+ }
152
+ const modelName = Model.modelName;
153
+ let fullArgs;
154
+ if (!optionsSupported && method === "count") fullArgs = [
155
+ modelName,
156
+ cb,
157
+ args[0]
158
+ ];
159
+ else {
160
+ fullArgs = [modelName].concat(args);
161
+ if (optionsSupported) fullArgs.push(opts);
162
+ fullArgs.push(cb);
163
+ }
164
+ connector[method].apply(connector, fullArgs);
165
+ }
166
+ DataAccessObject._forDB = function(data) {
167
+ if (!(this.getDataSource().isRelational && this.getDataSource().isRelational())) return data;
168
+ const res = {};
169
+ for (const propName in data) {
170
+ const type = this.getPropertyType(propName);
171
+ const value = data[propName];
172
+ if (value !== null && (type === "JSON" || type === "Any" || type === "Object" || value instanceof Array)) res[propName] = JSON.stringify(value);
173
+ else res[propName] = value;
174
+ }
175
+ return res;
176
+ };
177
+ DataAccessObject.defaultScope = function(target, inst) {
178
+ let scope = this.definition.settings.scope;
179
+ if (typeof scope === "function") scope = this.definition.settings.scope.call(this, target, inst);
180
+ return scope;
181
+ };
182
+ DataAccessObject.applyScope = function(query, inst) {
183
+ const scope = this.defaultScope(query, inst) || {};
184
+ if (typeof scope === "object") mergeQuery(query, scope || {}, this.definition.settings.scope);
185
+ };
186
+ DataAccessObject.applyProperties = function(data, inst) {
187
+ let properties = this.definition.settings.properties;
188
+ properties = properties || this.definition.settings.attributes;
189
+ if (typeof properties === "object") Object.assign(data, properties);
190
+ else if (typeof properties === "function") Object.assign(data, properties.call(this, data, inst) || {});
191
+ else if (properties !== false) {
192
+ const scope = this.defaultScope(data, inst) || {};
193
+ if (typeof scope.where === "object") setScopeValuesFromWhere(data, scope.where, this);
194
+ }
195
+ };
196
+ DataAccessObject.lookupModel = function(_data) {
197
+ return this;
198
+ };
199
+ /**
200
+ * Get the connector instance for the given model class
201
+ * @returns {Connector} The connector instance
202
+ */
203
+ DataAccessObject.getConnector = function() {
204
+ return this.getDataSource().connector;
205
+ };
206
+ /**
207
+ * Create an instance of Model with given data and save to the attached data source. Callback is optional.
208
+ * Example:
209
+ *```js
210
+ * User.create({first: 'Joe', last: 'Bob'}, function(err, user) {
211
+ * console.log(user instanceof User); // true
212
+ * });
213
+ * ```
214
+ * Note: You must include a callback and use the created model provided in the callback if your code depends on your model being
215
+ * saved or having an ID.
216
+ *
217
+ * @param {Object} [data] Optional data object
218
+ * @param {Object} [options] Options for create
219
+ * @param {Function} [cb] Callback function called with these arguments:
220
+ * - err (null or Error)
221
+ * - instance (null or Model)
222
+ */
223
+ DataAccessObject.create = function(data, options, cb) {
224
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
225
+ if (connectionPromise) return connectionPromise;
226
+ let Model = this;
227
+ const connector = Model.getConnector();
228
+ assert(typeof connector.create === "function", "create() must be implemented by the connector");
229
+ const self = this;
230
+ if (options === void 0 && cb === void 0) {
231
+ if (typeof data === "function") {
232
+ cb = data;
233
+ data = {};
234
+ }
235
+ } else if (cb === void 0) {
236
+ if (typeof options === "function") {
237
+ cb = options;
238
+ options = {};
239
+ }
240
+ }
241
+ data = data || {};
242
+ options = options || {};
243
+ cb = cb || utils.createPromiseCallback();
244
+ assert(typeof data === "object", "The data argument must be an object or array");
245
+ assert(typeof options === "object", "The options argument must be an object");
246
+ assert(typeof cb === "function", "The cb argument must be a function");
247
+ const hookState = {};
248
+ if (Array.isArray(data)) {
249
+ for (let i = 0, n = data.length; i < n; i++) if (data[i] === void 0) data[i] = {};
250
+ mapParallel(data, function(item, done) {
251
+ self.create(item, options, function(err, result) {
252
+ done(null, {
253
+ err,
254
+ result: result || item
255
+ });
256
+ });
257
+ }, function(err, results) {
258
+ if (err) return cb(err, results);
259
+ let errors = null;
260
+ const data = [];
261
+ for (let i = 0, n = results.length; i < n; i++) {
262
+ if (results[i].err) {
263
+ if (!errors) errors = [];
264
+ errors[i] = results[i].err;
265
+ }
266
+ data[i] = results[i].result;
267
+ }
268
+ cb(errors, data);
269
+ });
270
+ return cb.promise;
271
+ }
272
+ const enforced = {};
273
+ let obj;
274
+ const idValue = getIdValue(this, data);
275
+ try {
276
+ if (data instanceof Model && !idValue) obj = data;
277
+ else obj = new Model(data);
278
+ this.applyProperties(enforced, obj);
279
+ obj.setAttributes(enforced);
280
+ } catch (err) {
281
+ process.nextTick(function() {
282
+ cb(err);
283
+ });
284
+ return cb.promise;
285
+ }
286
+ Model = this.lookupModel(data);
287
+ if (Model !== obj.constructor) obj = new Model(data);
288
+ let context = {
289
+ Model,
290
+ instance: obj,
291
+ isNewInstance: true,
292
+ hookState,
293
+ options
294
+ };
295
+ Model.notifyObserversOf("before save", context, function(err) {
296
+ if (err) return cb(err);
297
+ data = obj.toObject(true);
298
+ if (options.validate === false) return create();
299
+ if (options.validate === void 0 && Model.settings.automaticValidation === false) return create();
300
+ obj.isValid(function(valid) {
301
+ if (valid) create();
302
+ else cb(new ValidationError(obj), obj);
303
+ }, data, options);
304
+ });
305
+ function create() {
306
+ obj.trigger("create", function(createDone) {
307
+ obj.trigger("save", function(saveDone) {
308
+ const _idName = idName(Model);
309
+ let val = Model._sanitizeData(obj.toObject(true), options);
310
+ function createCallback(err, id, rev) {
311
+ if (id) {
312
+ obj.__data[_idName] = id;
313
+ defineReadonlyProp(obj, _idName, id);
314
+ }
315
+ if (rev) obj._rev = rev;
316
+ if (err) return cb(err, obj);
317
+ obj.__persisted = true;
318
+ const context = {
319
+ Model,
320
+ data: val,
321
+ isNewInstance: true,
322
+ hookState,
323
+ options
324
+ };
325
+ Model.notifyObserversOf("loaded", context, function(err) {
326
+ if (err) return cb(err);
327
+ if (Model.settings.updateOnLoad) obj.setAttributes(context.data);
328
+ saveDone.call(obj, function() {
329
+ createDone.call(obj, function() {
330
+ if (err) return cb(err, obj);
331
+ const context = {
332
+ Model,
333
+ instance: obj,
334
+ isNewInstance: true,
335
+ hookState,
336
+ options
337
+ };
338
+ if (options.notify !== false) Model.notifyObserversOf("after save", context, function(err) {
339
+ cb(err, obj);
340
+ });
341
+ else cb(null, obj);
342
+ });
343
+ });
344
+ });
345
+ }
346
+ val = applyDefaultsOnWrites(val, Model.definition);
347
+ context = {
348
+ Model,
349
+ data: val,
350
+ isNewInstance: true,
351
+ currentInstance: obj,
352
+ hookState,
353
+ options
354
+ };
355
+ Model.notifyObserversOf("persist", context, function(err, ctx) {
356
+ if (err) return cb(err);
357
+ val = ctx.data;
358
+ invokeConnectorMethod(connector, "create", Model, [obj.constructor._forDB(ctx.data)], options, createCallback);
359
+ });
360
+ }, obj, cb);
361
+ }, obj, cb);
362
+ }
363
+ return cb.promise;
364
+ };
365
+ /**
366
+ * Create an instances of Model with given data array and save to the attached data source. Callback is optional.
367
+ * Example:
368
+ *```js
369
+ * User.createAll([{first: 'Joe', last: 'Bob'},{first: 'Tom', last: 'Cat'}], function(err, users) {
370
+ * console.log(users[0] instanceof User); // true
371
+ * });
372
+ * ```
373
+ * Note: You must include a callback and use the created models provided in the callback if your code depends on your model being
374
+ * saved or having an ID.
375
+ *
376
+ * @param {Object} [dataArray] Optional data object with array of records
377
+ * @param {Object} [options] Options for create
378
+ * @param {Function} [cb] Callback function called with these arguments:
379
+ * - err (null or Error)
380
+ * - instance (null or Models)
381
+ */
382
+ DataAccessObject.createAll = function(dataArray, options, cb) {
383
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
384
+ if (connectionPromise) return connectionPromise;
385
+ let Model = this;
386
+ const connector = Model.getConnector();
387
+ if (!connector.multiInsertSupported) return this.create(dataArray, options, cb);
388
+ assert(typeof connector.createAll === "function", "createAll() must be implemented by the connector");
389
+ if (options === void 0 && cb === void 0) {
390
+ if (typeof dataArray === "function") {
391
+ cb = dataArray;
392
+ dataArray = [];
393
+ }
394
+ } else if (cb === void 0) {
395
+ if (typeof options === "function") {
396
+ cb = options;
397
+ options = {};
398
+ }
399
+ }
400
+ dataArray = dataArray || [];
401
+ options = options || {};
402
+ cb = cb || utils.createPromiseCallback();
403
+ assert(typeof dataArray === "object" && dataArray.length, "The data argument must be an array with length > 0");
404
+ assert(typeof options === "object", "The options argument must be an object");
405
+ assert(typeof cb === "function", "The cb argument must be a function");
406
+ const validationPromises = [];
407
+ for (let index = 0; index < dataArray.length; index++) {
408
+ const data = dataArray[index];
409
+ const hookState = {};
410
+ const enforced = {};
411
+ let obj;
412
+ try {
413
+ obj = new Model(data);
414
+ this.applyProperties(enforced, obj);
415
+ obj.setAttributes(enforced);
416
+ } catch (err) {
417
+ process.nextTick(function() {
418
+ cb(err);
419
+ });
420
+ return cb.promise;
421
+ }
422
+ Model = this.lookupModel(data);
423
+ if (Model !== obj.constructor) obj = new Model(data);
424
+ const context = {
425
+ Model,
426
+ instance: obj,
427
+ isNewInstance: true,
428
+ hookState,
429
+ options
430
+ };
431
+ const promise = new Promise((resolve, reject) => {
432
+ Model.notifyObserversOf("before save", context, function(err) {
433
+ if (err) return reject({
434
+ error: err,
435
+ data: obj
436
+ });
437
+ const d = obj.toObject(true);
438
+ if (options.validate === false) return resolve(obj);
439
+ if (options.validate === void 0 && Model.settings.automaticValidation === false) return resolve(obj);
440
+ obj.isValid(function(valid) {
441
+ if (valid) resolve(obj);
442
+ else reject({
443
+ error: new ValidationError(obj),
444
+ data: obj
445
+ });
446
+ }, d, options);
447
+ });
448
+ });
449
+ validationPromises.push(promise);
450
+ }
451
+ Promise.all(validationPromises).then((objArray) => {
452
+ const values = [];
453
+ const valMap = /* @__PURE__ */ new Map();
454
+ objArray.forEach((obj) => {
455
+ const val = Model._sanitizeData(obj.toObject(true), options);
456
+ values.push(val);
457
+ valMap.set(obj, applyDefaultsOnWrites(val, Model.definition));
458
+ });
459
+ const _idName = idName(Model);
460
+ function createCallback(err, savedArray) {
461
+ if (err) return cb(err, objArray);
462
+ const contextArr = savedArray.map((obj, i) => {
463
+ return {
464
+ Model,
465
+ data: obj,
466
+ isNewInstance: true,
467
+ hookState: context[i].hookState,
468
+ options: context[i].options
469
+ };
470
+ });
471
+ Model.notifyObserversOf("loaded", contextArr, function(err) {
472
+ if (err) return cb(err);
473
+ const afterSavePromises = [];
474
+ savedArray.map((obj, i) => {
475
+ const dataModel = context[i].currentInstance;
476
+ const id = obj[_idName];
477
+ if (id) {
478
+ dataModel.__data[_idName] = id;
479
+ defineReadonlyProp(dataModel, _idName, id);
480
+ }
481
+ dataModel.__persisted = true;
482
+ if (Model.settings.updateOnLoad) dataModel.setAttributes(obj);
483
+ const contxt = {
484
+ Model,
485
+ instance: dataModel,
486
+ isNewInstance: true,
487
+ hookState: context[i].hookState,
488
+ options: context[i].options
489
+ };
490
+ let afterSavePromise;
491
+ if (options.notify !== false) {
492
+ afterSavePromise = new Promise((resolve, reject) => {
493
+ Model.notifyObserversOf("after save", contxt, function(err) {
494
+ if (err) reject(err);
495
+ else resolve(dataModel);
496
+ });
497
+ });
498
+ afterSavePromises.push(afterSavePromise);
499
+ } else afterSavePromises.push(Promise.resolve(dataModel));
500
+ });
501
+ Promise.all(afterSavePromises).then((saved) => {
502
+ cb(null, saved);
503
+ }).catch((err) => {
504
+ cb(err, objArray);
505
+ });
506
+ });
507
+ }
508
+ const context = objArray.map((obj) => {
509
+ return {
510
+ Model,
511
+ data: valMap.get(obj),
512
+ isNewInstance: true,
513
+ currentInstance: obj,
514
+ hookState: {},
515
+ options
516
+ };
517
+ });
518
+ new Promise((resolve, reject) => {
519
+ Model.notifyObserversOf("persist", context, function(err, ctx) {
520
+ if (err) return reject(err);
521
+ resolve(ctx.map((obj) => {
522
+ return obj.currentInstance.constructor._forDB(obj.data);
523
+ }).filter((objData) => !!objData));
524
+ });
525
+ }).then((objDataArray) => {
526
+ invokeConnectorMethod(connector, "createAll", Model, [objDataArray], options, createCallback);
527
+ }).catch((err) => {
528
+ if (err) cb(err);
529
+ });
530
+ }).catch((err) => {
531
+ if (err) cb(err.error, err.data);
532
+ });
533
+ return cb.promise;
534
+ };
535
+ function applyDefaultsOnWrites(obj, modelDefinition) {
536
+ for (const key in modelDefinition.properties) {
537
+ const prop = modelDefinition.properties[key];
538
+ if ("applyDefaultOnWrites" in prop && !prop.applyDefaultOnWrites && prop.default !== void 0 && prop.default === obj[key]) delete obj[key];
539
+ }
540
+ return obj;
541
+ }
542
+ function stillConnecting(dataSource, obj, args) {
543
+ if (typeof args[args.length - 1] === "function") return dataSource.ready(obj, args);
544
+ const promiseArgs = Array.prototype.slice.call(args);
545
+ promiseArgs.callee = args.callee;
546
+ const cb = utils.createPromiseCallback();
547
+ promiseArgs.push(cb);
548
+ if (dataSource.ready(obj, promiseArgs)) return cb.promise;
549
+ else return false;
550
+ }
551
+ /**
552
+ * Update or insert a model instance: update exiting record if one is found, such that parameter `data.id` matches `id` of model instance;
553
+ * otherwise, insert a new record.
554
+ *
555
+ * NOTE: No setters, validations, or hooks are applied when using upsert.
556
+ * `updateOrCreate` and `patchOrCreate` are aliases
557
+ * @param {Object} data The model instance data
558
+ * @param {Object} [options] Options for upsert
559
+ * @param {Function} cb The callback function (optional).
560
+ */
561
+ DataAccessObject.updateOrCreate = DataAccessObject.patchOrCreate = DataAccessObject.upsert = function(data, options, cb) {
562
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
563
+ if (connectionPromise) return connectionPromise;
564
+ if (options === void 0 && cb === void 0) {
565
+ if (typeof data === "function") {
566
+ cb = data;
567
+ data = {};
568
+ }
569
+ } else if (cb === void 0) {
570
+ if (typeof options === "function") {
571
+ cb = options;
572
+ options = {};
573
+ }
574
+ }
575
+ cb = cb || utils.createPromiseCallback();
576
+ data = data || {};
577
+ options = options || {};
578
+ assert(typeof data === "object", "The data argument must be an object");
579
+ assert(typeof options === "object", "The options argument must be an object");
580
+ assert(typeof cb === "function", "The cb argument must be a function");
581
+ if (Array.isArray(data)) {
582
+ cb(/* @__PURE__ */ new Error("updateOrCreate does not support bulk mode or any array input"));
583
+ return cb.promise;
584
+ }
585
+ const hookState = {};
586
+ const self = this;
587
+ let Model = this;
588
+ const connector = Model.getConnector();
589
+ const id = getIdValue(this, data);
590
+ if (id === void 0 || id === null) return this.create(data, options, cb);
591
+ let doValidate = void 0;
592
+ if (options.validate === void 0) if (Model.settings.validateUpsert === void 0) {
593
+ if (Model.settings.automaticValidation !== void 0) doValidate = Model.settings.automaticValidation;
594
+ } else doValidate = Model.settings.validateUpsert;
595
+ else doValidate = options.validate;
596
+ if (this.settings.forceId) {
597
+ options = Object.create(options);
598
+ options.validate = !!doValidate;
599
+ Model.findById(id, options, function(err, model) {
600
+ if (err) return cb(err);
601
+ if (!model) return cb(errorModelNotFound(id));
602
+ model.updateAttributes(data, options, cb);
603
+ });
604
+ return cb.promise;
605
+ }
606
+ const context = {
607
+ Model,
608
+ query: byIdQuery(Model, id),
609
+ hookState,
610
+ options
611
+ };
612
+ Model.notifyObserversOf("access", context, doUpdateOrCreate);
613
+ function doUpdateOrCreate(err, ctx) {
614
+ if (err) return cb(err);
615
+ const isOriginalQuery = isWhereByGivenId(Model, ctx.query.where, id);
616
+ if (connector.updateOrCreate && isOriginalQuery) {
617
+ let context = {
618
+ Model,
619
+ where: ctx.query.where,
620
+ data,
621
+ hookState,
622
+ options
623
+ };
624
+ Model.notifyObserversOf("before save", context, function(err, ctx) {
625
+ if (err) return cb(err);
626
+ data = ctx.data;
627
+ let update = data;
628
+ let inst = data;
629
+ if (!(data instanceof Model)) inst = new Model(data, { applyDefaultValues: false });
630
+ update = inst.toObject(false);
631
+ Model.applyProperties(update, inst);
632
+ Model = Model.lookupModel(update);
633
+ if (doValidate === false) callConnector();
634
+ else inst.isValid(function(valid) {
635
+ if (!valid) if (doValidate) return cb(new ValidationError(inst), inst);
636
+ else {
637
+ g.warn("Ignoring validation errors in {{updateOrCreate()}}:");
638
+ g.warn(" %s", new ValidationError(inst).message);
639
+ }
640
+ callConnector();
641
+ }, update, options);
642
+ function callConnector() {
643
+ update = Model._sanitizeData(update, options);
644
+ context = {
645
+ Model,
646
+ where: ctx.where,
647
+ data: update,
648
+ currentInstance: inst,
649
+ hookState: ctx.hookState,
650
+ options
651
+ };
652
+ Model.notifyObserversOf("persist", context, function(err) {
653
+ if (err) return done(err);
654
+ invokeConnectorMethod(connector, "updateOrCreate", Model, [update], options, done);
655
+ });
656
+ }
657
+ function done(err, data, info) {
658
+ if (err) return cb(err);
659
+ const context = {
660
+ Model,
661
+ data,
662
+ isNewInstance: info && info.isNewInstance,
663
+ hookState: ctx.hookState,
664
+ options
665
+ };
666
+ Model.notifyObserversOf("loaded", context, function(err) {
667
+ if (err) return cb(err);
668
+ let obj;
669
+ if (data && !(data instanceof Model)) {
670
+ inst._initProperties(data, { persisted: true });
671
+ obj = inst;
672
+ } else obj = data;
673
+ if (err) cb(err, obj);
674
+ else {
675
+ const context = {
676
+ Model,
677
+ instance: obj,
678
+ isNewInstance: info ? info.isNewInstance : void 0,
679
+ hookState,
680
+ options
681
+ };
682
+ if (options.notify !== false) Model.notifyObserversOf("after save", context, function(err) {
683
+ cb(err, obj);
684
+ });
685
+ else cb(null, obj);
686
+ }
687
+ });
688
+ }
689
+ });
690
+ } else {
691
+ const opts = { notify: false };
692
+ if (ctx.options && ctx.options.transaction) opts.transaction = ctx.options.transaction;
693
+ Model.findOne({ where: ctx.query.where }, opts, function(err, inst) {
694
+ if (err) return cb(err);
695
+ if (!isOriginalQuery) delete data[idName(Model)];
696
+ if (inst) inst.updateAttributes(data, options, cb);
697
+ else {
698
+ Model = self.lookupModel(data);
699
+ new Model(data).save(options, cb);
700
+ }
701
+ });
702
+ }
703
+ }
704
+ return cb.promise;
705
+ };
706
+ /**
707
+ * Update or insert a model instance based on the search criteria.
708
+ * If there is a single instance retrieved, update the retrieved model.
709
+ * Creates a new model if no model instances were found.
710
+ * Returns an error if multiple instances are found.
711
+ * @param {Object} [where] `where` filter, like
712
+ * ```
713
+ * { key: val, key2: {gt: 'val2'}, ...}
714
+ * ```
715
+ * <br/>see
716
+ * [Where filter](https://docs.strongloop.com/display/LB/Where+filter#Wherefilter-Whereclauseforothermethods).
717
+ * @param {Object} data The model instance data to insert.
718
+ * @callback {Function} callback Callback function called with `cb(err, obj)` signature.
719
+ * @param {Error} err Error object; see [Error object](http://docs.strongloop.com/display/LB/Error+object).
720
+ * @param {Object} model Updated model instance.
721
+ */
722
+ DataAccessObject.patchOrCreateWithWhere = DataAccessObject.upsertWithWhere = function(where, data, options, cb) {
723
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
724
+ if (connectionPromise) return connectionPromise;
725
+ if (cb === void 0) {
726
+ if (typeof options === "function") {
727
+ cb = options;
728
+ options = {};
729
+ }
730
+ }
731
+ cb = cb || utils.createPromiseCallback();
732
+ options = options || {};
733
+ assert(typeof where === "object", "The where argument must be an object");
734
+ assert(typeof data === "object", "The data argument must be an object");
735
+ assert(typeof options === "object", "The options argument must be an object");
736
+ assert(typeof cb === "function", "The cb argument must be a function");
737
+ if (Object.keys(data).length === 0) {
738
+ const err = /* @__PURE__ */ new Error("data object cannot be empty!");
739
+ err.statusCode = 400;
740
+ process.nextTick(function() {
741
+ cb(err);
742
+ });
743
+ return cb.promise;
744
+ }
745
+ const hookState = {};
746
+ const self = this;
747
+ let Model = this;
748
+ const connector = Model.getConnector();
749
+ const query = { where };
750
+ const context = {
751
+ Model,
752
+ query,
753
+ hookState,
754
+ options
755
+ };
756
+ Model.notifyObserversOf("access", context, doUpsertWithWhere);
757
+ function doUpsertWithWhere(err, ctx) {
758
+ if (err) return cb(err);
759
+ ctx.data = data;
760
+ if (connector.upsertWithWhere) {
761
+ let context = {
762
+ Model,
763
+ where: ctx.query.where,
764
+ data: ctx.data,
765
+ hookState,
766
+ options
767
+ };
768
+ Model.notifyObserversOf("before save", context, function(err, ctx) {
769
+ if (err) return cb(err);
770
+ data = ctx.data;
771
+ let update = data;
772
+ let inst = data;
773
+ if (!(data instanceof Model)) inst = new Model(data, { applyDefaultValues: false });
774
+ update = inst.toObject(false);
775
+ Model.applyScope(query);
776
+ Model.applyProperties(update, inst);
777
+ Model = Model.lookupModel(update);
778
+ if (options.validate === false) return callConnector();
779
+ if (options.validate === void 0 && Model.settings.automaticValidation === false) return callConnector();
780
+ inst.isValid(function(valid) {
781
+ if (!valid) return cb(new ValidationError(inst), inst);
782
+ callConnector();
783
+ }, update, options);
784
+ function callConnector() {
785
+ try {
786
+ ctx.where = Model._sanitizeQuery(ctx.where, options);
787
+ ctx.where = Model._coerce(ctx.where, options);
788
+ update = Model._sanitizeData(update, options);
789
+ update = Model._coerce(update, options);
790
+ } catch (err) {
791
+ return process.nextTick(function() {
792
+ cb(err);
793
+ });
794
+ }
795
+ context = {
796
+ Model,
797
+ where: ctx.where,
798
+ data: update,
799
+ currentInstance: inst,
800
+ hookState: ctx.hookState,
801
+ options
802
+ };
803
+ Model.notifyObserversOf("persist", context, function(err) {
804
+ if (err) return done(err);
805
+ invokeConnectorMethod(connector, "upsertWithWhere", Model, [ctx.where, update], options, done);
806
+ });
807
+ }
808
+ function done(err, data, info) {
809
+ if (err) return cb(err);
810
+ const contxt = {
811
+ Model,
812
+ data,
813
+ isNewInstance: info && info.isNewInstance,
814
+ hookState: ctx.hookState,
815
+ options
816
+ };
817
+ Model.notifyObserversOf("loaded", contxt, function(err) {
818
+ if (err) return cb(err);
819
+ let obj;
820
+ if (contxt.data && !(contxt.data instanceof Model)) {
821
+ inst._initProperties(contxt.data, { persisted: true });
822
+ obj = inst;
823
+ } else obj = contxt.data;
824
+ const context = {
825
+ Model,
826
+ instance: obj,
827
+ isNewInstance: info ? info.isNewInstance : void 0,
828
+ hookState,
829
+ options
830
+ };
831
+ Model.notifyObserversOf("after save", context, function(err) {
832
+ cb(err, obj);
833
+ });
834
+ });
835
+ }
836
+ });
837
+ } else {
838
+ const opts = { notify: false };
839
+ if (ctx.options && ctx.options.transaction) opts.transaction = ctx.options.transaction;
840
+ self.find({ where: ctx.query.where }, opts, function(err, instances) {
841
+ if (err) return cb(err);
842
+ const modelsLength = instances.length;
843
+ if (modelsLength === 0) self.create(data, options, cb);
844
+ else if (modelsLength === 1) instances[0].updateAttributes(data, options, cb);
845
+ else process.nextTick(function() {
846
+ const error = /* @__PURE__ */ new Error("There are multiple instances found.Upsert Operation will not be performed!");
847
+ error.statusCode = 400;
848
+ cb(error);
849
+ });
850
+ });
851
+ }
852
+ }
853
+ return cb.promise;
854
+ };
855
+ /**
856
+ * Replace or insert a model instance: replace exiting record if one is found, such that parameter `data.id` matches `id` of model instance;
857
+ * otherwise, insert a new record.
858
+ *
859
+ * @param {Object} data The model instance data
860
+ * @param {Object} [options] Options for replaceOrCreate
861
+ * @param {Function} cb The callback function (optional).
862
+ */
863
+ DataAccessObject.replaceOrCreate = function replaceOrCreate(data, options, cb) {
864
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
865
+ if (connectionPromise) return connectionPromise;
866
+ if (cb === void 0) {
867
+ if (typeof options === "function") {
868
+ cb = options;
869
+ options = {};
870
+ }
871
+ }
872
+ cb = cb || utils.createPromiseCallback();
873
+ data = data || {};
874
+ options = options || {};
875
+ assert(typeof data === "object", "The data argument must be an object");
876
+ assert(typeof options === "object", "The options argument must be an object");
877
+ assert(typeof cb === "function", "The cb argument must be a function");
878
+ const hookState = {};
879
+ const self = this;
880
+ let Model = this;
881
+ const connector = Model.getConnector();
882
+ let id = getIdValue(this, data);
883
+ if (id === void 0 || id === null) return this.create(data, options, cb);
884
+ if (this.settings.forceId) return Model.replaceById(id, data, options, cb);
885
+ let inst;
886
+ if (data instanceof Model) inst = data;
887
+ else inst = new Model(data);
888
+ const strict = inst.__strict;
889
+ const context = {
890
+ Model,
891
+ query: byIdQuery(Model, id),
892
+ hookState,
893
+ options
894
+ };
895
+ Model.notifyObserversOf("access", context, doReplaceOrCreate);
896
+ function doReplaceOrCreate(err, ctx) {
897
+ if (err) return cb(err);
898
+ const isOriginalQuery = isWhereByGivenId(Model, ctx.query.where, id);
899
+ const where = ctx.query.where;
900
+ if (connector.replaceOrCreate && isOriginalQuery) {
901
+ let context = {
902
+ Model,
903
+ instance: inst,
904
+ hookState,
905
+ options
906
+ };
907
+ Model.notifyObserversOf("before save", context, function(err, ctx) {
908
+ if (err) return cb(err);
909
+ let update = inst.toObject(false);
910
+ if (strict) applyStrictCheck(Model, strict, update, inst, validateAndCallConnector);
911
+ else validateAndCallConnector();
912
+ function validateAndCallConnector(err) {
913
+ if (err) return cb(err);
914
+ Model.applyProperties(update, inst);
915
+ Model = Model.lookupModel(update);
916
+ if (options.validate === false) return callConnector();
917
+ if (options.validate === void 0 && Model.settings.automaticValidation === false) return callConnector();
918
+ inst.isValid(function(valid) {
919
+ if (!valid) return cb(new ValidationError(inst), inst);
920
+ callConnector();
921
+ }, update, options);
922
+ function callConnector() {
923
+ update = Model._sanitizeData(update, options);
924
+ context = {
925
+ Model,
926
+ where,
927
+ data: update,
928
+ currentInstance: inst,
929
+ hookState: ctx.hookState,
930
+ options
931
+ };
932
+ Model.notifyObserversOf("persist", context, function(err) {
933
+ if (err) return done(err);
934
+ invokeConnectorMethod(connector, "replaceOrCreate", Model, [context.data], options, done);
935
+ });
936
+ }
937
+ function done(err, data, info) {
938
+ if (err) return cb(err);
939
+ const context = {
940
+ Model,
941
+ data,
942
+ isNewInstance: info ? info.isNewInstance : void 0,
943
+ hookState: ctx.hookState,
944
+ options
945
+ };
946
+ Model.notifyObserversOf("loaded", context, function(err) {
947
+ if (err) return cb(err);
948
+ let obj;
949
+ if (data && !(data instanceof Model)) {
950
+ inst._initProperties(data, { persisted: true });
951
+ obj = inst;
952
+ } else obj = data;
953
+ if (err) cb(err, obj);
954
+ else {
955
+ const context = {
956
+ Model,
957
+ instance: obj,
958
+ isNewInstance: info ? info.isNewInstance : void 0,
959
+ hookState,
960
+ options
961
+ };
962
+ Model.notifyObserversOf("after save", context, function(err) {
963
+ cb(err, obj, info);
964
+ });
965
+ }
966
+ });
967
+ }
968
+ }
969
+ });
970
+ } else {
971
+ const opts = { notify: false };
972
+ if (ctx.options && ctx.options.transaction) opts.transaction = ctx.options.transaction;
973
+ Model.findOne({ where: ctx.query.where }, opts, function(err, found) {
974
+ if (err) return cb(err);
975
+ if (!isOriginalQuery) {
976
+ const pkName = idName(Model);
977
+ delete data[pkName];
978
+ if (found) id = found[pkName];
979
+ }
980
+ if (found) self.replaceById(id, data, options, cb);
981
+ else {
982
+ Model = self.lookupModel(data);
983
+ new Model(data).save(options, cb);
984
+ }
985
+ });
986
+ }
987
+ }
988
+ return cb.promise;
989
+ };
990
+ /**
991
+ * Find one record that matches specified query criteria. Same as `find`, but limited to one record, and this function returns an
992
+ * object, not a collection.
993
+ * If the specified instance is not found, then create it using data provided as second argument.
994
+ *
995
+ * @param {Object} query Search conditions. See [find](#dataaccessobjectfindquery-callback) for query format.
996
+ * For example: `{where: {test: 'me'}}`.
997
+ * @param {Object} data Object to create.
998
+ * @param {Object} [options] Option for findOrCreate
999
+ * @param {Function} cb Callback called with (err, instance, created)
1000
+ */
1001
+ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb) {
1002
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1003
+ if (connectionPromise) return connectionPromise;
1004
+ assert(arguments.length >= 1, "At least one argument is required");
1005
+ if (data === void 0 && options === void 0 && cb === void 0) {
1006
+ assert(typeof query === "object", "Single argument must be data object");
1007
+ data = query;
1008
+ query = { where: data };
1009
+ } else if (options === void 0 && cb === void 0) {
1010
+ if (typeof data === "function") {
1011
+ cb = data;
1012
+ data = query;
1013
+ query = { where: data };
1014
+ }
1015
+ } else if (cb === void 0) {
1016
+ if (typeof options === "function") {
1017
+ cb = options;
1018
+ options = {};
1019
+ }
1020
+ }
1021
+ cb = cb || utils.createPromiseCallback();
1022
+ query = query || { where: {} };
1023
+ data = data || {};
1024
+ options = options || {};
1025
+ assert(typeof query === "object", "The query argument must be an object");
1026
+ assert(typeof data === "object", "The data argument must be an object");
1027
+ assert(typeof options === "object", "The options argument must be an object");
1028
+ assert(typeof cb === "function", "The cb argument must be a function");
1029
+ const hookState = {};
1030
+ const Model = this;
1031
+ const self = this;
1032
+ const connector = Model.getConnector();
1033
+ function _findOrCreate(query, data, currentInstance) {
1034
+ function findOrCreateCallback(err, data, created) {
1035
+ if (err) return cb(err);
1036
+ const context = {
1037
+ Model,
1038
+ data,
1039
+ isNewInstance: created,
1040
+ hookState,
1041
+ options
1042
+ };
1043
+ Model.notifyObserversOf("loaded", context, function(err, ctx) {
1044
+ if (err) return cb(err);
1045
+ data = ctx.data;
1046
+ const Model = self.lookupModel(data);
1047
+ let obj;
1048
+ if (data) {
1049
+ const ctorOpts = {
1050
+ fields: query.fields,
1051
+ applySetters: false,
1052
+ persisted: true,
1053
+ applyDefaultValues: false
1054
+ };
1055
+ obj = new Model(data, ctorOpts);
1056
+ }
1057
+ if (created) {
1058
+ const context = {
1059
+ Model,
1060
+ instance: obj,
1061
+ isNewInstance: true,
1062
+ hookState,
1063
+ options
1064
+ };
1065
+ Model.notifyObserversOf("after save", context, function(err) {
1066
+ if (cb.promise) cb(err, [obj, created]);
1067
+ else cb(err, obj, created);
1068
+ });
1069
+ } else if (cb.promise) cb(err, [obj, created]);
1070
+ else cb(err, obj, created);
1071
+ });
1072
+ }
1073
+ data = Model._sanitizeData(data, options);
1074
+ const context = {
1075
+ Model,
1076
+ where: query.where,
1077
+ data,
1078
+ isNewInstance: true,
1079
+ currentInstance,
1080
+ hookState,
1081
+ options
1082
+ };
1083
+ Model.notifyObserversOf("persist", context, function(err) {
1084
+ if (err) return cb(err);
1085
+ invokeConnectorMethod(connector, "findOrCreate", Model, [query, self._forDB(context.data)], options, findOrCreateCallback);
1086
+ });
1087
+ }
1088
+ if (connector.findOrCreate) {
1089
+ query.limit = 1;
1090
+ try {
1091
+ this._normalize(query, options);
1092
+ } catch (err) {
1093
+ process.nextTick(function() {
1094
+ cb(err);
1095
+ });
1096
+ return cb.promise;
1097
+ }
1098
+ this.applyScope(query);
1099
+ const context = {
1100
+ Model,
1101
+ query,
1102
+ hookState,
1103
+ options
1104
+ };
1105
+ Model.notifyObserversOf("access", context, function(err, ctx) {
1106
+ if (err) return cb(err);
1107
+ const query = ctx.query;
1108
+ const enforced = {};
1109
+ const Model = self.lookupModel(data);
1110
+ const obj = data instanceof Model ? data : new Model(data);
1111
+ Model.applyProperties(enforced, obj);
1112
+ obj.setAttributes(enforced);
1113
+ const context = {
1114
+ Model,
1115
+ instance: obj,
1116
+ isNewInstance: true,
1117
+ hookState,
1118
+ options
1119
+ };
1120
+ Model.notifyObserversOf("before save", context, function(err, ctx) {
1121
+ if (err) return cb(err);
1122
+ const obj = ctx.instance;
1123
+ const data = obj.toObject(true);
1124
+ if (options.validate === false) return _findOrCreate(query, data, obj);
1125
+ if (options.validate === void 0 && Model.settings.automaticValidation === false) return _findOrCreate(query, data, obj);
1126
+ obj.isValid(function(valid) {
1127
+ if (valid) _findOrCreate(query, data, obj);
1128
+ else cb(new ValidationError(obj), obj);
1129
+ }, data, options);
1130
+ });
1131
+ });
1132
+ } else Model.findOne(query, options, function(err, record) {
1133
+ if (err) return cb(err);
1134
+ if (record) if (cb.promise) return cb(null, [record, false]);
1135
+ else return cb(null, record, false);
1136
+ Model.create(data, options, function(err, record) {
1137
+ if (cb.promise) cb(err, [record, record != null]);
1138
+ else cb(err, record, record != null);
1139
+ });
1140
+ });
1141
+ return cb.promise;
1142
+ };
1143
+ /**
1144
+ * Check whether a model instance exists in database
1145
+ *
1146
+ * @param {id} id Identifier of object (primary key value)
1147
+ * @param {Object} [options] Options
1148
+ * @param {Function} cb Callback function called with (err, exists: Bool)
1149
+ */
1150
+ DataAccessObject.exists = function exists(id, options, cb) {
1151
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1152
+ if (connectionPromise) return connectionPromise;
1153
+ assert(arguments.length >= 1, "The id argument is required");
1154
+ if (cb === void 0) {
1155
+ if (typeof options === "function") {
1156
+ cb = options;
1157
+ options = {};
1158
+ }
1159
+ }
1160
+ cb = cb || utils.createPromiseCallback();
1161
+ options = options || {};
1162
+ assert(typeof options === "object", "The options argument must be an object");
1163
+ assert(typeof cb === "function", "The cb argument must be a function");
1164
+ if (id !== void 0 && id !== null && id !== "") this.count(byIdQuery(this, id).where, options, function(err, count) {
1165
+ cb(err, err ? false : count === 1);
1166
+ });
1167
+ else process.nextTick(function() {
1168
+ cb(new Error(g.f("{{Model::exists}} requires the {{id}} argument")));
1169
+ });
1170
+ return cb.promise;
1171
+ };
1172
+ /**
1173
+ * Find model instance by ID.
1174
+ *
1175
+ * Example:
1176
+ * ```js
1177
+ * User.findById(23, function(err, user) {
1178
+ * console.info(user.id); // 23
1179
+ * });
1180
+ * ```
1181
+ *
1182
+ * @param {*} id Primary key value
1183
+ * @param {Object} [filter] The filter that contains `include` or `fields`.
1184
+ * Other settings such as `where`, `order`, `limit`, or `offset` will be
1185
+ * ignored.
1186
+ * @param {Object} [options] Options
1187
+ * @param {Function} cb Callback called with (err, instance)
1188
+ */
1189
+ DataAccessObject.findById = function findById(id, filter, options, cb) {
1190
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1191
+ if (connectionPromise) return connectionPromise;
1192
+ assert(arguments.length >= 1, "The id argument is required");
1193
+ if (options === void 0 && cb === void 0) {
1194
+ if (typeof filter === "function") {
1195
+ cb = filter;
1196
+ filter = {};
1197
+ }
1198
+ } else if (cb === void 0) {
1199
+ if (typeof options === "function") {
1200
+ cb = options;
1201
+ options = {};
1202
+ if (typeof filter === "object" && !(filter.include || filter.fields)) {
1203
+ options = filter;
1204
+ filter = {};
1205
+ }
1206
+ }
1207
+ }
1208
+ cb = cb || utils.createPromiseCallback();
1209
+ options = options || {};
1210
+ filter = filter || {};
1211
+ assert(typeof filter === "object", "The filter argument must be an object");
1212
+ assert(typeof options === "object", "The options argument must be an object");
1213
+ assert(typeof cb === "function", "The cb argument must be a function");
1214
+ if (isPKMissing(this, cb)) return cb.promise;
1215
+ else if (id == null || id === "") process.nextTick(function() {
1216
+ cb(new Error(g.f("{{Model::findById}} requires the {{id}} argument")));
1217
+ });
1218
+ else {
1219
+ const query = byIdQuery(this, id);
1220
+ if (filter.include) query.include = filter.include;
1221
+ if (filter.fields) query.fields = filter.fields;
1222
+ this.findOne(query, options, cb);
1223
+ }
1224
+ return cb.promise;
1225
+ };
1226
+ /**
1227
+ * Find model instances by ids
1228
+ * @param {Array} ids An array of ids
1229
+ * @param {Object} query Query filter
1230
+ * @param {Object} [options] Options
1231
+ * @param {Function} cb Callback called with (err, instance)
1232
+ */
1233
+ DataAccessObject.findByIds = function(ids, query, options, cb) {
1234
+ if (options === void 0 && cb === void 0) {
1235
+ if (typeof query === "function") {
1236
+ cb = query;
1237
+ query = {};
1238
+ }
1239
+ } else if (cb === void 0) {
1240
+ if (typeof options === "function") {
1241
+ cb = options;
1242
+ options = {};
1243
+ }
1244
+ }
1245
+ cb = cb || utils.createPromiseCallback();
1246
+ options = options || {};
1247
+ query = query || {};
1248
+ assert(Array.isArray(ids), "The ids argument must be an array");
1249
+ assert(typeof query === "object", "The query argument must be an object");
1250
+ assert(typeof options === "object", "The options argument must be an object");
1251
+ assert(typeof cb === "function", "The cb argument must be a function");
1252
+ if (isPKMissing(this, cb)) return cb.promise;
1253
+ else if (ids.length === 0) {
1254
+ process.nextTick(function() {
1255
+ cb(null, []);
1256
+ });
1257
+ return cb.promise;
1258
+ }
1259
+ const filter = { where: {} };
1260
+ const pk = idName(this);
1261
+ filter.where[pk] = { inq: [].concat(ids) };
1262
+ mergeQuery(filter, query || {});
1263
+ const toSortObjectsByIds = filter.order ? false : true;
1264
+ this.find(filter, options, function(err, results) {
1265
+ cb(err, toSortObjectsByIds ? utils.sortObjectsByIds(pk, ids, results) : results);
1266
+ });
1267
+ return cb.promise;
1268
+ };
1269
+ DataAccessObject.all = function() {
1270
+ return DataAccessObject.find.apply(this, arguments);
1271
+ };
1272
+ /**
1273
+ * Find all instances of Model that match the specified query.
1274
+ * Fields used for filter and sort should be declared with `{index: true}` in model definition.
1275
+ * See [Querying models](http://docs.strongloop.com/display/DOC/Querying+models) for more information.
1276
+ *
1277
+ * For example, find the second page of ten users over age 21 in descending order exluding the password property.
1278
+ *
1279
+ * ```js
1280
+ * User.find({
1281
+ * where: {
1282
+ * age: {gt: 21}},
1283
+ * order: 'age DESC',
1284
+ * limit: 10,
1285
+ * skip: 10,
1286
+ * fields: {password: false}
1287
+ * },
1288
+ * console.log
1289
+ * );
1290
+ * ```
1291
+ *
1292
+ * @options {Object} [query] Optional JSON object that specifies query criteria and parameters.
1293
+ * @property {Object} where Search criteria in JSON format `{ key: val, key2: {gt: 'val2'}}`.
1294
+ * Operations:
1295
+ * - gt: >
1296
+ * - gte: >=
1297
+ * - lt: <
1298
+ * - lte: <=
1299
+ * - between
1300
+ * - inq: IN
1301
+ * - nin: NOT IN
1302
+ * - neq: !=
1303
+ * - like: LIKE
1304
+ * - nlike: NOT LIKE
1305
+ * - ilike: ILIKE
1306
+ * - nilike: NOT ILIKE
1307
+ * - regexp: REGEXP
1308
+ *
1309
+ * You can also use `and` and `or` operations. See [Querying models](http://docs.strongloop.com/display/DOC/Querying+models) for more information.
1310
+ * @property {String|Object|Array} include Allows you to load relations of several objects and optimize numbers of requests.
1311
+ * Format examples;
1312
+ * - `'posts'`: Load posts
1313
+ * - `['posts', 'passports']`: Load posts and passports
1314
+ * - `{'owner': 'posts'}`: Load owner and owner's posts
1315
+ * - `{'owner': ['posts', 'passports']}`: Load owner, owner's posts, and owner's passports
1316
+ * - `{'owner': [{posts: 'images'}, 'passports']}`: Load owner, owner's posts, owner's posts' images, and owner's passports
1317
+ * See `DataAccessObject.include()`.
1318
+ * @property {String} order Sort order. Format: `'key1 ASC, key2 DESC'`
1319
+ * @property {Number} limit Maximum number of instances to return.
1320
+ * @property {Number} skip Number of instances to skip.
1321
+ * @property {Number} offset Alias for `skip`.
1322
+ * @property {Object|Array|String} fields Included/excluded fields.
1323
+ * - `['foo']` or `'foo'` - include only the foo property
1324
+ * - `['foo', 'bar']` - include the foo and bar properties. Format:
1325
+ * - `{foo: true}` - include only foo
1326
+ * - `{bat: false}` - include all properties, exclude bat
1327
+ *
1328
+ * @param {Function} cb Optional callback function. Call this function with two arguments: `err` (null or Error) and an array of instances.
1329
+ * @return {Promise} results If no callback function is provided, a promise (which resolves to an array of instances) is returned
1330
+ */
1331
+ DataAccessObject.find = function find(query, options, cb) {
1332
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1333
+ if (connectionPromise) return connectionPromise;
1334
+ if (options === void 0 && cb === void 0) {
1335
+ if (typeof query === "function") {
1336
+ cb = query;
1337
+ query = {};
1338
+ }
1339
+ } else if (cb === void 0) {
1340
+ if (typeof options === "function") {
1341
+ cb = options;
1342
+ options = {};
1343
+ }
1344
+ }
1345
+ cb = cb || utils.createPromiseCallback();
1346
+ query = query || {};
1347
+ options = options || {};
1348
+ assert(typeof query === "object", "The query argument must be an object");
1349
+ assert(typeof options === "object", "The options argument must be an object");
1350
+ assert(typeof cb === "function", "The cb argument must be a function");
1351
+ const hookState = {};
1352
+ const self = this;
1353
+ const connector = self.getConnector();
1354
+ assert(typeof connector.all === "function", "all() must be implemented by the connector");
1355
+ try {
1356
+ this._normalize(query, options);
1357
+ } catch (err) {
1358
+ process.nextTick(function() {
1359
+ cb(err);
1360
+ });
1361
+ return cb.promise;
1362
+ }
1363
+ this.applyScope(query);
1364
+ let near = query && geo.nearFilter(query.where);
1365
+ const supportsGeo = !!connector.buildNearFilter;
1366
+ let geoQueryObject;
1367
+ if (near) {
1368
+ if (supportsGeo) connector.buildNearFilter(query, near);
1369
+ else if (query.where) {
1370
+ if (options.notify === false) queryGeo(query);
1371
+ else withNotifyGeo();
1372
+ function withNotifyGeo() {
1373
+ const context = {
1374
+ Model: self,
1375
+ query,
1376
+ hookState,
1377
+ options
1378
+ };
1379
+ self.notifyObserversOf("access", context, function(err, ctx) {
1380
+ if (err) return cb(err);
1381
+ queryGeo(ctx.query);
1382
+ });
1383
+ }
1384
+ return cb.promise;
1385
+ }
1386
+ }
1387
+ function geoCallback(err, data) {
1388
+ const memory = new Memory();
1389
+ const modelName = self.modelName;
1390
+ if (err) cb(err);
1391
+ else if (Array.isArray(data)) {
1392
+ memory.define({
1393
+ properties: self.dataSource.definitions[modelName].properties,
1394
+ settings: self.dataSource.definitions[modelName].settings,
1395
+ model: self
1396
+ });
1397
+ data.forEach(function(obj) {
1398
+ memory.create(modelName, obj, options, function() {});
1399
+ });
1400
+ memory.all(modelName, geoQueryObject, options, allCb);
1401
+ } else cb(null, []);
1402
+ }
1403
+ function queryGeo(query) {
1404
+ geoQueryObject = query;
1405
+ near = query && geo.nearFilter(query.where);
1406
+ invokeConnectorMethod(connector, "all", self, [{}], options, geoCallback);
1407
+ }
1408
+ function allCb(err, data) {
1409
+ let normalizedIncludes = null;
1410
+ let includedRelationNames = null;
1411
+ if (query && query.include && !query.collect) {
1412
+ normalizedIncludes = Inclusion.normalizeInclude(query.include || []);
1413
+ includedRelationNames = [];
1414
+ for (let i = 0; i < normalizedIncludes.length; i++) {
1415
+ const inc = normalizedIncludes[i];
1416
+ includedRelationNames.push(utils.isPlainObject(inc) ? Object.keys(inc)[0] : inc);
1417
+ }
1418
+ }
1419
+ if (!err && Array.isArray(data)) mapParallel(data, function(item, next) {
1420
+ const Model = self.lookupModel(item);
1421
+ if (options.notify === false) buildResult(item, next);
1422
+ else withNotify(item, next);
1423
+ function buildResult(data, callback) {
1424
+ const ctorOpts = {
1425
+ fields: query.fields,
1426
+ applySetters: false,
1427
+ persisted: true,
1428
+ applyDefaultValues: false
1429
+ };
1430
+ let obj;
1431
+ try {
1432
+ obj = new Model(data, ctorOpts);
1433
+ } catch (err) {
1434
+ return callback(err);
1435
+ }
1436
+ if (query && query.include) if (query.collect) {
1437
+ obj = obj.__cachedRelations[query.collect];
1438
+ if (obj === null) obj = void 0;
1439
+ } else {
1440
+ for (let i = 0; i < includedRelationNames.length; i++) {
1441
+ const relationName = includedRelationNames[i];
1442
+ let included = obj.__cachedRelations[relationName];
1443
+ if (Array.isArray(included)) included = new List(included, null, obj);
1444
+ if (included) obj.__data[relationName] = included;
1445
+ }
1446
+ delete obj.__data.__cachedRelations;
1447
+ }
1448
+ callback(null, obj);
1449
+ }
1450
+ function withNotify(data, callback) {
1451
+ const context = {
1452
+ Model,
1453
+ data,
1454
+ isNewInstance: false,
1455
+ hookState,
1456
+ options
1457
+ };
1458
+ Model.notifyObserversOf("loaded", context, function(err) {
1459
+ if (err) return callback(err);
1460
+ buildResult(context.data, callback);
1461
+ });
1462
+ }
1463
+ }, function(err, results) {
1464
+ if (err) return cb(err);
1465
+ results = results.filter(isDefined);
1466
+ if (data && data.countBeforeLimit) results.countBeforeLimit = data.countBeforeLimit;
1467
+ if (!supportsGeo && near) results = geo.filter(results, near);
1468
+ cb(err, results);
1469
+ });
1470
+ else cb(err, data || []);
1471
+ }
1472
+ if (options.notify === false) invokeConnectorMethod(connector, "all", self, [query], options, allCb);
1473
+ else {
1474
+ const context = {
1475
+ Model: this,
1476
+ query,
1477
+ hookState,
1478
+ options
1479
+ };
1480
+ this.notifyObserversOf("access", context, function(err, ctx) {
1481
+ if (err) return cb(err);
1482
+ invokeConnectorMethod(connector, "all", self, [ctx.query], options, allCb);
1483
+ });
1484
+ }
1485
+ return cb.promise;
1486
+ };
1487
+ function isDefined(value) {
1488
+ return value !== void 0;
1489
+ }
1490
+ /**
1491
+ * Find one record, same as `find`, but limited to one result. This function returns an object, not a collection.
1492
+ *
1493
+ * @param {Object} query Search conditions. See [find](#dataaccessobjectfindquery-callback) for query format.
1494
+ * For example: `{where: {test: 'me'}}`.
1495
+ * @param {Object} [options] Options
1496
+ * @param {Function} cb Callback function called with (err, instance)
1497
+ */
1498
+ DataAccessObject.findOne = function findOne(query, options, cb) {
1499
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1500
+ if (connectionPromise) return connectionPromise;
1501
+ if (options === void 0 && cb === void 0) {
1502
+ if (typeof query === "function") {
1503
+ cb = query;
1504
+ query = {};
1505
+ }
1506
+ } else if (cb === void 0) {
1507
+ if (typeof options === "function") {
1508
+ cb = options;
1509
+ options = {};
1510
+ }
1511
+ }
1512
+ cb = cb || utils.createPromiseCallback();
1513
+ query = query || {};
1514
+ options = options || {};
1515
+ assert(typeof query === "object", "The query argument must be an object");
1516
+ assert(typeof options === "object", "The options argument must be an object");
1517
+ assert(typeof cb === "function", "The cb argument must be a function");
1518
+ query.limit = 1;
1519
+ this.find(query, options, function(err, collection) {
1520
+ if (err || !collection || !collection.length > 0) return cb(err, null);
1521
+ cb(err, collection[0]);
1522
+ });
1523
+ return cb.promise;
1524
+ };
1525
+ /**
1526
+ * Destroy all matching records.
1527
+ * Delete all model instances from data source. Note: destroyAll method does not destroy hooks.
1528
+ * Example:
1529
+ *````js
1530
+ * Product.destroyAll({price: {gt: 99}}, function(err) {
1531
+ // removed matching products
1532
+ * });
1533
+ * ````
1534
+ *
1535
+ * @param {Object} [where] Optional object that defines the criteria. This is a "where" object. Do NOT pass a filter object.
1536
+ * @param {Object) [options] Options
1537
+ * @param {Function} [cb] Callback called with (err, info)
1538
+ */
1539
+ DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyAll = function destroyAll(where, options, cb) {
1540
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1541
+ if (connectionPromise) return connectionPromise;
1542
+ const Model = this;
1543
+ const connector = Model.getConnector();
1544
+ assert(typeof connector.destroyAll === "function", "destroyAll() must be implemented by the connector");
1545
+ if (options === void 0 && cb === void 0) {
1546
+ if (typeof where === "function") {
1547
+ cb = where;
1548
+ where = {};
1549
+ }
1550
+ } else if (cb === void 0) {
1551
+ if (typeof options === "function") {
1552
+ cb = options;
1553
+ options = {};
1554
+ }
1555
+ }
1556
+ cb = cb || utils.createPromiseCallback();
1557
+ where = where || {};
1558
+ options = options || {};
1559
+ assert(typeof where === "object", "The where argument must be an object");
1560
+ assert(typeof options === "object", "The options argument must be an object");
1561
+ assert(typeof cb === "function", "The cb argument must be a function");
1562
+ const hookState = {};
1563
+ let query = { where };
1564
+ this.applyScope(query);
1565
+ where = query.where;
1566
+ if (options.notify === false) doDelete(where);
1567
+ else {
1568
+ query = { where: whereIsEmpty(where) ? {} : where };
1569
+ const context = {
1570
+ Model,
1571
+ query,
1572
+ hookState,
1573
+ options
1574
+ };
1575
+ Model.notifyObserversOf("access", context, function(err, ctx) {
1576
+ if (err) return cb(err);
1577
+ const context = {
1578
+ Model,
1579
+ where: ctx.query.where,
1580
+ hookState,
1581
+ options
1582
+ };
1583
+ Model.notifyObserversOf("before delete", context, function(err, ctx) {
1584
+ if (err) return cb(err);
1585
+ doDelete(ctx.where);
1586
+ });
1587
+ });
1588
+ }
1589
+ function doDelete(where) {
1590
+ whereIsEmpty(where);
1591
+ if (whereIsEmpty(where)) invokeConnectorMethod(connector, "destroyAll", Model, [{}], options, done);
1592
+ else {
1593
+ try {
1594
+ where = Model._sanitizeQuery(where, options);
1595
+ where = Model._coerce(where, options);
1596
+ } catch (err) {
1597
+ return process.nextTick(function() {
1598
+ cb(err);
1599
+ });
1600
+ }
1601
+ invokeConnectorMethod(connector, "destroyAll", Model, [where], options, done);
1602
+ }
1603
+ function done(err, info) {
1604
+ if (err) return cb(err);
1605
+ if (options.notify === false) return cb(err, info);
1606
+ const context = {
1607
+ Model,
1608
+ where,
1609
+ hookState,
1610
+ options,
1611
+ info
1612
+ };
1613
+ Model.notifyObserversOf("after delete", context, function(err) {
1614
+ cb(err, info);
1615
+ });
1616
+ }
1617
+ }
1618
+ return cb.promise;
1619
+ };
1620
+ function whereIsEmpty(where) {
1621
+ return !where || typeof where === "object" && Object.keys(where).length === 0;
1622
+ }
1623
+ /**
1624
+ * Delete the record with the specified ID.
1625
+ * Aliases are `destroyById` and `deleteById`.
1626
+ * @param {*} id The id value
1627
+ * @param {Function} cb Callback called with (err)
1628
+ */
1629
+ DataAccessObject.removeById = DataAccessObject.destroyById = DataAccessObject.deleteById = function deleteById(id, options, cb) {
1630
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1631
+ if (connectionPromise) return connectionPromise;
1632
+ assert(arguments.length >= 1, "The id argument is required");
1633
+ if (cb === void 0) {
1634
+ if (typeof options === "function") {
1635
+ cb = options;
1636
+ options = {};
1637
+ }
1638
+ }
1639
+ options = options || {};
1640
+ cb = cb || utils.createPromiseCallback();
1641
+ assert(typeof options === "object", "The options argument must be an object");
1642
+ assert(typeof cb === "function", "The cb argument must be a function");
1643
+ if (isPKMissing(this, cb)) return cb.promise;
1644
+ else if (id == null || id === "") {
1645
+ process.nextTick(function() {
1646
+ cb(new Error(g.f("{{Model::deleteById}} requires the {{id}} argument")));
1647
+ });
1648
+ return cb.promise;
1649
+ }
1650
+ const Model = this;
1651
+ this.remove(byIdQuery(this, id).where, options, function(err, info) {
1652
+ if (err) return cb(err);
1653
+ const deleted = info && info.count > 0;
1654
+ if (Model.settings.strictDelete && !deleted) {
1655
+ err = new Error(g.f("No instance with {{id}} %s found for %s", id, Model.modelName));
1656
+ err.code = "NOT_FOUND";
1657
+ err.statusCode = 404;
1658
+ return cb(err);
1659
+ }
1660
+ cb(null, info);
1661
+ });
1662
+ return cb.promise;
1663
+ };
1664
+ /**
1665
+ * Return count of matched records. Optional query parameter allows you to count filtered set of model instances.
1666
+ * Example:
1667
+ *
1668
+ *```js
1669
+ * User.count({approved: true}, function(err, count) {
1670
+ * console.log(count); // 2081
1671
+ * });
1672
+ * ```
1673
+ *
1674
+ * @param {Object} [where] Search conditions (optional)
1675
+ * @param {Object} [options] Options
1676
+ * @param {Function} cb Callback, called with (err, count)
1677
+ */
1678
+ DataAccessObject.count = function(where, options, cb) {
1679
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1680
+ if (connectionPromise) return connectionPromise;
1681
+ if (options === void 0 && cb === void 0) {
1682
+ if (typeof where === "function") {
1683
+ cb = where;
1684
+ where = {};
1685
+ }
1686
+ } else if (cb === void 0) {
1687
+ if (typeof options === "function") {
1688
+ cb = options;
1689
+ options = {};
1690
+ }
1691
+ }
1692
+ cb = cb || utils.createPromiseCallback();
1693
+ where = where || {};
1694
+ options = options || {};
1695
+ assert(typeof where === "object", "The where argument must be an object");
1696
+ assert(typeof options === "object", "The options argument must be an object");
1697
+ assert(typeof cb === "function", "The cb argument must be a function");
1698
+ const Model = this;
1699
+ const connector = Model.getConnector();
1700
+ assert(typeof connector.count === "function", "count() must be implemented by the connector");
1701
+ assert(connector.count.length >= 3, "count() must take at least 3 arguments");
1702
+ const hookState = {};
1703
+ const query = { where };
1704
+ this.applyScope(query);
1705
+ where = query.where;
1706
+ try {
1707
+ where = Model._sanitizeQuery(where, options);
1708
+ where = this._coerce(where, options);
1709
+ } catch (err) {
1710
+ process.nextTick(function() {
1711
+ cb(err);
1712
+ });
1713
+ return cb.promise;
1714
+ }
1715
+ const context = {
1716
+ Model,
1717
+ query: { where },
1718
+ hookState,
1719
+ options
1720
+ };
1721
+ this.notifyObserversOf("access", context, function(err, ctx) {
1722
+ if (err) return cb(err);
1723
+ invokeConnectorMethod(connector, "count", Model, [ctx.query.where], options, cb);
1724
+ });
1725
+ return cb.promise;
1726
+ };
1727
+ /**
1728
+ * Save instance. If the instance does not have an ID, call `create` instead.
1729
+ * Triggers: validate, save, update or create.
1730
+ * @options {Object} options Optional options to use.
1731
+ * @property {Boolean} validate Default is true.
1732
+ * @property {Boolean} throws Default is false.
1733
+ * @param {Function} cb Callback function with err and object arguments
1734
+ */
1735
+ DataAccessObject.prototype.save = function(options, cb) {
1736
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1737
+ if (connectionPromise) return connectionPromise;
1738
+ const Model = this.constructor;
1739
+ if (typeof options === "function") {
1740
+ cb = options;
1741
+ options = {};
1742
+ }
1743
+ cb = cb || utils.createPromiseCallback();
1744
+ options = options || {};
1745
+ assert(typeof options === "object", "The options argument should be an object");
1746
+ assert(typeof cb === "function", "The cb argument should be a function");
1747
+ if (isPKMissing(Model, cb)) return cb.promise;
1748
+ else if (this.isNewRecord()) return Model.create(this, options, cb);
1749
+ const hookState = {};
1750
+ if (options.validate === void 0) if (Model.settings.automaticValidation === void 0) options.validate = true;
1751
+ else options.validate = Model.settings.automaticValidation;
1752
+ if (options.throws === void 0) options.throws = false;
1753
+ const inst = this;
1754
+ const connector = inst.getConnector();
1755
+ let context = {
1756
+ Model,
1757
+ instance: inst,
1758
+ hookState,
1759
+ options
1760
+ };
1761
+ Model.notifyObserversOf("before save", context, function(err) {
1762
+ if (err) return cb(err);
1763
+ let data = inst.toObject(true);
1764
+ Model.applyProperties(data, inst);
1765
+ inst.setAttributes(data);
1766
+ if (!options.validate) return save();
1767
+ inst.isValid(function(valid) {
1768
+ if (valid) save();
1769
+ else {
1770
+ const err = new ValidationError(inst);
1771
+ if (options.throws) throw err;
1772
+ cb(err, inst);
1773
+ }
1774
+ }, data, options);
1775
+ function save() {
1776
+ inst.trigger("save", function(saveDone) {
1777
+ inst.trigger("update", function(updateDone) {
1778
+ data = Model._sanitizeData(data, options);
1779
+ function saveCallback(err, unusedData, result) {
1780
+ if (err) return cb(err, inst);
1781
+ const context = {
1782
+ Model,
1783
+ data,
1784
+ isNewInstance: result && result.isNewInstance,
1785
+ hookState,
1786
+ options
1787
+ };
1788
+ Model.notifyObserversOf("loaded", context, function(err, ctx) {
1789
+ if (err) return cb(err);
1790
+ data = ctx.data;
1791
+ inst._initProperties(data, { persisted: true });
1792
+ const context = {
1793
+ Model,
1794
+ instance: inst,
1795
+ isNewInstance: result && result.isNewInstance,
1796
+ hookState,
1797
+ options
1798
+ };
1799
+ Model.notifyObserversOf("after save", context, function(err) {
1800
+ if (err) return cb(err, inst);
1801
+ updateDone.call(inst, function() {
1802
+ saveDone.call(inst, function() {
1803
+ cb(err, inst);
1804
+ });
1805
+ });
1806
+ });
1807
+ });
1808
+ }
1809
+ context = {
1810
+ Model,
1811
+ data,
1812
+ where: byIdQuery(Model, getIdValue(Model, inst)).where,
1813
+ currentInstance: inst,
1814
+ hookState,
1815
+ options
1816
+ };
1817
+ Model.notifyObserversOf("persist", context, function(err, ctx) {
1818
+ if (err) return cb(err);
1819
+ data = ctx.data;
1820
+ invokeConnectorMethod(connector, "save", Model, [Model._forDB(data)], options, saveCallback);
1821
+ });
1822
+ }, data, cb);
1823
+ }, data, cb);
1824
+ }
1825
+ });
1826
+ return cb.promise;
1827
+ };
1828
+ /**
1829
+ * Update multiple instances that match the where clause
1830
+ *
1831
+ * Example:
1832
+ *
1833
+ *```js
1834
+ * Employee.update({managerId: 'x001'}, {managerId: 'x002'}, function(err) {
1835
+ * ...
1836
+ * });
1837
+ * ```
1838
+ *
1839
+ * @param {Object} [where] Search conditions (optional)
1840
+ * @param {Object} data Changes to be made
1841
+ * @param {Object} [options] Options for update
1842
+ * @param {Function} cb Callback, called with (err, info)
1843
+ */
1844
+ DataAccessObject.update = DataAccessObject.updateAll = function(where, data, options, cb) {
1845
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1846
+ if (connectionPromise) return connectionPromise;
1847
+ assert(arguments.length >= 1, "At least one argument is required");
1848
+ if (data === void 0 && options === void 0 && cb === void 0 && arguments.length === 1) {
1849
+ data = where;
1850
+ where = {};
1851
+ } else if (options === void 0 && cb === void 0) {
1852
+ if (typeof data === "function") {
1853
+ cb = data;
1854
+ data = where;
1855
+ where = {};
1856
+ }
1857
+ } else if (cb === void 0) {
1858
+ if (typeof options === "function") {
1859
+ cb = options;
1860
+ options = {};
1861
+ }
1862
+ }
1863
+ data = data || {};
1864
+ options = options || {};
1865
+ cb = cb || utils.createPromiseCallback();
1866
+ assert(typeof where === "object", "The where argument must be an object");
1867
+ assert(typeof data === "object", "The data argument must be an object");
1868
+ assert(typeof options === "object", "The options argument must be an object");
1869
+ assert(typeof cb === "function", "The cb argument must be a function");
1870
+ const Model = this;
1871
+ const connector = Model.getDataSource().connector;
1872
+ assert(typeof connector.update === "function", "update() must be implemented by the connector");
1873
+ const hookState = {};
1874
+ const query = { where };
1875
+ this.applyScope(query);
1876
+ this.applyProperties(data);
1877
+ let doValidate = false;
1878
+ if (options.validate === void 0) if (Model.settings.validateUpdate === void 0) {
1879
+ if (Model.settings.automaticValidation !== void 0) doValidate = Model.settings.automaticValidation;
1880
+ } else doValidate = Model.settings.validateUpdate;
1881
+ else doValidate = options.validate;
1882
+ where = query.where;
1883
+ const context = {
1884
+ Model,
1885
+ query: { where },
1886
+ hookState,
1887
+ options
1888
+ };
1889
+ Model.notifyObserversOf("access", context, function(err, ctx) {
1890
+ if (err) return cb(err);
1891
+ const context = {
1892
+ Model,
1893
+ where: ctx.query.where,
1894
+ data,
1895
+ hookState,
1896
+ options
1897
+ };
1898
+ Model.notifyObserversOf("before save", context, function(err, ctx) {
1899
+ if (err) return cb(err);
1900
+ data = ctx.data;
1901
+ let inst = data;
1902
+ if (!(data instanceof Model)) try {
1903
+ inst = new Model(data, { applyDefaultValues: false });
1904
+ } catch (err) {
1905
+ return cb(err);
1906
+ }
1907
+ if (doValidate === false) doUpdate(ctx.where, ctx.data);
1908
+ else inst.isValid(function(valid) {
1909
+ if (!valid) return cb(new ValidationError(inst));
1910
+ doUpdate(ctx.where, ctx.data);
1911
+ }, options);
1912
+ });
1913
+ });
1914
+ function doUpdate(where, data) {
1915
+ try {
1916
+ where = Model._sanitizeQuery(where, options);
1917
+ where = Model._coerce(where, options);
1918
+ data = Model._sanitizeData(data, options);
1919
+ data = Model._coerce(data, options);
1920
+ } catch (err) {
1921
+ return process.nextTick(function() {
1922
+ cb(err);
1923
+ });
1924
+ }
1925
+ function updateCallback(err, info) {
1926
+ if (err) return cb(err);
1927
+ const context = {
1928
+ Model,
1929
+ where,
1930
+ data,
1931
+ hookState,
1932
+ options,
1933
+ info
1934
+ };
1935
+ Model.notifyObserversOf("after save", context, function(err, _ctx) {
1936
+ return cb(err, info);
1937
+ });
1938
+ }
1939
+ const context = {
1940
+ Model,
1941
+ where,
1942
+ data,
1943
+ hookState,
1944
+ options
1945
+ };
1946
+ Model.notifyObserversOf("persist", context, function(err, ctx) {
1947
+ if (err) return cb(err);
1948
+ data = ctx.data;
1949
+ invokeConnectorMethod(connector, "update", Model, [where, Model._forDB(data)], options, updateCallback);
1950
+ });
1951
+ }
1952
+ return cb.promise;
1953
+ };
1954
+ DataAccessObject.prototype.isNewRecord = function() {
1955
+ return !this.__persisted;
1956
+ };
1957
+ /**
1958
+ * Return connector of current record
1959
+ * @private
1960
+ */
1961
+ DataAccessObject.prototype.getConnector = function() {
1962
+ return this.getDataSource().connector;
1963
+ };
1964
+ /**
1965
+ * Delete object from persistence
1966
+ *
1967
+ * Triggers `destroy` hook (async) before and after destroying object
1968
+ *
1969
+ * @param {Object} [options] Options for delete
1970
+ * @param {Function} cb Callback
1971
+ */
1972
+ DataAccessObject.prototype.remove = DataAccessObject.prototype.delete = DataAccessObject.prototype.destroy = function(options, cb) {
1973
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
1974
+ if (connectionPromise) return connectionPromise;
1975
+ if (cb === void 0 && typeof options === "function") {
1976
+ cb = options;
1977
+ options = {};
1978
+ }
1979
+ cb = cb || utils.createPromiseCallback();
1980
+ options = options || {};
1981
+ assert(typeof options === "object", "The options argument should be an object");
1982
+ assert(typeof cb === "function", "The cb argument should be a function");
1983
+ const inst = this;
1984
+ const connector = this.getConnector();
1985
+ const Model = this.constructor;
1986
+ const id = getIdValue(this.constructor, this);
1987
+ const hookState = {};
1988
+ if (isPKMissing(Model, cb)) return cb.promise;
1989
+ const context = {
1990
+ Model,
1991
+ query: byIdQuery(Model, id),
1992
+ hookState,
1993
+ options
1994
+ };
1995
+ Model.notifyObserversOf("access", context, function(err, ctx) {
1996
+ if (err) return cb(err);
1997
+ const context = {
1998
+ Model,
1999
+ where: ctx.query.where,
2000
+ instance: inst,
2001
+ hookState,
2002
+ options
2003
+ };
2004
+ Model.notifyObserversOf("before delete", context, function(err, ctx) {
2005
+ if (err) return cb(err);
2006
+ doDeleteInstance(ctx.where);
2007
+ });
2008
+ });
2009
+ function doDeleteInstance(where) {
2010
+ if (!isWhereByGivenId(Model, where, id)) {
2011
+ Model.deleteAll(where, { notify: false }, function(err, info) {
2012
+ if (err) return cb(err, false);
2013
+ const deleted = info && info.count > 0;
2014
+ if (Model.settings.strictDelete && !deleted) {
2015
+ err = new Error(g.f("No instance with {{id}} %s found for %s", id, Model.modelName));
2016
+ err.code = "NOT_FOUND";
2017
+ err.statusCode = 404;
2018
+ return cb(err, false);
2019
+ }
2020
+ const context = {
2021
+ Model,
2022
+ where,
2023
+ instance: inst,
2024
+ hookState,
2025
+ options,
2026
+ info
2027
+ };
2028
+ Model.notifyObserversOf("after delete", context, function(err) {
2029
+ cb(err, info);
2030
+ });
2031
+ });
2032
+ return;
2033
+ }
2034
+ inst.trigger("destroy", function(destroyed) {
2035
+ function destroyCallback(err, info) {
2036
+ if (err) return cb(err);
2037
+ const deleted = info && info.count > 0;
2038
+ if (Model.settings.strictDelete && !deleted) {
2039
+ err = new Error(g.f("No instance with {{id}} %s found for %s", id, Model.modelName));
2040
+ err.code = "NOT_FOUND";
2041
+ err.statusCode = 404;
2042
+ return cb(err);
2043
+ }
2044
+ destroyed(function() {
2045
+ const context = {
2046
+ Model,
2047
+ where,
2048
+ instance: inst,
2049
+ hookState,
2050
+ options,
2051
+ info
2052
+ };
2053
+ Model.notifyObserversOf("after delete", context, function(err) {
2054
+ cb(err, info);
2055
+ });
2056
+ });
2057
+ }
2058
+ invokeConnectorMethod(connector, "destroy", Model, [id], options, destroyCallback);
2059
+ }, null, cb);
2060
+ }
2061
+ return cb.promise;
2062
+ };
2063
+ /**
2064
+ * Set a single attribute.
2065
+ * Equivalent to `setAttributes({name: value})`
2066
+ *
2067
+ * @param {String} name Name of property
2068
+ * @param {Mixed} value Value of property
2069
+ */
2070
+ DataAccessObject.prototype.setAttribute = function setAttribute(name, value) {
2071
+ this[name] = value;
2072
+ };
2073
+ /**
2074
+ * Update a single attribute.
2075
+ * Equivalent to `updateAttributes({name: value}, cb)`
2076
+ *
2077
+ * @param {String} name Name of property
2078
+ * @param {Mixed} value Value of property
2079
+ * @param {Function} cb Callback function called with (err, instance)
2080
+ */
2081
+ DataAccessObject.prototype.updateAttribute = function updateAttribute(name, value, options, cb) {
2082
+ const data = {};
2083
+ data[name] = value;
2084
+ return this.updateAttributes(data, options, cb);
2085
+ };
2086
+ /**
2087
+ * Update set of attributes.
2088
+ *
2089
+ * @trigger `change` hook
2090
+ * @param {Object} data Data to update
2091
+ */
2092
+ DataAccessObject.prototype.setAttributes = function setAttributes(data) {
2093
+ if (typeof data !== "object") return;
2094
+ this.constructor.applyProperties(data, this);
2095
+ const Model = this.constructor;
2096
+ const inst = this;
2097
+ for (const key in data) inst.setAttribute(key, data[key]);
2098
+ Model.emit("set", inst);
2099
+ };
2100
+ DataAccessObject.prototype.unsetAttribute = function unsetAttribute(name, nullify) {
2101
+ if (nullify || this.constructor.definition.settings.persistUndefinedAsNull) this[name] = this.__data[name] = null;
2102
+ else {
2103
+ delete this[name];
2104
+ delete this.__data[name];
2105
+ }
2106
+ };
2107
+ /**
2108
+ * Replace set of attributes.
2109
+ * Performs validation before replacing.
2110
+ *
2111
+ * @trigger `validation`, `save` and `update` hooks
2112
+ * @param {Object} data Data to replace
2113
+ * @param {Object} [options] Options for replace
2114
+ * @param {Function} cb Callback function called with (err, instance)
2115
+ */
2116
+ DataAccessObject.prototype.replaceAttributes = function(data, options, cb) {
2117
+ const Model = this.constructor;
2118
+ const id = getIdValue(this.constructor, this);
2119
+ return Model.replaceById(id, data, options, cb);
2120
+ };
2121
+ DataAccessObject.replaceById = function(id, data, options, cb) {
2122
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
2123
+ if (connectionPromise) return connectionPromise;
2124
+ if (cb === void 0) {
2125
+ if (typeof options === "function") {
2126
+ cb = options;
2127
+ options = {};
2128
+ }
2129
+ }
2130
+ cb = cb || utils.createPromiseCallback();
2131
+ options = options || {};
2132
+ assert(typeof data === "object" && data !== null, "The data argument must be an object");
2133
+ assert(typeof options === "object", "The options argument must be an object");
2134
+ assert(typeof cb === "function", "The cb argument must be a function");
2135
+ const connector = this.getConnector();
2136
+ let err;
2137
+ if (typeof connector.replaceById !== "function") {
2138
+ err = new Error(g.f("The connector %s does not support {{replaceById}} operation. This is not a bug in LoopBack. Please contact the authors of the connector, preferably via GitHub issues.", connector.name));
2139
+ return cb(err);
2140
+ }
2141
+ const pkName = idName(this);
2142
+ if (!data[pkName]) data[pkName] = id;
2143
+ let Model = this;
2144
+ let inst;
2145
+ try {
2146
+ inst = new Model(data, { persisted: true });
2147
+ const enforced = {};
2148
+ this.applyProperties(enforced, inst);
2149
+ inst.setAttributes(enforced);
2150
+ } catch (err) {
2151
+ process.nextTick(function() {
2152
+ cb(err);
2153
+ });
2154
+ return cb.promise;
2155
+ }
2156
+ Model = this.lookupModel(data);
2157
+ if (Model !== inst.constructor) inst = new Model(data);
2158
+ const strict = inst.__strict;
2159
+ if (isPKMissing(Model, cb)) return cb.promise;
2160
+ const hookState = {};
2161
+ if (id !== data[pkName]) {
2162
+ err = new Error(g.f("{{id}} property (%s) cannot be updated from %s to %s", pkName, id, data[pkName]));
2163
+ err.statusCode = 400;
2164
+ process.nextTick(function() {
2165
+ cb(err);
2166
+ });
2167
+ return cb.promise;
2168
+ } else id = inst[pkName];
2169
+ let context = {
2170
+ Model,
2171
+ instance: inst,
2172
+ isNewInstance: false,
2173
+ hookState,
2174
+ options
2175
+ };
2176
+ Model.notifyObserversOf("before save", context, function(err, ctx) {
2177
+ if (err) return cb(err);
2178
+ if (ctx.instance[pkName] !== id && !Model._warned.cannotOverwritePKInBeforeSaveHook) {
2179
+ Model._warned.cannotOverwritePKInBeforeSaveHook = true;
2180
+ g.warn("WARNING: {{id}} property cannot be changed from %s to %s for model:%s in {{'before save'}} operation hook", id, inst[pkName], Model.modelName);
2181
+ }
2182
+ data = inst.toObject(false);
2183
+ if (strict) applyStrictCheck(Model, strict, data, inst, validateAndCallConnector);
2184
+ else validateAndCallConnector(null, data);
2185
+ function validateAndCallConnector(err, data) {
2186
+ if (err) return cb(err);
2187
+ data = Model._sanitizeData(data, options);
2188
+ inst.setAttributes(data);
2189
+ let doValidate = true;
2190
+ if (options.validate === void 0) {
2191
+ if (Model.settings.automaticValidation !== void 0) doValidate = Model.settings.automaticValidation;
2192
+ } else doValidate = options.validate;
2193
+ if (doValidate) inst.isValid(function(valid) {
2194
+ if (!valid) return cb(new ValidationError(inst), inst);
2195
+ callConnector();
2196
+ }, data, options);
2197
+ else callConnector();
2198
+ function callConnector() {
2199
+ copyData(data, inst);
2200
+ const typedData = convertSubsetOfPropertiesByType(inst, data);
2201
+ context.data = typedData;
2202
+ function replaceCallback(err, dbResponse) {
2203
+ if (err) return cb(err);
2204
+ if (typeof connector.generateContextData === "function") context = connector.generateContextData(context, dbResponse);
2205
+ const ctx = {
2206
+ Model,
2207
+ hookState,
2208
+ data: context.data,
2209
+ isNewInstance: false,
2210
+ options
2211
+ };
2212
+ Model.notifyObserversOf("loaded", ctx, function(err) {
2213
+ if (err) return cb(err);
2214
+ if (ctx.data[pkName] !== id && !Model._warned.cannotOverwritePKInLoadedHook) {
2215
+ Model._warned.cannotOverwritePKInLoadedHook = true;
2216
+ g.warn("WARNING: {{id}} property cannot be changed from %s to %s for model:%s in {{'loaded'}} operation hook", id, ctx.data[pkName], Model.modelName);
2217
+ }
2218
+ inst.__persisted = true;
2219
+ ctx.data[pkName] = id;
2220
+ inst.setAttributes(ctx.data);
2221
+ const context = {
2222
+ Model,
2223
+ instance: inst,
2224
+ isNewInstance: false,
2225
+ hookState,
2226
+ options
2227
+ };
2228
+ Model.notifyObserversOf("after save", context, function(err) {
2229
+ cb(err, inst);
2230
+ });
2231
+ });
2232
+ }
2233
+ const ctx = {
2234
+ Model,
2235
+ where: byIdQuery(Model, id).where,
2236
+ data: context.data,
2237
+ isNewInstance: false,
2238
+ currentInstance: inst,
2239
+ hookState,
2240
+ options
2241
+ };
2242
+ Model.notifyObserversOf("persist", ctx, function(err) {
2243
+ if (err) return cb(err);
2244
+ context.data = ctx.data;
2245
+ invokeConnectorMethod(connector, "replaceById", Model, [id, Model._forDB(ctx.data)], options, replaceCallback);
2246
+ });
2247
+ }
2248
+ }
2249
+ });
2250
+ return cb.promise;
2251
+ };
2252
+ /**
2253
+ * Update set of attributes.
2254
+ * Performs validation before updating.
2255
+ * NOTE: `patchOrCreate` is an alias.
2256
+ *
2257
+ * @trigger `validation`, `save` and `update` hooks
2258
+ * @param {Object} data Data to update
2259
+ * @param {Object} [options] Options for updateAttributes
2260
+ * @param {Function} cb Callback function called with (err, instance)
2261
+ */
2262
+ DataAccessObject.prototype.updateAttributes = DataAccessObject.prototype.patchAttributes = function(data, options, cb) {
2263
+ const self = this;
2264
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
2265
+ if (connectionPromise) return connectionPromise;
2266
+ if (options === void 0 && cb === void 0) {
2267
+ if (typeof data === "function") {
2268
+ cb = data;
2269
+ data = void 0;
2270
+ }
2271
+ } else if (cb === void 0) {
2272
+ if (typeof options === "function") {
2273
+ cb = options;
2274
+ options = {};
2275
+ }
2276
+ }
2277
+ cb = cb || utils.createPromiseCallback();
2278
+ options = options || {};
2279
+ assert(typeof data === "object" && data !== null, "The data argument must be an object");
2280
+ assert(typeof options === "object", "The options argument must be an object");
2281
+ assert(typeof cb === "function", "The cb argument must be a function");
2282
+ const inst = this;
2283
+ const Model = this.constructor;
2284
+ const connector = inst.getConnector();
2285
+ assert(typeof connector.updateAttributes === "function", "updateAttributes() must be implemented by the connector");
2286
+ if (isPKMissing(Model, cb)) return cb.promise;
2287
+ const allowExtendedOperators = Model._allowExtendedOperators(options);
2288
+ const strict = this.__strict;
2289
+ const hookState = {};
2290
+ if (data instanceof Model) data = data.toObject(false);
2291
+ data = Model._sanitizeData(data, options);
2292
+ const idNames = Model.definition.idNames();
2293
+ for (let i = 0, n = idNames.length; i < n; i++) {
2294
+ const idName = idNames[i];
2295
+ if (data[idName] !== void 0 && !idEquals(data[idName], inst[idName])) {
2296
+ const err = new Error(g.f("{{id}} cannot be updated from %s to %s when {{forceId}} is set to true", inst[idName], data[idName]));
2297
+ err.statusCode = 400;
2298
+ process.nextTick(function() {
2299
+ cb(err);
2300
+ });
2301
+ return cb.promise;
2302
+ }
2303
+ }
2304
+ let context = {
2305
+ Model,
2306
+ where: byIdQuery(Model, getIdValue(Model, inst)).where,
2307
+ data,
2308
+ currentInstance: inst,
2309
+ hookState,
2310
+ options
2311
+ };
2312
+ Model.notifyObserversOf("before save", context, function(err, ctx) {
2313
+ if (err) return cb(err);
2314
+ data = ctx.data;
2315
+ if (strict && !allowExtendedOperators) applyStrictCheck(self.constructor, strict, data, inst, validateAndSave);
2316
+ else validateAndSave(null, data);
2317
+ function validateAndSave(err, data) {
2318
+ if (err) return cb(err);
2319
+ let doValidate = true;
2320
+ if (options.validate === void 0) {
2321
+ if (Model.settings.automaticValidation !== void 0) doValidate = Model.settings.automaticValidation;
2322
+ } else doValidate = options.validate;
2323
+ try {
2324
+ inst.setAttributes(data);
2325
+ } catch (err) {
2326
+ return cb(err);
2327
+ }
2328
+ if (doValidate) inst.isValid(function(valid) {
2329
+ if (!valid) {
2330
+ cb(new ValidationError(inst), inst);
2331
+ return;
2332
+ }
2333
+ triggerSave();
2334
+ }, data, options);
2335
+ else triggerSave();
2336
+ function triggerSave() {
2337
+ inst.trigger("save", function(saveDone) {
2338
+ inst.trigger("update", function(done) {
2339
+ copyData(data, inst);
2340
+ const typedData = convertSubsetOfPropertiesByType(inst, data);
2341
+ context.data = Model._sanitizeData(typedData, options);
2342
+ function updateAttributesCallback(err, dbResponse) {
2343
+ if (err) return cb(err);
2344
+ if (typeof connector.generateContextData === "function") context = connector.generateContextData(context, dbResponse);
2345
+ const ctx = {
2346
+ Model,
2347
+ data: context.data,
2348
+ hookState,
2349
+ options,
2350
+ isNewInstance: false
2351
+ };
2352
+ Model.notifyObserversOf("loaded", ctx, function(err) {
2353
+ if (err) return cb(err);
2354
+ inst.__persisted = true;
2355
+ if (Model.settings.updateOnLoad) inst.setAttributes(ctx.data);
2356
+ done.call(inst, function() {
2357
+ saveDone.call(inst, function() {
2358
+ if (err) return cb(err, inst);
2359
+ const context = {
2360
+ Model,
2361
+ instance: inst,
2362
+ isNewInstance: false,
2363
+ hookState,
2364
+ options
2365
+ };
2366
+ Model.notifyObserversOf("after save", context, function(err) {
2367
+ cb(err, inst);
2368
+ });
2369
+ });
2370
+ });
2371
+ });
2372
+ }
2373
+ const ctx = {
2374
+ Model,
2375
+ where: byIdQuery(Model, getIdValue(Model, inst)).where,
2376
+ data: context.data,
2377
+ currentInstance: inst,
2378
+ isNewInstance: false,
2379
+ hookState,
2380
+ options
2381
+ };
2382
+ Model.notifyObserversOf("persist", ctx, function(err) {
2383
+ if (err) return cb(err);
2384
+ context.data = ctx.data;
2385
+ invokeConnectorMethod(connector, "updateAttributes", Model, [getIdValue(Model, inst), Model._forDB(ctx.data)], options, updateAttributesCallback);
2386
+ });
2387
+ }, data, cb);
2388
+ }, data, cb);
2389
+ }
2390
+ }
2391
+ });
2392
+ return cb.promise;
2393
+ };
2394
+ /**
2395
+ * Reload object from persistence
2396
+ * Requires `id` member of `object` to be able to call `find`
2397
+ * @param {Function} cb Called with (err, instance) arguments
2398
+ * @private
2399
+ */
2400
+ DataAccessObject.prototype.reload = function reload(cb) {
2401
+ const connectionPromise = stillConnecting(this.getDataSource(), this, arguments);
2402
+ if (connectionPromise) return connectionPromise;
2403
+ return this.constructor.findById(getIdValue(this.constructor, this), cb);
2404
+ };
2405
+ function defineReadonlyProp(obj, key, value) {
2406
+ Object.defineProperty(obj, key, {
2407
+ writable: false,
2408
+ enumerable: true,
2409
+ configurable: true,
2410
+ value
2411
+ });
2412
+ }
2413
+ const defineScope = require_lib_scope.defineScope;
2414
+ /**
2415
+ * Define a scope for the model class. Scopes enable you to specify commonly-used
2416
+ * queries that you can reference as method calls on a model.
2417
+ *
2418
+ * @param {String} name The scope name
2419
+ * @param {Object} query The query object for DataAccessObject.find()
2420
+ * @param {ModelClass} [targetClass] The model class for the query, default to
2421
+ * the declaring model
2422
+ */
2423
+ DataAccessObject.scope = function(name, query, targetClass, methods, options) {
2424
+ let cls = this;
2425
+ if (options && options.isStatic === false) cls = cls.prototype;
2426
+ return defineScope(cls, targetClass || cls, name, query, methods, options);
2427
+ };
2428
+ jutil.mixin(DataAccessObject, Inclusion);
2429
+ jutil.mixin(DataAccessObject, Relation);
2430
+ jutil.mixin(DataAccessObject, require_lib_transaction);
2431
+ function PKMissingError(modelName) {
2432
+ this.name = "PKMissingError";
2433
+ this.message = "Primary key is missing for the " + modelName + " model";
2434
+ }
2435
+ PKMissingError.prototype = /* @__PURE__ */ new Error();
2436
+ function isPKMissing(modelClass, cb) {
2437
+ if (modelClass.definition.hasPK()) return false;
2438
+ process.nextTick(function() {
2439
+ cb(new PKMissingError(modelClass.modelName));
2440
+ });
2441
+ return true;
2442
+ }
2443
+ }));
2444
+ //#endregion
2445
+ module.exports = require_dao();