@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,742 @@
1
+ "use strict";
2
+ const require_runtime = require("../_virtual/_rolldown/runtime.js");
3
+ const require_lib_globalize = require("./globalize.js");
4
+ //#region src/lib/validations.ts
5
+ var require_validations = /* @__PURE__ */ require_runtime.__commonJSMin(((exports) => {
6
+ const g = require_lib_globalize();
7
+ const util = require("util");
8
+ /*!
9
+ * Module exports
10
+ */
11
+ exports.ValidationError = ValidationError;
12
+ exports.Validatable = Validatable;
13
+ /**
14
+ * This class provides methods that add validation cababilities to models.
15
+ * Each of the validations runs when the `obj.isValid()` method is called.
16
+ *
17
+ * All of the methods have an options object parameter that has a
18
+ * `message` property. When there is only a single error message, this property is just a string;
19
+ * for example: `Post.validatesPresenceOf('title', { message: 'can not be blank' });`
20
+ *
21
+ * In more complicated cases it can be a set of messages, for each possible error condition; for example:
22
+ * `User.validatesLengthOf('password', { min: 6, max: 20, message: {min: 'too short', max: 'too long'}});`
23
+ * @class Validatable
24
+ */
25
+ function Validatable() {}
26
+ /**
27
+ * Validate presence of one or more specified properties.
28
+ *
29
+ * Requires a model to include a property to be considered valid; fails when validated field is blank.
30
+ *
31
+ * For example, validate presence of title
32
+ * ```
33
+ * Post.validatesPresenceOf('title');
34
+ * ```
35
+ * Validate that model has first, last, and age properties:
36
+ * ```
37
+ * User.validatesPresenceOf('first', 'last', 'age');
38
+ * ```
39
+ * Example with custom message
40
+ * ```
41
+ * Post.validatesPresenceOf('title', {message: 'Cannot be blank'});
42
+ * ```
43
+ *
44
+ * @param {String} propertyName One or more property names.
45
+ * @options {Object} options Configuration parameters; see below.
46
+ * @property {String} message Error message to use instead of default.
47
+ * @property {String} if Validate only if `if` exists.
48
+ * @property {String} unless Validate only if `unless` exists.
49
+ */
50
+ Validatable.validatesPresenceOf = getConfigurator("presence");
51
+ /**
52
+ * Validate absence of one or more specified properties.
53
+ *
54
+ * A model should not include a property to be considered valid; fails when validated field is not blank.
55
+ *
56
+ * For example, validate absence of reserved
57
+ * ```
58
+ * Post.validatesAbsenceOf('reserved', { unless: 'special' });
59
+ * ```
60
+ *
61
+ * @param {String} propertyName One or more property names.
62
+ * @options {Object} options Configuration parameters; see below.
63
+ * @property {String} message Error message to use instead of default.
64
+ * @property {String} if Validate only if `if` exists.
65
+ * @property {String} unless Validate only if `unless` exists.
66
+ */
67
+ Validatable.validatesAbsenceOf = getConfigurator("absence");
68
+ /**
69
+ * Validate length.
70
+ *
71
+ * Require a property length to be within a specified range.
72
+ *
73
+ * There are three kinds of validations: min, max, is.
74
+ *
75
+ * Default error messages:
76
+ *
77
+ * - min: too short
78
+ * - max: too long
79
+ * - is: length is wrong
80
+ *
81
+ * Example: length validations
82
+ * ```
83
+ * User.validatesLengthOf('password', {min: 7});
84
+ * User.validatesLengthOf('email', {max: 100});
85
+ * User.validatesLengthOf('state', {is: 2});
86
+ * User.validatesLengthOf('nick', {min: 3, max: 15});
87
+ * ```
88
+ * Example: length validations with custom error messages
89
+ * ```
90
+ * User.validatesLengthOf('password', {min: 7, message: {min: 'too weak'}});
91
+ * User.validatesLengthOf('state', {is: 2, message: {is: 'is not valid state name'}});
92
+ * ```
93
+ *
94
+ * @param {String} propertyName Property name to validate.
95
+ * @options {Object} options Configuration parameters; see below.
96
+ * @property {Number} is Value that property must equal to validate.
97
+ * @property {Number} min Value that property must be less than to be valid.
98
+ * @property {Number} max Value that property must be less than to be valid.
99
+ * @property {Object} message Optional object with string properties for custom error message for each validation: is, min, or max.
100
+ */
101
+ Validatable.validatesLengthOf = getConfigurator("length");
102
+ /**
103
+ * Validate numericality.
104
+ *
105
+ * Requires a value for property to be either an integer or number.
106
+ *
107
+ * Example
108
+ * ```
109
+ * User.validatesNumericalityOf('age', { message: { number: 'is not a number' }});
110
+ * User.validatesNumericalityOf('age', {int: true, message: { int: 'is not an integer' }});
111
+ * ```
112
+ *
113
+ * @param {String} propertyName Property name to validate.
114
+ * @options {Object} options Configuration parameters; see below.
115
+ * @property {Boolean} int If true, then property must be an integer to be valid.
116
+ * @property {Boolean} allowBlank Allow property to be blank.
117
+ * @property {Boolean} allowNull Allow property to be null.
118
+ * @property {Object} message Optional object with string properties for 'int' for integer validation. Default error messages:
119
+ * - number: is not a number
120
+ * - int: is not an integer
121
+ */
122
+ Validatable.validatesNumericalityOf = getConfigurator("numericality");
123
+ /**
124
+ * Validate inclusion in set.
125
+ *
126
+ * Require a value for property to be in the specified array.
127
+ *
128
+ * Example:
129
+ * ```
130
+ * User.validatesInclusionOf('gender', {in: ['male', 'female']});
131
+ * User.validatesInclusionOf('role', {
132
+ * in: ['admin', 'moderator', 'user'], message: 'is not allowed'
133
+ * });
134
+ * ```
135
+ *
136
+ * @param {String} propertyName Property name to validate.
137
+ * @options {Object} options Configuration parameters; see below.
138
+ * @property {Array} in Property must match one of the values in the array to be valid.
139
+ * @property {String} message Optional error message if property is not valid.
140
+ * Default error message: "is not included in the list".
141
+ * @property {Boolean} allowNull Whether null values are allowed.
142
+ */
143
+ Validatable.validatesInclusionOf = getConfigurator("inclusion");
144
+ /**
145
+ * Validate exclusion in a set.
146
+ *
147
+ * Require a property value not be in the specified array.
148
+ *
149
+ * Example: `Company.validatesExclusionOf('domain', {in: ['www', 'admin']});`
150
+ *
151
+ * @param {String} propertyName Property name to validate.
152
+ * @options {Object} options Configuration parameters; see below.
153
+ * @property {Array} in Property must not match any of the values in the array to be valid.
154
+ * @property {String} message Optional error message if property is not valid. Default error message: "is reserved".
155
+ * @property {Boolean} allowNull Whether null values are allowed.
156
+ */
157
+ Validatable.validatesExclusionOf = getConfigurator("exclusion");
158
+ /**
159
+ * Validate format.
160
+ *
161
+ * Require a model to include a property that matches the given format.
162
+ *
163
+ * Example: `User.validatesFormatOf('name', {with: /\w+/});`
164
+ *
165
+ * @param {String} propertyName Property name to validate.
166
+ * @options {Object} options Configuration parameters; see below.
167
+ * @property {RegExp} with Regular expression to validate format.
168
+ * @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
169
+ * @property {Boolean} allowNull Whether null values are allowed.
170
+ */
171
+ Validatable.validatesFormatOf = getConfigurator("format");
172
+ /**
173
+ * Validate using custom validation function.
174
+ *
175
+ * Example:
176
+ *```javascript
177
+ * User.validate('name', customValidator, {message: 'Bad name'});
178
+ * function customValidator(err) {
179
+ * if (this.name === 'bad') err();
180
+ * });
181
+ * var user = new User({name: 'Peter'});
182
+ * user.isValid(); // true
183
+ * user.name = 'bad';
184
+ * user.isValid(); // false
185
+ * ```
186
+ *
187
+ * @param {String} propertyName Property name to validate.
188
+ * @param {Function} validatorFn Custom validation function.
189
+ * @options {Object} options Configuration parameters; see below.
190
+ * @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
191
+ * @property {Boolean} allowNull Whether null values are allowed.
192
+ */
193
+ Validatable.validate = getConfigurator("custom");
194
+ /**
195
+ * Validate using custom asynchronous validation function.
196
+ *
197
+ * Example:
198
+ *```js
199
+ * User.validateAsync('name', customValidator, {message: 'Bad name'});
200
+ * function customValidator(err, done) {
201
+ * process.nextTick(function () {
202
+ * if (this.name === 'bad') err();
203
+ * done();
204
+ * });
205
+ * });
206
+ * var user = new User({name: 'Peter'});
207
+ * user.isValid(); // false (because async validation setup)
208
+ * user.isValid(function (isValid) {
209
+ * isValid; // true
210
+ * })
211
+ * user.name = 'bad';
212
+ * user.isValid(); // false
213
+ * user.isValid(function (isValid) {
214
+ * isValid; // false
215
+ * })
216
+ * ```
217
+ *
218
+ * @param {String} propertyName Property name to validate.
219
+ * @param {Function} validatorFn Custom validation function.
220
+ * @options {Object} options Configuration parameters; see below.
221
+ * @property {String} message Optional error message if property is not valid. Default error message: " is invalid".
222
+ * @property {Boolean} allowNull Whether null values are allowed.
223
+ */
224
+ Validatable.validateAsync = getConfigurator("custom", { async: true });
225
+ /**
226
+ * Validate uniqueness of the value for a property in the collection of models.
227
+ *
228
+ * Not available for all connectors. Currently supported with these connectors:
229
+ * - In Memory
230
+ * - Oracle
231
+ * - MongoDB
232
+ *
233
+ * ```
234
+ * // The login must be unique across all User instances.
235
+ * User.validatesUniquenessOf('login');
236
+ *
237
+ * // Assuming SiteUser.belongsTo(Site)
238
+ * // The login must be unique within each Site.
239
+ * SiteUser.validateUniquenessOf('login', { scopedTo: ['siteId'] });
240
+ * ```
241
+ *
242
+ * @param {String} propertyName Property name to validate.
243
+ * @options {Object} options Configuration parameters; see below.
244
+ * @property {RegExp} with Regular expression to validate format.
245
+ * @property {Array.<String>} scopedTo List of properties defining the scope.
246
+ * @property {String} message Optional error message if property is not valid. Default error message: "is not unique".
247
+ * @property {Boolean} allowNull Whether null values are allowed.
248
+ * @property {String} ignoreCase Make the validation case insensitive.
249
+ * @property {String} if Validate only if `if` exists.
250
+ * @property {String} unless Validate only if `unless` exists.
251
+ */
252
+ Validatable.validatesUniquenessOf = getConfigurator("uniqueness", { async: true });
253
+ /**
254
+ * Validate if a value for a property is a Date.
255
+ *
256
+ * Example
257
+ * ```
258
+ * User.validatesDateOf('today', {message: 'today is not a date!'});
259
+ * ```
260
+ *
261
+ * @param {String} propertyName Property name to validate.
262
+ * @options {Object} options Configuration parameters; see below.
263
+ * @property {String} message Error message to use instead of default.
264
+ */
265
+ Validatable.validatesDateOf = getConfigurator("date");
266
+ /*!
267
+ * Presence validator
268
+ */
269
+ function validatePresence(attr, conf, err, _options) {
270
+ if (blank(this[attr])) err();
271
+ }
272
+ /*!
273
+ * Absence validator
274
+ */
275
+ function validateAbsence(attr, conf, err, _options) {
276
+ if (!blank(this[attr])) err();
277
+ }
278
+ /*!
279
+ * Length validator
280
+ */
281
+ function validateLength(attr, conf, err, _options) {
282
+ if (nullCheck.call(this, attr, conf, err)) return;
283
+ const len = this[attr].length;
284
+ if (conf.min && len < conf.min) err("min");
285
+ if (conf.max && len > conf.max) err("max");
286
+ if (conf.is && len !== conf.is) err("is");
287
+ }
288
+ /*!
289
+ * Numericality validator
290
+ */
291
+ function validateNumericality(attr, conf, err, _options) {
292
+ if (nullCheck.call(this, attr, conf, err)) return;
293
+ if (typeof this[attr] !== "number" || isNaN(this[attr])) return err("number");
294
+ if (conf.int && this[attr] !== Math.round(this[attr])) return err("int");
295
+ }
296
+ /*!
297
+ * Inclusion validator
298
+ */
299
+ function validateInclusion(attr, conf, err, _options) {
300
+ if (nullCheck.call(this, attr, conf, err)) return;
301
+ if (!~conf.in.indexOf(this[attr])) err();
302
+ }
303
+ /*!
304
+ * Exclusion validator
305
+ */
306
+ function validateExclusion(attr, conf, err, _options) {
307
+ if (nullCheck.call(this, attr, conf, err)) return;
308
+ if (~conf.in.indexOf(this[attr])) err();
309
+ }
310
+ /*!
311
+ * Format validator
312
+ */
313
+ function validateFormat(attr, conf, err, _options) {
314
+ if (nullCheck.call(this, attr, conf, err)) return;
315
+ if (typeof this[attr] === "string" || typeof this[attr] === "number") {
316
+ if (!new RegExp(conf["with"]).test(this[attr])) err();
317
+ } else err();
318
+ }
319
+ /*!
320
+ * Custom validator
321
+ */
322
+ function validateCustom(attr, conf, err, options, done) {
323
+ if (typeof options === "function") {
324
+ done = options;
325
+ options = {};
326
+ }
327
+ if (!done) conf.customValidator.call(this, err, options);
328
+ else if (conf.customValidator.length === 3) conf.customValidator.call(this, err, options, done);
329
+ else conf.customValidator.call(this, err, done);
330
+ }
331
+ function escapeStringRegexp(str) {
332
+ if (typeof str !== "string") throw new TypeError("Expected a string");
333
+ return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
334
+ }
335
+ /*!
336
+ * Uniqueness validator
337
+ */
338
+ function validateUniqueness(attr, conf, err, options, done) {
339
+ if (typeof options === "function") {
340
+ done = options;
341
+ options = {};
342
+ }
343
+ if (blank(this[attr])) return process.nextTick(done);
344
+ const cond = { where: {} };
345
+ if (conf && conf.ignoreCase) cond.where[attr] = new RegExp("^" + escapeStringRegexp(this[attr]) + "$", "i");
346
+ else cond.where[attr] = this[attr];
347
+ if (conf && conf.scopedTo) conf.scopedTo.forEach(function(k) {
348
+ if (this[k] !== void 0) cond.where[k] = this[k];
349
+ }, this);
350
+ const idName = this.constructor.definition.idName();
351
+ const isNewRecord = this.isNewRecord();
352
+ this.constructor.find(cond, options, function(error, found) {
353
+ if (error) err(error);
354
+ else if (found.length > 1) err();
355
+ else if (found.length === 1 && idName === attr && isNewRecord) err();
356
+ else if (found.length === 1 && (!this.id || !found[0].id || found[0].id.toString() != this.id.toString())) err();
357
+ done();
358
+ }.bind(this));
359
+ }
360
+ /*!
361
+ * Date validator
362
+ */
363
+ function validateDate(attr, conf, err) {
364
+ if (this[attr] === null || this[attr] === void 0) return;
365
+ const date = new Date(this[attr]);
366
+ if (isNaN(date.getTime())) return err();
367
+ }
368
+ const validators = {
369
+ presence: validatePresence,
370
+ absence: validateAbsence,
371
+ length: validateLength,
372
+ numericality: validateNumericality,
373
+ inclusion: validateInclusion,
374
+ exclusion: validateExclusion,
375
+ format: validateFormat,
376
+ custom: validateCustom,
377
+ uniqueness: validateUniqueness,
378
+ date: validateDate
379
+ };
380
+ function getConfigurator(name, opts) {
381
+ return function() {
382
+ const args = Array.prototype.slice.call(arguments);
383
+ args[1] = args[1] || {};
384
+ configure(this, name, args, opts);
385
+ };
386
+ }
387
+ /**
388
+ * This method performs validation and triggers validation hooks.
389
+ * Before validation the `obj.errors` collection is cleaned.
390
+ * Each validation can add errors to `obj.errors` collection.
391
+ * If collection is not blank, validation failed.
392
+ *
393
+ * NOTE: This method can be called as synchronous only when no asynchronous validation is
394
+ * configured. It's strongly recommended to run all validations as asyncronous.
395
+ *
396
+ * Example: ExpressJS controller - render user if valid, show flash otherwise
397
+ * ```javascript
398
+ * user.isValid(function (valid) {
399
+ * if (valid) res.render({user: user});
400
+ * else res.flash('error', 'User is not valid'), console.log(user.errors), res.redirect('/users');
401
+ * });
402
+ * ```
403
+ * Another example:
404
+ * ```javascript
405
+ * user.isValid(function (valid) {
406
+ * if (!valid) {
407
+ * console.log(user.errors);
408
+ * // => hash of errors
409
+ * // => {
410
+ * // => username: [errmessage, errmessage, ...],
411
+ * // => email: ...
412
+ * // => }
413
+ * }
414
+ * });
415
+ * ```
416
+ * @callback {Function} callback Called with (valid).
417
+ * @param {Object} data Data to be validated.
418
+ * @param {Object} options Options to be specified upon validation.
419
+ * @returns {Boolean} True if no asynchronous validation is configured and all properties pass validation.
420
+ */
421
+ Validatable.prototype.isValid = function(callback, data, options) {
422
+ options = options || {};
423
+ let valid = true, wait = 0, async = false;
424
+ const inst = this;
425
+ const validations = this.constructor.validations;
426
+ const reportDiscardedProperties = this.__strict && this.__unknownProperties && this.__unknownProperties.length;
427
+ if (typeof validations !== "object" && !reportDiscardedProperties) {
428
+ cleanErrors(this);
429
+ if (callback) this.trigger("validate", function(validationsDone) {
430
+ validationsDone.call(inst, function() {
431
+ callback(valid);
432
+ });
433
+ }, data, callback);
434
+ return valid;
435
+ }
436
+ Object.defineProperty(this, "errors", {
437
+ enumerable: false,
438
+ configurable: true,
439
+ value: new Errors()
440
+ });
441
+ this.trigger("validate", function(validationsDone) {
442
+ const inst = this;
443
+ let asyncFail = false;
444
+ Object.keys(validations || {}).forEach(function(attr) {
445
+ (validations[attr] || []).forEach(function(v) {
446
+ if (v.options && v.options.async) {
447
+ async = true;
448
+ wait += 1;
449
+ process.nextTick(function() {
450
+ validationFailed(inst, attr, v, options, done);
451
+ });
452
+ } else if (validationFailed(inst, attr, v, options)) valid = false;
453
+ });
454
+ });
455
+ if (reportDiscardedProperties) for (const ix in inst.__unknownProperties) {
456
+ const key = inst.__unknownProperties[ix];
457
+ const code = "unknown-property";
458
+ const msg = defaultMessages[code];
459
+ inst.errors.add(key, msg, code);
460
+ valid = false;
461
+ }
462
+ if (!async) validationsDone.call(inst, function() {
463
+ if (valid) cleanErrors(inst);
464
+ if (callback) callback(valid);
465
+ });
466
+ function done(fail) {
467
+ asyncFail = asyncFail || fail;
468
+ if (--wait === 0) validationsDone.call(inst, function() {
469
+ if (valid && !asyncFail) cleanErrors(inst);
470
+ if (callback) callback(valid && !asyncFail);
471
+ });
472
+ }
473
+ }, data, callback);
474
+ if (async) return;
475
+ else return valid;
476
+ };
477
+ function cleanErrors(inst) {
478
+ Object.defineProperty(inst, "errors", {
479
+ enumerable: false,
480
+ configurable: true,
481
+ value: false
482
+ });
483
+ }
484
+ function validationFailed(inst, attr, conf, options, cb) {
485
+ conf.options;
486
+ if (typeof options === "function") {
487
+ cb = options;
488
+ options = {};
489
+ }
490
+ if (typeof attr !== "string") return false;
491
+ if (skipValidation(inst, conf, "if") || skipValidation(inst, conf, "unless")) {
492
+ if (cb) cb(false);
493
+ return false;
494
+ }
495
+ let fail = false;
496
+ const validator = validators[conf.validation];
497
+ const validatorArguments = [];
498
+ validatorArguments.push(attr);
499
+ validatorArguments.push(conf);
500
+ validatorArguments.push(function onerror(kind) {
501
+ let message, code = conf.code || conf.validation;
502
+ if (conf.message) message = conf.message;
503
+ if (!message && defaultMessages[conf.validation]) message = defaultMessages[conf.validation];
504
+ if (!message) message = "is invalid";
505
+ if (kind) {
506
+ code += "." + kind;
507
+ if (message[kind]) message = message[kind];
508
+ else if (defaultMessages.common[kind]) message = defaultMessages.common[kind];
509
+ else message = "is invalid";
510
+ }
511
+ if (kind !== false) inst.errors.add(attr, message, code);
512
+ fail = true;
513
+ });
514
+ validatorArguments.push(options);
515
+ if (cb) validatorArguments.push(function() {
516
+ cb(fail);
517
+ });
518
+ validator.apply(inst, validatorArguments);
519
+ return fail;
520
+ }
521
+ function skipValidation(inst, conf, kind) {
522
+ let doValidate = true;
523
+ if (typeof conf[kind] === "function") {
524
+ doValidate = conf[kind].call(inst);
525
+ if (kind === "unless") doValidate = !doValidate;
526
+ } else if (typeof conf[kind] === "string") if (typeof inst[conf[kind]] === "function") {
527
+ doValidate = inst[conf[kind]].call(inst);
528
+ if (kind === "unless") doValidate = !doValidate;
529
+ } else if (inst.__data.hasOwnProperty(conf[kind])) {
530
+ doValidate = inst[conf[kind]];
531
+ if (kind === "unless") doValidate = !doValidate;
532
+ } else doValidate = kind === "if";
533
+ return !doValidate;
534
+ }
535
+ const defaultMessages = {
536
+ presence: "can't be blank",
537
+ absence: "can't be set",
538
+ "unknown-property": "is not defined in the model",
539
+ length: {
540
+ min: "too short",
541
+ max: "too long",
542
+ is: "length is wrong"
543
+ },
544
+ common: {
545
+ blank: "is blank",
546
+ null: "is null"
547
+ },
548
+ numericality: {
549
+ int: "is not an integer",
550
+ number: "is not a number"
551
+ },
552
+ inclusion: "is not included in the list",
553
+ exclusion: "is reserved",
554
+ uniqueness: "is not unique",
555
+ date: "is not a valid date"
556
+ };
557
+ /**
558
+ * Checks if attribute is undefined or null. Calls err function with 'blank' or 'null'.
559
+ * See defaultMessages. You can affect this behaviour with conf.allowBlank and conf.allowNull.
560
+ * @private
561
+ * @param {String} attr Property name of attribute
562
+ * @param {Object} conf conf object for validator
563
+ * @param {Function} err
564
+ * @return {Boolean} returns true if attribute is null or blank
565
+ */
566
+ function nullCheck(attr, conf, err) {
567
+ if (typeof this[attr] === "undefined" || this[attr] === "") {
568
+ if (!conf.allowBlank) err("blank");
569
+ return true;
570
+ } else if (this[attr] === null) {
571
+ if (!conf.allowNull) err("null");
572
+ return true;
573
+ }
574
+ return false;
575
+ }
576
+ /*!
577
+ * Return true when v is undefined, blank array, null or empty string
578
+ * otherwise returns false
579
+ *
580
+ * @param {Mix} v
581
+ * Returns true if `v` is blank.
582
+ */
583
+ function blank(v) {
584
+ if (typeof v === "undefined") return true;
585
+ if (v instanceof Array && v.length === 0) return true;
586
+ if (v === null) return true;
587
+ if (typeof v === "number" && isNaN(v)) return true;
588
+ if (typeof v == "string" && v === "") return true;
589
+ return false;
590
+ }
591
+ function configure(cls, validation, args, opts) {
592
+ if (!cls.validations) Object.defineProperty(cls, "validations", {
593
+ writable: true,
594
+ configurable: true,
595
+ enumerable: false,
596
+ value: {}
597
+ });
598
+ args = [].slice.call(args);
599
+ let conf;
600
+ if (typeof args[args.length - 1] === "object") conf = args.pop();
601
+ else conf = {};
602
+ if (validation === "custom" && typeof args[args.length - 1] === "function") conf.customValidator = args.pop();
603
+ conf.validation = validation;
604
+ args.forEach(function(attr) {
605
+ if (typeof attr === "string") {
606
+ const validation = Object.assign({}, conf);
607
+ validation.options = opts || {};
608
+ cls.validations[attr] = cls.validations[attr] || [];
609
+ cls.validations[attr].push(validation);
610
+ }
611
+ });
612
+ }
613
+ function Errors() {
614
+ Object.defineProperty(this, "codes", {
615
+ enumerable: false,
616
+ configurable: true,
617
+ value: {}
618
+ });
619
+ }
620
+ Errors.prototype.add = function(field, message, code) {
621
+ code = code || "invalid";
622
+ if (!this[field]) {
623
+ this[field] = [];
624
+ this.codes[field] = [];
625
+ }
626
+ this[field].push(message);
627
+ this.codes[field].push(code);
628
+ };
629
+ /**
630
+ * ValidationError is raised when the application attempts to save an invalid model instance.
631
+ * Example:
632
+ * ```
633
+ * {
634
+ * "name": "ValidationError",
635
+ * "status": 422,
636
+ * "message": "The Model instance is not valid. \
637
+ * See `details` property of the error object for more info.",
638
+ * "statusCode": 422,
639
+ * "details": {
640
+ * "context": "user",
641
+ * "codes": {
642
+ * "password": [
643
+ * "presence"
644
+ * ],
645
+ * "email": [
646
+ * "uniqueness"
647
+ * ]
648
+ * },
649
+ * "messages": {
650
+ * "password": [
651
+ * "can't be blank"
652
+ * ],
653
+ * "email": [
654
+ * "Email already exists"
655
+ * ]
656
+ * }
657
+ * },
658
+ * }
659
+ * ```
660
+ * You might run into situations where you need to raise a validation error yourself, for example in a "before" hook or a
661
+ * custom model method.
662
+ * ```
663
+ * MyModel.prototype.preflight = function(changes, callback) {
664
+ * // Update properties, do not save to db
665
+ * for (var key in changes) {
666
+ * model[key] = changes[key];
667
+ * }
668
+ *
669
+ * if (model.isValid()) {
670
+ * return callback(null, { success: true });
671
+ * }
672
+ *
673
+ * // This line shows how to create a ValidationError
674
+ * var err = new MyModel.ValidationError(model);
675
+ * callback(err);
676
+ * }
677
+ * ```
678
+ *
679
+ * @private
680
+ */
681
+ function ValidationError(obj) {
682
+ if (!(this instanceof ValidationError)) return new ValidationError(obj);
683
+ this.name = "ValidationError";
684
+ const context = obj && obj.constructor && obj.constructor.modelName;
685
+ this.message = g.f("The %s instance is not valid. Details: %s.", context ? "`" + context + "`" : "model", formatErrors(obj.errors, obj.toJSON()) || "(unknown)");
686
+ this.statusCode = 422;
687
+ this.details = {
688
+ context,
689
+ codes: obj.errors && obj.errors.codes,
690
+ messages: obj.errors
691
+ };
692
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
693
+ else if (errorHasStackProperty) this.stack = (/* @__PURE__ */ new Error()).stack;
694
+ }
695
+ util.inherits(ValidationError, Error);
696
+ const errorHasStackProperty = !!(/* @__PURE__ */ new Error()).stack;
697
+ ValidationError.maxPropertyStringLength = 32;
698
+ function formatErrors(errors, propertyValues) {
699
+ const DELIM = "; ";
700
+ errors = errors || {};
701
+ return Object.getOwnPropertyNames(errors).filter(function(propertyName) {
702
+ return Array.isArray(errors[propertyName]);
703
+ }).map(function(propertyName) {
704
+ const messages = errors[propertyName];
705
+ const propertyValue = propertyValues[propertyName];
706
+ return messages.map(function(msg) {
707
+ return formatPropertyError(propertyName, propertyValue, msg);
708
+ }).join(DELIM);
709
+ }).join(DELIM);
710
+ }
711
+ function formatPropertyError(propertyName, propertyValue, errorMessage) {
712
+ let formattedValue;
713
+ const valueType = typeof propertyValue;
714
+ if (valueType === "string") formattedValue = JSON.stringify(truncatePropertyString(propertyValue));
715
+ else if (propertyValue instanceof Date) formattedValue = isNaN(propertyValue.getTime()) ? propertyValue.toString() : propertyValue.toISOString();
716
+ else if (valueType === "object") {
717
+ formattedValue = util.inspect(propertyValue, {
718
+ showHidden: false,
719
+ color: false,
720
+ depth: Array.isArray(propertyValue) ? 1 : 0
721
+ });
722
+ formattedValue = truncatePropertyString(formattedValue);
723
+ } else formattedValue = truncatePropertyString("" + propertyValue);
724
+ return "`" + propertyName + "` " + errorMessage + " (value: " + formattedValue + ")";
725
+ }
726
+ function truncatePropertyString(value) {
727
+ let len = ValidationError.maxPropertyStringLength;
728
+ if (value.length <= len) return value;
729
+ let tail;
730
+ const m = value.match(/([ \t})\]]+)$/);
731
+ if (m) {
732
+ tail = m[1].slice(-3);
733
+ len -= tail.length;
734
+ } else {
735
+ tail = value.slice(-3);
736
+ len -= 3;
737
+ }
738
+ return value.slice(0, len - 4) + "..." + tail;
739
+ }
740
+ }));
741
+ //#endregion
742
+ module.exports = require_validations();