spice-js 2.7.23 → 2.7.26
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.
|
@@ -696,6 +696,9 @@ class SpiceModel {
|
|
|
696
696
|
try {
|
|
697
697
|
if (_.isString(data)) {
|
|
698
698
|
var result = yield _this7.database.get(data);
|
|
699
|
+
if (!result) {
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
699
702
|
if (result.type) if (result.type != _this7.type) {
|
|
700
703
|
return false;
|
|
701
704
|
}
|
|
@@ -703,6 +706,9 @@ class SpiceModel {
|
|
|
703
706
|
return false;
|
|
704
707
|
}
|
|
705
708
|
} else {
|
|
709
|
+
if (!data) {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
706
712
|
if (data.type) if (data.type != _this7.type) {
|
|
707
713
|
return false;
|
|
708
714
|
}
|
|
@@ -1036,65 +1042,33 @@ class SpiceModel {
|
|
|
1036
1042
|
}
|
|
1037
1043
|
filterResultsByColumns(data, columns) {
|
|
1038
1044
|
if (columns && columns !== "") {
|
|
1045
|
+
// Remove backticks and replace meta().id with id
|
|
1039
1046
|
var cleanedColumns = columns.replace(/`/g, "").replace(/meta\(\)\.id/g, "id");
|
|
1040
|
-
|
|
1047
|
+
|
|
1048
|
+
// Process each column by splitting on comma and trimming
|
|
1049
|
+
var columnList = cleanedColumns.split(",").map(col => col.trim()).map(col => {
|
|
1050
|
+
// Check for alias with AS (case-insensitive)
|
|
1041
1051
|
var aliasMatch = col.match(/\s+AS\s+([\w]+)/i);
|
|
1042
1052
|
if (aliasMatch) {
|
|
1043
|
-
return
|
|
1044
|
-
original: col,
|
|
1045
|
-
path: col.replace(/\s+AS\s+[\w]+/i, "").trim(),
|
|
1046
|
-
alias: aliasMatch[1].trim()
|
|
1047
|
-
};
|
|
1053
|
+
return aliasMatch[1].trim();
|
|
1048
1054
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1055
|
+
// Otherwise, for dot-notation, keep the first segment after removing
|
|
1056
|
+
// the base model prefix (e.g. user.group.name -> group).
|
|
1057
|
+
if (col.includes(".")) {
|
|
1058
|
+
var pathParts = col.split(".").map(part => part.trim()).filter(part => part !== "");
|
|
1059
|
+
if (pathParts[0] === this.type && pathParts.length > 1) {
|
|
1060
|
+
pathParts = pathParts.slice(1);
|
|
1061
|
+
}
|
|
1062
|
+
return pathParts[0];
|
|
1063
|
+
}
|
|
1064
|
+
return col;
|
|
1054
1065
|
});
|
|
1055
|
-
var requiredKeys = ["_permissions", "_permissions_", "id"];
|
|
1056
|
-
return data.map(entry => {
|
|
1057
|
-
var result = {};
|
|
1058
|
-
|
|
1059
|
-
// Add required keys
|
|
1060
|
-
requiredKeys.forEach(key => {
|
|
1061
|
-
if (entry.hasOwnProperty(key)) {
|
|
1062
|
-
result[key] = entry[key];
|
|
1063
|
-
}
|
|
1064
|
-
});
|
|
1065
1066
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
alias
|
|
1071
|
-
} = _ref10;
|
|
1072
|
-
var actualPath = path;
|
|
1073
|
-
|
|
1074
|
-
// Remove table prefix if it matches this.type
|
|
1075
|
-
if (path.includes(".")) {
|
|
1076
|
-
var parts = path.split(".");
|
|
1077
|
-
if (parts[0] === this.type) {
|
|
1078
|
-
actualPath = parts.slice(1).join(".");
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
var value = _.get(entry, actualPath);
|
|
1082
|
-
if (value !== undefined) {
|
|
1083
|
-
if (alias) {
|
|
1084
|
-
result[alias] = value;
|
|
1085
|
-
} else if (actualPath.includes(".")) {
|
|
1086
|
-
// For nested paths, use the last part as the key
|
|
1087
|
-
var key = actualPath.split(".").pop();
|
|
1088
|
-
result[key] = value;
|
|
1089
|
-
} else {
|
|
1090
|
-
result[actualPath] = value;
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
});
|
|
1094
|
-
return result;
|
|
1095
|
-
});
|
|
1067
|
+
// Ensure that essential keys are always picked
|
|
1068
|
+
var requiredKeys = ["_permissions", "_permissions_", "id"];
|
|
1069
|
+
var finalKeys = [...new Set([...columnList, ...requiredKeys])];
|
|
1070
|
+
return data.map(entry => _.pick(entry, finalKeys));
|
|
1096
1071
|
}
|
|
1097
|
-
console.log("filterResultsByColumns", data);
|
|
1098
1072
|
return data;
|
|
1099
1073
|
}
|
|
1100
1074
|
extractNestings(string, localType) {
|
|
@@ -1135,12 +1109,12 @@ class SpiceModel {
|
|
|
1135
1109
|
}
|
|
1136
1110
|
createJoinSection(mappedNestings) {
|
|
1137
1111
|
if (!mappedNestings || mappedNestings.length === 0) return "";
|
|
1138
|
-
return mappedNestings.map(
|
|
1112
|
+
return mappedNestings.map(_ref10 => {
|
|
1139
1113
|
var {
|
|
1140
1114
|
alias,
|
|
1141
1115
|
reference,
|
|
1142
1116
|
is_array
|
|
1143
|
-
} =
|
|
1117
|
+
} = _ref10;
|
|
1144
1118
|
var keyspace = (0, _fix.fixCollection)(reference);
|
|
1145
1119
|
if (is_array === true) {
|
|
1146
1120
|
return "LEFT NEST `" + keyspace + "` AS `" + alias + "` ON KEYS `" + this.type + "`.`" + alias + "`";
|
|
@@ -1285,8 +1259,8 @@ class SpiceModel {
|
|
|
1285
1259
|
// Profiling: use track() for proper async context forking
|
|
1286
1260
|
var p = (_this10$_ctx = _this10[_ctx]) == null ? void 0 : _this10$_ctx.profiler;
|
|
1287
1261
|
var doList = /*#__PURE__*/function () {
|
|
1288
|
-
var
|
|
1289
|
-
var _args10, _args11
|
|
1262
|
+
var _ref11 = _asyncToGenerator(function* () {
|
|
1263
|
+
var _args10, _args11;
|
|
1290
1264
|
if (args.mapping_dept) _this10[_mapping_dept] = args.mapping_dept;
|
|
1291
1265
|
if (args.mapping_dept_exempt) _this10[_mapping_dept_exempt] = args.mapping_dept_exempt;
|
|
1292
1266
|
|
|
@@ -1302,12 +1276,15 @@ class SpiceModel {
|
|
|
1302
1276
|
var originalColumns = args.columns;
|
|
1303
1277
|
|
|
1304
1278
|
// Find alias tokens from query/columns/sort
|
|
1305
|
-
var nestings = [..._this10.extractNestings(((_args10 = args) == null ? void 0 : _args10.query) || "", _this10.type),
|
|
1279
|
+
var nestings = [..._this10.extractNestings(((_args10 = args) == null ? void 0 : _args10.query) || "", _this10.type),
|
|
1280
|
+
//...this.extractNestings(args?.columns || "", this.type),
|
|
1281
|
+
..._this10.extractNestings(((_args11 = args) == null ? void 0 : _args11.sort) || "", _this10.type)];
|
|
1306
1282
|
|
|
1307
1283
|
// Build join metadata and prepare columns
|
|
1308
1284
|
var {
|
|
1309
1285
|
mappedNestings
|
|
1310
1286
|
} = _this10.buildJoinMetadata(nestings, args);
|
|
1287
|
+
|
|
1311
1288
|
// Build JOIN/NEST from the mapped keyspaces
|
|
1312
1289
|
args._join = _this10.createJoinSection(mappedNestings);
|
|
1313
1290
|
|
|
@@ -1357,20 +1334,20 @@ class SpiceModel {
|
|
|
1357
1334
|
if (args.skip_hooks !== true) {
|
|
1358
1335
|
yield _this10.run_hook(results.data, "list", "after");
|
|
1359
1336
|
}
|
|
1360
|
-
results.data = _this10.filterResultsByColumns(results.data,
|
|
1337
|
+
results.data = _this10.filterResultsByColumns(results.data, args.columns);
|
|
1361
1338
|
//console.log("results.data", results.data);
|
|
1362
1339
|
return results;
|
|
1363
1340
|
});
|
|
1364
1341
|
return function doList() {
|
|
1365
|
-
return
|
|
1342
|
+
return _ref11.apply(this, arguments);
|
|
1366
1343
|
};
|
|
1367
1344
|
}();
|
|
1368
1345
|
try {
|
|
1369
1346
|
if (p) {
|
|
1370
|
-
var
|
|
1347
|
+
var _args12, _args13;
|
|
1371
1348
|
return yield p.track(_this10.type + ".list", doList, {
|
|
1372
|
-
limit: (
|
|
1373
|
-
offset: (
|
|
1349
|
+
limit: (_args12 = args) == null ? void 0 : _args12.limit,
|
|
1350
|
+
offset: (_args13 = args) == null ? void 0 : _args13.offset
|
|
1374
1351
|
});
|
|
1375
1352
|
}
|
|
1376
1353
|
return yield doList();
|
|
@@ -1416,7 +1393,7 @@ class SpiceModel {
|
|
|
1416
1393
|
// Profiling: use track() for proper async context forking
|
|
1417
1394
|
var p = (_this11$_ctx = _this11[_ctx]) == null ? void 0 : _this11$_ctx.profiler;
|
|
1418
1395
|
var doFetch = /*#__PURE__*/function () {
|
|
1419
|
-
var
|
|
1396
|
+
var _ref12 = _asyncToGenerator(function* () {
|
|
1420
1397
|
if (args.is_custom_query === "true" && args.ids.length > 0) {
|
|
1421
1398
|
return yield _this11.database.query(query);
|
|
1422
1399
|
} else if (args.is_full_text === "true") {
|
|
@@ -1428,7 +1405,7 @@ class SpiceModel {
|
|
|
1428
1405
|
}
|
|
1429
1406
|
});
|
|
1430
1407
|
return function doFetch() {
|
|
1431
|
-
return
|
|
1408
|
+
return _ref12.apply(this, arguments);
|
|
1432
1409
|
};
|
|
1433
1410
|
}();
|
|
1434
1411
|
if (p) {
|
|
@@ -1437,12 +1414,12 @@ class SpiceModel {
|
|
|
1437
1414
|
return yield doFetch();
|
|
1438
1415
|
})();
|
|
1439
1416
|
}
|
|
1440
|
-
addHook(
|
|
1417
|
+
addHook(_ref13) {
|
|
1441
1418
|
var {
|
|
1442
1419
|
operation,
|
|
1443
1420
|
when,
|
|
1444
1421
|
execute
|
|
1445
|
-
} =
|
|
1422
|
+
} = _ref13;
|
|
1446
1423
|
this[_hooks][operation][when].push(execute);
|
|
1447
1424
|
}
|
|
1448
1425
|
run_hook(data, op, when, old_data) {
|
|
@@ -1564,7 +1541,7 @@ class SpiceModel {
|
|
|
1564
1541
|
|
|
1565
1542
|
// ⚡ Wrap in profiler track() to ensure proper async context for child operations
|
|
1566
1543
|
var fetchRelated = /*#__PURE__*/function () {
|
|
1567
|
-
var
|
|
1544
|
+
var _ref14 = _asyncToGenerator(function* () {
|
|
1568
1545
|
return yield Promise.allSettled(_.map(classes, obj => {
|
|
1569
1546
|
var objInstance = new obj(_extends({}, _this13[_args], {
|
|
1570
1547
|
skip_cache: _this13[_skip_cache],
|
|
@@ -1582,7 +1559,7 @@ class SpiceModel {
|
|
|
1582
1559
|
}));
|
|
1583
1560
|
});
|
|
1584
1561
|
return function fetchRelated() {
|
|
1585
|
-
return
|
|
1562
|
+
return _ref14.apply(this, arguments);
|
|
1586
1563
|
};
|
|
1587
1564
|
}();
|
|
1588
1565
|
var returned_all;
|
|
@@ -1682,7 +1659,7 @@ class SpiceModel {
|
|
|
1682
1659
|
|
|
1683
1660
|
// ⚡ Wrap in profiler track() to ensure proper async context for child operations
|
|
1684
1661
|
var fetchRelated = /*#__PURE__*/function () {
|
|
1685
|
-
var
|
|
1662
|
+
var _ref15 = _asyncToGenerator(function* () {
|
|
1686
1663
|
return yield Promise.allSettled(_.map(classes, obj => {
|
|
1687
1664
|
return new obj(_extends({}, _this14[_args], {
|
|
1688
1665
|
skip_cache: _this14[_skip_cache],
|
|
@@ -1699,7 +1676,7 @@ class SpiceModel {
|
|
|
1699
1676
|
}));
|
|
1700
1677
|
});
|
|
1701
1678
|
return function fetchRelated() {
|
|
1702
|
-
return
|
|
1679
|
+
return _ref15.apply(this, arguments);
|
|
1703
1680
|
};
|
|
1704
1681
|
}();
|
|
1705
1682
|
var returned_all;
|
|
@@ -1747,11 +1724,11 @@ class SpiceModel {
|
|
|
1747
1724
|
return original_is_array ? data : data[0];
|
|
1748
1725
|
})();
|
|
1749
1726
|
}
|
|
1750
|
-
addModifier(
|
|
1727
|
+
addModifier(_ref16) {
|
|
1751
1728
|
var {
|
|
1752
1729
|
when,
|
|
1753
1730
|
execute
|
|
1754
|
-
} =
|
|
1731
|
+
} = _ref16;
|
|
1755
1732
|
if (this[_serializers][when]) {
|
|
1756
1733
|
this[_serializers][when]["modifiers"].push(execute);
|
|
1757
1734
|
}
|
|
@@ -1881,7 +1858,7 @@ class SpiceModel {
|
|
|
1881
1858
|
// Profiling: use track() for proper async context forking
|
|
1882
1859
|
var p = (_this16$_ctx = _this16[_ctx]) == null ? void 0 : _this16$_ctx.profiler;
|
|
1883
1860
|
var doSerialize = /*#__PURE__*/function () {
|
|
1884
|
-
var
|
|
1861
|
+
var _ref17 = _asyncToGenerator(function* () {
|
|
1885
1862
|
var _this16$_serializers, _this16$_serializers$;
|
|
1886
1863
|
// Early exit if serialization should not run.
|
|
1887
1864
|
if (!_this16.shouldSerializerRun(args, type)) {
|
|
@@ -1949,7 +1926,7 @@ class SpiceModel {
|
|
|
1949
1926
|
return originalIsArray ? data : data[0];
|
|
1950
1927
|
});
|
|
1951
1928
|
return function doSerialize() {
|
|
1952
|
-
return
|
|
1929
|
+
return _ref17.apply(this, arguments);
|
|
1953
1930
|
};
|
|
1954
1931
|
}();
|
|
1955
1932
|
try {
|
package/package.json
CHANGED
package/src/models/SpiceModel.js
CHANGED
|
@@ -762,6 +762,9 @@ export default class SpiceModel {
|
|
|
762
762
|
try {
|
|
763
763
|
if (_.isString(data)) {
|
|
764
764
|
let result = await this.database.get(data);
|
|
765
|
+
if (!result) {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
765
768
|
if (result.type)
|
|
766
769
|
if (result.type != this.type) {
|
|
767
770
|
return false;
|
|
@@ -771,6 +774,9 @@ export default class SpiceModel {
|
|
|
771
774
|
return false;
|
|
772
775
|
}
|
|
773
776
|
} else {
|
|
777
|
+
if (!data) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
774
780
|
if (data.type)
|
|
775
781
|
if (data.type != this.type) {
|
|
776
782
|
return false;
|
|
@@ -32,6 +32,18 @@ class MockDatabase {
|
|
|
32
32
|
return this.mockData.get(id);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Mock update operation
|
|
37
|
+
* @param {string} id - Document ID to update
|
|
38
|
+
* @param {Object} data - Updated document data
|
|
39
|
+
* @returns {Promise<Object>} Updated document
|
|
40
|
+
*/
|
|
41
|
+
async update(id, data, ttl) {
|
|
42
|
+
const updated = { ...data, id };
|
|
43
|
+
this.mockData.set(id, updated);
|
|
44
|
+
return updated;
|
|
45
|
+
}
|
|
46
|
+
|
|
35
47
|
/**
|
|
36
48
|
* Seed mock database with test data
|
|
37
49
|
* @param {string} id - Document ID
|
|
@@ -578,6 +578,12 @@ describe('SpiceModel - Critical Fixes for Empty/Null Values', () => {
|
|
|
578
578
|
model = createTestModel({ type: 'user' });
|
|
579
579
|
});
|
|
580
580
|
|
|
581
|
+
test('should fail update with a controlled not-found error when database returns undefined', async () => {
|
|
582
|
+
await expect(
|
|
583
|
+
model.update({ id: 'missing-user' })
|
|
584
|
+
).rejects.toThrow('user does not exist. in update');
|
|
585
|
+
});
|
|
586
|
+
|
|
581
587
|
test('should handle undefined columns parameter', async () => {
|
|
582
588
|
seedDatabase(model, sampleDbResults.users);
|
|
583
589
|
|