@acodeninja/persist 3.0.0-next.26 → 3.0.0-next.28

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.
package/src/Schema.js CHANGED
@@ -14,7 +14,7 @@ class Schema {
14
14
  * It uses AJV for the validation process and integrates with model types and their specific validation rules.
15
15
  *
16
16
  * @param {Object|Model} rawSchema - The raw schema or model definition to be compiled.
17
- * @returns {CompiledSchema} - A class that extends `CompiledSchema`, with the compiled schema and validator attached.
17
+ * @returns {CompiledSchema} - A compiled schema, ready to validate instances of the model.
18
18
  *
19
19
  * @example
20
20
  * const schemaClass = Schema.compile(MyModelSchema);
@@ -39,7 +39,7 @@ class Schema {
39
39
  const thisSchema = {};
40
40
 
41
41
  if (Model.isModel(schemaSegment)) {
42
- thisSchema.required = ['id'];
42
+ thisSchema.required = [];
43
43
  thisSchema.type = 'object';
44
44
  thisSchema.additionalProperties = false;
45
45
  thisSchema.properties = {
@@ -62,7 +62,7 @@ class Schema {
62
62
  thisSchema.properties[name] = {
63
63
  type: 'object',
64
64
  additionalProperties: false,
65
- required: ['id'],
65
+ required: [],
66
66
  properties: {
67
67
  id: {
68
68
  type: 'string',
package/src/data/Model.js CHANGED
@@ -151,6 +151,8 @@ class Model {
151
151
  * @static
152
152
  */
153
153
  static get required() {
154
+ const ThisModel = this;
155
+
154
156
  /**
155
157
  * A subclass of the current model with the `_required` flag set to `true`.
156
158
  * Used to indicate that the property is required during validation or schema generation.
@@ -159,11 +161,11 @@ class Model {
159
161
  * @extends {Model}
160
162
  * @private
161
163
  */
162
- class Required extends this {
164
+ class Required extends ThisModel {
163
165
  static _required = true;
164
166
  }
165
167
 
166
- Object.defineProperty(Required, 'name', {value: `${this.toString()}`});
168
+ Object.defineProperty(Required, 'name', {value: ThisModel.name});
167
169
 
168
170
  return Required;
169
171
  }
@@ -192,11 +194,17 @@ class Model {
192
194
  */
193
195
  static indexedPropertiesResolved() {
194
196
  return [
195
- ...Object.entries(this)
196
- .filter(([_name, type]) => !type._type && (this.isModel(type) || this.isModel(type())))
197
+ ...Object.entries(this.properties)
198
+ .filter(([name, type]) => !['indexedProperties', 'searchProperties'].includes(name) && !type._type && (this.isModel(type) || (typeof type === 'function' && this.isModel(type()))))
197
199
  .map(([name, _type]) => `${name}.id`),
198
- ...Object.entries(this)
199
- .filter(([_name, type]) => !type._type && !this.isModel(type) && !type._items?._type && (this.isModel(type._items) || this.isModel(type()._items)))
200
+ ...Object.entries(this.properties)
201
+ .filter(([_name, type]) => {
202
+ return !Model.isModel(type) && (
203
+ (type._type === 'array' && this.isModel(type._items))
204
+ ||
205
+ (!type._type && typeof type === 'function' && this.isModel(type()._items))
206
+ );
207
+ })
200
208
  .map(([name, _type]) => `${name}.[*].id`),
201
209
  ...this.indexedProperties(),
202
210
  'id',
@@ -285,16 +293,62 @@ class Model {
285
293
  * @static
286
294
  *
287
295
  * @example
288
- * export default class TestModel {
296
+ * export default class TestModel extends Model {
289
297
  * static {
290
- * this.withName('TestModel');
291
- * this.string = Persist.Type.String;
298
+ * TestModel.withName('TestModel');
299
+ * TestModel.string = Persist.Property.String;
292
300
  * }
293
301
  * }
294
302
  */
295
303
  static withName(name) {
296
304
  Object.defineProperty(this, 'name', {value: name});
297
305
  }
306
+
307
+ /**
308
+ * Discover model properties all the way up the prototype chain.
309
+ *
310
+ * @return {Model}
311
+ */
312
+ static get properties() {
313
+ const modelClass = this;
314
+ const props = {};
315
+ const chain = [];
316
+
317
+ let current = modelClass;
318
+ while (current !== Function.prototype) {
319
+ chain.push(current);
320
+ current = Object.getPrototypeOf(current);
321
+ }
322
+
323
+ for (const item of chain) {
324
+ for (const property of Object.getOwnPropertyNames(item)) {
325
+ if (
326
+ [
327
+ '_required',
328
+ 'fromData',
329
+ 'indexedProperties',
330
+ 'indexedPropertiesResolved',
331
+ 'isDryModel',
332
+ 'isModel',
333
+ 'length',
334
+ 'name',
335
+ 'properties',
336
+ 'prototype',
337
+ 'required',
338
+ 'searchProperties',
339
+ 'toString',
340
+ 'withName',
341
+ ].includes(property)
342
+ ) continue;
343
+
344
+ if (Object.keys(props).includes(property)) continue;
345
+
346
+ props[property] = item[property];
347
+ }
348
+ }
349
+
350
+ return Object.assign(modelClass, props);
351
+ }
298
352
  }
299
353
 
300
354
  export default Model;
@@ -5,6 +5,7 @@ import DateType from './properties/DateType.js';
5
5
  import NumberType from './properties/NumberType.js';
6
6
  import SlugType from './properties/SlugType.js';
7
7
  import StringType from './properties/StringType.js';
8
+ import Type from './properties/Type.js';
8
9
 
9
10
  const Property = {
10
11
  Array: ArrayType,
@@ -14,6 +15,7 @@ const Property = {
14
15
  Number: NumberType,
15
16
  Slug: SlugType,
16
17
  String: StringType,
18
+ Type,
17
19
  };
18
20
 
19
21
  export default Property;
@@ -51,12 +51,14 @@ class ArrayType {
51
51
  * const requiredArrayOfStrings = ArrayType.of(StringType).required;
52
52
  */
53
53
  static get required() {
54
+ const ThisType = this;
55
+
54
56
  /**
55
57
  * @class RequiredArrayOf
56
58
  * @extends ArrayOf
57
59
  * Represents a required array of a specific type.
58
60
  */
59
- class Required extends this {
61
+ class Required extends ThisType {
60
62
  /** @type {boolean} Indicates that the array is required */
61
63
  static _required = true;
62
64
 
@@ -70,7 +72,7 @@ class ArrayType {
70
72
  }
71
73
  }
72
74
 
73
- Object.defineProperty(Required, 'name', {value: `Required${this.toString()}`});
75
+ Object.defineProperty(Required, 'name', {value: `Required${ThisType.name}`});
74
76
 
75
77
  return Required;
76
78
  }
@@ -15,9 +15,9 @@ class BooleanType extends Type {
15
15
  * @static
16
16
  * @property {string} _type - The type identifier for BooleanType, set to `'boolean'`.
17
17
  */
18
- this._type = 'boolean';
18
+ BooleanType._type = 'boolean';
19
19
 
20
- Object.defineProperty(this, 'name', {value: 'Boolean'});
20
+ Object.defineProperty(BooleanType, 'name', {value: 'Boolean'});
21
21
  }
22
22
  }
23
23
 
@@ -37,12 +37,12 @@ class CustomType {
37
37
  class Custom extends Type {
38
38
  static {
39
39
  /** @type {string} The data type, which is 'object' */
40
- this._type = 'object';
40
+ Custom._type = 'object';
41
41
 
42
42
  /** @type {Object} The JSON schema that defines the structure and validation rules */
43
- this._schema = schema;
43
+ Custom._schema = schema;
44
44
 
45
- Object.defineProperty(this, 'name', {value: 'Custom'});
45
+ Object.defineProperty(Custom, 'name', {value: 'Custom'});
46
46
  }
47
47
  }
48
48
 
@@ -50,7 +50,7 @@ class CustomType {
50
50
  }
51
51
 
52
52
  static {
53
- Object.defineProperty(this, 'name', {value: 'Custom'});
53
+ Object.defineProperty(CustomType, 'name', {value: 'Custom'});
54
54
  }
55
55
  }
56
56
 
@@ -15,15 +15,15 @@ class DateType extends Type {
15
15
  * @static
16
16
  * @property {string} _type - The type identifier for DateType, set to `'string'`.
17
17
  */
18
- this._type = 'string';
18
+ DateType._type = 'string';
19
19
 
20
20
  /**
21
21
  * @static
22
22
  * @property {string} _format - The format for DateType, set to `'iso-date-time'`.
23
23
  */
24
- this._format = 'iso-date-time';
24
+ DateType._format = 'iso-date-time';
25
25
 
26
- Object.defineProperty(this, 'name', {value: 'Date'});
26
+ Object.defineProperty(DateType, 'name', {value: 'Date'});
27
27
  }
28
28
 
29
29
  /**
@@ -15,9 +15,9 @@ class NumberType extends Type {
15
15
  * @static
16
16
  * @property {string} _type - The type identifier for NumberType, set to `'number'`.
17
17
  */
18
- this._type = 'number';
18
+ NumberType._type = 'number';
19
19
 
20
- Object.defineProperty(this, 'name', {value: 'Number'});
20
+ Object.defineProperty(NumberType, 'name', {value: 'Number'});
21
21
  }
22
22
  }
23
23
 
@@ -65,7 +65,7 @@ class SlugType extends ResolvedType {
65
65
  }
66
66
 
67
67
  static {
68
- Object.defineProperty(this, 'name', {value: 'Slug'});
68
+ Object.defineProperty(SlugType, 'name', {value: 'Slug'});
69
69
  }
70
70
  }
71
71
 
@@ -15,9 +15,9 @@ class StringType extends Type {
15
15
  * @static
16
16
  * @property {string} _type - The type identifier for the string type.
17
17
  */
18
- this._type = 'string';
18
+ StringType._type = 'string';
19
19
 
20
- Object.defineProperty(this, 'name', {value: 'String'});
20
+ Object.defineProperty(StringType, 'name', {value: 'String'});
21
21
  }
22
22
  }
23
23
 
@@ -53,6 +53,8 @@ class Type {
53
53
  * @returns {Type} A subclass of the current type with `_required` set to `true`.
54
54
  */
55
55
  static get required() {
56
+ const ThisType = this;
57
+
56
58
  /**
57
59
  * A subclass of the current type with the `_required` flag set to `true`.
58
60
  * Used to indicate that the property is required during validation or schema generation.
@@ -61,18 +63,18 @@ class Type {
61
63
  * @extends {Type}
62
64
  * @private
63
65
  */
64
- class Required extends this {
66
+ class Required extends ThisType {
65
67
  static _required = true;
66
68
  }
67
69
 
68
70
  // Define the class name as "Required<OriginalTypeName>"
69
- Object.defineProperty(Required, 'name', {value: `Required${this.toString()}`});
71
+ Object.defineProperty(Required, 'name', {value: `Required${ThisType.name}`});
70
72
 
71
73
  return Required;
72
74
  }
73
75
 
74
76
  static {
75
- Object.defineProperty(this, 'name', {value: 'Type'});
77
+ Object.defineProperty(Type, 'name', {value: 'Type'});
76
78
  }
77
79
  }
78
80
 
@@ -132,7 +132,9 @@ export class ModelNotFoundStorageEngineError extends StorageEngineError {
132
132
  export class DeleteHasUnintendedConsequencesStorageEngineError extends StorageEngineError {
133
133
  /**
134
134
  * @param {string} modelId
135
- * @param {object} consequences
135
+ * @param {Object} consequences
136
+ * @param {Array<String>?} consequences.willDelete
137
+ * @param {Array<String>?} consequences.willUpdate
136
138
  */
137
139
  constructor(modelId, consequences) {
138
140
  super(`Deleting ${modelId} has unintended consequences`);