functional-models 3.10.0 → 3.11.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 (83) hide show
  1. package/cjs/errors.cjs +38 -0
  2. package/cjs/errors.cjs.map +7 -0
  3. package/cjs/index.cjs +2426 -0
  4. package/cjs/index.cjs.map +7 -0
  5. package/cjs/lib.cjs +431 -0
  6. package/cjs/lib.cjs.map +7 -0
  7. package/cjs/models.cjs +571 -0
  8. package/cjs/models.cjs.map +7 -0
  9. package/cjs/orm/index.cjs +1765 -0
  10. package/cjs/orm/index.cjs.map +7 -0
  11. package/cjs/orm/internal-libs.cjs +136 -0
  12. package/cjs/orm/internal-libs.cjs.map +7 -0
  13. package/cjs/orm/libs.cjs +88 -0
  14. package/cjs/orm/libs.cjs.map +7 -0
  15. package/cjs/orm/models.cjs +1027 -0
  16. package/cjs/orm/models.cjs.map +7 -0
  17. package/cjs/orm/properties.cjs +989 -0
  18. package/cjs/orm/properties.cjs.map +7 -0
  19. package/cjs/orm/query.cjs +376 -0
  20. package/cjs/orm/query.cjs.map +7 -0
  21. package/cjs/orm/types.cjs +59 -0
  22. package/cjs/orm/types.cjs.map +7 -0
  23. package/cjs/orm/validation.cjs +301 -0
  24. package/cjs/orm/validation.cjs.map +7 -0
  25. package/cjs/properties.cjs +998 -0
  26. package/cjs/properties.cjs.map +7 -0
  27. package/cjs/serialization.cjs +75 -0
  28. package/cjs/serialization.cjs.map +7 -0
  29. package/cjs/types.cjs +65 -0
  30. package/cjs/types.cjs.map +7 -0
  31. package/cjs/utils.cjs +187 -0
  32. package/cjs/utils.cjs.map +7 -0
  33. package/cjs/validation.cjs +431 -0
  34. package/cjs/validation.cjs.map +7 -0
  35. package/errors.js +3 -4
  36. package/errors.js.map +1 -1
  37. package/index.d.ts +13 -13
  38. package/index.js +13 -52
  39. package/index.js.map +1 -1
  40. package/lib.d.ts +2 -2
  41. package/lib.js +45 -65
  42. package/lib.js.map +1 -1
  43. package/models.d.ts +1 -1
  44. package/models.js +22 -30
  45. package/models.js.map +1 -1
  46. package/orm/index.d.ts +9 -9
  47. package/orm/index.js +9 -48
  48. package/orm/index.js.map +1 -1
  49. package/orm/internal-libs.js +7 -11
  50. package/orm/internal-libs.js.map +1 -1
  51. package/orm/libs.d.ts +1 -1
  52. package/orm/libs.js +8 -16
  53. package/orm/libs.js.map +1 -1
  54. package/orm/models.d.ts +2 -2
  55. package/orm/models.js +20 -26
  56. package/orm/models.js.map +1 -1
  57. package/orm/properties.d.ts +22 -22
  58. package/orm/properties.js +26 -36
  59. package/orm/properties.js.map +1 -1
  60. package/orm/query.d.ts +1 -1
  61. package/orm/query.js +31 -52
  62. package/orm/query.js.map +1 -1
  63. package/orm/types.d.ts +1 -1
  64. package/orm/types.js +7 -10
  65. package/orm/types.js.map +1 -1
  66. package/orm/validation.d.ts +2 -2
  67. package/orm/validation.js +5 -13
  68. package/orm/validation.js.map +1 -1
  69. package/package.json +50 -65
  70. package/properties.d.ts +21 -21
  71. package/properties.js +65 -94
  72. package/properties.js.map +1 -1
  73. package/serialization.d.ts +1 -1
  74. package/serialization.js +3 -9
  75. package/serialization.js.map +1 -1
  76. package/types.js +4 -6
  77. package/types.js.map +1 -1
  78. package/utils.d.ts +2 -1
  79. package/utils.js +8 -23
  80. package/utils.js.map +1 -1
  81. package/validation.d.ts +1 -1
  82. package/validation.js +19 -50
  83. package/validation.js.map +1 -1
