electrodb 2.10.1 → 2.10.3
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 +11 -8
- package/src/clauses.js +26 -8
- package/src/entity.js +39 -51
- package/tsconfig.json +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electrodb",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.3",
|
|
4
4
|
"description": "A library to more easily create and interact with multiple entities and heretical relationships in dynamodb",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"build:browser": "browserify playground/browser.js -o playground/bundle.js",
|
|
9
9
|
"test": "./test.sh",
|
|
10
10
|
"test:ci": "npm install && npm test",
|
|
11
|
-
"test:run": "npm run test:
|
|
11
|
+
"test:run": "npm run test:types && npm run test:init && npm run test:unit",
|
|
12
12
|
"test:init": "node ./test/init.js",
|
|
13
13
|
"test:unit": "mocha -r ts-node/register ./test/**.spec.*",
|
|
14
14
|
"test:types": "tsd",
|
|
@@ -16,15 +16,16 @@
|
|
|
16
16
|
"coverage": "npm run test:init && nyc npm run test:unit && nyc report --reporter=text-lcov | coveralls",
|
|
17
17
|
"coverage:local:coveralls": "npm run test:init && nyc npm run test:unit && nyc report --reporter=text-lcov | coveralls",
|
|
18
18
|
"coverage:local:html": "npm run test:init && nyc npm run test:unit && nyc report --reporter=html",
|
|
19
|
-
"ddb:start": "docker compose up -d",
|
|
19
|
+
"ddb:start": "docker compose up -d dynamodb",
|
|
20
20
|
"ddb:load": "docker compose exec electro npm run test:init",
|
|
21
21
|
"ddb:stop": "docker compose stop",
|
|
22
22
|
"examples:load:library": "npm run ddb:start && npm run local:init && ts-node ./examples/library/load.ts",
|
|
23
23
|
"examples:query:library": "npm run ddb:start && npm run local:init && ts-node ./examples/library/query.ts",
|
|
24
|
-
"examples:load:taskmanager": "npm run ddb:start && npm run local:init && ts-node ./examples/
|
|
25
|
-
"examples:query:taskmanager": "npm run ddb:start && npm run local:init && ts-node ./examples/
|
|
26
|
-
"examples:load:versioncontrol": "npm run ddb:start && npm run local:init && ts-node ./examples/
|
|
27
|
-
"examples:query:versioncontrol": "npm run ddb:start && npm run local:init && ts-node ./examples/
|
|
24
|
+
"examples:load:taskmanager": "npm run ddb:start && npm run local:init && ts-node ./examples/taskManager/load.ts",
|
|
25
|
+
"examples:query:taskmanager": "npm run ddb:start && npm run local:init && ts-node ./examples/taskManager/query.ts",
|
|
26
|
+
"examples:load:versioncontrol": "npm run ddb:start && npm run local:init && ts-node ./examples/versionControl/load.ts",
|
|
27
|
+
"examples:query:versioncontrol": "npm run ddb:start && npm run local:init && ts-node ./examples/versionControl/query.ts",
|
|
28
|
+
"examples:provisiontable": "npm run ddb:start && npm run local:init && ts-node ./examples/provisionTable",
|
|
28
29
|
"examples:locks": "npm run ddb:start && npm run local:init && ts-node ./examples/locks",
|
|
29
30
|
"local:init": "LOCAL_DYNAMO_ENDPOINT='http://localhost:8000' npm run test:init",
|
|
30
31
|
"local:start": "npm run ddb:start && npm run local:init",
|
|
@@ -64,10 +65,12 @@
|
|
|
64
65
|
"prettier": "^3.0.3",
|
|
65
66
|
"prettier-plugin-astro": "^0.12.0",
|
|
66
67
|
"source-map-support": "^0.5.19",
|
|
68
|
+
"sst": "^2.28.0",
|
|
67
69
|
"ts-node": "^10.9.1",
|
|
68
70
|
"tsd": "^0.28.1",
|
|
69
71
|
"typescript": "^5.2.2",
|
|
70
|
-
"uuid": "7.0.1"
|
|
72
|
+
"uuid": "7.0.1",
|
|
73
|
+
"aws-cdk-lib": "^2.100.0"
|
|
71
74
|
},
|
|
72
75
|
"keywords": [
|
|
73
76
|
"electrodb",
|
package/src/clauses.js
CHANGED
|
@@ -973,12 +973,21 @@ let clauses = {
|
|
|
973
973
|
sk,
|
|
974
974
|
pk,
|
|
975
975
|
);
|
|
976
|
+
|
|
977
|
+
const accessPattern =
|
|
978
|
+
entity.model.translations.indexes.fromIndexToAccessPattern[
|
|
979
|
+
state.query.index
|
|
980
|
+
];
|
|
981
|
+
|
|
982
|
+
if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
|
|
983
|
+
state.filterProperties(FilterOperationNames.lte, endingSk.composites);
|
|
984
|
+
}
|
|
985
|
+
|
|
976
986
|
return state
|
|
977
987
|
.setType(QueryTypes.and)
|
|
978
988
|
.setSK(endingSk.composites)
|
|
979
989
|
.setType(QueryTypes.between)
|
|
980
|
-
.setSK(startingSk.composites)
|
|
981
|
-
.filterProperties(FilterOperationNames.lte, endingSk.composites);
|
|
990
|
+
.setSK(startingSk.composites);
|
|
982
991
|
} catch (err) {
|
|
983
992
|
state.setError(err);
|
|
984
993
|
return state;
|
|
@@ -1019,9 +1028,14 @@ let clauses = {
|
|
|
1019
1028
|
pk,
|
|
1020
1029
|
);
|
|
1021
1030
|
state.setSK(composites);
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1031
|
+
const accessPattern =
|
|
1032
|
+
entity.model.translations.indexes.fromIndexToAccessPattern[
|
|
1033
|
+
state.query.index
|
|
1034
|
+
];
|
|
1035
|
+
|
|
1036
|
+
if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
|
|
1037
|
+
state.filterProperties(FilterOperationNames.gt, composites);
|
|
1038
|
+
}
|
|
1025
1039
|
});
|
|
1026
1040
|
} catch (err) {
|
|
1027
1041
|
state.setError(err);
|
|
@@ -1086,9 +1100,13 @@ let clauses = {
|
|
|
1086
1100
|
pk,
|
|
1087
1101
|
);
|
|
1088
1102
|
state.setSK(composites);
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1103
|
+
const accessPattern =
|
|
1104
|
+
entity.model.translations.indexes.fromIndexToAccessPattern[
|
|
1105
|
+
state.query.index
|
|
1106
|
+
];
|
|
1107
|
+
if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
|
|
1108
|
+
state.filterProperties(FilterOperationNames.lte, composites);
|
|
1109
|
+
}
|
|
1092
1110
|
});
|
|
1093
1111
|
} catch (err) {
|
|
1094
1112
|
state.setError(err);
|
package/src/entity.js
CHANGED
|
@@ -184,36 +184,6 @@ class Entity {
|
|
|
184
184
|
return this.model.version;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
// ownsItem(item) {
|
|
188
|
-
// return (
|
|
189
|
-
// item &&
|
|
190
|
-
// this.getName() === item[this.identifiers.entity] &&
|
|
191
|
-
// this.getVersion() === item[this.identifiers.version] &&
|
|
192
|
-
// validations.isStringHasLength(item[this.identifiers.entity]) &&
|
|
193
|
-
// validations.isStringHasLength(item[this.identifiers.version])
|
|
194
|
-
// ) || !!this.ownsKeys(item)
|
|
195
|
-
// }
|
|
196
|
-
|
|
197
|
-
// ownsKeys({keys = {}}) {
|
|
198
|
-
// let {pk, sk} = this.model.prefixes[TableIndex];
|
|
199
|
-
// let hasSK = this.model.lookup.indexHasSortKeys[TableIndex];
|
|
200
|
-
// let pkMatch = typeof keys[pk.field] === "string" && keys[pk.field].startsWith(pk.prefix);
|
|
201
|
-
// let skMatch = pkMatch && !hasSK;
|
|
202
|
-
// if (pkMatch && hasSK) {
|
|
203
|
-
// skMatch = typeof keys[sk.field] === "string" && keys[sk.field].startsWith(sk.prefix);
|
|
204
|
-
// }
|
|
205
|
-
//
|
|
206
|
-
// return (pkMatch && skMatch &&
|
|
207
|
-
// this._formatKeysToItem(TableIndex, key) !== null);
|
|
208
|
-
// }
|
|
209
|
-
|
|
210
|
-
// ownsCursor({ cursor }) {
|
|
211
|
-
// if (typeof cursor === 'string') {
|
|
212
|
-
// cursor = u.cursorFormatter.deserialize(cursor);
|
|
213
|
-
// }
|
|
214
|
-
// return this.ownsKeys({ keys: cursor });
|
|
215
|
-
// }
|
|
216
|
-
|
|
217
187
|
ownsItem(item) {
|
|
218
188
|
return (
|
|
219
189
|
item &&
|
|
@@ -246,13 +216,18 @@ class Entity {
|
|
|
246
216
|
ownsKeys(key = {}) {
|
|
247
217
|
let { pk, sk } = this.model.prefixes[TableIndex];
|
|
248
218
|
let hasSK = this.model.lookup.indexHasSortKeys[TableIndex];
|
|
249
|
-
|
|
250
|
-
|
|
219
|
+
const typeofPkProvided = typeof key[pk.field];
|
|
220
|
+
const pkPrefixMatch =
|
|
221
|
+
typeofPkProvided === "string" && key[pk.field].startsWith(pk.prefix);
|
|
222
|
+
const isNumericPk = typeofPkProvided === "number" && pk.cast === "number";
|
|
223
|
+
let pkMatch = pkPrefixMatch || isNumericPk;
|
|
251
224
|
let skMatch = pkMatch && !hasSK;
|
|
252
225
|
if (pkMatch && hasSK) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
key[sk.field].startsWith(sk.prefix);
|
|
226
|
+
const typeofSkProvided = typeof key[sk.field];
|
|
227
|
+
const skPrefixMatch =
|
|
228
|
+
typeofSkProvided === "string" && key[sk.field].startsWith(sk.prefix);
|
|
229
|
+
const isNumericSk = typeofSkProvided === "number" && sk.cast === "number";
|
|
230
|
+
skMatch = skPrefixMatch || isNumericSk;
|
|
256
231
|
}
|
|
257
232
|
|
|
258
233
|
return (
|
|
@@ -1481,7 +1456,7 @@ class Entity {
|
|
|
1481
1456
|
}
|
|
1482
1457
|
|
|
1483
1458
|
_createKeyDeconstructor(prefixes = {}, labels = [], attributes = {}) {
|
|
1484
|
-
let { prefix, isCustom, postfix } = prefixes;
|
|
1459
|
+
let { prefix, isCustom, postfix, cast } = prefixes;
|
|
1485
1460
|
let names = [];
|
|
1486
1461
|
let types = [];
|
|
1487
1462
|
let pattern = `^${this._regexpEscape(prefix || "")}`;
|
|
@@ -1512,16 +1487,19 @@ class Entity {
|
|
|
1512
1487
|
let regex = new RegExp(pattern, "i");
|
|
1513
1488
|
|
|
1514
1489
|
return ({ key } = {}) => {
|
|
1515
|
-
|
|
1490
|
+
const typeofKey = typeof key;
|
|
1491
|
+
if (!["string", "number"].includes(typeofKey)) {
|
|
1516
1492
|
return null;
|
|
1517
1493
|
}
|
|
1518
1494
|
key = `${key}`;
|
|
1495
|
+
const isNumeric =
|
|
1496
|
+
cast === CastKeyOptions.number && typeofKey === "number";
|
|
1519
1497
|
let match = key.match(regex);
|
|
1520
1498
|
let results = {};
|
|
1521
|
-
if (match) {
|
|
1499
|
+
if (match || isNumeric) {
|
|
1522
1500
|
for (let i = 0; i < names.length; i++) {
|
|
1523
|
-
let
|
|
1524
|
-
let value = match[i + 1];
|
|
1501
|
+
let keyName = names[i];
|
|
1502
|
+
let value = isNumeric ? key : match[i + 1];
|
|
1525
1503
|
let type = types[i];
|
|
1526
1504
|
switch (type) {
|
|
1527
1505
|
case "number": {
|
|
@@ -1533,8 +1511,8 @@ class Entity {
|
|
|
1533
1511
|
break;
|
|
1534
1512
|
}
|
|
1535
1513
|
}
|
|
1536
|
-
if (
|
|
1537
|
-
results[
|
|
1514
|
+
if (keyName && value !== undefined) {
|
|
1515
|
+
results[keyName] = value;
|
|
1538
1516
|
}
|
|
1539
1517
|
}
|
|
1540
1518
|
} else {
|
|
@@ -1565,7 +1543,7 @@ class Entity {
|
|
|
1565
1543
|
let skComposites = {};
|
|
1566
1544
|
if (indexHasSortKey) {
|
|
1567
1545
|
const sk = keys[skName];
|
|
1568
|
-
if (
|
|
1546
|
+
if (sk === undefined) {
|
|
1569
1547
|
return null;
|
|
1570
1548
|
}
|
|
1571
1549
|
skComposites = deconstructors.sk({ key: sk });
|
|
@@ -2724,8 +2702,9 @@ class Entity {
|
|
|
2724
2702
|
|
|
2725
2703
|
if (
|
|
2726
2704
|
this.model.lookup.indexHasSortKeys[index] &&
|
|
2727
|
-
typeof keyExpressions.ExpressionAttributeValues[":sk1"] === "
|
|
2728
|
-
|
|
2705
|
+
(typeof keyExpressions.ExpressionAttributeValues[":sk1"] === "number" ||
|
|
2706
|
+
(typeof keyExpressions.ExpressionAttributeValues[":sk1"] === "string" &&
|
|
2707
|
+
keyExpressions.ExpressionAttributeValues[":sk1"].length > 0))
|
|
2729
2708
|
) {
|
|
2730
2709
|
if (type === QueryTypes.is) {
|
|
2731
2710
|
KeyConditionExpression = `${KeyConditionExpression} and #sk1 = :sk1`;
|
|
@@ -2834,17 +2813,18 @@ class Entity {
|
|
|
2834
2813
|
filter = {},
|
|
2835
2814
|
indexKeys = {},
|
|
2836
2815
|
) {
|
|
2837
|
-
const { pk
|
|
2816
|
+
const { pk } = indexKeys;
|
|
2838
2817
|
const sk = indexKeys.sk[0];
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2818
|
+
|
|
2819
|
+
let operator =
|
|
2820
|
+
typeof sk === "number"
|
|
2821
|
+
? Comparisons[comparison]
|
|
2822
|
+
: PartialComparisons[comparison];
|
|
2843
2823
|
|
|
2844
2824
|
if (!operator) {
|
|
2845
2825
|
throw new Error(
|
|
2846
2826
|
`Unexpected comparison operator "${comparison}", expected ${u.commaSeparatedString(
|
|
2847
|
-
Object.values(
|
|
2827
|
+
Object.values(PartialComparisons),
|
|
2848
2828
|
)}`,
|
|
2849
2829
|
);
|
|
2850
2830
|
}
|
|
@@ -2853,6 +2833,7 @@ class Entity {
|
|
|
2853
2833
|
pk,
|
|
2854
2834
|
sk,
|
|
2855
2835
|
);
|
|
2836
|
+
|
|
2856
2837
|
let params = {
|
|
2857
2838
|
TableName: this.getTableName(),
|
|
2858
2839
|
ExpressionAttributeNames: this._mergeExpressionsAttributes(
|
|
@@ -4409,6 +4390,7 @@ class Entity {
|
|
|
4409
4390
|
getClient: () => this.client,
|
|
4410
4391
|
isRoot: true,
|
|
4411
4392
|
});
|
|
4393
|
+
|
|
4412
4394
|
let filters = this._normalizeFilters(model.filters);
|
|
4413
4395
|
// todo: consider a rename
|
|
4414
4396
|
let prefixes = this._normalizeKeyFixings({
|
|
@@ -4445,6 +4427,12 @@ class Entity {
|
|
|
4445
4427
|
labels,
|
|
4446
4428
|
attributes,
|
|
4447
4429
|
);
|
|
4430
|
+
for (let attributeName in schema.attributes) {
|
|
4431
|
+
const { field } = schema.attributes[attributeName];
|
|
4432
|
+
if (indexes[accessPattern][keyType].field === field) {
|
|
4433
|
+
indexes[accessPattern][keyType].isFieldRef = true;
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4448
4436
|
}
|
|
4449
4437
|
}
|
|
4450
4438
|
|
package/tsconfig.json
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
|
8
8
|
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
|
9
9
|
"lib": ["ESNext"], /* Specify library files to be included in the compilation. */
|
|
10
|
+
"resolveJsonModule": true,
|
|
10
11
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
|
11
12
|
// "checkJs": true, /* Report errors in .js files. */
|
|
12
13
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|