electrodb 1.12.1 → 2.1.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 +712 -668
- package/index.d.ts +192 -179
- package/package.json +1 -1
- package/src/clauses.js +15 -32
- package/src/entity.js +184 -92
- package/src/errors.js +6 -0
- package/src/filters.js +2 -2
- package/src/operations.js +1 -1
- package/src/schema.js +68 -12
- package/src/service.js +48 -117
- package/src/types.js +15 -2
- package/src/util.js +63 -0
- package/src/validations.js +12 -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/clauses.js
CHANGED
|
@@ -50,11 +50,11 @@ let clauses = {
|
|
|
50
50
|
return state;
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
|
-
children: ["params", "go"
|
|
53
|
+
children: ["params", "go"],
|
|
54
54
|
},
|
|
55
55
|
scan: {
|
|
56
56
|
name: "scan",
|
|
57
|
-
action(entity, state) {
|
|
57
|
+
action(entity, state, config) {
|
|
58
58
|
if (state.getError() !== null) {
|
|
59
59
|
return state;
|
|
60
60
|
}
|
|
@@ -65,7 +65,7 @@ let clauses = {
|
|
|
65
65
|
return state;
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
|
-
children: ["params", "go"
|
|
68
|
+
children: ["params", "go"],
|
|
69
69
|
},
|
|
70
70
|
get: {
|
|
71
71
|
name: "get",
|
|
@@ -397,6 +397,7 @@ let clauses = {
|
|
|
397
397
|
return state;
|
|
398
398
|
}
|
|
399
399
|
try {
|
|
400
|
+
state.addOption('_isPagination', true);
|
|
400
401
|
const attributes = state.getCompositeAttributes();
|
|
401
402
|
return state
|
|
402
403
|
.setMethod(MethodTypes.query)
|
|
@@ -410,7 +411,7 @@ let clauses = {
|
|
|
410
411
|
return state;
|
|
411
412
|
}
|
|
412
413
|
},
|
|
413
|
-
children: ["between", "gte", "gt", "lte", "lt", "begins", "params", "go"
|
|
414
|
+
children: ["between", "gte", "gt", "lte", "lt", "begins", "params", "go"],
|
|
414
415
|
},
|
|
415
416
|
between: {
|
|
416
417
|
name: "between",
|
|
@@ -430,7 +431,7 @@ let clauses = {
|
|
|
430
431
|
return state;
|
|
431
432
|
}
|
|
432
433
|
},
|
|
433
|
-
children: ["go", "params"
|
|
434
|
+
children: ["go", "params"],
|
|
434
435
|
},
|
|
435
436
|
begins: {
|
|
436
437
|
name: "begins",
|
|
@@ -450,7 +451,7 @@ let clauses = {
|
|
|
450
451
|
return state;
|
|
451
452
|
}
|
|
452
453
|
},
|
|
453
|
-
children: ["go", "params"
|
|
454
|
+
children: ["go", "params"],
|
|
454
455
|
},
|
|
455
456
|
gt: {
|
|
456
457
|
name: "gt",
|
|
@@ -470,7 +471,7 @@ let clauses = {
|
|
|
470
471
|
return state;
|
|
471
472
|
}
|
|
472
473
|
},
|
|
473
|
-
children: ["go", "params"
|
|
474
|
+
children: ["go", "params"],
|
|
474
475
|
},
|
|
475
476
|
gte: {
|
|
476
477
|
name: "gte",
|
|
@@ -490,7 +491,7 @@ let clauses = {
|
|
|
490
491
|
return state;
|
|
491
492
|
}
|
|
492
493
|
},
|
|
493
|
-
children: ["go", "params"
|
|
494
|
+
children: ["go", "params"],
|
|
494
495
|
},
|
|
495
496
|
lt: {
|
|
496
497
|
name: "lt",
|
|
@@ -509,7 +510,7 @@ let clauses = {
|
|
|
509
510
|
return state;
|
|
510
511
|
}
|
|
511
512
|
},
|
|
512
|
-
children: ["go", "params"
|
|
513
|
+
children: ["go", "params"],
|
|
513
514
|
},
|
|
514
515
|
lte: {
|
|
515
516
|
name: "lte",
|
|
@@ -528,7 +529,7 @@ let clauses = {
|
|
|
528
529
|
return state;
|
|
529
530
|
}
|
|
530
531
|
},
|
|
531
|
-
children: ["go", "params"
|
|
532
|
+
children: ["go", "params"],
|
|
532
533
|
},
|
|
533
534
|
params: {
|
|
534
535
|
name: "params",
|
|
@@ -589,28 +590,6 @@ let clauses = {
|
|
|
589
590
|
},
|
|
590
591
|
children: [],
|
|
591
592
|
},
|
|
592
|
-
page: {
|
|
593
|
-
name: "page",
|
|
594
|
-
action(entity, state, page = null, options = {}) {
|
|
595
|
-
if (state.getError() !== null) {
|
|
596
|
-
return Promise.reject(state.error);
|
|
597
|
-
}
|
|
598
|
-
try {
|
|
599
|
-
if (entity.client === undefined) {
|
|
600
|
-
throw new e.ElectroError(e.ErrorCodes.NoClientDefined, "No client defined on model");
|
|
601
|
-
}
|
|
602
|
-
options.page = page;
|
|
603
|
-
options._isPagination = true;
|
|
604
|
-
options.terminalOperation = TerminalOperation.page;
|
|
605
|
-
let params = clauses.params.action(entity, state, options);
|
|
606
|
-
let {config} = entity._applyParameterOptions({}, state.getOptions(), options);
|
|
607
|
-
return entity.go(state.getMethod(), params, config);
|
|
608
|
-
} catch(err) {
|
|
609
|
-
return Promise.reject(err);
|
|
610
|
-
}
|
|
611
|
-
},
|
|
612
|
-
children: []
|
|
613
|
-
},
|
|
614
593
|
};
|
|
615
594
|
|
|
616
595
|
class ChainState {
|
|
@@ -677,6 +656,10 @@ class ChainState {
|
|
|
677
656
|
return this.query.options;
|
|
678
657
|
}
|
|
679
658
|
|
|
659
|
+
addOption(key, value) {
|
|
660
|
+
this.query.options[key] = value;
|
|
661
|
+
}
|
|
662
|
+
|
|
680
663
|
_appendProvided(type, attributes) {
|
|
681
664
|
const newAttributes = Object.keys(attributes).map(attribute => {
|
|
682
665
|
return {
|
package/src/entity.js
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { Schema } = require("./schema");
|
|
3
|
-
const {
|
|
3
|
+
const { AllPages,
|
|
4
|
+
KeyCasing,
|
|
5
|
+
TableIndex,
|
|
6
|
+
FormatToReturnValues,
|
|
7
|
+
ReturnValues,
|
|
8
|
+
EntityVersions,
|
|
9
|
+
ItemOperations,
|
|
10
|
+
UnprocessedTypes,
|
|
11
|
+
Pager,
|
|
12
|
+
ElectroInstance,
|
|
13
|
+
KeyTypes,
|
|
14
|
+
QueryTypes,
|
|
15
|
+
MethodTypes,
|
|
16
|
+
Comparisons,
|
|
17
|
+
ExpressionTypes,
|
|
18
|
+
ModelVersions,
|
|
19
|
+
ElectroInstanceTypes,
|
|
20
|
+
MaxBatchItems,
|
|
21
|
+
TerminalOperation,
|
|
22
|
+
ResultOrderOption,
|
|
23
|
+
ResultOrderParam
|
|
24
|
+
} = require("./types");
|
|
4
25
|
const { FilterFactory } = require("./filters");
|
|
5
26
|
const { FilterOperations } = require("./operations");
|
|
6
27
|
const { WhereFactory } = require("./where");
|
|
@@ -10,6 +31,7 @@ const validations = require("./validations");
|
|
|
10
31
|
const c = require('./client');
|
|
11
32
|
const u = require("./util");
|
|
12
33
|
const e = require("./errors");
|
|
34
|
+
const { validate } = require("jsonschema");
|
|
13
35
|
|
|
14
36
|
class Entity {
|
|
15
37
|
constructor(model, config = {}) {
|
|
@@ -30,7 +52,7 @@ class Entity {
|
|
|
30
52
|
this._whereBuilder = new WhereFactory(this.model.schema.attributes, FilterOperations);
|
|
31
53
|
this._clausesWithFilters = this._filterBuilder.injectFilterClauses(clauses, this.model.filters);
|
|
32
54
|
this._clausesWithFilters = this._whereBuilder.injectWhereClauses(this._clausesWithFilters);
|
|
33
|
-
this.scan = this._makeChain(TableIndex, this._clausesWithFilters, clauses.index).scan();
|
|
55
|
+
this.scan = this._makeChain(TableIndex, this._clausesWithFilters, clauses.index, {_isPagination: true}).scan();
|
|
34
56
|
this.query = {};
|
|
35
57
|
for (let accessPattern in this.model.indexes) {
|
|
36
58
|
let index = this.model.indexes[accessPattern].index;
|
|
@@ -84,14 +106,30 @@ class Entity {
|
|
|
84
106
|
return pkMatch;
|
|
85
107
|
}
|
|
86
108
|
|
|
109
|
+
ownsCursor(cursor) {
|
|
110
|
+
if (typeof cursor === 'string') {
|
|
111
|
+
cursor = u.cursorFormatter.deserialize(cursor);
|
|
112
|
+
}
|
|
113
|
+
return this.ownsLastEvaluatedKey(cursor);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
serializeCursor(key) {
|
|
117
|
+
return u.cursorFormatter.serialize(key);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
deserializeCursor(cursor) {
|
|
121
|
+
return u.cursorFormatter.deserialize(cursor);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** @depricated pagers no longer exist, use the new cursor api */
|
|
87
125
|
ownsPager(pager, index = TableIndex) {
|
|
88
126
|
if (pager === null) {
|
|
89
127
|
return false;
|
|
90
128
|
}
|
|
91
|
-
let tableIndexFacets = this.model.facets.byIndex[
|
|
129
|
+
let tableIndexFacets = this.model.facets.byIndex[index];
|
|
92
130
|
// todo: is the fact it doesn't use the provided index a bug?
|
|
93
131
|
// feels like collections may have played a roll into why this is this way
|
|
94
|
-
let indexFacets = this.model.facets.byIndex[
|
|
132
|
+
let indexFacets = this.model.facets.byIndex[index];
|
|
95
133
|
|
|
96
134
|
// Unknown index
|
|
97
135
|
if (tableIndexFacets === undefined || indexFacets === undefined) {
|
|
@@ -114,9 +152,10 @@ class Entity {
|
|
|
114
152
|
}
|
|
115
153
|
|
|
116
154
|
match(facets = {}) {
|
|
117
|
-
|
|
155
|
+
const options = { _isPagination: true };
|
|
156
|
+
const match = this._findBestIndexKeyMatch(facets);
|
|
118
157
|
if (match.shouldScan) {
|
|
119
|
-
return this._makeChain(TableIndex, this._clausesWithFilters, clauses.index)
|
|
158
|
+
return this._makeChain(TableIndex, this._clausesWithFilters, clauses.index, options)
|
|
120
159
|
.scan()
|
|
121
160
|
.filter(attr => {
|
|
122
161
|
let eqFilters = [];
|
|
@@ -128,7 +167,7 @@ class Entity {
|
|
|
128
167
|
return eqFilters.join(" AND ");
|
|
129
168
|
});
|
|
130
169
|
} else {
|
|
131
|
-
return this._makeChain(match.index, this._clausesWithFilters, clauses.index)
|
|
170
|
+
return this._makeChain(match.index, this._clausesWithFilters, clauses.index, options)
|
|
132
171
|
.query(facets)
|
|
133
172
|
.filter(attr => {
|
|
134
173
|
let eqFilters = [];
|
|
@@ -143,16 +182,17 @@ class Entity {
|
|
|
143
182
|
}
|
|
144
183
|
|
|
145
184
|
find(facets = {}) {
|
|
146
|
-
|
|
185
|
+
const options = { _isPagination: true };
|
|
186
|
+
const match = this._findBestIndexKeyMatch(facets);
|
|
147
187
|
if (match.shouldScan) {
|
|
148
|
-
return this._makeChain(TableIndex, this._clausesWithFilters, clauses.index).scan();
|
|
188
|
+
return this._makeChain(TableIndex, this._clausesWithFilters, clauses.index, options).scan();
|
|
149
189
|
} else {
|
|
150
|
-
return this._makeChain(match.index, this._clausesWithFilters, clauses.index).query(facets);
|
|
190
|
+
return this._makeChain(match.index, this._clausesWithFilters, clauses.index, options).query(facets);
|
|
151
191
|
}
|
|
152
192
|
}
|
|
153
193
|
|
|
154
194
|
collection(collection = "", clauses = {}, facets = {}, {expressions = {}, parse} = {}) {
|
|
155
|
-
|
|
195
|
+
const options = {
|
|
156
196
|
parse,
|
|
157
197
|
expressions: {
|
|
158
198
|
names: expressions.names || {},
|
|
@@ -239,7 +279,8 @@ class Entity {
|
|
|
239
279
|
case MethodTypes.batchGet:
|
|
240
280
|
return await this.executeBulkGet(parameters, config);
|
|
241
281
|
case MethodTypes.query:
|
|
242
|
-
|
|
282
|
+
case MethodTypes.scan:
|
|
283
|
+
return await this.executeQuery(method, parameters, config);
|
|
243
284
|
default:
|
|
244
285
|
return await this.executeOperation(method, parameters, config);
|
|
245
286
|
}
|
|
@@ -305,20 +346,20 @@ class Entity {
|
|
|
305
346
|
await Promise.all(operation.map(async params => {
|
|
306
347
|
let response = await this._exec(MethodTypes.batchWrite, params, config);
|
|
307
348
|
if (validations.isFunction(config.parse)) {
|
|
308
|
-
let parsed =
|
|
349
|
+
let parsed = config.parse(config, response);
|
|
309
350
|
if (parsed) {
|
|
310
351
|
results.push(parsed);
|
|
311
352
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
353
|
+
} else {
|
|
354
|
+
let {unprocessed} = this.formatBulkWriteResponse(response, config);
|
|
355
|
+
for (let u of unprocessed) {
|
|
356
|
+
results.push(u);
|
|
357
|
+
}
|
|
317
358
|
}
|
|
318
359
|
}));
|
|
319
360
|
}
|
|
320
361
|
|
|
321
|
-
return results;
|
|
362
|
+
return { unprocessed: results };
|
|
322
363
|
}
|
|
323
364
|
|
|
324
365
|
_createNewBatchGetOrderMaintainer(config = {}) {
|
|
@@ -356,26 +397,29 @@ class Entity {
|
|
|
356
397
|
await Promise.all(operation.map(async params => {
|
|
357
398
|
let response = await this._exec(MethodTypes.batchGet, params, config);
|
|
358
399
|
if (validations.isFunction(config.parse)) {
|
|
359
|
-
resultsAll.push(
|
|
360
|
-
|
|
400
|
+
resultsAll.push(config.parse(config, response));
|
|
401
|
+
} else {
|
|
402
|
+
this.applyBulkGetResponseFormatting({
|
|
403
|
+
orderMaintainer,
|
|
404
|
+
resultsAll,
|
|
405
|
+
unprocessedAll,
|
|
406
|
+
response,
|
|
407
|
+
config
|
|
408
|
+
});
|
|
361
409
|
}
|
|
362
|
-
this.applyBulkGetResponseFormatting({
|
|
363
|
-
orderMaintainer,
|
|
364
|
-
resultsAll,
|
|
365
|
-
unprocessedAll,
|
|
366
|
-
response,
|
|
367
|
-
config
|
|
368
|
-
});
|
|
369
410
|
}));
|
|
370
411
|
}
|
|
371
|
-
return
|
|
412
|
+
return { data: resultsAll, unprocessed: unprocessedAll };
|
|
372
413
|
}
|
|
373
414
|
|
|
374
|
-
async executeQuery(parameters, config = {}) {
|
|
415
|
+
async executeQuery(method, parameters, config = {}) {
|
|
375
416
|
let results = config._isCollectionQuery
|
|
376
417
|
? {}
|
|
377
418
|
: [];
|
|
378
|
-
let ExclusiveStartKey;
|
|
419
|
+
let ExclusiveStartKey = this._formatExclusiveStartKey(config);
|
|
420
|
+
if (ExclusiveStartKey === null) {
|
|
421
|
+
ExclusiveStartKey = undefined;
|
|
422
|
+
}
|
|
379
423
|
let pages = this._normalizePagesValue(config.pages);
|
|
380
424
|
let max = this._normalizeLimitValue(config.limit);
|
|
381
425
|
let iterations = 0;
|
|
@@ -384,53 +428,48 @@ class Entity {
|
|
|
384
428
|
let limit = max === undefined
|
|
385
429
|
? parameters.Limit
|
|
386
430
|
: max - count;
|
|
387
|
-
let response = await this._exec(
|
|
388
|
-
|
|
431
|
+
let response = await this._exec(method, {ExclusiveStartKey, ...parameters, Limit: limit}, config);
|
|
389
432
|
ExclusiveStartKey = response.LastEvaluatedKey;
|
|
390
|
-
|
|
391
|
-
if (
|
|
392
|
-
response = config.parse(config, response);
|
|
393
|
-
} else {
|
|
394
|
-
response = this.formatResponse(response, parameters.IndexName, config);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
if (config.raw || config._isPagination) {
|
|
433
|
+
response = this.formatResponse(response, parameters.IndexName, config);
|
|
434
|
+
if (config.raw) {
|
|
398
435
|
return response;
|
|
399
436
|
} else if (config._isCollectionQuery) {
|
|
400
|
-
for (const entity in response) {
|
|
437
|
+
for (const entity in response.data) {
|
|
401
438
|
if (max) {
|
|
402
|
-
count += response[entity].length;
|
|
439
|
+
count += response.data[entity].length;
|
|
403
440
|
}
|
|
404
441
|
results[entity] = results[entity] || [];
|
|
405
|
-
results[entity] = [...results[entity], ...response[entity]];
|
|
442
|
+
results[entity] = [...results[entity], ...response.data[entity]];
|
|
406
443
|
}
|
|
407
|
-
} else if (Array.isArray(response)) {
|
|
444
|
+
} else if (Array.isArray(response.data)) {
|
|
408
445
|
if (max) {
|
|
409
|
-
count += response.length;
|
|
446
|
+
count += response.data.length;
|
|
410
447
|
}
|
|
411
|
-
results = [...results, ...response];
|
|
448
|
+
results = [...results, ...response.data];
|
|
412
449
|
} else {
|
|
413
450
|
return response;
|
|
414
451
|
}
|
|
415
|
-
|
|
416
452
|
iterations++;
|
|
417
|
-
} while(
|
|
418
|
-
|
|
453
|
+
} while(
|
|
454
|
+
ExclusiveStartKey &&
|
|
455
|
+
(pages === AllPages || iterations < pages) &&
|
|
456
|
+
(max === undefined || count < max)
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
const cursor = this._formatReturnPager(config, ExclusiveStartKey);
|
|
460
|
+
return { data: results, cursor };
|
|
419
461
|
}
|
|
420
462
|
|
|
421
463
|
async executeOperation(method, parameters, config) {
|
|
422
464
|
let response = await this._exec(method, parameters, config);
|
|
423
|
-
if (validations.isFunction(config.parse)) {
|
|
424
|
-
return config.parse(config, response);
|
|
425
|
-
}
|
|
426
465
|
switch (parameters.ReturnValues) {
|
|
427
466
|
case FormatToReturnValues.none:
|
|
428
|
-
return null;
|
|
467
|
+
return { data: null };
|
|
429
468
|
case FormatToReturnValues.all_new:
|
|
430
469
|
case FormatToReturnValues.all_old:
|
|
431
470
|
case FormatToReturnValues.updated_new:
|
|
432
471
|
case FormatToReturnValues.updated_old:
|
|
433
|
-
return this.formatResponse(response,
|
|
472
|
+
return this.formatResponse(response, config);
|
|
434
473
|
case FormatToReturnValues.default:
|
|
435
474
|
default:
|
|
436
475
|
return this._formatDefaultResponse(method, parameters.IndexName, parameters, config, response);
|
|
@@ -475,9 +514,9 @@ class Entity {
|
|
|
475
514
|
const index = TableIndex;
|
|
476
515
|
let unprocessed = response.UnprocessedItems[table];
|
|
477
516
|
if (Array.isArray(unprocessed) && unprocessed.length) {
|
|
478
|
-
|
|
517
|
+
unprocessed = unprocessed.map(request => {
|
|
479
518
|
if (request.PutRequest) {
|
|
480
|
-
return this.formatResponse(request.PutRequest, index, config);
|
|
519
|
+
return this.formatResponse(request.PutRequest, index, config).data;
|
|
481
520
|
} else if (request.DeleteRequest) {
|
|
482
521
|
if (config.unprocessed === UnprocessedTypes.raw) {
|
|
483
522
|
return request.DeleteRequest.Key;
|
|
@@ -487,10 +526,12 @@ class Entity {
|
|
|
487
526
|
} else {
|
|
488
527
|
throw new Error("Unknown response format");
|
|
489
528
|
}
|
|
490
|
-
})
|
|
529
|
+
});
|
|
491
530
|
} else {
|
|
492
|
-
|
|
531
|
+
unprocessed = [];
|
|
493
532
|
}
|
|
533
|
+
|
|
534
|
+
return { unprocessed };
|
|
494
535
|
}
|
|
495
536
|
|
|
496
537
|
applyBulkGetResponseFormatting({
|
|
@@ -526,9 +567,9 @@ class Entity {
|
|
|
526
567
|
const slot = orderMaintainer.getOrder(item);
|
|
527
568
|
const formatted = this.formatResponse({Item: item}, index, config);
|
|
528
569
|
if (slot !== -1) {
|
|
529
|
-
resultsAll[slot] = formatted;
|
|
570
|
+
resultsAll[slot] = formatted.data;
|
|
530
571
|
} else {
|
|
531
|
-
resultsAll.push(formatted);
|
|
572
|
+
resultsAll.push(formatted.data);
|
|
532
573
|
}
|
|
533
574
|
}
|
|
534
575
|
}
|
|
@@ -541,14 +582,16 @@ class Entity {
|
|
|
541
582
|
}
|
|
542
583
|
try {
|
|
543
584
|
let results = {};
|
|
544
|
-
if (
|
|
585
|
+
if (validations.isFunction(config.parse)) {
|
|
586
|
+
results = config.parse(config, response);
|
|
587
|
+
} else if (config.raw && !config._isPagination) {
|
|
545
588
|
if (response.TableName) {
|
|
546
589
|
results = {};
|
|
547
590
|
} else {
|
|
548
591
|
results = response;
|
|
549
592
|
}
|
|
550
593
|
} else if (config.raw && (config._isPagination || config.lastEvaluatedKeyRaw)) {
|
|
551
|
-
|
|
594
|
+
results = response;
|
|
552
595
|
} else {
|
|
553
596
|
if (response.Item) {
|
|
554
597
|
if (config.ignoreOwnership || this.ownsItem(response.Item)) {
|
|
@@ -573,18 +616,18 @@ class Entity {
|
|
|
573
616
|
results = null;
|
|
574
617
|
}
|
|
575
618
|
} else if (config._objectOnEmpty) {
|
|
576
|
-
return {};
|
|
619
|
+
return { data: {} };
|
|
577
620
|
} else {
|
|
578
621
|
results = null;
|
|
579
622
|
}
|
|
580
623
|
}
|
|
581
624
|
|
|
582
|
-
if (config._isPagination) {
|
|
583
|
-
|
|
584
|
-
|
|
625
|
+
if (config._isPagination || response.LastEvaluatedKey) {
|
|
626
|
+
const nextPage = this._formatReturnPager(config, response.LastEvaluatedKey);
|
|
627
|
+
return { cursor: nextPage ?? null, data: results };
|
|
585
628
|
}
|
|
586
629
|
|
|
587
|
-
return results;
|
|
630
|
+
return { data: results };
|
|
588
631
|
|
|
589
632
|
} catch (err) {
|
|
590
633
|
if (config.originalErr || stackTrace === undefined) {
|
|
@@ -608,16 +651,20 @@ class Entity {
|
|
|
608
651
|
return this.formatResponse(item, TableIndex, config);
|
|
609
652
|
}
|
|
610
653
|
|
|
611
|
-
_formatReturnPager(config,
|
|
612
|
-
let page = lastEvaluatedKey
|
|
613
|
-
if (config.pager
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
654
|
+
_formatReturnPager(config, lastEvaluatedKey) {
|
|
655
|
+
let page = lastEvaluatedKey ?? null;
|
|
656
|
+
if (config.raw || config.pager === Pager.raw) {
|
|
657
|
+
return page;
|
|
658
|
+
}
|
|
659
|
+
return config.formatCursor.serialize(page) ?? null;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
_formatExclusiveStartKey(config) {
|
|
663
|
+
let exclusiveStartKey = config.cursor;
|
|
664
|
+
if (config.raw || config.pager === Pager.raw) {
|
|
665
|
+
return exclusiveStartKey ?? null;
|
|
619
666
|
}
|
|
620
|
-
return
|
|
667
|
+
return config.formatCursor.deserialize(exclusiveStartKey) ?? null;
|
|
621
668
|
}
|
|
622
669
|
|
|
623
670
|
_getTableName() {
|
|
@@ -674,10 +721,13 @@ class Entity {
|
|
|
674
721
|
return value;
|
|
675
722
|
}
|
|
676
723
|
|
|
677
|
-
_normalizePagesValue(value
|
|
724
|
+
_normalizePagesValue(value) {
|
|
725
|
+
if (value === AllPages) {
|
|
726
|
+
return value;
|
|
727
|
+
}
|
|
678
728
|
value = parseInt(value);
|
|
679
729
|
if (isNaN(value) || value < 1) {
|
|
680
|
-
throw new e.ElectroError(e.ErrorCodes.InvalidPagesOption,
|
|
730
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidPagesOption, `Query option 'pages' must be of type 'number' and greater than zero or the string value '${AllPages}'`);
|
|
681
731
|
}
|
|
682
732
|
return value;
|
|
683
733
|
}
|
|
@@ -819,17 +869,34 @@ class Entity {
|
|
|
819
869
|
pager: Pager.named,
|
|
820
870
|
unprocessed: UnprocessedTypes.item,
|
|
821
871
|
response: 'default',
|
|
872
|
+
cursor: null,
|
|
873
|
+
data: 'attributes',
|
|
822
874
|
ignoreOwnership: false,
|
|
823
875
|
_isPagination: false,
|
|
824
876
|
_isCollectionQuery: false,
|
|
825
|
-
pages:
|
|
877
|
+
pages: 1,
|
|
826
878
|
listeners: [],
|
|
827
879
|
preserveBatchOrder: false,
|
|
828
880
|
attributes: [],
|
|
829
881
|
terminalOperation: undefined,
|
|
882
|
+
formatCursor: u.cursorFormatter,
|
|
883
|
+
order: undefined,
|
|
830
884
|
};
|
|
831
885
|
|
|
832
886
|
config = options.reduce((config, option) => {
|
|
887
|
+
if (typeof option.order === 'string') {
|
|
888
|
+
switch (option.order.toLowerCase()) {
|
|
889
|
+
case 'asc':
|
|
890
|
+
config.params[ResultOrderParam] = ResultOrderOption.asc;
|
|
891
|
+
break;
|
|
892
|
+
case 'desc':
|
|
893
|
+
config.params[ResultOrderParam] = ResultOrderOption.desc;
|
|
894
|
+
break;
|
|
895
|
+
default:
|
|
896
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidOptions, `Invalid value for query option "order" provided. Valid options include 'asc' and 'desc, received: "${option.order}"`);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
833
900
|
if (typeof option.response === 'string' && option.response.length) {
|
|
834
901
|
const format = ReturnValues[option.response];
|
|
835
902
|
if (format === undefined) {
|
|
@@ -839,6 +906,18 @@ class Entity {
|
|
|
839
906
|
config.params.ReturnValues = FormatToReturnValues[format];
|
|
840
907
|
}
|
|
841
908
|
|
|
909
|
+
if (option.formatCursor) {
|
|
910
|
+
const isValid = ['serialize', 'deserialize'].every(method =>
|
|
911
|
+
method in option.formatCursor &&
|
|
912
|
+
validate.isFunction(option.formatCursor[method])
|
|
913
|
+
);
|
|
914
|
+
if (isValid) {
|
|
915
|
+
config.formatCursor = option.formatCursor;
|
|
916
|
+
} else {
|
|
917
|
+
throw new e.ElectroError(e.ErrorCodes.InvalidOptions, `Invalid value for query option "formatCursor" provided. Formatter interface must have serialize and deserialize functions`);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
842
921
|
if (option.terminalOperation in TerminalOperation) {
|
|
843
922
|
config.terminalOperation = TerminalOperation[option.terminalOperation];
|
|
844
923
|
}
|
|
@@ -881,6 +960,22 @@ class Entity {
|
|
|
881
960
|
config.unprocessed = UnprocessedTypes.raw;
|
|
882
961
|
}
|
|
883
962
|
|
|
963
|
+
if (option.cursor) {
|
|
964
|
+
config.cursor = option.cursor;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
if (option.data) {
|
|
968
|
+
config.data = option.data;
|
|
969
|
+
switch(option.data) {
|
|
970
|
+
case 'raw':
|
|
971
|
+
config.raw = true;
|
|
972
|
+
break;
|
|
973
|
+
case 'includeKeys':
|
|
974
|
+
config.includeKeys = true;
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
884
979
|
if (option.limit !== undefined) {
|
|
885
980
|
config.limit = option.limit;
|
|
886
981
|
config.params.Limit = option.limit;
|
|
@@ -945,15 +1040,7 @@ class Entity {
|
|
|
945
1040
|
}
|
|
946
1041
|
}
|
|
947
1042
|
|
|
948
|
-
|
|
949
|
-
if (config.raw || config.pager === Pager.raw) {
|
|
950
|
-
parameters.ExclusiveStartKey = config.page;
|
|
951
|
-
} else {
|
|
952
|
-
parameters.ExclusiveStartKey = this._formatSuppliedPager(params.IndexName, config.page);
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
return {parameters, config};
|
|
1043
|
+
return { parameters, config };
|
|
957
1044
|
}
|
|
958
1045
|
|
|
959
1046
|
addListeners(logger) {
|
|
@@ -2091,12 +2178,17 @@ class Entity {
|
|
|
2091
2178
|
}
|
|
2092
2179
|
let key = prefix;
|
|
2093
2180
|
for (let i = 0; i < labels.length; i++) {
|
|
2094
|
-
|
|
2095
|
-
|
|
2181
|
+
const { name, label } = labels[i];
|
|
2182
|
+
const attribute = this.model.schema.getAttribute(name);
|
|
2183
|
+
let value = supplied[name];
|
|
2096
2184
|
if (supplied[name] === undefined && excludeLabelTail) {
|
|
2097
2185
|
break;
|
|
2098
2186
|
}
|
|
2099
2187
|
|
|
2188
|
+
if (attribute && validations.isFunction(attribute.format)) {
|
|
2189
|
+
value = attribute.format(`${value}`);
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2100
2192
|
if (isCustom) {
|
|
2101
2193
|
key = `${key}${label}`;
|
|
2102
2194
|
} else {
|
|
@@ -2107,7 +2199,7 @@ class Entity {
|
|
|
2107
2199
|
break;
|
|
2108
2200
|
}
|
|
2109
2201
|
|
|
2110
|
-
key = `${key}${
|
|
2202
|
+
key = `${key}${value}`;
|
|
2111
2203
|
}
|
|
2112
2204
|
|
|
2113
2205
|
return u.formatKeyCasing(key, casing);
|
package/src/errors.js
CHANGED
|
@@ -217,6 +217,12 @@ const ErrorCodes = {
|
|
|
217
217
|
name: "NoOwnerForPager",
|
|
218
218
|
sym: ErrorCode,
|
|
219
219
|
},
|
|
220
|
+
NoOwnerForCursor: {
|
|
221
|
+
code: 5004,
|
|
222
|
+
section: "no-owner-for-pager",
|
|
223
|
+
name: "NoOwnerForCursor",
|
|
224
|
+
sym: ErrorCode,
|
|
225
|
+
},
|
|
220
226
|
PagerNotUnique: {
|
|
221
227
|
code: 5005,
|
|
222
228
|
section: "pager-not-unique",
|
package/src/filters.js
CHANGED
|
@@ -84,7 +84,7 @@ class FilterFactory {
|
|
|
84
84
|
injected[name] = {
|
|
85
85
|
name: name,
|
|
86
86
|
action: this.buildClause(filter),
|
|
87
|
-
children: ["params", "go", "
|
|
87
|
+
children: ["params", "go", "filter", ...modelFilters],
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
filterChildren.push("filter");
|
|
@@ -93,7 +93,7 @@ class FilterFactory {
|
|
|
93
93
|
action: (entity, state, fn) => {
|
|
94
94
|
return this.buildClause(fn)(entity, state);
|
|
95
95
|
},
|
|
96
|
-
children: ["params", "go", "
|
|
96
|
+
children: ["params", "go", "filter", ...modelFilters],
|
|
97
97
|
};
|
|
98
98
|
for (let parent of filterParents) {
|
|
99
99
|
injected[parent] = { ...injected[parent] };
|
package/src/operations.js
CHANGED
|
@@ -388,7 +388,7 @@ class AttributeOperationProxy {
|
|
|
388
388
|
const attributeValues = [];
|
|
389
389
|
let hasNestedValue = false;
|
|
390
390
|
for (let value of values) {
|
|
391
|
-
value = target.
|
|
391
|
+
value = target.applyFixings(value);
|
|
392
392
|
// template.length is to see if function takes value argument
|
|
393
393
|
if (template.length > 3) {
|
|
394
394
|
if (seen.has(value)) {
|