electrodb 2.14.3 → 3.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/src/clauses.js CHANGED
@@ -9,6 +9,7 @@ const {
9
9
  KeyTypes,
10
10
  IndexTypes,
11
11
  UpsertOperations,
12
+ ComparisonTypes,
12
13
  } = require("./types");
13
14
  const {
14
15
  AttributeOperationProxy,
@@ -119,13 +120,27 @@ let clauses = {
119
120
  pk,
120
121
  );
121
122
  state.setSK(composites);
122
- // we must apply eq on filter on all provided because if the user then does a sort key operation, it'd actually then unexpect results
123
- if (sk.length > 1) {
124
- state.filterProperties(FilterOperationNames.eq, {
125
- ...unused,
126
- ...composites,
127
- });
128
- }
123
+ state.beforeBuildParams(({ options, state }) => {
124
+ const accessPattern =
125
+ entity.model.translations.indexes.fromIndexToAccessPattern[
126
+ state.query.index
127
+ ];
128
+
129
+ if (
130
+ options.compare === ComparisonTypes.attributes ||
131
+ options.compare === ComparisonTypes.v2
132
+ ) {
133
+ if (
134
+ !entity.model.indexes[accessPattern].sk.isFieldRef &&
135
+ sk.length > 1
136
+ ) {
137
+ state.filterProperties(FilterOperationNames.eq, {
138
+ ...unused,
139
+ ...composites,
140
+ });
141
+ }
142
+ }
143
+ });
129
144
  })