@@ -0,0 +1,1027 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/orm/models.ts
31
+ var models_exports = {};
32
+ __export(models_exports, {
33
+ createOrm: () => createOrm
34
+ });
35
+ module.exports = __toCommonJS(models_exports);
36
+ var import_merge6 = __toESM(require("lodash/merge.js"), 1);
37
+ var import_modern_async = require("modern-async");
38
+
39
+ // src/models.ts
40
+ var import_merge4 = __toESM(require("lodash/merge.js"), 1);
41
+ var import_zod2 = __toESM(require("zod"), 1);
42
+
43
+ // src/serialization.ts
44
+ var import_merge = __toESM(require("lodash/merge.js"), 1);
45
+ var isModelInstance = (obj) => {
46
+ return Boolean(obj.toObj);
47
+ };
48
+ var _getValue = async (value) => {
49
+ if (value === void 0) {
50
+ return void 0;
51
+ }
52
+ if (value === null) {
53
+ return null;
54
+ }
55
+ const type = typeof value;
56
+ const asFunction = value;
57
+ if (type === "function") {
58
+ return _getValue(await asFunction());
59
+ }
60
+ if (isModelInstance(value)) {
61
+ return _getValue(await value.toObj());
62
+ }
63
+ const asDate = value;
64
+ if (type === "object" && asDate.toISOString) {
65
+ return _getValue(asDate.toISOString());
66
+ }
67
+ return value;
68
+ };
69
+ var toJsonAble = (keyToFunc) => () => {
70
+ return Object.entries(keyToFunc).reduce(async (acc, [key, value]) => {
71
+ const realAcc = await acc;
72
+ const trueValue = await _getValue(await value);
73
+ if (trueValue === void 0) {
74
+ return realAcc;
75
+ }
76
+ return (0, import_merge.default)(realAcc, { [key]: trueValue });
77
+ }, Promise.resolve({}));
78
+ };
79
+
80
+ // src/validation.ts
81
+ var import_isEmpty = __toESM(require("lodash/isEmpty.js"), 1);
82
+ var import_merge2 = __toESM(require("lodash/merge.js"), 1);
83
+ var import_flatMap = __toESM(require("lodash/flatMap.js"), 1);
84
+ var import_get = __toESM(require("lodash/get.js"), 1);
85
+
86
+ // src/types.ts
87
+ var ApiMethod = /* @__PURE__ */ ((ApiMethod2) => {
88
+ ApiMethod2["create"] = "create";
89
+ ApiMethod2["retrieve"] = "retrieve";
90
+ ApiMethod2["update"] = "update";
91
+ ApiMethod2["delete"] = "delete";
92
+ ApiMethod2["search"] = "search";
93
+ return ApiMethod2;
94
+ })(ApiMethod || {});
95
+
96
+ // src/utils.ts
97
+ var import_async_lock = __toESM(require("async-lock"), 1);
98
+
99
+ // node_modules/uuid/dist-node/stringify.js
100
+ var byteToHex = [];
101
+ for (let i = 0; i < 256; ++i) {
102
+ byteToHex.push((i + 256).toString(16).slice(1));
103
+ }
104
+ function unsafeStringify(arr, offset = 0) {
105
+ return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
106
+ }
107
+
108
+ // node_modules/uuid/dist-node/rng.js
109
+ var rnds8 = new Uint8Array(16);
110
+ function rng() {
111
+ return crypto.getRandomValues(rnds8);
112
+ }
113
+
114
+ // node_modules/uuid/dist-node/v4.js
115
+ function v4(options, buf, offset) {
116
+ if (!buf && !options && crypto.randomUUID) {
117
+ return crypto.randomUUID();
118
+ }
119
+ return _v4(options, buf, offset);
120
+ }
121
+ function _v4(options, buf, offset) {
122
+ options = options || {};
123
+ const rnds = options.random ?? options.rng?.() ?? rng();
124
+ if (rnds.length < 16) {
125
+ throw new Error("Random bytes length must be >= 16");
126
+ }
127
+ rnds[6] = rnds[6] & 15 | 64;
128
+ rnds[8] = rnds[8] & 63 | 128;
129
+ if (buf) {
130
+ offset = offset || 0;
131
+ if (offset < 0 || offset + 16 > buf.length) {
132
+ throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
133
+ }
134
+ for (let i = 0; i < 16; ++i) {
135
+ buf[offset + i] = rnds[i];
136
+ }
137
+ return buf;
138
+ }
139
+ return unsafeStringify(rnds);
140
+ }
141
+ var v4_default = v4;
142
+
143
+ // src/utils.ts
144
+ var import_get_random_values = __toESM(require("get-random-values"), 1);
145
+ var toTitleCase = (string) => {
146
+ return `${string.slice(0, 1).toUpperCase()}${string.slice(1)}`;
147
+ };
148
+ var PluralEndings = /* @__PURE__ */ ((PluralEndings2) => {
149
+ PluralEndings2["ves"] = "fe";
150
+ PluralEndings2["ies"] = "y";
151
+ PluralEndings2["i"] = "us";
152
+ PluralEndings2["zes"] = "ze";
153
+ PluralEndings2["ses"] = "s";
154
+ PluralEndings2["es"] = "e";
155
+ PluralEndings2["s"] = "";
156
+ return PluralEndings2;
157
+ })(PluralEndings || {});
158
+ var _singularizingRe = new RegExp(
159
+ `(${Object.keys(PluralEndings).join("|")})$`,
160
+ "u"
161
+ );
162
+ var singularize = (word) => {
163
+ return word.replace(_singularizingRe, (r) => PluralEndings[r]);
164
+ };
165
+ var flowFindFirst = (funcs) => (input) => {
166
+ return funcs.reduce((acc, func) => {
167
+ if (acc) {
168
+ return acc;
169
+ }
170
+ return func(input);
171
+ }, void 0);
172
+ };
173
+ var memoizeSync = (method) => {
174
+ let value = void 0;
175
+ let called = false;
176
+ return (...args) => {
177
+ if (!called) {
178
+ called = true;
179
+ value = method(...args);
180
+ }
181
+ return value;
182
+ };
183
+ };
184
+ var memoizeAsync = (method) => {
185
+ const key = v4_default();
186
+ const lock = new import_async_lock.default();
187
+ let value = void 0;
188
+ let called = false;
189
+ return async (...args) => {
190
+ return lock.acquire(key, async () => {
191
+ if (!called) {
192
+ called = true;
193
+ value = await method(...args);
194
+ }
195
+ return value;
196
+ });
197
+ };
198
+ };
199
+
200
+ // src/validation.ts
201
+ var multiValidator = (validators) => {
202
+ const flow3 = flowFindFirst(
203
+ validators
204
+ );
205
+ return flow3;
206
+ };
207
+ var _trueOrError = (method, error) => (value) => {
208
+ if (method(value) === false) {
209
+ return error;
210
+ }
211
+ return void 0;
212
+ };
213
+ var _typeOrError = (type, errorMessage) => (value) => {
214
+ if (typeof value !== type) {
215
+ return errorMessage;
216
+ }
217
+ return void 0;
218
+ };
219
+ var isType = (type) => (value) => {
220
+ return _typeOrError(type, `Must be a ${type}`)(value);
221
+ };
222
+ var isNumber = isType("number");
223
+ var isInteger = _trueOrError(Number.isInteger, "Must be an integer");
224
+ var isObject = multiValidator([
225
+ isType("object"),
226
+ (x) => Array.isArray(x) ? "Must be an object, but got an array" : void 0
227
+ ]);
228
+ var isBoolean = isType("boolean");
229
+ var isString = isType("string");
230
+ var isArray = _trueOrError(
231
+ (v) => Array.isArray(v),
232
+ "Value is not an array"
233
+ );
234
+ var PRIMITIVE_TO_SPECIAL_TYPE_VALIDATOR = {
235
+ ["boolean" /* boolean */]: isBoolean,
236
+ ["string" /* string */]: isString,
237
+ ["integer" /* integer */]: isInteger,
238
+ ["number" /* number */]: isNumber,
239
+ ["object" /* object */]: isObject
240
+ };
241
+ var createModelValidator = (validators, modelValidators) => {
242
+ const _modelValidator = async (instance, propertyConfiguration) => {
243
+ return Promise.resolve().then(async () => {
244
+ if (!instance) {
245
+ throw new Error(`Instance cannot be empty`);
246
+ }
247
+ const model = instance.getModel();
248
+ const keysAndFunctions = Object.entries(validators);
249
+ const instanceData = await instance.toObj();
250
+ const propertyValidationErrors = await Promise.all(
251
+ keysAndFunctions.map(async ([key, validator]) => {
252
+ return [
253
+ key,
254
+ await validator(model, instanceData, propertyConfiguration)
255
+ ];
256
+ })
257
+ );
258
+ const modelValidationErrors = (await Promise.all(
259
+ modelValidators ? modelValidators.map((validator) => {
260
+ return validator(model, instanceData, propertyConfiguration);
261
+ }) : []
262
+ )).filter((x) => x);
263
+ const propertyErrors = propertyValidationErrors.filter(([, errors]) => Boolean(errors) && errors.length > 0).reduce((acc, [key, errors]) => {
264
+ return (0, import_merge2.default)(acc, { [String(key)]: errors });
265
+ }, {});
266
+ const final = modelValidationErrors.length > 0 ? (0, import_merge2.default)(propertyErrors, { overall: modelValidationErrors }) : propertyErrors;
267
+ if ((0, import_isEmpty.default)(final)) {
268
+ return void 0;
269
+ }
270
+ return final;
271
+ });
272
+ };
273
+ return _modelValidator;
274
+ };
275
+
276
+ // src/lib.ts
277
+ var import_openapi_types = require("openapi-types");
278
+ var import_kebabCase = __toESM(require("lodash/kebabCase.js"), 1);
279
+ var import_flow = __toESM(require("lodash/flow.js"), 1);
280
+ var import_merge3 = __toESM(require("lodash/merge.js"), 1);
281
+ var import_get2 = __toESM(require("lodash/get.js"), 1);
282
+ var import_zod = require("zod");
283
+ var HttpMethods = import_openapi_types.OpenAPIV3.HttpMethods;
284
+ var NULL_ENDPOINT = "NULL";
285
+ var NULL_METHOD = HttpMethods.HEAD;
286
+ var ID_KEY = ":id";
287
+ var getModelName = (namespace, pluralName) => {
288
+ return `${namespace}/${pluralName}`;
289
+ };
290
+ var buildValidEndpoint = (...components) => {
291
+ const suffix = components.map((x) => {
292
+ if (x === ID_KEY) {
293
+ return x;
294
+ }
295
+ return (0, import_kebabCase.default)(x);
296
+ }).map((s) => s.toLowerCase()).join("/");
297
+ return `/${suffix}`;
298
+ };
299
+ var _generateRestInfo = (method, withId, ...additional) => (pluralName, namespace) => (existing) => {
300
+ if (existing) {
301
+ return {
302
+ // Default add security, then override it.
303
+ security: {},
304
+ ...existing
305
+ };
306
+ }
307
+ const endpoint = withId ? buildValidEndpoint(namespace, pluralName, ID_KEY) : buildValidEndpoint(namespace, pluralName, ...additional);
308
+ return {
309
+ method,
310
+ endpoint,
311
+ // We cannot auto create security.
312
+ security: {}
313
+ };
314
+ };
315
+ var _apiMethodToRestInfoGenerator = {
316
+ ["create" /* create */]: _generateRestInfo(HttpMethods.POST, false),
317
+ ["retrieve" /* retrieve */]: _generateRestInfo(HttpMethods.GET, true),
318
+ ["update" /* update */]: _generateRestInfo(HttpMethods.PUT, true),
319
+ ["delete" /* delete */]: _generateRestInfo(HttpMethods.DELETE, true),
320
+ ["search" /* search */]: _generateRestInfo(HttpMethods.POST, false, "search")
321
+ };
322
+ var getNullRestInfo = () => {
323
+ return {
324
+ endpoint: NULL_ENDPOINT,
325
+ method: NULL_METHOD,
326
+ security: {}
327
+ };
328
+ };
329
+ var _fillOutRestInfo = (pluralName, namespace, partial, nullRest) => {
330
+ const finishedRestInfo = Object.entries(
331
+ ApiMethod
332
+ ).reduce(
333
+ (acc, [, method]) => {
334
+ const existing = partial && partial.rest && partial.rest[method] ? partial.rest[method] : void 0;
335
+ const restInfo = _apiMethodToRestInfoGenerator[method](
336
+ pluralName,
337
+ namespace
338
+ )(existing);
339
+ return (0, import_merge3.default)(acc, {
340
+ [method]: restInfo
341
+ });
342
+ },
343
+ nullRest
344
+ );
345
+ return {
346
+ noPublish: false,
347
+ onlyPublish: [],
348
+ rest: finishedRestInfo,
349
+ createOnlyOne: partial?.createOnlyOne || false
350
+ };
351
+ };
352
+ var populateApiInformation = (pluralName, namespace, partial) => {
353
+ const nullRest = {
354
+ delete: getNullRestInfo(),
355
+ search: getNullRestInfo(),
356
+ update: getNullRestInfo(),
357
+ retrieve: getNullRestInfo(),
358
+ create: getNullRestInfo()
359
+ };
360
+ if (!partial) {
361
+ return _fillOutRestInfo(pluralName, namespace, partial, nullRest);
362
+ }
363
+ if (partial.noPublish) {
364
+ return {
365
+ onlyPublish: [],
366
+ noPublish: true,
367
+ rest: nullRest,
368
+ createOnlyOne: false
369
+ };
370
+ }
371
+ const rest = partial.rest || {};
372
+ if (partial.onlyPublish && partial.onlyPublish.length > 0) {
373
+ return partial.onlyPublish.reduce(
374
+ (acc, method) => {
375
+ const restInfo = _apiMethodToRestInfoGenerator[method](
376
+ pluralName,
377
+ namespace
378
+ )(rest[method]);
379
+ return (0, import_merge3.default)(acc, {
380
+ rest: {
381
+ [method]: restInfo
382
+ }
383
+ });
384
+ },
385
+ {
386
+ noPublish: false,
387
+ onlyPublish: partial.onlyPublish,
388
+ createOnlyOne: Boolean(partial.createOnlyOne),
389
+ rest: nullRest
390
+ }
391
+ );
392
+ }
393
+ return _fillOutRestInfo(pluralName, namespace, partial, nullRest);
394
+ };
395
+
396
+ // src/models.ts
397
+ var _defaultOptions = () => ({
398
+ instanceCreatedCallback: void 0
399
+ });
400
+ var _convertOptions = (options) => {
401
+ const r = (0, import_merge4.default)({}, _defaultOptions(), options);
402
+ return r;
403
+ };
404
+ var _addDescription = (schema, description) => {
405
+ if (!description) {
406
+ return schema;
407
+ }
408
+ if (typeof schema.openapi === "function") {
409
+ return schema.openapi({ description });
410
+ }
411
+ return schema.meta ? schema.meta({ description }) : schema.describe(description);
412
+ };
413
+ var _createZod = (modelDefinition) => {
414
+ if (modelDefinition.schema) {
415
+ return _addDescription(modelDefinition.schema, modelDefinition.description);
416
+ }
417
+ const properties = Object.entries(modelDefinition.properties).reduce(
418
+ (acc, [key, property2]) => {
419
+ const asProp = property2;
420
+ return (0, import_merge4.default)(acc, {
421
+ [key]: asProp.getZod()
422
+ });
423
+ },
424
+ {}
425
+ );
426
+ const obj = import_zod2.default.object(properties);
427
+ return _addDescription(obj, modelDefinition.description);
428
+ };
429
+ var _toModelDefinition = (minimal) => {
430
+ return {
431
+ singularName: singularize(minimal.pluralName),
432
+ displayName: toTitleCase(minimal.pluralName),
433
+ description: "",
434
+ primaryKeyName: "id",
435
+ modelValidators: [],
436
+ schema: _createZod(minimal),
437
+ ...minimal
438
+ };
439
+ };
440
+ var _validateModelDefinition = (modelDefinition) => {
441
+ const primaryKeyName = modelDefinition.primaryKeyName || "id";
442
+ const primaryKeyProperty = (
443
+ // @ts-ignore
444
+ modelDefinition.properties[primaryKeyName]
445
+ );
446
+ if (!primaryKeyProperty) {
447
+ throw new Error(`Property missing for primaryKey named ${primaryKeyName}`);
448
+ }
449
+ if (!modelDefinition.pluralName) {
450
+ throw new Error(`Must include pluralName for model.`);
451
+ }
452
+ if (!modelDefinition.namespace) {
453
+ throw new Error(`Must include namespace for model.`);
454
+ }
455
+ };
456
+ var Model = (minimalModelDefinitions, options) => {
457
+ _validateModelDefinition(minimalModelDefinitions);
458
+ let model = null;
459
+ const theOptions = _convertOptions(options);
460
+ const modelDefinition = _toModelDefinition(minimalModelDefinitions);
461
+ const getPrimaryKeyName = () => modelDefinition.primaryKeyName;
462
+ const getPrimaryKey = (loadedInternals) => {
463
+ const property2 = loadedInternals.get[getPrimaryKeyName()];
464
+ return property2();
465
+ };
466
+ const create = (instanceValues) => {
467
+ let instance = null;
468
+ const startingInternals = {
469
+ get: {},
470
+ validators: {},
471
+ references: {}
472
+ };
473
+ const prop = Object.entries(
474
+ modelDefinition.properties
475
+ );
476
+ const loadedInternals = prop.reduce(
477
+ (acc, [key, property2]) => {
478
+ const propertyGetter = memoizeSync(
479
+ () => property2.createGetter(
480
+ //@ts-ignore
481
+ instanceValues[key],
482
+ instanceValues,
483
+ // NOTE: By the time it gets here, it has already been implemented.
484
+ instance
485
+ )()
486
+ );
487
+ const propertyValidator = property2.getValidator(propertyGetter);
488
+ const fleshedOutInstanceProperties = {
489
+ get: {
490
+ [key]: () => propertyGetter()
491
+ },
492
+ validators: {
493
+ [key]: propertyValidator
494
+ }
495
+ };
496
+ const asReferenced = property2;
497
+ const referencedProperty = asReferenced.getReferencedId ? {
498
+ references: {
499
+ [key]: () => asReferenced.getReferencedId(
500
+ // @ts-ignore
501
+ instanceValues[key]
502
+ )
503
+ }
504
+ } : {};
505
+ return (0, import_merge4.default)(
506
+ acc,
507
+ fleshedOutInstanceProperties,
508
+ referencedProperty
509
+ );
510
+ },
511
+ startingInternals
512
+ );
513
+ const getModel = () => model;
514
+ const toObj = memoizeAsync(() => {
515
+ return toJsonAble(loadedInternals.get)();
516
+ });
517
+ const validate = memoizeAsync((options2 = {}) => {
518
+ return Promise.resolve().then(() => {
519
+ return createModelValidator(
520
+ loadedInternals.validators,
521
+ modelDefinition.modelValidators
522
+ )(instance, options2);
523
+ });
524
+ });
525
+ const getReferences = () => loadedInternals.references;
526
+ const getValidators = () => loadedInternals.validators;
527
+ instance = {
528
+ get: loadedInternals.get,
529
+ getReferences,
530
+ getValidators,
531
+ getModel,
532
+ toObj,
533
+ getPrimaryKey: () => getPrimaryKey(loadedInternals),
534
+ validate
535
+ };
536
+ if (theOptions.instanceCreatedCallback) {
537
+ const toCall = Array.isArray(theOptions.instanceCreatedCallback) ? theOptions.instanceCreatedCallback : [theOptions.instanceCreatedCallback];
538
+ toCall.map((func) => func(instance));
539
+ }
540
+ return instance;
541
+ };
542
+ const getApiInfo = memoizeSync(() => {
543
+ return populateApiInformation(
544
+ modelDefinition.pluralName,
545
+ modelDefinition.namespace,
546
+ modelDefinition.api
547
+ );
548
+ });
549
+ model = {
550
+ /**
551
+ * Creates a model instance.
552
+ */
553
+ create,
554
+ getName: () => getModelName(modelDefinition.namespace, modelDefinition.pluralName),
555
+ getModelDefinition: memoizeSync(() => modelDefinition),
556
+ getPrimaryKey,
557
+ getApiInfo
558
+ };
559
+ return model;
560
+ };
561
+
562
+ // src/errors.ts
563
+ var ValidationError = class extends Error {
564
+ constructor(modelName, keysToErrors) {
565
+ super(`${modelName} did not pass validation`);
566
+ this.name = "ValidationError";
567
+ this.modelName = modelName;
568
+ this.keysToErrors = keysToErrors;
569
+ }
570
+ };
571
+
572
+ // src/orm/validation.ts
573
+ var import_flow2 = __toESM(require("lodash/flow.js"), 1);
574
+
575
+ // src/orm/query.ts
576
+ var import_merge5 = __toESM(require("lodash/merge.js"), 1);
577
+ var import_omit = __toESM(require("lodash/omit.js"), 1);
578
+
579
+ // src/orm/types.ts
580
+ var EqualitySymbol = /* @__PURE__ */ ((EqualitySymbol2) => {
581
+ EqualitySymbol2["eq"] = "=";
582
+ EqualitySymbol2["lt"] = "<";
583
+ EqualitySymbol2["lte"] = "<=";
584
+ EqualitySymbol2["gt"] = ">";
585
+ EqualitySymbol2["gte"] = ">=";
586
+ EqualitySymbol2["ne"] = "!=";
587
+ return EqualitySymbol2;
588
+ })(EqualitySymbol || {});
589
+ var AllowableEqualitySymbols = Object.values(EqualitySymbol);
590
+
591
+ // src/orm/query.ts
592
+ var _objectize = (key, value) => {
593
+ return value ? {
594
+ [key]: value
595
+ } : {};
596
+ };
597
+ var _additionalLink = (data) => {
598
+ const inner = _builderV2(data);
599
+ const partialLink = (0, import_omit.default)(_link(data), ["and", "or"]);
600
+ return {
601
+ ...inner,
602
+ ...partialLink
603
+ };
604
+ };
605
+ var _link = (data) => {
606
+ return {
607
+ and: () => {
608
+ return _queryBuilder({ ...data, query: data.query.concat("AND") });
609
+ },
610
+ or: () => {
611
+ return _queryBuilder({ ...data, query: data.query.concat("OR") });
612
+ },
613
+ compile: () => {
614
+ return data;
615
+ },
616
+ take: (num) => {
617
+ return _additionalLink({ ...data, take: take(num) });
618
+ },
619
+ sort: (key, order = "asc" /* asc */) => {
620
+ return _additionalLink({ ...data, sort: sort(key, order) });
621
+ },
622
+ pagination: (value) => {
623
+ return _additionalLink({ ...data, page: pagination(value) });
624
+ }
625
+ };
626
+ };
627
+ var _canCompile = (obj) => {
628
+ return Boolean(obj.compile);
629
+ };
630
+ var _builderV2 = (data) => {
631
+ const _myProperty = (name, value, options) => {
632
+ const p = property(name, value, options);
633
+ return _link((0, import_merge5.default)(data, { query: data.query.concat(p) }));
634
+ };
635
+ const complex = (subBuilderFunc) => {
636
+ const subBuilder = _queryBuilder();
637
+ const result = subBuilderFunc(subBuilder);
638
+ if (_canCompile(result)) {
639
+ const queryTokens = [result.compile().query];
640
+ return _link(
641
+ (0, import_merge5.default)(data, {
642
+ query: data.query.concat(queryTokens)
643
+ })
644
+ );
645
+ }
646
+ return _link((0, import_merge5.default)(data, { query: data.query.concat([result.query]) }));
647
+ };
648
+ const thisDatesBefore = (key, jsDate, { valueType = "date" /* date */, equalToAndBefore = true } = {}) => {
649
+ const p = datesBefore(key, jsDate, { valueType, equalToAndBefore });
650
+ return _link((0, import_merge5.default)(data, { query: data.query.concat(p) }));
651
+ };
652
+ const thisDatesAfter = (key, jsDate, { valueType = "date" /* date */, equalToAndAfter = true } = {}) => {
653
+ const p = datesAfter(key, jsDate, { valueType, equalToAndAfter });
654
+ return _link((0, import_merge5.default)(data, { query: data.query.concat(p) }));
655
+ };
656
+ return {
657
+ datesBefore: thisDatesBefore,
658
+ datesAfter: thisDatesAfter,
659
+ complex,
660
+ property: _myProperty
661
+ };
662
+ };
663
+ var _queryBuilder = (data = void 0) => {
664
+ const theData = (0, import_merge5.default)(
665
+ {
666
+ query: []
667
+ },
668
+ data
669
+ );
670
+ const builder = _builderV2(theData);
671
+ const linkData = _additionalLink(theData);
672
+ return {
673
+ ...builder,
674
+ ...linkData,
675
+ compile: () => {
676
+ return {
677
+ ..._objectize("take", theData.take),
678
+ ..._objectize("sort", theData.sort),
679
+ ..._objectize("page", theData.page),
680
+ query: []
681
+ };
682
+ }
683
+ };
684
+ };
685
+ var property = (key, value, options = {}) => {
686
+ const {
687
+ equalitySymbol = "=" /* eq */,
688
+ caseSensitive,
689
+ startsWith,
690
+ endsWith,
691
+ includes,
692
+ type
693
+ } = options;
694
+ const typeToUse = type || "string" /* string */;
695
+ if (!AllowableEqualitySymbols.includes(equalitySymbol)) {
696
+ throw new Error(`${equalitySymbol} is not a valid symbol`);
697
+ }
698
+ if (equalitySymbol !== "=" /* eq */ && equalitySymbol !== "!=" /* ne */ && typeToUse === "string" /* string */) {
699
+ throw new Error(`Cannot use a non = symbol for a string type`);
700
+ }
701
+ const propertyEntry = {
702
+ type: "property",
703
+ key,
704
+ value,
705
+ valueType: typeToUse,
706
+ equalitySymbol,
707
+ options: {
708
+ ..._objectize("caseSensitive", caseSensitive),
709
+ ..._objectize("startsWith", startsWith),
710
+ ..._objectize("endsWith", endsWith),
711
+ ..._objectize("includes", includes)
712
+ }
713
+ };
714
+ return propertyEntry;
715
+ };
716
+ var take = (max) => {
717
+ const parsed = parseInt(`${max}`, 10);
718
+ if (Number.isNaN(parsed)) {
719
+ throw new Error(`Number "${max}" is not integerable`);
720
+ }
721
+ return parsed;
722
+ };
723
+ var sort = (key, order = "asc" /* asc */) => {
724
+ if (order !== "asc" /* asc */ && order !== "dsc" /* dsc */) {
725
+ throw new Error("Sort must be either asc or dsc");
726
+ }
727
+ return {
728
+ key,
729
+ order
730
+ };
731
+ };
732
+ var pagination = (value) => {
733
+ return value;
734
+ };
735
+ var datesAfter = (key, jsDate, options = {
736
+ valueType: "date" /* date */,
737
+ equalToAndAfter: true
738
+ }) => {
739
+ const { valueType = "date" /* date */, equalToAndAfter = true } = options;
740
+ return {
741
+ type: "datesAfter",
742
+ key,
743
+ date: isDate(jsDate) ? jsDate.toISOString() : jsDate,
744
+ valueType,
745
+ options: {
746
+ equalToAndAfter
747
+ }
748
+ };
749
+ };
750
+ var isDate = (obj) => {
751
+ return Boolean(obj.toISOString);
752
+ };
753
+ var datesBefore = (key, jsDate, options = {
754
+ valueType: "date" /* date */,
755
+ equalToAndBefore: true
756
+ }) => {
757
+ const { valueType = "date" /* date */, equalToAndBefore = true } = options;
758
+ return {
759
+ type: "datesBefore",
760
+ key,
761
+ date: isDate(jsDate) ? jsDate.toISOString() : jsDate,
762
+ valueType,
763
+ options: {
764
+ equalToAndBefore
765
+ }
766
+ };
767
+ };
768
+ var queryBuilder = () => {
769
+ return _queryBuilder();
770
+ };
771
+
772
+ // src/orm/validation.ts
773
+ var _doUniqueCheck = async (query, model, instanceData, buildErrorMessage) => {
774
+ const results = await model.search(query);
775
+ const resultsLength = results.instances.length;
776
+ if (resultsLength < 1) {
777
+ return void 0;
778
+ }
779
+ const ids = await Promise.all(
780
+ results.instances.map((x) => x.getPrimaryKey())
781
+ );
782
+ const instanceId = instanceData[model.getModelDefinition().primaryKeyName];
783
+ if (ids.length === 1 && ids[0] === instanceId) {
784
+ return void 0;
785
+ }
786
+ if (ids.length > 1) {
787
+ if (ids.find((x) => x === instanceId)) {
788
+ return void 0;
789
+ }
790
+ }
791
+ return buildErrorMessage();
792
+ };
793
+ var uniqueTogether = (propertyKeyArray) => {
794
+ const _uniqueTogether = async (model, instanceData, options) => {
795
+ if (options?.noOrmValidation) {
796
+ return void 0;
797
+ }
798
+ const properties = propertyKeyArray.map((key) => {
799
+ return [key, instanceData[key]];
800
+ });
801
+ const query = (0, import_flow2.default)(
802
+ properties.map(([key, value], index) => {
803
+ return (b) => {
804
+ if (index + 1 >= properties.length) {
805
+ return b.property(key, value, { caseSensitive: false });
806
+ }
807
+ return b.property(key, value, { caseSensitive: false }).and();
808
+ };
809
+ })
810
+ )(queryBuilder().take(2)).compile();
811
+ return _doUniqueCheck(query, model, instanceData, () => {
812
+ return propertyKeyArray.length > 1 ? `${propertyKeyArray.join(
813
+ ","
814
+ )} must be unique together. Another instance found.` : `${propertyKeyArray[0]} must be unique. Another instance found.`;
815
+ });
816
+ };
817
+ return _uniqueTogether;
818
+ };
819
+
820
+ // src/orm/models.ts
821
+ var createOrm = ({
822
+ datastoreAdapter,
823
+ Model: Model2 = Model
824
+ }) => {
825
+ if (!datastoreAdapter) {
826
+ throw new Error(`Must include a datastoreAdapter`);
827
+ }
828
+ const _retrievedObjToModel = (model) => (obj) => {
829
+ return model.create(obj);
830
+ };
831
+ const fetcher = async (model, id) => {
832
+ const x = retrieve(
833
+ model,
834
+ id
835
+ );
836
+ return x;
837
+ };
838
+ const retrieve = async (model, id) => {
839
+ const obj = await datastoreAdapter.retrieve(model, id);
840
+ if (!obj) {
841
+ return void 0;
842
+ }
843
+ return _retrievedObjToModel(model)(obj);
844
+ };
845
+ const _defaultOptions2 = () => ({
846
+ instanceCreatedCallback: void 0
847
+ });
848
+ const _convertOptions2 = (options) => {
849
+ const r = (0, import_merge6.default)(
850
+ {},
851
+ _defaultOptions2(),
852
+ options
853
+ );
854
+ return r;
855
+ };
856
+ const ThisModel = (modelDefinition, options) => {
857
+ let model = null;
858
+ const theOptions = _convertOptions2(options);
859
+ const search = (ormQuery) => {
860
+ return datastoreAdapter.search(model, ormQuery).then((result) => {
861
+ const conversionFunc = _retrievedObjToModel(model);
862
+ return {
863
+ // @ts-ignore
864
+ instances: result.instances.map(conversionFunc),
865
+ page: result.page
866
+ };
867
+ });
868
+ };
869
+ const searchOne = (ormQuery) => {
870
+ ormQuery = (0, import_merge6.default)(ormQuery, { take: 1 });
871
+ return search(ormQuery).then(({ instances }) => {
872
+ return instances[0];
873
+ });
874
+ };
875
+ const bulkInsert = async (instances) => {
876
+ if (datastoreAdapter.bulkInsert) {
877
+ await datastoreAdapter.bulkInsert(model, instances);
878
+ return void 0;
879
+ }
880
+ await (0, import_modern_async.asyncMap)(instances, (x) => x.save());
881
+ return void 0;
882
+ };
883
+ const bulkDelete = async (keysOrInstances) => {
884
+ const ids = typeof keysOrInstances[0] === "object" ? keysOrInstances.map(
885
+ (x) => x.getPrimaryKey()
886
+ ) : keysOrInstances;
887
+ if (datastoreAdapter.bulkDelete) {
888
+ await datastoreAdapter.bulkDelete(model, ids);
889
+ return void 0;
890
+ }
891
+ await (0, import_modern_async.asyncMap)(ids, (id) => model.delete(id));
892
+ return void 0;
893
+ };
894
+ const loadedRetrieve = (id) => {
895
+ return retrieve(model, id);
896
+ };
897
+ const modelValidators = modelDefinition?.uniqueTogether ? (modelDefinition.modelValidators || []).concat(
898
+ // @ts-ignore
899
+ uniqueTogether(modelDefinition.uniqueTogether)
900
+ ) : modelDefinition.modelValidators;
901
+ const ormModelDefinition = (0, import_merge6.default)({}, modelDefinition, {
902
+ modelValidators
903
+ });
904
+ const _updateLastModifiedIfExistsReturnNewObj = async (instance) => {
905
+ const hasLastModified = Object.entries(
906
+ instance.getModel().getModelDefinition().properties
907
+ ).filter((propertyEntry) => {
908
+ const property2 = propertyEntry[1];
909
+ return Boolean("lastModifiedUpdateMethod" in property2);
910
+ })[0];
911
+ const doLastModified = async () => {
912
+ const obj = await instance.toObj();
913
+ const newInstance = model.create(
914
+ // @ts-ignore
915
+ (0, import_merge6.default)(obj, {
916
+ [hasLastModified[0]]: (
917
+ // @ts-ignore
918
+ hasLastModified[1].lastModifiedUpdateMethod()
919
+ )
920
+ })
921
+ );
922
+ return newInstance;
923
+ };
924
+ return hasLastModified ? doLastModified() : instance;
925
+ };
926
+ const save = async (instance) => {
927
+ return Promise.resolve().then(async () => {
928
+ const newInstance = await _updateLastModifiedIfExistsReturnNewObj(instance);
929
+ const invalid = await newInstance.validate();
930
+ if (invalid) {
931
+ throw new ValidationError(model.getName(), invalid);
932
+ }
933
+ const savedObj = await datastoreAdapter.save(newInstance);
934
+ return _retrievedObjToModel(model)(savedObj);
935
+ });
936
+ };
937
+ const createAndSave = async (data) => {
938
+ if (datastoreAdapter.createAndSave) {
939
+ const response = await datastoreAdapter.createAndSave(data);
940
+ return _retrievedObjToModel(model)(response);
941
+ }
942
+ const instance = model.create(await data.toObj());
943
+ return instance.save();
944
+ };
945
+ const deleteObj = (id) => {
946
+ return Promise.resolve().then(async () => {
947
+ await datastoreAdapter.delete(model, id);
948
+ });
949
+ };
950
+ const _getSave = (instance) => {
951
+ if (theOptions.save !== void 0) {
952
+ return () => theOptions.save(save, instance);
953
+ }
954
+ return () => save(instance);
955
+ };
956
+ const _getDelete = (instance) => {
957
+ if (theOptions.delete) {
958
+ return () => theOptions.delete(deleteObj, instance);
959
+ }
960
+ return () => deleteObj(instance.getPrimaryKey());
961
+ };
962
+ const instanceCreatedCallback = (instance) => {
963
+ instance.save = _getSave(instance);
964
+ instance.delete = _getDelete(instance);
965
+ if (theOptions.instanceCreatedCallback) {
966
+ const callbacks = Array.isArray(theOptions.instanceCreatedCallback) ? theOptions.instanceCreatedCallback : [theOptions.instanceCreatedCallback];
967
+ callbacks.forEach((x) => x(instance));
968
+ }
969
+ };
970
+ const overridedOptions = (0, import_merge6.default)({}, theOptions, {
971
+ instanceCreatedCallback: [instanceCreatedCallback]
972
+ });
973
+ const baseModel = Model2(ormModelDefinition, overridedOptions);
974
+ const lowerLevelCreate = baseModel.create;
975
+ const _convertModelInstance = (instance) => {
976
+ return (0, import_merge6.default)(instance, {
977
+ create,
978
+ getModel: () => model,
979
+ save: _getSave(instance),
980
+ delete: _getDelete(instance)
981
+ });
982
+ };
983
+ const create = (data) => {
984
+ const result = lowerLevelCreate(data);
985
+ return _convertModelInstance(result);
986
+ };
987
+ const _countRecursive = async (page = null) => {
988
+ const results = await model.search(
989
+ queryBuilder().pagination(page).compile()
990
+ );
991
+ const length1 = results.instances.length;
992
+ if (results.page && results.page !== page) {
993
+ const length2 = await _countRecursive(results.page);
994
+ return length1 + length2;
995
+ }
996
+ return length1;
997
+ };
998
+ const count = async () => {
999
+ if (datastoreAdapter.count) {
1000
+ return datastoreAdapter.count(model);
1001
+ }
1002
+ return _countRecursive();
1003
+ };
1004
+ model = (0, import_merge6.default)(baseModel, {
1005
+ create,
1006
+ save,
1007
+ delete: deleteObj,
1008
+ retrieve: loadedRetrieve,
1009
+ search,
1010
+ searchOne,
1011
+ createAndSave,
1012
+ bulkInsert,
1013
+ bulkDelete,
1014
+ count
1015
+ });
1016
+ return model;
1017
+ };
1018
+ return {
1019
+ Model: ThisModel,
1020
+ fetcher
1021
+ };
1022
+ };
1023
+ // Annotate the CommonJS export names for ESM import in node:
1024
+ 0 && (module.exports = {
1025
+ createOrm
1026
+ });
1027
+ //# sourceMappingURL=models.cjs.map