@acodeninja/persist 3.0.0-next.21 → 3.0.0-next.23
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
package/src/Connection.js
CHANGED
@@ -7,24 +7,6 @@ import Model from './data/Model.js';
|
|
7
7
|
import SearchIndex from './data/SearchIndex.js';
|
8
8
|
import _ from 'lodash';
|
9
9
|
|
10
|
-
/**
|
11
|
-
* Represents a transactional operation to be executed, typically queued and later committed.
|
12
|
-
*
|
13
|
-
* Stores the method to invoke, the arguments to apply, and tracks the result or error state
|
14
|
-
* of the transaction once it's processed.
|
15
|
-
*
|
16
|
-
* @class Transaction
|
17
|
-
*/
|
18
|
-
export class Transaction {
|
19
|
-
constructor(method, ...args) {
|
20
|
-
this.method = method;
|
21
|
-
this.args = args;
|
22
|
-
this.original = undefined;
|
23
|
-
this.error = undefined;
|
24
|
-
this.committed = false;
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
10
|
/**
|
29
11
|
* @class Connection
|
30
12
|
*/
|
@@ -189,11 +171,12 @@ export default class Connection {
|
|
189
171
|
|
190
172
|
if (modelToProcessHasChanged) modelsToPut.push(modelToProcess);
|
191
173
|
|
174
|
+
const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id).name;
|
175
|
+
|
192
176
|
if (
|
193
177
|
Boolean(modelToProcess.constructor.indexedProperties().length) &&
|
194
178
|
(!currentModel || !_.isEqual(currentModel.toIndexData(), modelToProcess.toIndexData()))
|
195
179
|
) {
|
196
|
-
const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id).name;
|
197
180
|
modelsToReindex[modelToProcessConstructor] = modelsToReindex[modelToProcessConstructor] || [];
|
198
181
|
modelsToReindex[modelToProcessConstructor].push(modelToProcess);
|
199
182
|
}
|
@@ -202,7 +185,6 @@ export default class Connection {
|
|
202
185
|
Boolean(modelToProcess.constructor.searchProperties().length) &&
|
203
186
|
(!currentModel || !_.isEqual(currentModel.toSearchData(), modelToProcess.toSearchData()))
|
204
187
|
) {
|
205
|
-
const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id).name;
|
206
188
|
modelsToReindexSearch[modelToProcessConstructor] = modelsToReindexSearch[modelToProcessConstructor] || [];
|
207
189
|
modelsToReindexSearch[modelToProcessConstructor].push(modelToProcess);
|
208
190
|
}
|
@@ -223,7 +205,7 @@ export default class Connection {
|
|
223
205
|
const index = await this.#storage.getIndex(modelConstructor);
|
224
206
|
|
225
207
|
await this.#storage.putIndex(modelConstructor, {
|
226
|
-
...index
|
208
|
+
...index,
|
227
209
|
...Object.fromEntries(models.map(m => [m.id, m.toIndexData()])),
|
228
210
|
});
|
229
211
|
})),
|
@@ -232,7 +214,7 @@ export default class Connection {
|
|
232
214
|
const index = await this.#storage.getSearchIndex(modelConstructor);
|
233
215
|
|
234
216
|
await this.#storage.putSearchIndex(modelConstructor, {
|
235
|
-
...index
|
217
|
+
...index,
|
236
218
|
...Object.fromEntries(models.map(m => [m.id, m.toSearchData()])),
|
237
219
|
});
|
238
220
|
})),
|
@@ -277,7 +259,8 @@ export default class Connection {
|
|
277
259
|
|
278
260
|
if (!modelsToDelete.includes(currentModel.id)) modelsToDelete.push(currentModel.id);
|
279
261
|
|
280
|
-
const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id);
|
262
|
+
const modelToProcessConstructor = this.#getModelConstructorFromId(modelToProcess.id).name;
|
263
|
+
|
281
264
|
indexActions[modelToProcessConstructor] = indexActions[modelToProcessConstructor] ?? [];
|
282
265
|
searchIndexActions[modelToProcessConstructor] = searchIndexActions[modelToProcessConstructor] ?? [];
|
283
266
|
|
@@ -433,42 +416,55 @@ export default class Connection {
|
|
433
416
|
* @return {Connection}
|
434
417
|
*/
|
435
418
|
transaction() {
|
436
|
-
const
|
419
|
+
const operations = [];
|
437
420
|
|
438
|
-
const engine = CreateTransactionalStorageEngine(
|
421
|
+
const engine = CreateTransactionalStorageEngine(operations, this.#storage);
|
439
422
|
|
440
|
-
const
|
423
|
+
const transaction = new this.constructor(engine, this.#cache, Object.values(this.#models));
|
441
424
|
|
442
|
-
|
425
|
+
transaction.commit = async () => {
|
443
426
|
try {
|
444
|
-
for (const [index,
|
427
|
+
for (const [index, operation] of operations.entries()) {
|
445
428
|
try {
|
446
|
-
if (
|
447
|
-
|
429
|
+
if (operation.method === 'putModel')
|
430
|
+
operations[index].original = await this.#storage.getModel(operation.args[0].id).catch(() => undefined);
|
448
431
|
|
449
|
-
if (
|
450
|
-
|
432
|
+
if (operation.method === 'deleteModel')
|
433
|
+
operations[index].original = await this.#storage.getModel(operation.args[0]);
|
451
434
|
|
452
|
-
|
435
|
+
if (operation.method === 'putIndex')
|
436
|
+
operations[index].original = await this.#storage.getIndex(operation.args[0]);
|
453
437
|
|
454
|
-
|
438
|
+
if (operation.method === 'putSearchIndex')
|
439
|
+
operations[index].original = await this.#storage.getSearchIndex(operation.args[0]);
|
440
|
+
|
441
|
+
await this.#storage[operation.method](...operation.args);
|
442
|
+
|
443
|
+
operations[index].committed = true;
|
455
444
|
} catch (error) {
|
456
|
-
|
445
|
+
operations[index].error = error;
|
457
446
|
throw error;
|
458
447
|
}
|
459
448
|
}
|
460
449
|
} catch (error) {
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
450
|
+
for (const operation of operations) {
|
451
|
+
if (operation.committed && operation.original) {
|
452
|
+
if (['putModel', 'deleteModel'].includes(operation.method))
|
453
|
+
await this.#storage.putModel(operation.original);
|
454
|
+
|
455
|
+
if (operation.method === 'putIndex')
|
456
|
+
await this.#storage.putIndex(operation.args[0], operation.original);
|
457
|
+
|
458
|
+
if (operation.method === 'putSearchIndex')
|
459
|
+
await this.#storage.putSearchIndex(operation.args[0], operation.original);
|
460
|
+
}
|
461
|
+
}
|
466
462
|
|
467
|
-
throw new CommitFailedTransactionError(
|
463
|
+
throw new CommitFailedTransactionError(operations, error);
|
468
464
|
}
|
469
465
|
};
|
470
466
|
|
471
|
-
return
|
467
|
+
return transaction;
|
472
468
|
}
|
473
469
|
|
474
470
|
/**
|
@@ -525,13 +521,11 @@ export default class Connection {
|
|
525
521
|
})),
|
526
522
|
)
|
527
523
|
.flat()
|
528
|
-
.reduce((accumulator, {containingModel, propertyName, propertyProperty}) =>
|
529
|
-
|
530
|
-
[containingModel]
|
531
|
-
|
532
|
-
|
533
|
-
},
|
534
|
-
}), {});
|
524
|
+
.reduce((accumulator, {containingModel, propertyName, propertyProperty}) => {
|
525
|
+
accumulator[containingModel] = accumulator[containingModel] ?? {};
|
526
|
+
accumulator[containingModel][propertyName] = propertyProperty;
|
527
|
+
return accumulator;
|
528
|
+
}, {});
|
535
529
|
}
|
536
530
|
|
537
531
|
/**
|
@@ -620,11 +614,11 @@ class TransactionError extends Error {
|
|
620
614
|
export class CommitFailedTransactionError extends TransactionError {
|
621
615
|
/**
|
622
616
|
*
|
623
|
-
* @param {Array<
|
617
|
+
* @param {Array<Operation>} transactions
|
624
618
|
* @param {Error} error
|
625
619
|
*/
|
626
620
|
constructor(transactions, error) {
|
627
|
-
super('
|
621
|
+
super('Operation failed to commit.');
|
628
622
|
this.transactions = transactions;
|
629
623
|
this.error = error;
|
630
624
|
}
|
@@ -29,7 +29,7 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
29
29
|
* Get a model
|
30
30
|
* @param {string} id
|
31
31
|
* @throws ModelNotFoundStorageEngineError
|
32
|
-
* @return Promise<
|
32
|
+
* @return Promise<Object>
|
33
33
|
*/
|
34
34
|
getModel(id) {
|
35
35
|
return this.#processFetch(this.#generateURL([id]), this.#getReadOptions())
|
@@ -43,7 +43,7 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
43
43
|
|
44
44
|
/**
|
45
45
|
* Update a model
|
46
|
-
* @param {
|
46
|
+
* @param {Object} model
|
47
47
|
* @throws HTTPRequestFailedError
|
48
48
|
* @return Promise<void>
|
49
49
|
*/
|
@@ -75,7 +75,7 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
75
75
|
/**
|
76
76
|
* Get a model's index data
|
77
77
|
* @param {Model.constructor} modelConstructor
|
78
|
-
* @return Promise<
|
78
|
+
* @return Promise<Record<String, Object>>
|
79
79
|
*/
|
80
80
|
getIndex(modelConstructor) {
|
81
81
|
return this.#processFetch(
|
@@ -88,7 +88,7 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
88
88
|
/**
|
89
89
|
* Put a model's index data
|
90
90
|
* @param {Model.constructor} modelConstructor
|
91
|
-
* @param {
|
91
|
+
* @param {Record<String, Object>} index
|
92
92
|
* @throws MethodNotImplementedStorageEngineError
|
93
93
|
* @return Promise<void>
|
94
94
|
*/
|
@@ -103,7 +103,7 @@ export default class HTTPStorageEngine extends StorageEngine {
|
|
103
103
|
* Get a model's raw search index data
|
104
104
|
* @param {Model.constructor} modelConstructor
|
105
105
|
* @throws MethodNotImplementedStorageEngineError
|
106
|
-
* @return Promise<
|
106
|
+
* @return Promise<Record<String, Object>>
|
107
107
|
*/
|
108
108
|
getSearchIndex(modelConstructor) {
|
109
109
|
return this.#processFetch(
|
@@ -48,7 +48,7 @@ class S3StorageEngine extends StorageEngine {
|
|
48
48
|
|
49
49
|
/**
|
50
50
|
* Upload an object to S3
|
51
|
-
* @param {
|
51
|
+
* @param {Object} model - The model object to upload.
|
52
52
|
* @returns {Promise<void>}
|
53
53
|
*/
|
54
54
|
async putModel(model) {
|
@@ -87,7 +87,7 @@ class S3StorageEngine extends StorageEngine {
|
|
87
87
|
* Get a model's index data
|
88
88
|
* @param {Model.constructor} modelConstructor
|
89
89
|
* @throws MethodNotImplementedStorageEngineError
|
90
|
-
* @return Promise<
|
90
|
+
* @return Promise<Record<String, Object>>
|
91
91
|
*/
|
92
92
|
async getIndex(modelConstructor) {
|
93
93
|
const Key = this.#generatePath([modelConstructor.name, '_index.json']);
|
@@ -106,7 +106,7 @@ class S3StorageEngine extends StorageEngine {
|
|
106
106
|
/**
|
107
107
|
* Put a model's index data
|
108
108
|
* @param {Model.constructor} modelConstructor
|
109
|
-
* @param {
|
109
|
+
* @param {Record<String, Object>} index
|
110
110
|
* @throws MethodNotImplementedStorageEngineError
|
111
111
|
* @return Promise<void>
|
112
112
|
*/
|
@@ -1,5 +1,3 @@
|
|
1
|
-
import {Transaction} from '../../Connection.js';
|
2
|
-
|
3
1
|
export default class StorageEngine {
|
4
2
|
/**
|
5
3
|
* @param {Object} configuration
|
@@ -13,7 +11,7 @@ export default class StorageEngine {
|
|
13
11
|
* @param {string} _id
|
14
12
|
* @throws MethodNotImplementedStorageEngineError
|
15
13
|
* @throws ModelNotFoundStorageEngineError
|
16
|
-
* @return Promise<
|
14
|
+
* @return Promise<Object>
|
17
15
|
*/
|
18
16
|
getModel(_id) {
|
19
17
|
return Promise.reject(new MethodNotImplementedStorageEngineError('getModel', this));
|
@@ -21,7 +19,7 @@ export default class StorageEngine {
|
|
21
19
|
|
22
20
|
/**
|
23
21
|
* Update a model
|
24
|
-
* @param {
|
22
|
+
* @param {Object} _model
|
25
23
|
* @throws MethodNotImplementedStorageEngineError
|
26
24
|
* @return Promise<void>
|
27
25
|
*/
|
@@ -44,7 +42,7 @@ export default class StorageEngine {
|
|
44
42
|
* Get a model's index data
|
45
43
|
* @param {Model.constructor} _modelConstructor
|
46
44
|
* @throws MethodNotImplementedStorageEngineError
|
47
|
-
* @return Promise<
|
45
|
+
* @return Promise<Record<String, Object>>
|
48
46
|
*/
|
49
47
|
getIndex(_modelConstructor) {
|
50
48
|
return Promise.reject(new MethodNotImplementedStorageEngineError('getIndex', this));
|
@@ -53,7 +51,7 @@ export default class StorageEngine {
|
|
53
51
|
/**
|
54
52
|
* Put a model's index data
|
55
53
|
* @param {Model.constructor} _modelConstructor
|
56
|
-
* @param {
|
54
|
+
* @param {Record<String, Object>} _data
|
57
55
|
* @throws MethodNotImplementedStorageEngineError
|
58
56
|
* @return Promise<void>
|
59
57
|
*/
|
@@ -65,7 +63,7 @@ export default class StorageEngine {
|
|
65
63
|
* Get a model's raw search index data
|
66
64
|
* @param {Model.constructor} _modelConstructor
|
67
65
|
* @throws MethodNotImplementedStorageEngineError
|
68
|
-
* @return Promise<
|
66
|
+
* @return Promise<Record<String, Object>>
|
69
67
|
*/
|
70
68
|
getSearchIndex(_modelConstructor) {
|
71
69
|
return Promise.reject(new MethodNotImplementedStorageEngineError('getSearchIndex', this));
|
@@ -76,7 +74,7 @@ export default class StorageEngine {
|
|
76
74
|
* @param {Model.constructor} _constructor
|
77
75
|
* @param {Record<string, object>} _index
|
78
76
|
* @throws MethodNotImplementedStorageEngineError
|
79
|
-
* @return Promise<
|
77
|
+
* @return Promise<Record<String, Object>>
|
80
78
|
*/
|
81
79
|
putSearchIndex(_constructor, _index) {
|
82
80
|
return Promise.reject(new MethodNotImplementedStorageEngineError('putSearchIndex', this));
|
@@ -142,32 +140,50 @@ export class DeleteHasUnintendedConsequencesStorageEngineError extends StorageEn
|
|
142
140
|
}
|
143
141
|
}
|
144
142
|
|
143
|
+
/**
|
144
|
+
* Represents a transactional operation to be executed, typically queued and later committed.
|
145
|
+
*
|
146
|
+
* Stores the method to invoke, the arguments to apply, and tracks the result or error state
|
147
|
+
* of the transaction once it's processed.
|
148
|
+
*
|
149
|
+
* @class Operation
|
150
|
+
*/
|
151
|
+
export class Operation {
|
152
|
+
constructor(method, ...args) {
|
153
|
+
this.method = method;
|
154
|
+
this.args = args;
|
155
|
+
this.original = undefined;
|
156
|
+
this.error = undefined;
|
157
|
+
this.committed = false;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
145
161
|
/**
|
146
162
|
*
|
147
|
-
* @param {Array<
|
163
|
+
* @param {Array<Operation>} transactions
|
148
164
|
* @param {StorageEngine} engine
|
149
165
|
* @return {StorageEngine}
|
150
166
|
*/
|
151
|
-
export function CreateTransactionalStorageEngine(
|
167
|
+
export function CreateTransactionalStorageEngine(operations, engine) {
|
152
168
|
const transactionalEngine = Object.create(engine);
|
153
169
|
|
154
170
|
transactionalEngine.putModel = (...args) => {
|
155
|
-
|
171
|
+
operations.push(new Operation('putModel', ...args));
|
156
172
|
return Promise.resolve();
|
157
173
|
};
|
158
174
|
|
159
175
|
transactionalEngine.deleteModel = (...args) => {
|
160
|
-
|
176
|
+
operations.push(new Operation('deleteModel', ...args));
|
161
177
|
return Promise.resolve();
|
162
178
|
};
|
163
179
|
|
164
180
|
transactionalEngine.putIndex = (...args) => {
|
165
|
-
|
181
|
+
operations.push(new Operation('putIndex', ...args));
|
166
182
|
return Promise.resolve();
|
167
183
|
};
|
168
184
|
|
169
185
|
transactionalEngine.putSearchIndex = (...args) => {
|
170
|
-
|
186
|
+
operations.push(new Operation('putSearchIndex', ...args));
|
171
187
|
return Promise.resolve();
|
172
188
|
};
|
173
189
|
|