@acodeninja/persist 3.0.0-next.12 → 3.0.0-next.13
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/README.md +58 -4
- package/docs/code-quirks.md +6 -6
- package/docs/defining-models.md +61 -0
- package/docs/future-interface.md +29 -0
- package/docs/http.openapi.yml +138 -0
- package/docs/{model-property-types.md → model-properties.md} +37 -35
- package/docs/models-as-properties.md +40 -40
- package/docs/search-queries.md +3 -5
- package/docs/storage-engines.md +15 -32
- package/docs/structured-queries.md +56 -45
- package/docs/transactions.md +6 -7
- package/exports/storage/http.js +3 -0
- package/exports/storage/s3.js +3 -0
- package/jest.config.cjs +8 -12
- package/package.json +2 -2
- package/src/Connection.js +610 -0
- package/src/Persist.js +27 -30
- package/src/Schema.js +166 -0
- package/src/{Query.js → data/FindIndex.js} +37 -22
- package/src/{type → data}/Model.js +14 -30
- package/src/data/Property.js +19 -0
- package/src/data/SearchIndex.js +19 -4
- package/src/{type/complex → data/properties}/ArrayType.js +1 -1
- package/src/{type/simple → data/properties}/BooleanType.js +1 -1
- package/src/{type/complex → data/properties}/CustomType.js +1 -1
- package/src/{type/simple → data/properties}/DateType.js +1 -1
- package/src/{type/simple → data/properties}/NumberType.js +1 -1
- package/src/{type/resolved → data/properties}/ResolvedType.js +3 -2
- package/src/{type/simple → data/properties}/StringType.js +1 -1
- package/src/engine/storage/HTTPStorageEngine.js +149 -253
- package/src/engine/storage/S3StorageEngine.js +108 -195
- package/src/engine/storage/StorageEngine.js +114 -550
- package/exports/engine/storage/file.js +0 -3
- package/exports/engine/storage/http.js +0 -3
- package/exports/engine/storage/s3.js +0 -3
- package/src/SchemaCompiler.js +0 -196
- package/src/Transactions.js +0 -145
- package/src/engine/StorageEngine.js +0 -517
- package/src/engine/storage/FileStorageEngine.js +0 -213
- package/src/type/index.js +0 -32
- /package/src/{type/resolved → data/properties}/SlugType.js +0 -0
- /package/src/{type → data/properties}/Type.js +0 -0
@@ -1,517 +0,0 @@
|
|
1
|
-
import Type from '../type/index.js';
|
2
|
-
import _ from 'lodash';
|
3
|
-
|
4
|
-
export default class StorageEngine {
|
5
|
-
/**
|
6
|
-
* @param {Object} configuration
|
7
|
-
* @param {Array<Type.Model.constructor>?} models
|
8
|
-
*/
|
9
|
-
constructor(configuration = {}, models = null) {
|
10
|
-
this.configuration = configuration;
|
11
|
-
this.models = Object.fromEntries((models ?? []).map(model => [model.name, model]));
|
12
|
-
}
|
13
|
-
|
14
|
-
/**
|
15
|
-
* Persists a model if it has changed, and updates all related models and their indexes
|
16
|
-
* @param {Type.Model} model
|
17
|
-
* @return {Promise<void>}
|
18
|
-
*/
|
19
|
-
async put(model) {
|
20
|
-
const processedModels = [];
|
21
|
-
const modelsToPut = [];
|
22
|
-
const modelsToReindex = {};
|
23
|
-
const modelsToReindexSearch = {};
|
24
|
-
|
25
|
-
/**
|
26
|
-
* @param {Type.Model} modelToProcess
|
27
|
-
* @return {Promise<void>}
|
28
|
-
*/
|
29
|
-
const processModel = async (modelToProcess) => {
|
30
|
-
if (processedModels.includes(modelToProcess.id))
|
31
|
-
return;
|
32
|
-
|
33
|
-
processedModels.push(modelToProcess.id);
|
34
|
-
|
35
|
-
if (!Object.keys(this.models).includes(modelToProcess.constructor.name))
|
36
|
-
throw new ModelNotRegisteredStorageEngineError(modelToProcess, this);
|
37
|
-
|
38
|
-
modelToProcess.validate();
|
39
|
-
const currentModel = await this.get(modelToProcess.id).catch(() => null);
|
40
|
-
|
41
|
-
const modelToProcessHasChanged = JSON.stringify(currentModel?.toData() || {}) !== JSON.stringify(modelToProcess.toData());
|
42
|
-
|
43
|
-
if (modelToProcessHasChanged) modelsToPut.push(modelToProcess);
|
44
|
-
|
45
|
-
if (
|
46
|
-
Boolean(modelToProcess.constructor.indexedProperties().length) &&
|
47
|
-
indexedFieldsHaveChanged(currentModel, modelToProcess)
|
48
|
-
) {
|
49
|
-
const modelToProcessConstructor = this.getModelConstructorFromId(modelToProcess.id);
|
50
|
-
modelsToReindex[modelToProcessConstructor] = modelsToReindex[modelToProcessConstructor] || [];
|
51
|
-
modelsToReindex[modelToProcessConstructor].push(modelToProcess);
|
52
|
-
}
|
53
|
-
|
54
|
-
if (
|
55
|
-
Boolean(modelToProcess.constructor.searchProperties().length) &&
|
56
|
-
searchableFieldsHaveChanged(currentModel, modelToProcess)
|
57
|
-
) {
|
58
|
-
const modelToProcessConstructor = this.getModelConstructorFromId(modelToProcess.id);
|
59
|
-
modelsToReindexSearch[modelToProcessConstructor] = modelsToReindexSearch[modelToProcessConstructor] || [];
|
60
|
-
modelsToReindexSearch[modelToProcessConstructor].push(modelToProcess);
|
61
|
-
}
|
62
|
-
|
63
|
-
for (const [field, value] of Object.entries(modelToProcess)) {
|
64
|
-
if (Type.Model.isModel(value)) {
|
65
|
-
await processModel(modelToProcess[field]);
|
66
|
-
}
|
67
|
-
}
|
68
|
-
};
|
69
|
-
|
70
|
-
await processModel(model);
|
71
|
-
|
72
|
-
await Promise.all([
|
73
|
-
Promise.all(modelsToPut.map(m => this._putModel(m.toData()))),
|
74
|
-
Promise.all(Object.entries(modelsToReindex).map(async ([constructorName, models]) => {
|
75
|
-
const modelConstructor = this.models[constructorName];
|
76
|
-
const index = await this._getIndex(modelConstructor);
|
77
|
-
|
78
|
-
await this._putIndex(modelConstructor, {
|
79
|
-
...index || {},
|
80
|
-
...Object.fromEntries(models.map(m => [m.id, m.toIndexData()])),
|
81
|
-
});
|
82
|
-
})),
|
83
|
-
Promise.all(Object.entries(modelsToReindexSearch).map(async ([constructorName, models]) => {
|
84
|
-
const modelConstructor = this.models[constructorName];
|
85
|
-
const index = await this._getSearchIndex(modelConstructor);
|
86
|
-
|
87
|
-
await this._putSearchIndex(modelConstructor, {
|
88
|
-
...index || {},
|
89
|
-
...Object.fromEntries(models.map(m => [m.id, m.toSearchData()])),
|
90
|
-
});
|
91
|
-
})),
|
92
|
-
]);
|
93
|
-
}
|
94
|
-
|
95
|
-
/**
|
96
|
-
* Get a model by its id
|
97
|
-
* @param {string} modelId
|
98
|
-
* @throws {ModelNotFoundStorageEngineError}
|
99
|
-
* @return {Promise<Type.Model>}
|
100
|
-
*/
|
101
|
-
get(modelId) {
|
102
|
-
try {
|
103
|
-
this.getModelConstructorFromId(modelId);
|
104
|
-
} catch (e) {
|
105
|
-
return Promise.reject(e);
|
106
|
-
}
|
107
|
-
return this._getModel(modelId);
|
108
|
-
}
|
109
|
-
|
110
|
-
/**
|
111
|
-
* Delete a model and update indexes that reference it
|
112
|
-
* @param {Type.Model} model
|
113
|
-
* @param {Array<string>} propagateTo - List of model ids that are expected to be deleted
|
114
|
-
* @throws {ModelNotRegisteredStorageEngineError}
|
115
|
-
* @throws {ModelNotFoundStorageEngineError}
|
116
|
-
*/
|
117
|
-
async delete(model, propagateTo = []) {
|
118
|
-
const processedModels = [];
|
119
|
-
const modelsToDelete = [];
|
120
|
-
const modelsToPut = [];
|
121
|
-
const indexCache = {};
|
122
|
-
const indexActions = {};
|
123
|
-
const searchIndexCache = {};
|
124
|
-
const searchIndexActions = {};
|
125
|
-
const modelCache = {};
|
126
|
-
|
127
|
-
propagateTo.push(model.id);
|
128
|
-
|
129
|
-
/**
|
130
|
-
* Process a model for deletion
|
131
|
-
* @param {Type.Model} modelToProcess
|
132
|
-
* @return {Promise<void>}
|
133
|
-
*/
|
134
|
-
const processModel = async (modelToProcess) => {
|
135
|
-
if (processedModels.includes(modelToProcess.id)) return;
|
136
|
-
processedModels.push(modelToProcess.id);
|
137
|
-
|
138
|
-
const modelsToProcess = [];
|
139
|
-
if (!Object.keys(this.models).includes(modelToProcess.constructor.name))
|
140
|
-
throw new ModelNotRegisteredStorageEngineError(modelToProcess, this);
|
141
|
-
|
142
|
-
const currentModel = modelCache[model.id] ?? await this.get(model.id);
|
143
|
-
modelCache[currentModel.id] = currentModel;
|
144
|
-
|
145
|
-
if (!modelsToDelete.includes(currentModel.id)) modelsToDelete.push(currentModel.id);
|
146
|
-
|
147
|
-
const modelToProcessConstructor = this.getModelConstructorFromId(modelToProcess.id);
|
148
|
-
indexActions[modelToProcessConstructor] = indexActions[modelToProcessConstructor] ?? [];
|
149
|
-
searchIndexActions[modelToProcessConstructor] = searchIndexActions[modelToProcessConstructor] ?? [];
|
150
|
-
|
151
|
-
if (currentModel.constructor.indexedPropertiesResolved().length) {
|
152
|
-
indexActions[modelToProcessConstructor].push(['delete', modelToProcess]);
|
153
|
-
}
|
154
|
-
|
155
|
-
if (currentModel.constructor.searchProperties().length) {
|
156
|
-
searchIndexActions[modelToProcessConstructor].push(['delete', modelToProcess]);
|
157
|
-
}
|
158
|
-
|
159
|
-
const linkedModels = await this.getInstancesLinkedTo(modelToProcess, indexCache);
|
160
|
-
const links = this.getLinksFor(modelToProcess.constructor);
|
161
|
-
Object.values(Object.fromEntries(await Promise.all(
|
162
|
-
Object.entries(linkedModels)
|
163
|
-
.map(async ([constructor, updatableModels]) => [
|
164
|
-
constructor,
|
165
|
-
await Promise.all(updatableModels.map(async m => {
|
166
|
-
const upToDateModel = modelCache[m.id] ?? await this.get(m.id);
|
167
|
-
modelCache[upToDateModel.id] = upToDateModel;
|
168
|
-
return upToDateModel;
|
169
|
-
})),
|
170
|
-
]),
|
171
|
-
))).flat(1)
|
172
|
-
.forEach(m =>
|
173
|
-
Object.entries(links[m.constructor.name])
|
174
|
-
.forEach(([linkName, modelConstructor]) => {
|
175
|
-
if ((
|
176
|
-
typeof modelConstructor[linkName] === 'function' &&
|
177
|
-
!/^class/.test(Function.prototype.toString.call(modelConstructor[linkName])) &&
|
178
|
-
!Type.Model.isModel(modelConstructor[linkName]) ?
|
179
|
-
modelConstructor[linkName]() : modelConstructor
|
180
|
-
)._required) {
|
181
|
-
if (!modelsToDelete.includes(m.id)) modelsToDelete.push(m.id);
|
182
|
-
modelsToProcess.push(m);
|
183
|
-
} else {
|
184
|
-
m[linkName] = undefined;
|
185
|
-
modelsToPut.push(m);
|
186
|
-
|
187
|
-
indexActions[this.getModelConstructorFromId(m.id)].push(['reindex', m]);
|
188
|
-
|
189
|
-
if (m.constructor.searchProperties().length) {
|
190
|
-
searchIndexActions[this.getModelConstructorFromId(m.id)].push(['reindex', m]);
|
191
|
-
}
|
192
|
-
}
|
193
|
-
}),
|
194
|
-
);
|
195
|
-
|
196
|
-
for (const modelToBeProcessed of modelsToProcess) {
|
197
|
-
await processModel(modelToBeProcessed);
|
198
|
-
}
|
199
|
-
};
|
200
|
-
|
201
|
-
await processModel(model);
|
202
|
-
|
203
|
-
const unrequestedDeletions = modelsToDelete.filter(m => !propagateTo.includes(m));
|
204
|
-
if (unrequestedDeletions.length) {
|
205
|
-
throw new DeleteHasUnintendedConsequencesStorageEngineError(model.id, {
|
206
|
-
willDelete: unrequestedDeletions,
|
207
|
-
});
|
208
|
-
}
|
209
|
-
|
210
|
-
await Promise.all([
|
211
|
-
Promise.all(Object.entries(indexActions).map(async ([constructorName, actions]) => {
|
212
|
-
const modelConstructor = this.models[constructorName];
|
213
|
-
indexCache[modelConstructor] = indexCache[modelConstructor] ?? await this._getIndex(modelConstructor);
|
214
|
-
|
215
|
-
actions.forEach(([action, actionModel]) => {
|
216
|
-
if (action === 'delete') {
|
217
|
-
indexCache[modelConstructor] = _.omit(indexCache[modelConstructor], [actionModel.id]);
|
218
|
-
}
|
219
|
-
if (action === 'reindex') {
|
220
|
-
indexCache[modelConstructor] = {
|
221
|
-
...indexCache[modelConstructor],
|
222
|
-
[actionModel.id]: actionModel.toIndexData(),
|
223
|
-
};
|
224
|
-
}
|
225
|
-
});
|
226
|
-
})),
|
227
|
-
Promise.all(Object.entries(searchIndexActions).map(async ([constructorName, actions]) => {
|
228
|
-
const modelConstructor = this.models[constructorName];
|
229
|
-
searchIndexCache[modelConstructor] = searchIndexCache[modelConstructor] ?? await this._getSearchIndex(modelConstructor);
|
230
|
-
|
231
|
-
actions.forEach(([action, actionModel]) => {
|
232
|
-
if (action === 'delete') {
|
233
|
-
searchIndexCache[modelConstructor] = _.omit(searchIndexCache[modelConstructor], [actionModel.id]);
|
234
|
-
}
|
235
|
-
if (action === 'reindex') {
|
236
|
-
searchIndexCache[modelConstructor] = {
|
237
|
-
...searchIndexCache[modelConstructor],
|
238
|
-
[actionModel.id]: actionModel.toSearchData(),
|
239
|
-
};
|
240
|
-
}
|
241
|
-
});
|
242
|
-
})),
|
243
|
-
]);
|
244
|
-
|
245
|
-
await Promise.all([
|
246
|
-
Promise.all(modelsToDelete.map(m => this._deleteModel(m))),
|
247
|
-
Promise.all(modelsToPut.map(m => this._putModel(m))),
|
248
|
-
Promise.all(
|
249
|
-
Object.entries(indexCache)
|
250
|
-
.map(([constructorName, index]) => this._putIndex(this.models[constructorName], index)),
|
251
|
-
),
|
252
|
-
Promise.all(
|
253
|
-
Object.entries(searchIndexCache)
|
254
|
-
.map(([constructorName, index]) => this._putSearchIndex(this.models[constructorName], index)),
|
255
|
-
),
|
256
|
-
]);
|
257
|
-
}
|
258
|
-
|
259
|
-
/**
|
260
|
-
* Get the model constructor from a model id
|
261
|
-
* @param {string} modelId
|
262
|
-
* @return {Model.constructor}
|
263
|
-
*/
|
264
|
-
getModelConstructorFromId(modelId) {
|
265
|
-
const modelName = modelId.split('/')[0];
|
266
|
-
const constructor = this.models[modelName];
|
267
|
-
|
268
|
-
if (!constructor) throw new ModelNotRegisteredStorageEngineError(modelName, this);
|
269
|
-
|
270
|
-
return constructor;
|
271
|
-
}
|
272
|
-
|
273
|
-
/**
|
274
|
-
* Get model instance that are directly linked to the given model in either direction
|
275
|
-
* @param {Type.Model} model
|
276
|
-
* @param {object} cache
|
277
|
-
* @return {Record<string, Record<string, Type.Model>>}
|
278
|
-
*/
|
279
|
-
async getInstancesLinkedTo(model, cache = {}) {
|
280
|
-
return Object.fromEntries(
|
281
|
-
Object.entries(
|
282
|
-
await Promise.all(
|
283
|
-
Object.entries(this.getLinksFor(model.constructor))
|
284
|
-
.map(([name, _index]) =>
|
285
|
-
cache[name] ? Promise.resolve([name, Object.values(cache[name])]) :
|
286
|
-
this._getIndex(this.models[name])
|
287
|
-
.then(i => {
|
288
|
-
cache[name] = i;
|
289
|
-
return [name, Object.values(i)];
|
290
|
-
}),
|
291
|
-
),
|
292
|
-
).then(Object.fromEntries),
|
293
|
-
).map(([name, index]) => [
|
294
|
-
name,
|
295
|
-
index.map(item => Object.fromEntries(
|
296
|
-
Object.entries(item)
|
297
|
-
.filter(([propertyName, property]) => propertyName === 'id' || property?.id === model.id),
|
298
|
-
)).filter(item => Object.keys(item).length > 1),
|
299
|
-
]),
|
300
|
-
);
|
301
|
-
}
|
302
|
-
|
303
|
-
/**
|
304
|
-
* Get model classes that are directly linked to the given model in either direction
|
305
|
-
* @param {Type.Model.constructor} model
|
306
|
-
* @return {Record<string, Record<string, Type.Model.constructor>>}
|
307
|
-
*/
|
308
|
-
getLinksFor(model) {
|
309
|
-
return Object.fromEntries(
|
310
|
-
Object.entries(this.getAllModelLinks())
|
311
|
-
.filter(([modelName, links]) =>
|
312
|
-
model.name === modelName ||
|
313
|
-
Object.values(links).some((link) => link.name === model.name),
|
314
|
-
),
|
315
|
-
);
|
316
|
-
}
|
317
|
-
|
318
|
-
/**
|
319
|
-
* Get all model links
|
320
|
-
* @return {Record<string, Record<string, Type.Model.constructor>>}
|
321
|
-
*/
|
322
|
-
getAllModelLinks() {
|
323
|
-
return Object.entries(this.models)
|
324
|
-
.map(([registeredModelName, registeredModelClass]) =>
|
325
|
-
Object.entries(registeredModelClass)
|
326
|
-
.map(([propertyName, propertyType]) => [
|
327
|
-
registeredModelName,
|
328
|
-
propertyName,
|
329
|
-
typeof propertyType === 'function' &&
|
330
|
-
!/^class/.test(Function.prototype.toString.call(propertyType)) &&
|
331
|
-
!Type.Model.isModel(propertyType) ?
|
332
|
-
propertyType() : propertyType,
|
333
|
-
])
|
334
|
-
.filter(([_m, _p, type]) => Type.Model.isModel(type))
|
335
|
-
.map(([containingModel, propertyName, propertyType]) => ({
|
336
|
-
containingModel,
|
337
|
-
propertyName,
|
338
|
-
propertyType,
|
339
|
-
})),
|
340
|
-
)
|
341
|
-
.flat()
|
342
|
-
.reduce((accumulator, {containingModel, propertyName, propertyType}) => ({
|
343
|
-
...accumulator,
|
344
|
-
[containingModel]: {
|
345
|
-
...accumulator[containingModel] || {},
|
346
|
-
[propertyName]: propertyType,
|
347
|
-
},
|
348
|
-
}), {});
|
349
|
-
}
|
350
|
-
|
351
|
-
/**
|
352
|
-
* Update a model
|
353
|
-
* @param {Model} _model
|
354
|
-
* @throws MethodNotImplementedStorageEngineError
|
355
|
-
* @return Promise<void>
|
356
|
-
*/
|
357
|
-
_putModel(_model) {
|
358
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_putModel', this));
|
359
|
-
}
|
360
|
-
|
361
|
-
/**
|
362
|
-
* Get a model
|
363
|
-
* @param {string} _id
|
364
|
-
* @throws MethodNotImplementedStorageEngineError
|
365
|
-
* @throws ModelNotFoundStorageEngineError
|
366
|
-
* @return Promise<Model>
|
367
|
-
*/
|
368
|
-
_getModel(_id) {
|
369
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_getModel', this));
|
370
|
-
}
|
371
|
-
|
372
|
-
/**
|
373
|
-
* Delete a model
|
374
|
-
* @param {string} _id
|
375
|
-
* @throws MethodNotImplementedStorageEngineError
|
376
|
-
* @throws ModelNotFoundStorageEngineError
|
377
|
-
* @return Promise<void>
|
378
|
-
*/
|
379
|
-
_deleteModel(_id) {
|
380
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_deleteModel', this));
|
381
|
-
}
|
382
|
-
|
383
|
-
/**
|
384
|
-
* Get a model's index data
|
385
|
-
* @param {Model.constructor} _modelConstructor
|
386
|
-
* @throws MethodNotImplementedStorageEngineError
|
387
|
-
* @return Promise<void>
|
388
|
-
*/
|
389
|
-
_getIndex(_modelConstructor) {
|
390
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_getIndex', this));
|
391
|
-
}
|
392
|
-
|
393
|
-
/**
|
394
|
-
* Put a model's index data
|
395
|
-
* @param {Model.constructor} _modelConstructor
|
396
|
-
* @param {object} _data
|
397
|
-
* @throws MethodNotImplementedStorageEngineError
|
398
|
-
* @return Promise<void>
|
399
|
-
*/
|
400
|
-
_putIndex(_modelConstructor, _data) {
|
401
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_putIndex', this));
|
402
|
-
}
|
403
|
-
|
404
|
-
/**
|
405
|
-
* Get a model's raw search index data
|
406
|
-
* @param {Model.constructor} _modelConstructor
|
407
|
-
* @throws MethodNotImplementedStorageEngineError
|
408
|
-
* @return Promise<void>
|
409
|
-
*/
|
410
|
-
_getSearchIndex(_modelConstructor) {
|
411
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_getSearchIndex', this));
|
412
|
-
}
|
413
|
-
|
414
|
-
/**
|
415
|
-
* Get a model's raw search index data
|
416
|
-
* @param {Model.constructor} _modelConstructor
|
417
|
-
* @throws MethodNotImplementedStorageEngineError
|
418
|
-
* @return Promise<void>
|
419
|
-
*/
|
420
|
-
_getSearchIndexCompiled(_modelConstructor) {
|
421
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_getSearchIndexCompiled', this));
|
422
|
-
}
|
423
|
-
|
424
|
-
/**
|
425
|
-
* Put a model's raw and compiled search index data
|
426
|
-
* @param {Model.constructor} _modelConstructor
|
427
|
-
* @param {object} _data
|
428
|
-
* @throws MethodNotImplementedStorageEngineError
|
429
|
-
* @return Promise<void>
|
430
|
-
*/
|
431
|
-
_putSearchIndex(_modelConstructor, _data) {
|
432
|
-
return Promise.reject(new MethodNotImplementedStorageEngineError('_putSearchIndex', this));
|
433
|
-
}
|
434
|
-
}
|
435
|
-
|
436
|
-
|
437
|
-
/**
|
438
|
-
* Decide if two models indexable fields are different
|
439
|
-
* @param {Type.Model} currentModel
|
440
|
-
* @param {Type.Model} modelToProcess
|
441
|
-
* @return {boolean}
|
442
|
-
* @private
|
443
|
-
*/
|
444
|
-
function indexedFieldsHaveChanged(currentModel, modelToProcess) {
|
445
|
-
return !currentModel || JSON.stringify(currentModel.toIndexData()) !== JSON.stringify(modelToProcess.toIndexData());
|
446
|
-
}
|
447
|
-
|
448
|
-
/**
|
449
|
-
* Decide if two models searchable fields have changed
|
450
|
-
* @param {Type.Model} currentModel
|
451
|
-
* @param {Type.Model} modelToProcess
|
452
|
-
* @return {boolean}
|
453
|
-
* @private
|
454
|
-
*/
|
455
|
-
function searchableFieldsHaveChanged(currentModel, modelToProcess) {
|
456
|
-
return !currentModel || JSON.stringify(currentModel.toSearchData()) !== JSON.stringify(modelToProcess.toSearchData());
|
457
|
-
}
|
458
|
-
|
459
|
-
/**
|
460
|
-
* @class StorageEngineError
|
461
|
-
* @extends Error
|
462
|
-
*/
|
463
|
-
export class StorageEngineError extends Error {
|
464
|
-
}
|
465
|
-
|
466
|
-
/**
|
467
|
-
* @class ModelNotRegisteredStorageEngineError
|
468
|
-
* @extends StorageEngineError
|
469
|
-
*/
|
470
|
-
export class ModelNotRegisteredStorageEngineError extends StorageEngineError {
|
471
|
-
/**
|
472
|
-
* @param {Type.Model} model
|
473
|
-
* @param {StorageEngine} storageEngine
|
474
|
-
*/
|
475
|
-
constructor(model, storageEngine) {
|
476
|
-
const modelName = typeof model === 'string' ? model : model.constructor.name;
|
477
|
-
super(`The model ${modelName} is not registered in the storage engine ${storageEngine.constructor.name}`);
|
478
|
-
}
|
479
|
-
}
|
480
|
-
|
481
|
-
/**
|
482
|
-
* @class MethodNotImplementedStorageEngineError
|
483
|
-
* @extends StorageEngineError
|
484
|
-
*/
|
485
|
-
export class MethodNotImplementedStorageEngineError extends StorageEngineError {
|
486
|
-
/**
|
487
|
-
* @param {string} method
|
488
|
-
* @param {StorageEngine} storageEngine
|
489
|
-
*/
|
490
|
-
constructor(method, storageEngine) {
|
491
|
-
super(`The method ${method} is not implemented in the storage engine ${storageEngine.constructor.name}`);
|
492
|
-
}
|
493
|
-
}
|
494
|
-
|
495
|
-
/**
|
496
|
-
* @class ModelNotFoundStorageEngineError
|
497
|
-
* @extends StorageEngineError
|
498
|
-
*/
|
499
|
-
export class ModelNotFoundStorageEngineError extends StorageEngineError {
|
500
|
-
/**
|
501
|
-
* @param {string} modelId
|
502
|
-
*/
|
503
|
-
constructor(modelId) {
|
504
|
-
super(`The model ${modelId} was not found`);
|
505
|
-
}
|
506
|
-
}
|
507
|
-
|
508
|
-
export class DeleteHasUnintendedConsequencesStorageEngineError extends StorageEngineError {
|
509
|
-
/**
|
510
|
-
* @param {string} modelId
|
511
|
-
* @param {object} consequences
|
512
|
-
*/
|
513
|
-
constructor(modelId, consequences) {
|
514
|
-
super(`Deleting ${modelId} has unintended consequences`);
|
515
|
-
this.consequences = consequences;
|
516
|
-
}
|
517
|
-
}
|