electrodb 2.4.0 → 2.4.2
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/index.d.ts +5 -1
- package/package.json +1 -1
- package/src/clauses.js +86 -19
- package/src/entity.js +39 -20
- package/src/schema.js +2 -1
- package/src/service.js +6 -1
package/index.d.ts
CHANGED
|
@@ -2257,6 +2257,10 @@ export type EntityConfiguration = {
|
|
|
2257
2257
|
client?: DocumentClient;
|
|
2258
2258
|
listeners?: Array<ElectroEventListener>;
|
|
2259
2259
|
logger?: ElectroEventListener;
|
|
2260
|
+
identifiers?: {
|
|
2261
|
+
entity?: string;
|
|
2262
|
+
version?: string;
|
|
2263
|
+
},
|
|
2260
2264
|
};
|
|
2261
2265
|
|
|
2262
2266
|
export class Entity<A extends string, F extends string, C extends string, S extends Schema<A,F,C>> {
|
|
@@ -2374,4 +2378,4 @@ declare function CustomAttributeType<T>(
|
|
|
2374
2378
|
? OpaquePrimitiveTypeName<T>
|
|
2375
2379
|
: CustomAttributeTypeName<T>;
|
|
2376
2380
|
|
|
2377
|
-
declare function createSchema<A extends string, F extends string, C extends string, S extends Schema<A,F,C>>(schema: S): S
|
|
2381
|
+
declare function createSchema<A extends string, F extends string, C extends string, S extends Schema<A,F,C>>(schema: S): S
|
package/package.json
CHANGED
package/src/clauses.js
CHANGED
|
@@ -37,7 +37,7 @@ let clauses = {
|
|
|
37
37
|
return state;
|
|
38
38
|
}
|
|
39
39
|
try {
|
|
40
|
-
const {pk, sk} = state.getCompositeAttributes();
|
|
40
|
+
const { pk, sk } = state.getCompositeAttributes();
|
|
41
41
|
return state
|
|
42
42
|
.setType(QueryTypes.clustered_collection)
|
|
43
43
|
.setMethod(MethodTypes.query)
|
|
@@ -50,6 +50,22 @@ let clauses = {
|
|
|
50
50
|
if (sk.length > 1) {
|
|
51
51
|
state.filterProperties(FilterOperationNames.eq, {...unused, ...composites});
|
|
52
52
|
}
|
|
53
|
+
})
|
|
54
|
+
.whenOptions(({ options, state }) => {
|
|
55
|
+
if (!options.ignoreOwnership) {
|
|
56
|
+
state.query.options.expressions.names = {
|
|
57
|
+
...state.query.options.expressions.names,
|
|
58
|
+
...state.query.options.identifiers.names,
|
|
59
|
+
};
|
|
60
|
+
state.query.options.expressions.values = {
|
|
61
|
+
...state.query.options.expressions.values,
|
|
62
|
+
...state.query.options.identifiers.values,
|
|
63
|
+
};
|
|
64
|
+
state.query.options.expressions.expression =
|
|
65
|
+
state.query.options.expressions.expression.length > 1
|
|
66
|
+
? `(${state.query.options.expressions.expression}) AND ${state.query.options.identifiers.expression}`
|
|
67
|
+
: `${state.query.options.identifiers.expression}`;
|
|
68
|
+
}
|
|
53
69
|
});
|
|
54
70
|
|
|
55
71
|
} catch(err) {
|
|
@@ -72,7 +88,23 @@ let clauses = {
|
|
|
72
88
|
.setType(QueryTypes.collection)
|
|
73
89
|
.setMethod(MethodTypes.query)
|
|
74
90
|
.setCollection(collection)
|
|
75
|
-
.setPK(entity._expectFacets(facets, pk))
|
|
91
|
+
.setPK(entity._expectFacets(facets, pk))
|
|
92
|
+
.whenOptions(({ options, state }) => {
|
|
93
|
+
if (!options.ignoreOwnership) {
|
|
94
|
+
state.query.options.expressions.names = {
|
|
95
|
+
...state.query.options.expressions.names,
|
|
96
|
+
...state.query.options.identifiers.names,
|
|
97
|
+
};
|
|
98
|
+
state.query.options.expressions.values = {
|
|
99
|
+
...state.query.options.expressions.values,
|
|
100
|
+
...state.query.options.identifiers.values,
|
|
101
|
+
};
|
|
102
|
+
state.query.options.expressions.expression =
|
|
103
|
+
state.query.options.expressions.expression.length > 1
|
|
104
|
+
? `(${state.query.options.expressions.expression}) AND ${state.query.options.identifiers.expression}`
|
|
105
|
+
: `${state.query.options.identifiers.expression}`;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
76
108
|
} catch(err) {
|
|
77
109
|
state.setError(err);
|
|
78
110
|
return state;
|
|
@@ -87,7 +119,13 @@ let clauses = {
|
|
|
87
119
|
return state;
|
|
88
120
|
}
|
|
89
121
|
try {
|
|
90
|
-
return state.setMethod(MethodTypes.scan)
|
|
122
|
+
return state.setMethod(MethodTypes.scan)
|
|
123
|
+
.whenOptions(({ state, options }) => {
|
|
124
|
+
if (!options.ignoreOwnership) {
|
|
125
|
+
state.unsafeApplyFilter(FilterOperationNames.eq, entity.identifiers.entity, entity.getName());
|
|
126
|
+
state.unsafeApplyFilter(FilterOperationNames.eq, entity.identifiers.version, entity.getVersion());
|
|
127
|
+
}
|
|
128
|
+
});
|
|
91
129
|
} catch(err) {
|
|
92
130
|
state.setError(err);
|
|
93
131
|
return state;
|
|
@@ -478,10 +516,13 @@ let clauses = {
|
|
|
478
516
|
if (sk.length > 1) {
|
|
479
517
|
state.filterProperties(FilterOperationNames.eq, {...unused, ...composites});
|
|
480
518
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
519
|
+
|
|
520
|
+
state.whenOptions(({ options, state }) => {
|
|
521
|
+
if (state.query.options.indexType === IndexTypes.clustered && Object.keys(composites).length < sk.length && !options.ignoreOwnership) {
|
|
522
|
+
state.unsafeApplyFilter(FilterOperationNames.eq, entity.identifiers.entity, entity.getName())
|
|
523
|
+
.unsafeApplyFilter(FilterOperationNames.eq, entity.identifiers.version, entity.getVersion());
|
|
524
|
+
}
|
|
525
|
+
});
|
|
485
526
|
});
|
|
486
527
|
} catch(err) {
|
|
487
528
|
state.setError(err);
|
|
@@ -632,20 +673,26 @@ let clauses = {
|
|
|
632
673
|
throw new e.ElectroError(e.ErrorCodes.MissingTable, `Table name not defined. Table names must be either defined on the model, instance configuration, or as a query option.`);
|
|
633
674
|
}
|
|
634
675
|
const method = state.getMethod();
|
|
676
|
+
const normalizedOptions = entity._normalizeExecutionOptions({ provided: [ state.getOptions(), state.query.options, options ] });
|
|
677
|
+
state.applyWithOptions(normalizedOptions);
|
|
635
678
|
let results;
|
|
636
679
|
switch (method) {
|
|
637
|
-
case MethodTypes.query:
|
|
638
|
-
results = entity._queryParams(state,
|
|
680
|
+
case MethodTypes.query: {
|
|
681
|
+
results = entity._queryParams(state, normalizedOptions);
|
|
639
682
|
break;
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
case MethodTypes.batchGet:
|
|
644
|
-
results = entity._batchGetParams(state, options);
|
|
683
|
+
}
|
|
684
|
+
case MethodTypes.batchWrite: {
|
|
685
|
+
results = entity._batchWriteParams(state, normalizedOptions);
|
|
645
686
|
break;
|
|
646
|
-
|
|
647
|
-
|
|
687
|
+
}
|
|
688
|
+
case MethodTypes.batchGet: {
|
|
689
|
+
results = entity._batchGetParams(state, normalizedOptions);
|
|
648
690
|
break;
|
|
691
|
+
}
|
|
692
|
+
default: {
|
|
693
|
+
results = entity._params(state, normalizedOptions);
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
649
696
|
}
|
|
650
697
|
|
|
651
698
|
if (method === MethodTypes.update && results.ExpressionAttributeValues && Object.keys(results.ExpressionAttributeValues).length === 0) {
|
|
@@ -653,6 +700,14 @@ let clauses = {
|
|
|
653
700
|
// todo: change the getValues() method to return undefined in this case (would potentially require a more generous refactor)
|
|
654
701
|
delete results.ExpressionAttributeValues;
|
|
655
702
|
}
|
|
703
|
+
|
|
704
|
+
if (options._returnOptions) {
|
|
705
|
+
return {
|
|
706
|
+
params: results,
|
|
707
|
+
options: normalizedOptions,
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
656
711
|
return results;
|
|
657
712
|
} catch(err) {
|
|
658
713
|
throw err;
|
|
@@ -671,9 +726,8 @@ let clauses = {
|
|
|
671
726
|
throw new e.ElectroError(e.ErrorCodes.NoClientDefined, "No client defined on model");
|
|
672
727
|
}
|
|
673
728
|
options.terminalOperation = TerminalOperation.go;
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
return entity.go(state.getMethod(), params, config);
|
|
729
|
+
const paramResults = clauses.params.action(entity, state, { ...options, _returnOptions: true });
|
|
730
|
+
return entity.go(state.getMethod(), paramResults.params, paramResults.options);
|
|
677
731
|
} catch(err) {
|
|
678
732
|
return Promise.reject(err);
|
|
679
733
|
}
|
|
@@ -718,6 +772,7 @@ class ChainState {
|
|
|
718
772
|
options,
|
|
719
773
|
};
|
|
720
774
|
this.subStates = [];
|
|
775
|
+
this.applyAfterOptions = [];
|
|
721
776
|
this.hasSortKey = hasSortKey;
|
|
722
777
|
this.prev = null;
|
|
723
778
|
this.self = null;
|
|
@@ -911,6 +966,18 @@ class ChainState {
|
|
|
911
966
|
this.query.put.data = {...this.query.put.data, ...data};
|
|
912
967
|
return this;
|
|
913
968
|
}
|
|
969
|
+
|
|
970
|
+
whenOptions(fn) {
|
|
971
|
+
if (v.isFunction(fn)) {
|
|
972
|
+
this.applyAfterOptions.push((options) => {
|
|
973
|
+
fn({ options, state: this });
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
applyWithOptions(options = {}) {
|
|
979
|
+
this.applyAfterOptions.forEach((fn) => fn(options));
|
|
980
|
+
}
|
|
914
981
|
}
|
|
915
982
|
|
|
916
983
|
module.exports = {
|
package/src/entity.js
CHANGED
|
@@ -583,7 +583,7 @@ class Entity {
|
|
|
583
583
|
for (let i = 0; i < responses.length; i++) {
|
|
584
584
|
const item = responses[i];
|
|
585
585
|
const slot = orderMaintainer.getOrder(item);
|
|
586
|
-
const formatted = this.formatResponse({Item: item}, index, config);
|
|
586
|
+
const formatted = this.formatResponse({ Item: item }, index, config);
|
|
587
587
|
if (slot !== -1) {
|
|
588
588
|
resultsAll[slot] = formatted.data;
|
|
589
589
|
} else {
|
|
@@ -617,6 +617,8 @@ class Entity {
|
|
|
617
617
|
if (Object.keys(results).length === 0) {
|
|
618
618
|
results = null;
|
|
619
619
|
}
|
|
620
|
+
} else if (!config._objectOnEmpty) {
|
|
621
|
+
results = null;
|
|
620
622
|
}
|
|
621
623
|
} else if (response.Items) {
|
|
622
624
|
results = [];
|
|
@@ -881,7 +883,7 @@ class Entity {
|
|
|
881
883
|
return pager
|
|
882
884
|
}
|
|
883
885
|
|
|
884
|
-
|
|
886
|
+
_normalizeExecutionOptions({ provided = [] } = {}) {
|
|
885
887
|
let config = {
|
|
886
888
|
includeKeys: false,
|
|
887
889
|
originalErr: false,
|
|
@@ -909,7 +911,7 @@ class Entity {
|
|
|
909
911
|
order: undefined,
|
|
910
912
|
};
|
|
911
913
|
|
|
912
|
-
|
|
914
|
+
return provided.filter(Boolean).reduce((config, option) => {
|
|
913
915
|
if (typeof option.order === 'string') {
|
|
914
916
|
switch (option.order.toLowerCase()) {
|
|
915
917
|
case 'asc':
|
|
@@ -933,7 +935,7 @@ class Entity {
|
|
|
933
935
|
}
|
|
934
936
|
|
|
935
937
|
if (option.formatCursor) {
|
|
936
|
-
const isValid = ['serialize', 'deserialize'].every(method =>
|
|
938
|
+
const isValid = ['serialize', 'deserialize'].every(method =>
|
|
937
939
|
method in option.formatCursor &&
|
|
938
940
|
validations.isFunction(option.formatCursor[method])
|
|
939
941
|
);
|
|
@@ -1058,16 +1060,18 @@ class Entity {
|
|
|
1058
1060
|
config.params = Object.assign({}, config.params, option.params);
|
|
1059
1061
|
return config;
|
|
1060
1062
|
}, config);
|
|
1063
|
+
}
|
|
1061
1064
|
|
|
1065
|
+
_applyParameterOptions({ params = {}, options = {} } = {}) {
|
|
1062
1066
|
let parameters = Object.assign({}, params);
|
|
1063
1067
|
|
|
1064
|
-
for (let customParameter of Object.keys(
|
|
1065
|
-
if (
|
|
1066
|
-
parameters[customParameter] =
|
|
1068
|
+
for (let customParameter of Object.keys(options.params || {})) {
|
|
1069
|
+
if (options.params[customParameter] !== undefined) {
|
|
1070
|
+
parameters[customParameter] = options.params[customParameter];
|
|
1067
1071
|
}
|
|
1068
1072
|
}
|
|
1069
1073
|
|
|
1070
|
-
return
|
|
1074
|
+
return parameters;
|
|
1071
1075
|
}
|
|
1072
1076
|
|
|
1073
1077
|
addListeners(logger) {
|
|
@@ -1117,7 +1121,7 @@ class Entity {
|
|
|
1117
1121
|
}
|
|
1118
1122
|
/* istanbul ignore next */
|
|
1119
1123
|
_params(state, config = {}) {
|
|
1120
|
-
|
|
1124
|
+
const { keys = {}, method = "", put = {}, update = {}, filter = {}, upsert } = state.query;
|
|
1121
1125
|
let consolidatedQueryFacets = this._consolidateQueryFacets(keys.sk);
|
|
1122
1126
|
let params = {};
|
|
1123
1127
|
switch (method) {
|
|
@@ -1148,8 +1152,13 @@ class Entity {
|
|
|
1148
1152
|
default:
|
|
1149
1153
|
throw new Error(`Invalid method: ${method}`);
|
|
1150
1154
|
}
|
|
1151
|
-
|
|
1152
|
-
|
|
1155
|
+
|
|
1156
|
+
let appliedParameters = this._applyParameterOptions({
|
|
1157
|
+
params,
|
|
1158
|
+
options: config,
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
return this._applyParameterExpressions(method, appliedParameters, config, filter);
|
|
1153
1162
|
}
|
|
1154
1163
|
|
|
1155
1164
|
_applyParameterExpressions(method, parameters, config, filter) {
|
|
@@ -1251,12 +1260,19 @@ class Entity {
|
|
|
1251
1260
|
_batchGetParams(state, config = {}) {
|
|
1252
1261
|
let table = config.table || this.getTableName();
|
|
1253
1262
|
let userDefinedParams = config.params || {};
|
|
1263
|
+
|
|
1264
|
+
// TableName is added when the config provided includes "table"
|
|
1265
|
+
// this is evaluated upstream so we remove it to avoid forming
|
|
1266
|
+
// bad syntax. Code should reconsider how this is applied to
|
|
1267
|
+
// make this cleaner :(
|
|
1268
|
+
delete userDefinedParams.TableName;
|
|
1269
|
+
|
|
1254
1270
|
let records = [];
|
|
1255
1271
|
for (let itemState of state.subStates) {
|
|
1256
1272
|
let method = itemState.query.method;
|
|
1257
1273
|
let params = this._params(itemState, config);
|
|
1258
1274
|
if (method === MethodTypes.get) {
|
|
1259
|
-
let {Key} = params;
|
|
1275
|
+
let { Key } = params;
|
|
1260
1276
|
records.push(Key);
|
|
1261
1277
|
}
|
|
1262
1278
|
}
|
|
@@ -1356,11 +1372,7 @@ class Entity {
|
|
|
1356
1372
|
),
|
|
1357
1373
|
FilterExpression: `begins_with(#${pkField}, :${pkField})`,
|
|
1358
1374
|
};
|
|
1359
|
-
|
|
1360
|
-
params.ExpressionAttributeNames["#" + this.identifiers.version] = this.identifiers.version;
|
|
1361
|
-
params.ExpressionAttributeValues[":" + this.identifiers.entity] = this.getName();
|
|
1362
|
-
params.ExpressionAttributeValues[":" + this.identifiers.version] = this.getVersion();
|
|
1363
|
-
params.FilterExpression = `${params.FilterExpression} AND #${this.identifiers.entity} = :${this.identifiers.entity} AND #${this.identifiers.version} = :${this.identifiers.version}`;
|
|
1375
|
+
|
|
1364
1376
|
if (hasSortKey) {
|
|
1365
1377
|
let skField = this.model.indexes[accessPattern].sk.field;
|
|
1366
1378
|
params.FilterExpression = `${params.FilterExpression} AND begins_with(#${skField}, :${skField})`;
|
|
@@ -1691,8 +1703,16 @@ class Entity {
|
|
|
1691
1703
|
default:
|
|
1692
1704
|
throw new Error(`Invalid query type: ${state.query.type}`);
|
|
1693
1705
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1706
|
+
|
|
1707
|
+
const appliedParameters = this._applyParameterOptions({
|
|
1708
|
+
params: parameters,
|
|
1709
|
+
options,
|
|
1710
|
+
});
|
|
1711
|
+
|
|
1712
|
+
return this._applyProjectionExpressions({
|
|
1713
|
+
parameters: appliedParameters,
|
|
1714
|
+
config: options,
|
|
1715
|
+
});
|
|
1696
1716
|
}
|
|
1697
1717
|
|
|
1698
1718
|
_makeBetweenQueryParams(index, filter, pk, ...sk) {
|
|
@@ -2293,7 +2313,6 @@ class Entity {
|
|
|
2293
2313
|
indexType,
|
|
2294
2314
|
isCollection = false,
|
|
2295
2315
|
}) {
|
|
2296
|
-
|
|
2297
2316
|
this._validateIndex(index);
|
|
2298
2317
|
const excludePostfix = indexType === IndexTypes.clustered && isCollection;
|
|
2299
2318
|
const transforms = this._makeKeyTransforms(queryType);
|
package/src/schema.js
CHANGED
package/src/service.js
CHANGED
|
@@ -391,13 +391,18 @@ class Service {
|
|
|
391
391
|
return this.expectCursorOwner(cursor).deserializeCursor(cursor);
|
|
392
392
|
}
|
|
393
393
|
},
|
|
394
|
-
|
|
394
|
+
identifiers: {
|
|
395
395
|
names: identifiers.names || {},
|
|
396
396
|
values: identifiers.values || {},
|
|
397
397
|
expression: allEntities.length > 1
|
|
398
398
|
? `(${expression})`
|
|
399
399
|
: expression
|
|
400
400
|
},
|
|
401
|
+
expressions: {
|
|
402
|
+
names: {},
|
|
403
|
+
values: {},
|
|
404
|
+
expression: '',
|
|
405
|
+
},
|
|
401
406
|
attributes,
|
|
402
407
|
entities,
|
|
403
408
|
indexType,
|