130
145
  .whenOptions(({ options, state }) => {
131
146
  if (!options.ignoreOwnership && !state.getParams()) {
@@ -204,11 +219,13 @@ let clauses = {
204
219
  .whenOptions(({ state, options }) => {
205
220
  if (!options.ignoreOwnership && !state.getParams()) {
206
221
  state.unsafeApplyFilter(
222
+ {},
207
223
  FilterOperationNames.eq,
208
224
  entity.identifiers.entity,
209
225
  entity.getName(),
210
226
  );
211
227
  state.unsafeApplyFilter(
228
+ {},
212
229
  FilterOperationNames.eq,
213
230
  entity.identifiers.version,
214
231
  entity.getVersion(),
@@ -324,9 +341,9 @@ let clauses = {
324
341
  const attributes = state.getCompositeAttributes();
325
342
  const filter = state.query.filter[ExpressionTypes.ConditionExpression];
326
343
  const { pk, sk } = entity._getPrimaryIndexFieldNames();
327
- filter.unsafeSet(FilterOperationNames.exists, pk);
344
+ filter.unsafeSet({}, FilterOperationNames.exists, pk);
328
345
  if (sk) {
329
- filter.unsafeSet(FilterOperationNames.exists, sk);
346
+ filter.unsafeSet({}, FilterOperationNames.exists, sk);
330
347
  }
331
348
  const pkComposite = entity._expectFacets(facets, attributes.pk);
332
349
  state.addOption("_includeOnResponseItem", pkComposite);
@@ -432,14 +449,15 @@ let clauses = {
432
449
  const { pk } = state.query.keys;
433
450
  const sk = state.query.keys.sk[0];
434
451
 
435
- const { updatedKeys, setAttributes, indexKey, deletedKeys = [] } = entity._getPutKeys(
436
- pk,
437
- sk && sk.facets,
438
- onlySetAppliedData,
439
- );
452
+ const {
453
+ updatedKeys,
454
+ setAttributes,
455
+ indexKey,
456
+ deletedKeys = [],
457
+ } = entity._getPutKeys(pk, sk && sk.facets, onlySetAppliedData);
440
458
 
441
459
  for (const deletedKey of deletedKeys) {
442
- state.query.update.remove(deletedKey)
460
+ state.query.update.remove(deletedKey);
443
461
  }
444
462
 
445
463
  // calculated here but needs to be used when building the params
@@ -540,9 +558,9 @@ let clauses = {
540
558
  const attributes = state.getCompositeAttributes();
541
559
  const filter = state.query.filter[ExpressionTypes.ConditionExpression];
542
560
  const { pk, sk } = entity._getPrimaryIndexFieldNames();
543
- filter.unsafeSet(FilterOperationNames.notExists, pk);
561
+ filter.unsafeSet({}, FilterOperationNames.notExists, pk);
544
562
  if (sk) {
545
- filter.unsafeSet(FilterOperationNames.notExists, sk);
563
+ filter.unsafeSet({}, FilterOperationNames.notExists, sk);
546
564
  }
547
565
  return state
548
566
  .setMethod(MethodTypes.put)
@@ -570,9 +588,9 @@ let clauses = {
570
588
  const attributes = state.getCompositeAttributes();
571
589
  const filter = state.query.filter[ExpressionTypes.ConditionExpression];
572
590
  const { pk, sk } = entity._getPrimaryIndexFieldNames();
573
- filter.unsafeSet(FilterOperationNames.exists, pk);
591
+ filter.unsafeSet({}, FilterOperationNames.exists, pk);
574
592
  if (sk) {
575
- filter.unsafeSet(FilterOperationNames.exists, sk);
593
+ filter.unsafeSet({}, FilterOperationNames.exists, sk);
576
594
  }
577
595
  const pkComposite = entity._expectFacets(facets, attributes.pk);
578
596
  state.addOption("_includeOnResponseItem", pkComposite);
@@ -923,15 +941,20 @@ let clauses = {
923
941
  pk,
924
942
  );
925
943
  state.setSK(state.buildQueryComposites(facets, sk));
926
- // we must apply eq on filter on all provided because if the user then does a sort key operation, it'd actually then unexpect results
927
- if (sk.length > 1) {
928
- state.filterProperties(FilterOperationNames.eq, {
929
- ...unused,
930
- ...composites,
931
- });
932
- }
933
944
 
934
945
  state.whenOptions(({ options, state }) => {
946
+ if (
947
+ options.compare === ComparisonTypes.attributes ||
948
+ options.compare === ComparisonTypes.v2
949
+ ) {
950
+ if (sk.length > 1) {
951
+ state.filterProperties(FilterOperationNames.eq, {
952
+ ...unused,
953
+ ...composites,
954
+ });
955
+ }
956
+ }
957
+
935
958
  if (
936
959
  state.query.options.indexType === IndexTypes.clustered &&
937
960
  Object.keys(composites).length < sk.length &&
@@ -940,11 +963,13 @@ let clauses = {
940
963
  ) {
941
964
  state
942
965
  .unsafeApplyFilter(
966
+ {},
943
967
  FilterOperationNames.eq,
944
968
  entity.identifiers.entity,
945
969
  entity.getName(),
946
970
  )
947
971
  .unsafeApplyFilter(
972
+ {},
948
973
  FilterOperationNames.eq,
949
974
  entity.identifiers.version,
950
975
  entity.getVersion(),
@@ -983,15 +1008,34 @@ let clauses = {
983
1008
  state.query.index
984
1009
  ];
985
1010
 
986
- if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
987
- state.filterProperties(FilterOperationNames.lte, endingSk.composites);
988
- }
989
-
990
1011
  return state
991
1012
  .setType(QueryTypes.and)
992
1013
  .setSK(endingSk.composites)
993
1014
  .setType(QueryTypes.between)
994
- .setSK(startingSk.composites);
1015
+ .setSK(startingSk.composites)
1016
+ .beforeBuildParams(({ options, state }) => {
1017
+ if (
1018
+ options.compare === ComparisonTypes.attributes ||
1019
+ options.compare === ComparisonTypes.v2
1020
+ ) {
1021
+ if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
1022
+ state.filterProperties(
1023
+ FilterOperationNames.lte,
1024
+ endingSk.composites,
1025
+ { asPrefix: true },
1026
+ );
1027
+ }
1028
+ if (options.compare === ComparisonTypes.attributes) {
1029
+ if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
1030
+ state.filterProperties(
1031
+ FilterOperationNames.gte,
1032
+ startingSk.composites,
1033
+ { asPrefix: true },
1034
+ );
1035
+ }
1036
+ }
1037
+ }
1038
+ });
995
1039
  } catch (err) {
996
1040
  state.setError(err);
997
1041
  return state;
@@ -1032,14 +1076,23 @@ let clauses = {
1032
1076
  pk,
1033
1077
  );
1034
1078
  state.setSK(composites);
1035
- const accessPattern =
1036
- entity.model.translations.indexes.fromIndexToAccessPattern[
1037
- state.query.index
1038
- ];
1039
-
1040
- if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
1041
- state.filterProperties(FilterOperationNames.gt, composites);
1042
- }
1079
+ state.beforeBuildParams(({ options, state }) => {
1080
+ if (
1081
+ options.compare === ComparisonTypes.attributes ||
1082
+ options.compare === ComparisonTypes.v2
1083
+ ) {
1084
+ const accessPattern =
1085
+ entity.model.translations.indexes.fromIndexToAccessPattern[
1086
+ state.query.index
1087
+ ];
1088
+
1089
+ if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
1090
+ state.filterProperties(FilterOperationNames.gt, composites, {
1091
+ asPrefix: true,
1092
+ });
1093
+ }
1094
+ }
1095
+ });
1043
1096
  });
1044
1097
  } catch (err) {
1045
1098
  state.setError(err);
@@ -1058,6 +1111,27 @@ let clauses = {
1058
1111
  return state.setType(QueryTypes.gte).ifSK((state) => {
1059
1112
  const attributes = state.getCompositeAttributes();
1060
1113
  state.setSK(state.buildQueryComposites(facets, attributes.sk));
1114
+ state.beforeBuildParams(({ options, state }) => {
1115
+ const { composites } = state.identifyCompositeAttributes(
1116
+ facets,
1117
+ attributes.sk,
1118
+ attributes.pk,
1119
+ );
1120
+ if (options.compare === ComparisonTypes.attributes) {
1121
+ const accessPattern =
1122
+ entity.model.translations.indexes.fromIndexToAccessPattern[
1123
+ state.query.index
1124
+ ];
1125
+ if (
1126
+ !entity.model.indexes[accessPattern].sk.isFieldRef &&
1127
+ attributes.sk.length > 1
1128
+ ) {
1129
+ state.filterProperties(FilterOperationNames.gte, composites, {
1130
+ asPrefix: true,
1131
+ });
1132
+ }
1133
+ }
1134
+ });
1061
1135
  });
1062
1136
  } catch (err) {
1063
1137
  state.setError(err);
@@ -1081,6 +1155,19 @@ let clauses = {
1081
1155
  pk,
1082
1156
  );
1083
1157
  state.setSK(composites);
1158
+ state.beforeBuildParams(({ options, state }) => {
1159
+ if (options.compare === ComparisonTypes.attributes) {
1160
+ const accessPattern =
1161
+ entity.model.translations.indexes.fromIndexToAccessPattern[
1162
+ state.query.index
1163
+ ];
1164
+ if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
1165
+ state.filterProperties(FilterOperationNames.lt, composites, {
1166
+ asPrefix: true,
1167
+ });
1168
+ }
1169
+ }
1170
+ });
1084
1171
  });
1085
1172
  } catch (err) {
1086
1173
  state.setError(err);
@@ -1104,13 +1191,23 @@ let clauses = {
1104
1191
  pk,
1105
1192
  );
1106
1193
  state.setSK(composites);
1107
- const accessPattern =
1108
- entity.model.translations.indexes.fromIndexToAccessPattern[
1109
- state.query.index
1110
- ];
1111
- if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
1112
- state.filterProperties(FilterOperationNames.lte, composites);
1113
- }
1194
+
1195
+ state.beforeBuildParams(({ options, state }) => {
1196
+ if (
1197
+ options.compare === ComparisonTypes.attributes ||
1198
+ options.compare === ComparisonTypes.v2
1199
+ ) {
1200
+ const accessPattern =
1201
+ entity.model.translations.indexes.fromIndexToAccessPattern[
1202
+ state.query.index
1203
+ ];
1204
+ if (!entity.model.indexes[accessPattern].sk.isFieldRef) {
1205
+ state.filterProperties(FilterOperationNames.lte, composites, {
1206
+ asPrefix: true,
1207
+ });
1208
+ }
1209
+ }
1210
+ });
1114
1211
  });
1115
1212
  } catch (err) {
1116
1213
  state.setError(err);
@@ -1430,14 +1527,20 @@ class ChainState {
1430
1527
  };
1431
1528
  }
1432
1529
 
1433
- applyFilter(operation, name, ...values) {
1530
+ applyFilter(operation, name, values, filterOptions) {
1434
1531
  if (
1435
- (FilterOperationNames[operation] !== undefined) & (name !== undefined) &&
1436
- values.length > 0
1532
+ FilterOperationNames[operation] !== undefined &&
1533
+ name !== undefined &&
1534
+ values !== undefined
1437
1535
  ) {
1438
1536
  const attribute = this.attributes[name];
1439
1537
  if (attribute !== undefined) {
1440
- this.unsafeApplyFilter(operation, attribute.field, ...values);
1538
+ this.unsafeApplyFilter(
1539
+ filterOptions,
1540
+ operation,
1541
+ attribute.field,
1542
+ values,
1543
+ );
1441
1544
  }
1442
1545
  }
1443
1546
  return this;
@@ -1452,28 +1555,28 @@ class ChainState {
1452
1555
  const attribute = this.attributes[name];
1453
1556
  if (attribute !== undefined) {
1454
1557
  const filter = this.query.filter[ExpressionTypes.ConditionExpression];
1455
- filter.unsafeSet(operation, attribute.field, ...values);
1558
+ filter.unsafeSet({}, operation, attribute.field, ...values);
1456
1559
  }
1457
1560
  }
1458
1561
  return this;
1459
1562
  }
1460
1563
 
1461
- unsafeApplyFilter(operation, name, ...values) {
1564
+ unsafeApplyFilter(filterOptions = {}, operation, name, values) {
1462
1565
  if (
1463
1566
  (FilterOperationNames[operation] !== undefined) & (name !== undefined) &&
1464
- values.length > 0
1567
+ values !== undefined
1465
1568
  ) {
1466
1569
  const filter = this.query.filter[ExpressionTypes.FilterExpression];
1467
- filter.unsafeSet(operation, name, ...values);
1570
+ filter.unsafeSet(filterOptions, operation, name, values);
1468
1571
  }
1469
1572
  return this;
1470
1573
  }
1471
1574
 
1472
- filterProperties(operation, obj = {}) {
1575
+ filterProperties(operation, obj = {}, filterOptions = {}) {
1473
1576
  for (const property in obj) {
1474
1577
  const value = obj[property];
1475
1578
  if (value !== undefined) {
1476
- this.applyFilter(operation, property, value);
1579
+ this.applyFilter(operation, property, value, filterOptions);
1477
1580
  }
1478
1581
  }
1479
1582
  return this;
@@ -1551,8 +1654,11 @@ class ChainState {
1551
1654
  fn({ options, state: this });
1552
1655
  });
1553
1656
  }
1657
+
1658
+ return this;
1554
1659
  }
1555
1660
 
1661
+ // these are ran before "beforeBuildParams"
1556
1662
  applyWithOptions(options = {}) {
1557
1663
  this.applyAfterOptions.forEach((fn) => fn(options));
1558
1664
  }
@@ -1563,6 +1669,7 @@ class ChainState {
1563
1669
  fn({ options, state: this });
1564
1670
  });
1565
1671
  }
1672
+ return this;
1566
1673
  }
1567
1674
 
1568
1675
  applyBeforeBuildParams(options = {}) {
package/src/client.js CHANGED
@@ -1,5 +1,5 @@
1
- const lib = require('@aws-sdk/lib-dynamodb')
2
- const util = require('@aws-sdk/lib-dynamodb/dist-cjs/commands/utils')
1
+ const lib = require("@aws-sdk/lib-dynamodb");
2
+ const util = require("@aws-sdk/util-dynamodb");
3
3
  const { isFunction } = require("./validations");
4
4
  const { ElectroError, ErrorCodes } = require("./errors");
5
5
  const DocumentClientVersions = {
@@ -7,7 +7,16 @@ const DocumentClientVersions = {
7
7
  v3: "v3",
8
8
  electro: "electro",
9
9
  };
10
- const unmarshallOutput = util.unmarshallOutput || ((val) => val);
10
+ const unmarshallItem = (value) => {
11
+ const unmarshall = util.unmarshall || ((val) => val);
12
+ try {
13
+ value.Item = unmarshall(value.Item);
14
+ } catch (err) {
15
+ console.error("Internal Error: Failed to unmarshal input", err);
16
+ }
17
+
18
+ return value;
19
+ };
11
20
 
12
21
  const v3Methods = ["send"];
13
22
  const v2Methods = [
@@ -89,7 +98,7 @@ class DocumentClientV2Wrapper {
89
98
  return {
90
99
  canceled: cancellationReasons.map((reason) => {
91
100
  if (reason.Item) {
92
- return unmarshallOutput(reason, [{ key: "Item" }]);
101
+ return unmarshallItem(reason);
93
102
  }
94
103
  return reason;
95
104
  }),
@@ -202,7 +211,7 @@ class DocumentClientV3Wrapper {
202
211
  return {
203
212
  canceled: err.CancellationReasons.map((reason) => {
204
213
  if (reason.Item) {
205
- return unmarshallOutput(reason, [{ key: "Item" }]);
214
+ return unmarshallItem(reason);
206
215
  }
207
216
  return reason;
208
217
  }),
@@ -225,7 +234,7 @@ class DocumentClientV3Wrapper {
225
234
  return {
226
235
  canceled: err.CancellationReasons.map((reason) => {
227
236
  if (reason.Item) {
228
- return unmarshallOutput(reason, [{ key: "Item" }]);
237
+ return unmarshallItem(reason);
229
238
  }
230
239
  return reason;
231
240
  }),
@@ -0,0 +1,68 @@
1
+ function createConversions(entity) {
2
+ const conversions = {
3
+ fromComposite: {
4
+ toKeys: (composite, options = {}) =>
5
+ entity._fromCompositeToKeys({ provided: composite }, options),
6
+ toCursor: (composite) =>
7
+ entity._fromCompositeToCursor(
8
+ { provided: composite },
9
+ { strict: "all" },
10
+ ),
11
+ },
12
+ fromKeys: {
13
+ toCursor: (keys) => entity._fromKeysToCursor({ provided: keys }, {}),
14
+ toComposite: (keys) => entity._fromKeysToComposite({ provided: keys }),
15
+ },
16
+ fromCursor: {
17
+ toKeys: (cursor) => entity._fromCursorToKeys({ provided: cursor }),
18
+ toComposite: (cursor) =>
19
+ entity._fromCursorToComposite({ provided: cursor }),
20
+ },
21
+ byAccessPattern: {},
22
+ };
23
+
24
+ for (let accessPattern in entity.model.indexes) {
25
+ let index = entity.model.indexes[accessPattern].index;
26
+ conversions.byAccessPattern[accessPattern] = {
27
+ fromKeys: {
28
+ toCursor: (keys) =>
29
+ entity._fromKeysToCursorByIndex({ indexName: index, provided: keys }),
30
+ toComposite: (keys) =>
31
+ entity._fromKeysToCompositeByIndex({
32
+ indexName: index,
33
+ provided: keys,
34
+ }),
35
+ },
36
+ fromCursor: {
37
+ toKeys: (cursor) =>
38
+ entity._fromCursorToKeysByIndex({
39
+ indexName: index,
40
+ provided: cursor,
41
+ }),
42
+ toComposite: (cursor) =>
43
+ entity._fromCursorToCompositeByIndex({
44
+ indexName: index,
45
+ provided: cursor,
46
+ }),
47
+ },
48
+ fromComposite: {
49
+ toCursor: (composite) =>
50
+ entity._fromCompositeToCursorByIndex(
51
+ { indexName: index, provided: composite },
52
+ { strict: "all" },
53
+ ),
54
+ toKeys: (composite, options = {}) =>
55
+ entity._fromCompositeToKeysByIndex(
56
+ { indexName: index, provided: composite },
57
+ options,
58
+ ),
59
+ },
60
+ };
61
+ }
62
+
63
+ return conversions;
64
+ }
65
+
66
+ module.exports = {
67
+ createConversions,
68
+ };