@acodeninja/persist 3.0.0-next.24 → 3.0.0-next.25

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acodeninja/persist",
3
- "version": "3.0.0-next.24",
3
+ "version": "3.0.0-next.25",
4
4
  "description": "A JSON based data modelling and persistence module with alternate storage mechanisms.",
5
5
  "type": "module",
6
6
  "scripts": {
package/src/Connection.js CHANGED
@@ -42,11 +42,11 @@ export default class Connection {
42
42
  * @return {Promise<Model>}
43
43
  */
44
44
  async get(modelId) {
45
- const constructor = this.#getModelConstructorFromId(modelId);
45
+ const modelConstructor = this.#getModelConstructorFromId(modelId);
46
46
 
47
47
  const data = await this.#storage.getModel(modelId);
48
48
 
49
- return constructor.fromData(data);
49
+ return modelConstructor.fromData(data);
50
50
  }
51
51
 
52
52
  /**
@@ -157,33 +157,37 @@ export default class Connection {
157
157
  throw new ModelNotRegisteredConnectionError(modelToProcess, this.#storage);
158
158
 
159
159
  modelToProcess.validate();
160
- const currentModel = await this.get(modelToProcess.id).catch(() => null);
160
+
161
+ const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id);
162
+ const currentModel = await this.hydrate(modelToProcess).catch(() => null);
161
163
 
162
164
  const modelToProcessHasChanged = !_.isEqual(currentModel?.toData() || {}, modelToProcess.toData());
163
165
 
164
166
  if (modelToProcessHasChanged) modelsToPut.push(modelToProcess);
165
167
 
166
- const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id).name;
168
+ const modelToProcessConstructorName = modelToProcessConstructor.name;
167
169
 
168
170
  if (
169
171
  Boolean(modelToProcess.constructor.indexedProperties().length) &&
170
172
  (!currentModel || !_.isEqual(currentModel.toIndexData(), modelToProcess.toIndexData()))
171
173
  ) {
172
- modelsToReindex[modelToProcessConstructor] = modelsToReindex[modelToProcessConstructor] || [];
173
- modelsToReindex[modelToProcessConstructor].push(modelToProcess);
174
+ modelsToReindex[modelToProcessConstructorName] = modelsToReindex[modelToProcessConstructorName] || [];
175
+ modelsToReindex[modelToProcessConstructorName].push(modelToProcess);
174
176
  }
175
177
 
176
178
  if (
177
179
  Boolean(modelToProcess.constructor.searchProperties().length) &&
178
180
  (!currentModel || !_.isEqual(currentModel.toSearchData(), modelToProcess.toSearchData()))
179
181
  ) {
180
- modelsToReindexSearch[modelToProcessConstructor] = modelsToReindexSearch[modelToProcessConstructor] || [];
181
- modelsToReindexSearch[modelToProcessConstructor].push(modelToProcess);
182
+ modelsToReindexSearch[modelToProcessConstructorName] = modelsToReindexSearch[modelToProcessConstructorName] || [];
183
+ modelsToReindexSearch[modelToProcessConstructorName].push(modelToProcess);
182
184
  }
183
185
 
184
- for (const [field, value] of Object.entries(modelToProcess)) {
185
- if (Model.isModel(value)) {
186
- await processModel(modelToProcess[field]);
186
+ for (const [_name, property] of Object.entries(modelToProcess)) {
187
+ if (Model.isModel(property)) {
188
+ await processModel(property);
189
+ } else if (Array.isArray(property) && Model.isModel(property[0])) {
190
+ await Promise.all(property.map(processModel));
187
191
  }
188
192
  }
189
193
  };
@@ -251,25 +255,23 @@ export default class Connection {
251
255
 
252
256
  if (!modelsToDelete.includes(currentModel.id)) modelsToDelete.push(currentModel.id);
253
257
 
254
- const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id).name;
258
+ const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id);
255
259
 
256
- indexActions[modelToProcessConstructor] = indexActions[modelToProcessConstructor] ?? [];
257
- searchIndexActions[modelToProcessConstructor] = searchIndexActions[modelToProcessConstructor] ?? [];
260
+ indexActions[modelToProcessConstructor.name] = indexActions[modelToProcessConstructor.name] ?? [];
261
+ searchIndexActions[modelToProcessConstructor.name] = searchIndexActions[modelToProcessConstructor.name] ?? [];
258
262
 
259
- if (currentModel.constructor.indexedPropertiesResolved().length) {
260
- indexActions[modelToProcessConstructor].push(['delete', modelToProcess]);
261
- }
263
+ indexActions[modelToProcessConstructor.name].push(['delete', modelToProcess]);
262
264
 
263
265
  if (currentModel.constructor.searchProperties().length) {
264
- searchIndexActions[modelToProcessConstructor].push(['delete', modelToProcess]);
266
+ searchIndexActions[modelToProcessConstructor.name].push(['delete', modelToProcess]);
265
267
  }
266
268
 
267
269
  const linkedModels = await this.#getInstancesLinkedTo(modelToProcess, indexCache);
268
270
  const links = this.#getLinksFor(modelToProcess.constructor);
269
271
  Object.values(Object.fromEntries(await Promise.all(
270
272
  Object.entries(linkedModels)
271
- .map(async ([constructor, updatableModels]) => [
272
- constructor,
273
+ .map(async ([modelConstructor, updatableModels]) => [
274
+ modelConstructor,
273
275
  await Promise.all(updatableModels.map(async m => {
274
276
  const upToDateModel = modelCache[m.id] ?? await this.get(m.id);
275
277
  modelCache[upToDateModel.id] = upToDateModel;
@@ -289,13 +291,16 @@ export default class Connection {
289
291
  if (!modelsToDelete.includes(m.id)) modelsToDelete.push(m.id);
290
292
  modelsToProcess.push(m);
291
293
  } else {
294
+ const modelConstructor = this.#getModelConstructorFromId(m.id);
292
295
  m[linkName] = undefined;
293
296
  modelsToPut.push(m);
294
297
 
295
- indexActions[this.#getModelConstructorFromId(m.id)].push(['reindex', m]);
298
+ indexActions[modelConstructor.name] = indexActions[modelConstructor.name] ?? [];
299
+ indexActions[modelConstructor.name].push(['reindex', m]);
296
300
 
297
301
  if (m.constructor.searchProperties().length) {
298
- searchIndexActions[this.#getModelConstructorFromId(m.id)].push(['reindex', m]);
302
+ searchIndexActions[modelConstructor.name] = searchIndexActions[modelConstructor.name] ?? [];
303
+ searchIndexActions[modelConstructor.name].push(['reindex', m]);
299
304
  }
300
305
  }
301
306
  }),
@@ -309,6 +314,7 @@ export default class Connection {
309
314
  await processModel(model);
310
315
 
311
316
  const unrequestedDeletions = modelsToDelete.filter(m => !propagateTo.includes(m));
317
+
312
318
  if (unrequestedDeletions.length) {
313
319
  throw new DeleteHasUnintendedConsequencesStorageEngineError(model.id, {
314
320
  willDelete: unrequestedDeletions,
@@ -351,8 +357,8 @@ export default class Connection {
351
357
  ]);
352
358
 
353
359
  await Promise.all([
354
- Promise.all(modelsToDelete.map(m => this.#storage.deleteModel(m))),
355
360
  Promise.all(modelsToPut.map(m => this.#storage.putModel(m.toData()))),
361
+ Promise.all(modelsToDelete.map(m => this.#storage.deleteModel(m))),
356
362
  Promise.all(
357
363
  Object.entries(indexCache)
358
364
  .map(([constructorName, index]) => this.#storage.putIndex(this.#models[constructorName], index)),
@@ -377,13 +383,13 @@ export default class Connection {
377
383
  * Must include: '+foo bar' must include 'foo' and may include 'bar'
378
384
  * Must not include: '-foo bar' must not include 'foo' and may include 'bar'
379
385
  * Mixed include: '+foo -bar' must include 'foo' must not include 'bar'
380
- * @param {Model.constructor} constructor
386
+ * @param {Model.constructor} modelConstructor
381
387
  * @param {string} query
382
388
  * @return {Promise<Array<SearchResult>>}
383
389
  */
384
- async search(constructor, query) {
385
- const searchIndex = await this.#storage.getSearchIndex(constructor)
386
- .then(index => new SearchIndex(constructor, index));
390
+ async search(modelConstructor, query) {
391
+ const searchIndex = await this.#storage.getSearchIndex(modelConstructor)
392
+ .then(index => new SearchIndex(modelConstructor, index));
387
393
 
388
394
  return searchIndex.search(query);
389
395
  }
@@ -391,13 +397,13 @@ export default class Connection {
391
397
  /**
392
398
  * Find using a structured query and indexed fields.
393
399
  *
394
- * @param {Model.constructor} constructor
400
+ * @param {Model.constructor} modelConstructor
395
401
  * @param {Object} query
396
402
  * @return {Promise<Array<SearchResult>>}
397
403
  */
398
- async find(constructor, query) {
399
- const findIndex = await this.#storage.getIndex(constructor)
400
- .then(index => new FindIndex(constructor, index));
404
+ async find(modelConstructor, query) {
405
+ const findIndex = await this.#storage.getIndex(modelConstructor)
406
+ .then(index => new FindIndex(modelConstructor, index));
401
407
 
402
408
  return findIndex.query(query);
403
409
  }
@@ -467,11 +473,11 @@ export default class Connection {
467
473
  */
468
474
  #getModelConstructorFromId(modelId) {
469
475
  const modelName = modelId.split('/')[0];
470
- const constructor = this.#models[modelName];
476
+ const modelConstructor = this.#models[modelName];
471
477
 
472
- if (!constructor) throw new ModelNotRegisteredConnectionError(modelName, this.#storage);
478
+ if (!modelConstructor) throw new ModelNotRegisteredConnectionError(modelName, this.#storage);
473
479
 
474
- return constructor;
480
+ return modelConstructor;
475
481
  }
476
482
 
477
483
  /**
@@ -577,11 +583,11 @@ export class MissingArgumentsConnectionError extends ConnectionError {
577
583
  */
578
584
  export class ModelNotRegisteredConnectionError extends ConnectionError {
579
585
  /**
580
- * @param {Model|String} constructor
586
+ * @param {Model|String} modelConstructor
581
587
  * @param {Connection} connection
582
588
  */
583
- constructor(constructor, connection) {
584
- const modelName = typeof constructor === 'string' ? constructor : constructor.constructor.name;
589
+ constructor(modelConstructor, connection) {
590
+ const modelName = typeof modelConstructor === 'string' ? modelConstructor : modelConstructor.constructor.name;
585
591
  super(`The model ${modelName} is not registered in the storage engine ${connection.constructor.name}`);
586
592
  }
587
593
  }
package/src/data/Model.js CHANGED
@@ -199,6 +199,7 @@ class Model {
199
199
  .filter(([_name, type]) => !type._type && !this.isModel(type) && !type._items?._type && (this.isModel(type._items) || this.isModel(type()._items)))
200
200
  .map(([name, _type]) => `${name}.[*].id`),
201
201
  ...this.indexedProperties(),
202
+ 'id',
202
203
  ];
203
204
  }
204
205