@awsless/dynamodb-server 0.1.1 → 0.1.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/dist/index.js +48 -28
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -251,6 +251,9 @@ function listTables(store, input) {
|
|
|
251
251
|
};
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
// src/expressions/condition.ts
|
|
255
|
+
import { cmp, parse } from "@awsless/big-float";
|
|
256
|
+
|
|
254
257
|
// src/expressions/path.ts
|
|
255
258
|
function parsePath(path, attributeNames) {
|
|
256
259
|
const segments = [];
|
|
@@ -710,7 +713,7 @@ function evaluateCondition(expression, item, context) {
|
|
|
710
713
|
if (!rightValue || !("N" in rightValue)) {
|
|
711
714
|
throw new ValidationException("Size comparison requires numeric operand");
|
|
712
715
|
}
|
|
713
|
-
return compareNumbers(size,
|
|
716
|
+
return compareNumbers(size, Number(rightValue.N), nextToken.value);
|
|
714
717
|
}
|
|
715
718
|
return size > 0;
|
|
716
719
|
}
|
|
@@ -778,20 +781,20 @@ function evaluateCondition(expression, item, context) {
|
|
|
778
781
|
}
|
|
779
782
|
return false;
|
|
780
783
|
}
|
|
781
|
-
const
|
|
784
|
+
const cmp5 = compareValues(left, right);
|
|
782
785
|
switch (op) {
|
|
783
786
|
case "=":
|
|
784
|
-
return
|
|
787
|
+
return cmp5 === 0;
|
|
785
788
|
case "<>":
|
|
786
|
-
return
|
|
789
|
+
return cmp5 !== 0;
|
|
787
790
|
case "<":
|
|
788
|
-
return
|
|
791
|
+
return cmp5 < 0;
|
|
789
792
|
case "<=":
|
|
790
|
-
return
|
|
793
|
+
return cmp5 <= 0;
|
|
791
794
|
case ">":
|
|
792
|
-
return
|
|
795
|
+
return cmp5 > 0;
|
|
793
796
|
case ">=":
|
|
794
|
-
return
|
|
797
|
+
return cmp5 >= 0;
|
|
795
798
|
default:
|
|
796
799
|
return false;
|
|
797
800
|
}
|
|
@@ -821,7 +824,7 @@ function compareValues(a, b) {
|
|
|
821
824
|
return a.S.localeCompare(b.S);
|
|
822
825
|
}
|
|
823
826
|
if ("N" in a && "N" in b) {
|
|
824
|
-
return
|
|
827
|
+
return cmp(parse(a.N), parse(b.N));
|
|
825
828
|
}
|
|
826
829
|
if ("B" in a && "B" in b) {
|
|
827
830
|
return a.B.localeCompare(b.B);
|
|
@@ -837,7 +840,11 @@ function compareValues(a, b) {
|
|
|
837
840
|
return aStr.localeCompare(bStr);
|
|
838
841
|
}
|
|
839
842
|
|
|
843
|
+
// src/expressions/key-condition.ts
|
|
844
|
+
import { cmp as cmp3, parse as parse3 } from "@awsless/big-float";
|
|
845
|
+
|
|
840
846
|
// src/store/item.ts
|
|
847
|
+
import { cmp as cmp2, parse as parse2 } from "@awsless/big-float";
|
|
841
848
|
function extractKey(item, keySchema) {
|
|
842
849
|
const key = {};
|
|
843
850
|
for (const element of keySchema) {
|
|
@@ -1009,21 +1016,21 @@ function matchesKeyCondition(item, condition) {
|
|
|
1009
1016
|
return true;
|
|
1010
1017
|
}
|
|
1011
1018
|
function matchesRangeCondition(value, condition) {
|
|
1012
|
-
const
|
|
1019
|
+
const cmp5 = compareValues2(value, condition.value);
|
|
1013
1020
|
switch (condition.operator) {
|
|
1014
1021
|
case "=":
|
|
1015
|
-
return
|
|
1022
|
+
return cmp5 === 0;
|
|
1016
1023
|
case "<":
|
|
1017
|
-
return
|
|
1024
|
+
return cmp5 < 0;
|
|
1018
1025
|
case "<=":
|
|
1019
|
-
return
|
|
1026
|
+
return cmp5 <= 0;
|
|
1020
1027
|
case ">":
|
|
1021
|
-
return
|
|
1028
|
+
return cmp5 > 0;
|
|
1022
1029
|
case ">=":
|
|
1023
|
-
return
|
|
1030
|
+
return cmp5 >= 0;
|
|
1024
1031
|
case "BETWEEN":
|
|
1025
1032
|
if (!condition.value2) return false;
|
|
1026
|
-
return
|
|
1033
|
+
return cmp5 >= 0 && compareValues2(value, condition.value2) <= 0;
|
|
1027
1034
|
case "begins_with":
|
|
1028
1035
|
if ("S" in value && "S" in condition.value) {
|
|
1029
1036
|
return value.S.startsWith(condition.value.S);
|
|
@@ -1047,7 +1054,7 @@ function compareValues2(a, b) {
|
|
|
1047
1054
|
return a.S.localeCompare(b.S);
|
|
1048
1055
|
}
|
|
1049
1056
|
if ("N" in a && "N" in b) {
|
|
1050
|
-
return
|
|
1057
|
+
return cmp3(parse3(a.N), parse3(b.N));
|
|
1051
1058
|
}
|
|
1052
1059
|
if ("B" in a && "B" in b) {
|
|
1053
1060
|
return a.B.localeCompare(b.B);
|
|
@@ -1073,6 +1080,7 @@ function applyProjection(item, projectionExpression, expressionAttributeNames) {
|
|
|
1073
1080
|
}
|
|
1074
1081
|
|
|
1075
1082
|
// src/expressions/update.ts
|
|
1083
|
+
import { add, parse as parse4, string, sub } from "@awsless/big-float";
|
|
1076
1084
|
function parseUpdateExpression(expression) {
|
|
1077
1085
|
const actions = [];
|
|
1078
1086
|
let remaining = expression.trim();
|
|
@@ -1266,6 +1274,20 @@ function resolveOperand(item, operand, context) {
|
|
|
1266
1274
|
if (operand.startsWith(":")) {
|
|
1267
1275
|
return context.expressionAttributeValues?.[operand];
|
|
1268
1276
|
}
|
|
1277
|
+
const ifNotExistsMatch = operand.match(/^if_not_exists\s*\(\s*([^,]+)\s*,\s*(.+)\s*\)$/i);
|
|
1278
|
+
if (ifNotExistsMatch) {
|
|
1279
|
+
const existing = resolveOperand(item, ifNotExistsMatch[1].trim(), context);
|
|
1280
|
+
return existing !== void 0 ? existing : resolveOperand(item, ifNotExistsMatch[2].trim(), context);
|
|
1281
|
+
}
|
|
1282
|
+
const listAppendMatch = operand.match(/^list_append\s*\(\s*([^,]+)\s*,\s*(.+)\s*\)$/i);
|
|
1283
|
+
if (listAppendMatch) {
|
|
1284
|
+
const list1 = resolveOperand(item, listAppendMatch[1].trim(), context);
|
|
1285
|
+
const list2 = resolveOperand(item, listAppendMatch[2].trim(), context);
|
|
1286
|
+
if (list1 && "L" in list1 && list2 && "L" in list2) {
|
|
1287
|
+
return { L: [...list1.L, ...list2.L] };
|
|
1288
|
+
}
|
|
1289
|
+
return list1 && "L" in list1 ? list1 : list2;
|
|
1290
|
+
}
|
|
1269
1291
|
const segments = parsePath(operand, context.expressionAttributeNames);
|
|
1270
1292
|
return getValueAtPath(item, segments);
|
|
1271
1293
|
}
|
|
@@ -1293,15 +1315,13 @@ function applySetAction(item, action, context) {
|
|
|
1293
1315
|
const left = resolveOperand(item, action.operands[0], context);
|
|
1294
1316
|
const right = resolveOperand(item, action.operands[1], context);
|
|
1295
1317
|
if (left && "N" in left && right && "N" in right) {
|
|
1296
|
-
|
|
1297
|
-
value = { N: String(result) };
|
|
1318
|
+
value = { N: string(add(parse4(left.N), parse4(right.N))) };
|
|
1298
1319
|
}
|
|
1299
1320
|
} else if (action.operation === "minus") {
|
|
1300
1321
|
const left = resolveOperand(item, action.operands[0], context);
|
|
1301
1322
|
const right = resolveOperand(item, action.operands[1], context);
|
|
1302
1323
|
if (left && "N" in left && right && "N" in right) {
|
|
1303
|
-
|
|
1304
|
-
value = { N: String(result) };
|
|
1324
|
+
value = { N: string(sub(parse4(left.N), parse4(right.N))) };
|
|
1305
1325
|
}
|
|
1306
1326
|
} else {
|
|
1307
1327
|
value = resolveOperand(item, action.value, context);
|
|
@@ -1323,8 +1343,7 @@ function applyAddAction(item, action, context) {
|
|
|
1323
1343
|
}
|
|
1324
1344
|
if ("N" in addValue) {
|
|
1325
1345
|
if (existingValue && "N" in existingValue) {
|
|
1326
|
-
|
|
1327
|
-
setValueAtPath(item, segments, { N: String(result) });
|
|
1346
|
+
setValueAtPath(item, segments, { N: string(add(parse4(existingValue.N), parse4(addValue.N))) });
|
|
1328
1347
|
} else if (!existingValue) {
|
|
1329
1348
|
setValueAtPath(item, segments, addValue);
|
|
1330
1349
|
}
|
|
@@ -2299,6 +2318,7 @@ function createServer(store, port) {
|
|
|
2299
2318
|
}
|
|
2300
2319
|
|
|
2301
2320
|
// src/store/table.ts
|
|
2321
|
+
import { cmp as cmp4, parse as parse5 } from "@awsless/big-float";
|
|
2302
2322
|
var sequenceCounter = 0;
|
|
2303
2323
|
function generateSequenceNumber() {
|
|
2304
2324
|
return String(++sequenceCounter).padStart(21, "0");
|
|
@@ -2618,8 +2638,8 @@ var Table = class {
|
|
|
2618
2638
|
if (!aVal && !bVal) return 0;
|
|
2619
2639
|
if (!aVal) return 1;
|
|
2620
2640
|
if (!bVal) return -1;
|
|
2621
|
-
const
|
|
2622
|
-
return options?.scanIndexForward === false ? -
|
|
2641
|
+
const cmp5 = this.compareAttributes(aVal, bVal);
|
|
2642
|
+
return options?.scanIndexForward === false ? -cmp5 : cmp5;
|
|
2623
2643
|
});
|
|
2624
2644
|
}
|
|
2625
2645
|
let startIdx = 0;
|
|
@@ -2671,8 +2691,8 @@ var Table = class {
|
|
|
2671
2691
|
if (!aVal && !bVal) return 0;
|
|
2672
2692
|
if (!aVal) return 1;
|
|
2673
2693
|
if (!bVal) return -1;
|
|
2674
|
-
const
|
|
2675
|
-
return options?.scanIndexForward === false ? -
|
|
2694
|
+
const cmp5 = this.compareAttributes(aVal, bVal);
|
|
2695
|
+
return options?.scanIndexForward === false ? -cmp5 : cmp5;
|
|
2676
2696
|
});
|
|
2677
2697
|
}
|
|
2678
2698
|
let startIdx = 0;
|
|
@@ -2775,7 +2795,7 @@ var Table = class {
|
|
|
2775
2795
|
}
|
|
2776
2796
|
compareAttributes(a, b) {
|
|
2777
2797
|
if ("S" in a && "S" in b) return a.S.localeCompare(b.S);
|
|
2778
|
-
if ("N" in a && "N" in b) return
|
|
2798
|
+
if ("N" in a && "N" in b) return cmp4(parse5(a.N), parse5(b.N));
|
|
2779
2799
|
if ("B" in a && "B" in b) return a.B.localeCompare(b.B);
|
|
2780
2800
|
return 0;
|
|
2781
2801
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awsless/dynamodb-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@aws-sdk/client-dynamodb": "3.363.0",
|
|
27
|
-
"@aws-sdk/lib-dynamodb": "3.363.0"
|
|
27
|
+
"@aws-sdk/lib-dynamodb": "3.363.0",
|
|
28
|
+
"@awsless/big-float": "^0.1.5"
|
|
28
29
|
},
|
|
29
30
|
"optionalDependencies": {
|
|
30
31
|
"dynamo-db-local": "^10.3.0"
|