electrodb 1.12.1 → 2.0.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.
- package/.travis.yml +1 -1
- package/README.md +686 -648
- package/index.d.ts +180 -179
- package/package.json +1 -1
- package/src/clauses.js +15 -32
- package/src/entity.js +176 -89
- package/src/errors.js +6 -0
- package/src/filters.js +2 -2
- package/src/service.js +30 -111
- package/src/types.js +15 -2
- package/src/util.js +24 -0
- package/src/where.js +2 -2
- package/notes +0 -45
- package/output +0 -106
- package/taskdata.json +0 -1
- package/typez.ts +0 -1736
package/src/service.js
CHANGED
|
@@ -243,13 +243,8 @@ class Service {
|
|
|
243
243
|
|
|
244
244
|
cleanseRetrievedData(collection = "", entities, data = {}, config = {}) {
|
|
245
245
|
if (config.raw) {
|
|
246
|
-
|
|
247
|
-
return [data.LastEvaluatedKey, data];
|
|
248
|
-
} else {
|
|
249
|
-
return data;
|
|
250
|
-
}
|
|
246
|
+
return data;
|
|
251
247
|
}
|
|
252
|
-
|
|
253
248
|
data.Items = data.Items || [];
|
|
254
249
|
let index = this.collectionSchema[collection].index;
|
|
255
250
|
let results = {};
|
|
@@ -268,18 +263,15 @@ class Service {
|
|
|
268
263
|
if (!entityAlias) {
|
|
269
264
|
continue;
|
|
270
265
|
}
|
|
271
|
-
|
|
272
266
|
// pager=false because we don't want the entity trying to parse the lastEvaluatedKey
|
|
273
|
-
let items = this.collectionSchema[collection].entities[entityAlias].formatResponse({Item: record}, index, {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return [page, results];
|
|
280
|
-
} else {
|
|
281
|
-
return results;
|
|
267
|
+
let items = this.collectionSchema[collection].entities[entityAlias].formatResponse({Item: record}, index, {
|
|
268
|
+
...config,
|
|
269
|
+
pager: false,
|
|
270
|
+
parse: undefined
|
|
271
|
+
});
|
|
272
|
+
results[entityAlias].push(items.data);
|
|
282
273
|
}
|
|
274
|
+
return results;
|
|
283
275
|
}
|
|
284
276
|
|
|
285
277
|
findKeyOwner(lastEvaluatedKey) {
|
|
@@ -287,92 +279,25 @@ class Service {
|
|
|
287
279
|
.find((entity) => entity.ownsLastEvaluatedKey(lastEvaluatedKey));
|
|
288
280
|
}
|
|
289
281
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
let matchingEntities = [];
|
|
295
|
-
if (pager === null) {
|
|
296
|
-
return matchingEntities;
|
|
297
|
-
}
|
|
298
|
-
for (let entity of Object.values(this.collectionSchema[collection].entities)) {
|
|
299
|
-
if (entity.ownsPager(pager, this.collectionSchema[collection].index)) {
|
|
300
|
-
matchingEntities.push(entity);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
return matchingEntities;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
findNamedPagerOwner(pager = {}) {
|
|
307
|
-
let identifiers = this._getEntityIdentifiers(this.entities);
|
|
308
|
-
for (let identifier of identifiers) {
|
|
309
|
-
let hasCorrectFieldProperties = typeof pager[identifier.nameField] === "string" && typeof pager[identifier.versionField] === "string";
|
|
310
|
-
let hasMatchingFieldValues = pager[identifier.nameField] === identifier.name && pager[identifier.versionField] === identifier.version;
|
|
311
|
-
if (hasCorrectFieldProperties && hasMatchingFieldValues) {
|
|
312
|
-
return identifier.entity;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
expectPagerOwner(type, collection, pager) {
|
|
318
|
-
if (type === Pager.raw) {
|
|
319
|
-
return Object.values(this.collectionSchema[collection].entities)[0];
|
|
320
|
-
} else if (type === Pager.named || type === undefined) {
|
|
321
|
-
let owner = this.findNamedPagerOwner(pager);
|
|
322
|
-
if (owner === undefined) {
|
|
323
|
-
throw new e.ElectroError(e.ErrorCodes.NoOwnerForPager, "Supplied Pager does not resolve to Entity within Service");
|
|
324
|
-
}
|
|
325
|
-
return owner;
|
|
326
|
-
} else if (type === Pager.item) {
|
|
327
|
-
let owners = this.findItemPagerOwner(collection, pager);
|
|
328
|
-
if (owners.length === 1) {
|
|
329
|
-
return owners[0];
|
|
330
|
-
} else {
|
|
331
|
-
throw new e.ElectroError(e.ErrorCodes.PagerNotUnique, "Supplied Pager did not resolve to single Entity");
|
|
332
|
-
}
|
|
333
|
-
} else {
|
|
334
|
-
throw new e.ElectroError(e.ErrorCodes.InvalidOptions, `Invalid value for option "pager" provider: "${pager}". Allowed values include ${u.commaSeparatedString(Object.keys(Pager))}.`)
|
|
282
|
+
expectKeyOwner(lastEvaluatedKey) {
|
|
283
|
+
const owner = this.findKeyOwner(lastEvaluatedKey);
|
|
284
|
+
if (owner === undefined) {
|
|
285
|
+
throw new e.ElectroError(e.ErrorCodes.NoOwnerForCursor, `Supplied cursor does not resolve to Entity within the Service ${this.service.name}`);
|
|
335
286
|
}
|
|
287
|
+
return owner;
|
|
336
288
|
}
|
|
337
289
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
let matchingIdentifiers = [];
|
|
343
|
-
if (pager === null) {
|
|
344
|
-
return matchingIdentifiers;
|
|
345
|
-
}
|
|
346
|
-
for (let entity of Object.values(this.collectionSchema[collection].entities)) {
|
|
347
|
-
if (entity.ownsPager(pager, this.collectionSchema[collection].index)) {
|
|
348
|
-
matchingIdentifiers.push({
|
|
349
|
-
[entity.identifiers.entity]: entity.getName(),
|
|
350
|
-
[entity.identifiers.version]: entity.getVersion(),
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return matchingIdentifiers;
|
|
290
|
+
findCursorOwner(cursor) {
|
|
291
|
+
return Object.values(this.entities)
|
|
292
|
+
.find(entity => entity.ownsCursor(cursor));
|
|
355
293
|
}
|
|
356
294
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
return null;
|
|
362
|
-
} else {
|
|
363
|
-
let entity = this.findKeyOwner(lastEvaluatedKey);
|
|
364
|
-
if (!entity) {
|
|
365
|
-
return lastReturned !== undefined
|
|
366
|
-
? this._formatReturnPager(config, index, lastReturned)
|
|
367
|
-
: null
|
|
368
|
-
}
|
|
369
|
-
let page = entity._formatKeysToItem(index, lastEvaluatedKey);
|
|
370
|
-
if (config.pager === "named") {
|
|
371
|
-
page[entity.identifiers.entity] = entity.getName();
|
|
372
|
-
page[entity.identifiers.version] = entity.getVersion();
|
|
373
|
-
}
|
|
374
|
-
return page;
|
|
295
|
+
expectCursorOwner(cursor) {
|
|
296
|
+
const owner = this.findCursorOwner(cursor);
|
|
297
|
+
if (owner === undefined) {
|
|
298
|
+
throw new e.ElectroError(e.ErrorCodes.NoOwnerForCursor, `Supplied cursor does not resolve to Entity within the Service ${this.service.name}`);
|
|
375
299
|
}
|
|
300
|
+
return owner;
|
|
376
301
|
}
|
|
377
302
|
|
|
378
303
|
_getTableName() {
|
|
@@ -389,21 +314,7 @@ class Service {
|
|
|
389
314
|
_makeCollectionChain(name = "", attributes = {}, initialClauses = {}, expressions = {}, entities = {}, entity = {}, facets = {}) {
|
|
390
315
|
let filterBuilder = new FilterFactory(attributes, FilterOperations);
|
|
391
316
|
let whereBuilder = new WhereFactory(attributes, FilterOperations);
|
|
392
|
-
|
|
393
|
-
let pageClause = {...initialClauses.page};
|
|
394
|
-
let pageAction = initialClauses.page.action;
|
|
395
|
-
pageClause.action = (entity, state, page = null, options = {}) => {
|
|
396
|
-
try {
|
|
397
|
-
if (page === null) {
|
|
398
|
-
return pageAction(entity, state, page, options);
|
|
399
|
-
}
|
|
400
|
-
let owner = this.expectPagerOwner(options.pager, name, page);
|
|
401
|
-
return pageAction(owner, state, page, options);
|
|
402
|
-
} catch(err) {
|
|
403
|
-
return Promise.reject(err);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
let clauses = {...initialClauses, page: pageClause};
|
|
317
|
+
let clauses = {...initialClauses};
|
|
407
318
|
|
|
408
319
|
clauses = filterBuilder.injectFilterClauses(clauses);
|
|
409
320
|
clauses = whereBuilder.injectWhereClauses(clauses);
|
|
@@ -412,6 +323,14 @@ class Service {
|
|
|
412
323
|
// expressions, // DynamoDB doesnt return what I expect it would when provided with these entity filters
|
|
413
324
|
parse: (options, data) => {
|
|
414
325
|
return this.cleanseRetrievedData(name, entities, data, options);
|
|
326
|
+
},
|
|
327
|
+
formatCursor: {
|
|
328
|
+
serialize: (key) => {
|
|
329
|
+
return this.expectKeyOwner(key).serializeCursor(key);
|
|
330
|
+
},
|
|
331
|
+
deserialize: (cursor) => {
|
|
332
|
+
return this.expectCursorOwner(cursor).deserilizeCursor(cursor);
|
|
333
|
+
}
|
|
415
334
|
}
|
|
416
335
|
};
|
|
417
336
|
|
package/src/types.js
CHANGED
|
@@ -110,7 +110,8 @@ const AttributeMutationMethods = {
|
|
|
110
110
|
const Pager = {
|
|
111
111
|
raw: "raw",
|
|
112
112
|
named: "named",
|
|
113
|
-
item: "item"
|
|
113
|
+
item: "item",
|
|
114
|
+
cursor: "cursor"
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
const UnprocessedTypes = {
|
|
@@ -194,6 +195,15 @@ const TerminalOperation = {
|
|
|
194
195
|
page: 'page',
|
|
195
196
|
}
|
|
196
197
|
|
|
198
|
+
const AllPages = 'all';
|
|
199
|
+
|
|
200
|
+
const ResultOrderOption = {
|
|
201
|
+
'asc': true,
|
|
202
|
+
'desc': false
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const ResultOrderParam = 'ScanIndexForward';
|
|
206
|
+
|
|
197
207
|
module.exports = {
|
|
198
208
|
Pager,
|
|
199
209
|
KeyTypes,
|
|
@@ -223,5 +233,8 @@ module.exports = {
|
|
|
223
233
|
AttributeProxySymbol,
|
|
224
234
|
ElectroInstanceTypes,
|
|
225
235
|
EventSubscriptionTypes,
|
|
226
|
-
AttributeMutationMethods
|
|
236
|
+
AttributeMutationMethods,
|
|
237
|
+
AllPages,
|
|
238
|
+
ResultOrderOption,
|
|
239
|
+
ResultOrderParam,
|
|
227
240
|
};
|
package/src/util.js
CHANGED
|
@@ -161,6 +161,29 @@ function getUnique(arr1, arr2) {
|
|
|
161
161
|
]));
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
const cursorFormatter = {
|
|
165
|
+
serialize: (key) => {
|
|
166
|
+
if (!key) {
|
|
167
|
+
return null;
|
|
168
|
+
} else if (typeof val !== 'string') {
|
|
169
|
+
key = JSON.stringify(key);
|
|
170
|
+
}
|
|
171
|
+
return Buffer.from(key).toString('base64url');
|
|
172
|
+
},
|
|
173
|
+
deserialize: (cursor) => {
|
|
174
|
+
if (!cursor) {
|
|
175
|
+
return undefined;
|
|
176
|
+
} else if (typeof cursor !== 'string') {
|
|
177
|
+
throw new Error(`Invalid cursor provided, expected type 'string' recieved: ${JSON.stringify(cursor)}`);
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
return JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'));
|
|
181
|
+
} catch(err) {
|
|
182
|
+
throw new Error('Unable to parse cursor');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
164
187
|
module.exports = {
|
|
165
188
|
getUnique,
|
|
166
189
|
batchItems,
|
|
@@ -171,6 +194,7 @@ module.exports = {
|
|
|
171
194
|
genericizeJSONPath,
|
|
172
195
|
commaSeparatedString,
|
|
173
196
|
formatAttributeCasing,
|
|
197
|
+
cursorFormatter,
|
|
174
198
|
applyBetaModelOverrides,
|
|
175
199
|
formatIndexNameForDisplay,
|
|
176
200
|
BatchGetOrderMaintainer,
|
package/src/where.js
CHANGED
|
@@ -120,7 +120,7 @@ class WhereFactory {
|
|
|
120
120
|
injected[name] = {
|
|
121
121
|
name,
|
|
122
122
|
action: this.buildClause(filter),
|
|
123
|
-
children: ["params", "go", "
|
|
123
|
+
children: ["params", "go", "where", ...modelFilters],
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
filterChildren.push("where");
|
|
@@ -129,7 +129,7 @@ class WhereFactory {
|
|
|
129
129
|
action: (entity, state, fn) => {
|
|
130
130
|
return this.buildClause(fn)(entity, state);
|
|
131
131
|
},
|
|
132
|
-
children: ["params", "go", "
|
|
132
|
+
children: ["params", "go", "where", ...modelFilters],
|
|
133
133
|
};
|
|
134
134
|
for (let parent of filterParents) {
|
|
135
135
|
injected[parent] = { ...injected[parent] };
|
package/notes
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
todo: better param typing
|
|
4
|
-
done: get typing
|
|
5
|
-
todo: get implementation
|
|
6
|
-
done: get[] typing
|
|
7
|
-
todo: get[] implementation
|
|
8
|
-
done: delete typing
|
|
9
|
-
todo: delete implementation
|
|
10
|
-
done: delete[] typing
|
|
11
|
-
todo: delete[] implementation
|
|
12
|
-
done: put[] typing
|
|
13
|
-
todo: put[] implementation
|
|
14
|
-
done: put typing
|
|
15
|
-
todo: put implementation
|
|
16
|
-
todo: update typing
|
|
17
|
-
done: update implementation
|
|
18
|
-
done: SetRecord
|
|
19
|
-
done: RemoveRecord
|
|
20
|
-
done: DataUpdateMethodRecord
|
|
21
|
-
|
|
22
|
-
done: scan typing
|
|
23
|
-
todo: scan implementation
|
|
24
|
-
done: query typing
|
|
25
|
-
todo: query implementation
|
|
26
|
-
done: find typing
|
|
27
|
-
todo: find implementation
|
|
28
|
-
done: match typing
|
|
29
|
-
todo: match implementation
|
|
30
|
-
done: parse typing
|
|
31
|
-
todo: parse implementation (requires cursor?)
|
|
32
|
-
todo: collection query
|
|
33
|
-
todo: collection impl
|
|
34
|
-
|
|
35
|
-
todo: add where to go?
|
|
36
|
-
todo: rethink option names
|
|
37
|
-
|
|
38
|
-
todo: add cursor to query options
|
|
39
|
-
todo: remove old doc notes on `join` and slim down `service`
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
find and test any add on set and number
|
|
44
|
-
try number enum?
|
|
45
|
-
integration test enum set ts
|
package/output
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
page {
|
|
2
|
-
"data": [
|
|
3
|
-
{
|
|
4
|
-
"prop2": "e3b142b1-e5d7-4b17-8a66-38fcdf6ef1ef",
|
|
5
|
-
"prop1": "value1",
|
|
6
|
-
"prop4": "value4"
|
|
7
|
-
},
|
|
8
|
-
{
|
|
9
|
-
"prop2": "e8ed19db-3ac4-45d6-8fb8-281ada117e96",
|
|
10
|
-
"prop1": "value1",
|
|
11
|
-
"prop4": "value4"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"prop2": "dcca03f5-7478-4afb-9297-20a68ff56559",
|
|
15
|
-
"prop1": "value1",
|
|
16
|
-
"prop4": "value4"
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"prop2": "03ccd79e-c5e5-4179-8213-196eafcbd4b9",
|
|
20
|
-
"prop1": "value1",
|
|
21
|
-
"prop4": "value4"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
"prop2": "2900735e-aaa4-4661-a52d-7aecb752e694",
|
|
25
|
-
"prop1": "value1",
|
|
26
|
-
"prop4": "value4"
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"prop2": "0f1da461-5257-4f6c-8cb3-af7b56819100",
|
|
30
|
-
"prop1": "value1",
|
|
31
|
-
"prop4": "value4"
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"prop2": "7562c43b-8ac9-483c-b950-4f0e1366c11a",
|
|
35
|
-
"prop1": "value1",
|
|
36
|
-
"prop4": "value4"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"prop2": "ee844e97-dc1c-4242-bd2b-45685e39d7fd",
|
|
40
|
-
"prop1": "value1",
|
|
41
|
-
"prop4": "value4"
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
"prop2": "4b55e242-9875-412e-b483-24e51dabf6c8",
|
|
45
|
-
"prop1": "value1",
|
|
46
|
-
"prop4": "value4"
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"prop2": "77a5b66e-c658-4ec6-9630-4d2469653bd4",
|
|
50
|
-
"prop1": "value1",
|
|
51
|
-
"prop4": "value4"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"prop2": "194efbfe-7be6-4662-9982-a1c8eb6ab36d",
|
|
55
|
-
"prop1": "value1",
|
|
56
|
-
"prop4": "value4"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"prop2": "value2",
|
|
60
|
-
"prop1": "value1",
|
|
61
|
-
"prop4": "value4"
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
"prop2": "516d8256-3b3e-41e1-a44a-0720fe748e23",
|
|
65
|
-
"prop1": "value1",
|
|
66
|
-
"prop4": "value4"
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
"prop2": "35bf3a7e-9dff-4817-a157-2be09c5fc8a8",
|
|
70
|
-
"prop1": "value1",
|
|
71
|
-
"prop4": "value4"
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
"prop2": "3836452b-6c00-415e-85ce-a9596644b6eb",
|
|
75
|
-
"prop1": "value1",
|
|
76
|
-
"prop4": "value4"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"prop2": "value2abc",
|
|
80
|
-
"prop1": "value1",
|
|
81
|
-
"prop4": "value4"
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"prop2": "887e5301-113c-4ca6-b6d0-ebaf27e217d5",
|
|
85
|
-
"prop1": "value1",
|
|
86
|
-
"prop4": "value4"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
"prop2": "6c6d9363-3821-40c8-b3d0-7ec2c6d3f1eb",
|
|
90
|
-
"prop1": "value1",
|
|
91
|
-
"prop4": "value4"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"prop2": "fcff14a3-ffa9-498e-a0ae-596c747b027b",
|
|
95
|
-
"prop1": "value1",
|
|
96
|
-
"prop4": "value4"
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
"prop2": "1d199eeb-ccc1-4c25-a1b6-1685126d44b3",
|
|
100
|
-
"prop1": "value1",
|
|
101
|
-
"prop4": "value4"
|
|
102
|
-
}
|
|
103
|
-
],
|
|
104
|
-
"count": 2,
|
|
105
|
-
"next": null
|
|
106
|
-
}
|