spice-js 2.7.8 → 2.7.9
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/build/models/SpiceModel.js +251 -84
- package/package.json +1 -1
- package/src/models/SpiceModel.js +272 -87
- package/, +0 -0
|
@@ -31,6 +31,7 @@ var SDate = require("sonover-date"),
|
|
|
31
31
|
_props = Symbol(),
|
|
32
32
|
_args = Symbol(),
|
|
33
33
|
_hooks = Symbol(),
|
|
34
|
+
_columns = Symbol(),
|
|
34
35
|
_disable_lifecycle_events = Symbol(),
|
|
35
36
|
_external_modifier_loaded = Symbol(),
|
|
36
37
|
_skip_cache = Symbol(),
|
|
@@ -60,7 +61,7 @@ class SpiceModel {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
try {
|
|
63
|
-
var _args2, _args2$args, _args3, _args3$args, _args$args, _args4, _args4$args, _args5, _args5$args, _args6, _args6$args, _args7, _args7$args;
|
|
64
|
+
var _args2, _args2$args, _args3, _args3$args, _args$args, _args4, _args4$args, _args5, _args5$args, _args6, _args6$args, _args7, _args7$args, _args8, _args8$args;
|
|
64
65
|
|
|
65
66
|
var dbtype = spice.config.database.connections[args.connection].type || "couchbase";
|
|
66
67
|
|
|
@@ -77,6 +78,7 @@ class SpiceModel {
|
|
|
77
78
|
this[_skip_cache] = ((_args5 = args) == null ? void 0 : (_args5$args = _args5.args) == null ? void 0 : _args5$args.skip_cache) || false;
|
|
78
79
|
this[_level] = ((_args6 = args) == null ? void 0 : (_args6$args = _args6.args) == null ? void 0 : _args6$args._level) || 0;
|
|
79
80
|
this[_current_path] = ((_args7 = args) == null ? void 0 : (_args7$args = _args7.args) == null ? void 0 : _args7$args._current_path) || "";
|
|
81
|
+
this[_columns] = ((_args8 = args) == null ? void 0 : (_args8$args = _args8.args) == null ? void 0 : _args8$args._columns) || "";
|
|
80
82
|
this[_hooks] = {
|
|
81
83
|
create: {
|
|
82
84
|
before: [],
|
|
@@ -608,13 +610,38 @@ class SpiceModel {
|
|
|
608
610
|
}
|
|
609
611
|
|
|
610
612
|
if (_.isString(args.id)) {
|
|
613
|
+
var _args9;
|
|
614
|
+
|
|
611
615
|
if (args.skip_hooks !== true) {
|
|
612
616
|
yield _this4.run_hook(args, "get", "before");
|
|
613
617
|
} // ⚡ Include columns in cache key if specified
|
|
614
618
|
|
|
615
619
|
|
|
616
620
|
var key = "get::" + _this4.type + "::" + args.id + (args.columns ? "::" + args.columns : "");
|
|
617
|
-
var results = {};
|
|
621
|
+
var results = {}; // Extract nestings from columns if specified
|
|
622
|
+
|
|
623
|
+
var nestings = _this4.extractNestings(((_args9 = args) == null ? void 0 : _args9.columns) || "", _this4.type); // Build join metadata and prepare columns
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
_this4.buildJoinMetadata(nestings, args);
|
|
627
|
+
|
|
628
|
+
var columns = args.columns;
|
|
629
|
+
var columnArray = [];
|
|
630
|
+
|
|
631
|
+
if (columns) {
|
|
632
|
+
columns.split(',').forEach(col => {
|
|
633
|
+
var parts = col.trim().split("."); // remove the first segment
|
|
634
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
635
|
+
|
|
636
|
+
var firstPart = parts[0]; // Remove backticks if present
|
|
637
|
+
|
|
638
|
+
var cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`') ? firstPart.slice(1, -1) : firstPart; //if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
639
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
640
|
+
// Remove backticks from each column segment, if present, before joining
|
|
641
|
+
|
|
642
|
+
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith('`') && segment.endsWith('`') ? segment.slice(1, -1) : segment).join(".")); // }
|
|
643
|
+
});
|
|
644
|
+
}
|
|
618
645
|
|
|
619
646
|
if (_this4.shouldUseCache(_this4.type)) {
|
|
620
647
|
// Retrieve the cached results
|
|
@@ -622,7 +649,7 @@ class SpiceModel {
|
|
|
622
649
|
|
|
623
650
|
var isCacheEmpty = (cached_results == null ? void 0 : cached_results.value) === undefined; // Check if the cached result should be refreshed
|
|
624
651
|
|
|
625
|
-
var shouldRefresh = yield _this4.shouldForceRefresh(cached_results);
|
|
652
|
+
var shouldRefresh = yield _this4.shouldForceRefresh(cached_results);
|
|
626
653
|
|
|
627
654
|
if (isCacheEmpty || shouldRefresh) {
|
|
628
655
|
// Retrieve from the database and update cache
|
|
@@ -630,10 +657,14 @@ class SpiceModel {
|
|
|
630
657
|
results = yield p.track(_this4.type + ".get.database",
|
|
631
658
|
/*#__PURE__*/
|
|
632
659
|
_asyncToGenerator(function* () {
|
|
633
|
-
return yield _this4.database.get(args.id
|
|
660
|
+
return yield _this4.database.get(args.id, {
|
|
661
|
+
columns: columnArray
|
|
662
|
+
});
|
|
634
663
|
}));
|
|
635
664
|
} else {
|
|
636
|
-
results = yield _this4.database.get(args.id
|
|
665
|
+
results = yield _this4.database.get(args.id, {
|
|
666
|
+
columns: columnArray
|
|
667
|
+
});
|
|
637
668
|
}
|
|
638
669
|
|
|
639
670
|
yield _this4.getCacheProviderObject(_this4.type).set(key, {
|
|
@@ -650,10 +681,14 @@ class SpiceModel {
|
|
|
650
681
|
results = yield p.track(_this4.type + ".get.database",
|
|
651
682
|
/*#__PURE__*/
|
|
652
683
|
_asyncToGenerator(function* () {
|
|
653
|
-
return yield _this4.database.get(args.id
|
|
684
|
+
return yield _this4.database.get(args.id, {
|
|
685
|
+
columns: columnArray
|
|
686
|
+
});
|
|
654
687
|
}));
|
|
655
688
|
} else {
|
|
656
|
-
results = yield _this4.database.get(args.id
|
|
689
|
+
results = yield _this4.database.get(args.id, {
|
|
690
|
+
columns: columnArray
|
|
691
|
+
});
|
|
657
692
|
}
|
|
658
693
|
}
|
|
659
694
|
|
|
@@ -694,10 +729,10 @@ class SpiceModel {
|
|
|
694
729
|
|
|
695
730
|
try {
|
|
696
731
|
if (p) {
|
|
697
|
-
var
|
|
732
|
+
var _args10;
|
|
698
733
|
|
|
699
734
|
return yield p.track(_this4.type + ".get", doGet, {
|
|
700
|
-
id: (
|
|
735
|
+
id: (_args10 = args) == null ? void 0 : _args10.id
|
|
701
736
|
});
|
|
702
737
|
}
|
|
703
738
|
|
|
@@ -745,8 +780,7 @@ class SpiceModel {
|
|
|
745
780
|
|
|
746
781
|
_.remove(args.ids, o => o == undefined);
|
|
747
782
|
|
|
748
|
-
var key = "multi-get::" + _this6.type + "::" + _.join(args.ids, "|");
|
|
749
|
-
|
|
783
|
+
var key = "multi-get::" + _this6.type + "::" + _.join(args.ids, "|") + ":" + args.columns;
|
|
750
784
|
var results = [];
|
|
751
785
|
|
|
752
786
|
if (args.ids.length > 0) {
|
|
@@ -755,7 +789,10 @@ class SpiceModel {
|
|
|
755
789
|
results = cached_results == null ? void 0 : cached_results.value;
|
|
756
790
|
|
|
757
791
|
if ((cached_results == null ? void 0 : cached_results.value) === undefined || (yield _this6.shouldForceRefresh(cached_results))) {
|
|
758
|
-
results = yield _this6.database.multi_get(args.ids,
|
|
792
|
+
results = yield _this6.database.multi_get(args.ids, {
|
|
793
|
+
keep_type: true,
|
|
794
|
+
columns: args.columns.length > 0 && args.columns != "" ? [...args.columns, 'type'] : []
|
|
795
|
+
});
|
|
759
796
|
|
|
760
797
|
_this6.getCacheProviderObject(_this6.type).set(key, {
|
|
761
798
|
value: results,
|
|
@@ -763,7 +800,10 @@ class SpiceModel {
|
|
|
763
800
|
}, _this6.getCacheConfig(_this6.type));
|
|
764
801
|
}
|
|
765
802
|
} else {
|
|
766
|
-
results = yield _this6.database.multi_get(args.ids,
|
|
803
|
+
results = yield _this6.database.multi_get(args.ids, {
|
|
804
|
+
keep_type: true,
|
|
805
|
+
columns: args.columns.length > 0 && args.columns != "" ? [...args.columns, 'type'] : []
|
|
806
|
+
});
|
|
767
807
|
}
|
|
768
808
|
}
|
|
769
809
|
|
|
@@ -787,10 +827,10 @@ class SpiceModel {
|
|
|
787
827
|
|
|
788
828
|
try {
|
|
789
829
|
if (p) {
|
|
790
|
-
var
|
|
830
|
+
var _args11, _args11$ids;
|
|
791
831
|
|
|
792
832
|
return yield p.track(_this6.type + ".getMulti", doGetMulti, {
|
|
793
|
-
ids_count: ((
|
|
833
|
+
ids_count: ((_args11 = args) == null ? void 0 : (_args11$ids = _args11.ids) == null ? void 0 : _args11$ids.length) || 0
|
|
794
834
|
});
|
|
795
835
|
}
|
|
796
836
|
|
|
@@ -1164,6 +1204,14 @@ class SpiceModel {
|
|
|
1164
1204
|
var _qualified = q(alias) + "." + q(field);
|
|
1165
1205
|
|
|
1166
1206
|
return explicitAs ? _qualified + " AS " + q(explicitAs) : _qualified;
|
|
1207
|
+
} // Check if alias has a map - if so, simplify to root column only (raw ID)
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
var prop = this.props[alias];
|
|
1211
|
+
|
|
1212
|
+
if (prop == null ? void 0 : prop.map) {
|
|
1213
|
+
// Return base table qualified root column, ignoring the .field part
|
|
1214
|
+
return q(this.type) + "." + q(alias);
|
|
1167
1215
|
}
|
|
1168
1216
|
|
|
1169
1217
|
if (arraySet.has(alias)) {
|
|
@@ -1207,8 +1255,9 @@ class SpiceModel {
|
|
|
1207
1255
|
}
|
|
1208
1256
|
|
|
1209
1257
|
return col;
|
|
1210
|
-
});
|
|
1211
|
-
|
|
1258
|
+
}); // Deduplicate columns (e.g., when multiple mapped dot-notations share the same root)
|
|
1259
|
+
|
|
1260
|
+
return _.join(_.uniq(_.compact(out)), ",");
|
|
1212
1261
|
}
|
|
1213
1262
|
|
|
1214
1263
|
filterResultsByColumns(data, columns) {
|
|
@@ -1241,24 +1290,33 @@ class SpiceModel {
|
|
|
1241
1290
|
}
|
|
1242
1291
|
|
|
1243
1292
|
extractNestings(string, localType) {
|
|
1244
|
-
var returnVal = [];
|
|
1293
|
+
var returnVal = []; // First, extract loop variables and embedded arrays from ANY/EVERY expressions
|
|
1294
|
+
// These should be EXCLUDED from join candidates
|
|
1295
|
+
|
|
1296
|
+
var anyEveryRegex = /(ANY|EVERY)\s+(\w+)\s+IN\s+`?(\w+)`?/gi;
|
|
1297
|
+
var anyEveryMatch;
|
|
1298
|
+
var loopVariables = new Set();
|
|
1299
|
+
var embeddedArrayFields = new Set();
|
|
1300
|
+
|
|
1301
|
+
while ((anyEveryMatch = anyEveryRegex.exec(string)) !== null) {
|
|
1302
|
+
loopVariables.add(anyEveryMatch[2]); // e.g., "p"
|
|
1303
|
+
|
|
1304
|
+
embeddedArrayFields.add(anyEveryMatch[3]); // e.g., "permissions"
|
|
1305
|
+
} // Now extract dot notation patterns, but skip loop variables and embedded arrays
|
|
1306
|
+
|
|
1307
|
+
|
|
1245
1308
|
var regex = /(`?\w+`?)\.(`?\w+`?)/g;
|
|
1246
1309
|
var match;
|
|
1247
1310
|
|
|
1248
1311
|
while ((match = regex.exec(string)) !== null) {
|
|
1249
|
-
var first = match[1].replace(/`/g, "");
|
|
1312
|
+
var first = match[1].replace(/`/g, ""); // Skip if it's the local type, a loop variable from ANY/EVERY, or an embedded array field
|
|
1250
1313
|
|
|
1251
|
-
if (first !== localType) {
|
|
1314
|
+
if (first !== localType && !loopVariables.has(first) && !embeddedArrayFields.has(first)) {
|
|
1252
1315
|
returnVal.push(first);
|
|
1253
1316
|
}
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
var queryRegex = /(ANY|EVERY)\s+\w+\s+IN\s+`?(\w+)`?/g;
|
|
1257
|
-
var queryMatch;
|
|
1317
|
+
} // DO NOT add embedded array fields from ANY/EVERY expressions
|
|
1318
|
+
// They iterate over document's embedded array, not join to another collection
|
|
1258
1319
|
|
|
1259
|
-
while ((queryMatch = queryRegex.exec(string)) !== null) {
|
|
1260
|
-
returnVal.push(queryMatch[2]);
|
|
1261
|
-
}
|
|
1262
1320
|
|
|
1263
1321
|
return [...new Set(returnVal)];
|
|
1264
1322
|
}
|
|
@@ -1286,6 +1344,53 @@ class SpiceModel {
|
|
|
1286
1344
|
parts[0] = "`" + parts[0] + "`";
|
|
1287
1345
|
return parts.join(" ");
|
|
1288
1346
|
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Builds join metadata from nestings for SQL joins and prepares columns.
|
|
1349
|
+
* @param {string[]} nestings - Array of alias names extracted from query/columns/sort
|
|
1350
|
+
* @param {Object} args - Arguments object containing columns (will be mutated with prepared columns)
|
|
1351
|
+
* @returns {Object} - { mappedNestings, protectedAliases, arrayAliases }
|
|
1352
|
+
*/
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
buildJoinMetadata(nestings, args) {
|
|
1356
|
+
// Decide which aliases we can join: only when map.type===MODEL AND reference is a STRING keyspace.
|
|
1357
|
+
var mappedNestings = _.compact(_.uniq(nestings).map(alias => {
|
|
1358
|
+
var prop = this.props[alias];
|
|
1359
|
+
if (!(prop == null ? void 0 : prop.map) || prop.map.type !== _2.MapType.MODEL) return null;
|
|
1360
|
+
var ref = prop.map.reference;
|
|
1361
|
+
|
|
1362
|
+
if (typeof ref !== "string") {
|
|
1363
|
+
// reference is a class/function/array-of-classes → no SQL join; serializer will handle it
|
|
1364
|
+
return null;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
var is_array = prop.type === "array" || prop.type === Array || prop.type === _2.DataType.ARRAY;
|
|
1368
|
+
return {
|
|
1369
|
+
alias,
|
|
1370
|
+
reference: ref.toLowerCase(),
|
|
1371
|
+
// keyspace to join
|
|
1372
|
+
is_array,
|
|
1373
|
+
type: prop.type,
|
|
1374
|
+
value_field: prop.map.value_field,
|
|
1375
|
+
destination: prop.map.destination || alias
|
|
1376
|
+
};
|
|
1377
|
+
}));
|
|
1378
|
+
|
|
1379
|
+
var protectedAliases = mappedNestings.map(m => m.alias);
|
|
1380
|
+
var arrayAliases = mappedNestings.filter(m => m.is_array).map(m => m.alias); // Columns: first prepare (prefix base table, rewrite array alias.field → ARRAY proj),
|
|
1381
|
+
// then normalize names and add default aliases
|
|
1382
|
+
//console.log("Columns in BuildJoinMetadata", args.columns);
|
|
1383
|
+
|
|
1384
|
+
this[_columns] = "" + args.columns;
|
|
1385
|
+
args.columns = this.prepColumns(args.columns, protectedAliases, arrayAliases);
|
|
1386
|
+
args.columns = this.fixColumnName(args.columns, protectedAliases); //console.log("Columns in BuildJoinMetadata after fixColumnName", args.columns);
|
|
1387
|
+
|
|
1388
|
+
return {
|
|
1389
|
+
mappedNestings,
|
|
1390
|
+
protectedAliases,
|
|
1391
|
+
arrayAliases
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1289
1394
|
/* removeSpaceAndSpecialCharacters(str) {
|
|
1290
1395
|
return str.replace(/[^a-zA-Z0-9]/g, "");
|
|
1291
1396
|
} */
|
|
@@ -1331,21 +1436,26 @@ class SpiceModel {
|
|
|
1331
1436
|
|
|
1332
1437
|
|
|
1333
1438
|
if (tableName && tableName !== this.type) {
|
|
1334
|
-
var newAlias = explicitAlias ||
|
|
1439
|
+
var newAlias = explicitAlias || "" + tableName;
|
|
1335
1440
|
|
|
1336
1441
|
if (!explicitAlias) {
|
|
1337
1442
|
if (aliasTracker.hasOwnProperty(newAlias)) {
|
|
1338
1443
|
aliasTracker[newAlias]++;
|
|
1339
|
-
newAlias =
|
|
1444
|
+
newAlias = "" + newAlias;
|
|
1340
1445
|
} else {
|
|
1341
1446
|
aliasTracker[newAlias] = 0;
|
|
1342
1447
|
}
|
|
1343
1448
|
|
|
1344
1449
|
return colWithoutAlias + " AS `" + newAlias + "`";
|
|
1345
1450
|
}
|
|
1451
|
+
} // If column is already qualified with base table (e.g., `user`.`field`), return as-is
|
|
1452
|
+
|
|
1453
|
+
|
|
1454
|
+
if (tableName === this.type && match) {
|
|
1455
|
+
return col;
|
|
1346
1456
|
}
|
|
1347
1457
|
|
|
1348
|
-
return col;
|
|
1458
|
+
return "`" + col + "`";
|
|
1349
1459
|
});
|
|
1350
1460
|
return _.join(_.compact(out), ", ");
|
|
1351
1461
|
}
|
|
@@ -1367,41 +1477,18 @@ class SpiceModel {
|
|
|
1367
1477
|
/*#__PURE__*/
|
|
1368
1478
|
function () {
|
|
1369
1479
|
var _ref13 = _asyncToGenerator(function* () {
|
|
1370
|
-
var
|
|
1480
|
+
var _args12, _args13;
|
|
1371
1481
|
|
|
1372
1482
|
if (args.mapping_dept) _this12[_mapping_dept] = args.mapping_dept;
|
|
1373
1483
|
if (args.mapping_dept_exempt) _this12[_mapping_dept_exempt] = args.mapping_dept_exempt; // Find alias tokens from query/columns/sort
|
|
1374
1484
|
|
|
1375
|
-
var nestings = [..._this12.extractNestings(((
|
|
1376
|
-
|
|
1377
|
-
var mappedNestings = _.compact(_.uniq(nestings).map(alias => {
|
|
1378
|
-
var prop = _this12.props[alias];
|
|
1379
|
-
if (!(prop == null ? void 0 : prop.map) || prop.map.type !== _2.MapType.MODEL) return null;
|
|
1380
|
-
var ref = prop.map.reference;
|
|
1381
|
-
|
|
1382
|
-
if (typeof ref !== "string") {
|
|
1383
|
-
// reference is a class/function/array-of-classes → no SQL join; serializer will handle it
|
|
1384
|
-
return null;
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
var is_array = prop.type === "array" || prop.type === Array || prop.type === _2.DataType.ARRAY;
|
|
1388
|
-
return {
|
|
1389
|
-
alias,
|
|
1390
|
-
reference: ref.toLowerCase(),
|
|
1391
|
-
// keyspace to join
|
|
1392
|
-
is_array,
|
|
1393
|
-
type: prop.type,
|
|
1394
|
-
value_field: prop.map.value_field,
|
|
1395
|
-
destination: prop.map.destination || alias
|
|
1396
|
-
};
|
|
1397
|
-
}));
|
|
1485
|
+
var nestings = [..._this12.extractNestings(((_args12 = args) == null ? void 0 : _args12.query) || "", _this12.type), //...this.extractNestings(args?.columns || "", this.type),
|
|
1486
|
+
..._this12.extractNestings(((_args13 = args) == null ? void 0 : _args13.sort) || "", _this12.type)]; // Build join metadata and prepare columns
|
|
1398
1487
|
|
|
1399
|
-
var
|
|
1400
|
-
|
|
1401
|
-
//
|
|
1488
|
+
var {
|
|
1489
|
+
mappedNestings
|
|
1490
|
+
} = _this12.buildJoinMetadata(nestings, args); // Build JOIN/NEST from the mapped keyspaces
|
|
1402
1491
|
|
|
1403
|
-
args.columns = _this12.prepColumns(args.columns, protectedAliases, arrayAliases);
|
|
1404
|
-
args.columns = _this12.fixColumnName(args.columns, protectedAliases); // Build JOIN/NEST from the mapped keyspaces
|
|
1405
1492
|
|
|
1406
1493
|
args._join = _this12.createJoinSection(mappedNestings); // WHERE
|
|
1407
1494
|
|
|
@@ -1469,11 +1556,11 @@ class SpiceModel {
|
|
|
1469
1556
|
|
|
1470
1557
|
try {
|
|
1471
1558
|
if (p) {
|
|
1472
|
-
var
|
|
1559
|
+
var _args14, _args15;
|
|
1473
1560
|
|
|
1474
1561
|
return yield p.track(_this12.type + ".list", doList, {
|
|
1475
|
-
limit: (
|
|
1476
|
-
offset: (
|
|
1562
|
+
limit: (_args14 = args) == null ? void 0 : _args14.limit,
|
|
1563
|
+
offset: (_args15 = args) == null ? void 0 : _args15.offset
|
|
1477
1564
|
});
|
|
1478
1565
|
}
|
|
1479
1566
|
|
|
@@ -1608,14 +1695,34 @@ class SpiceModel {
|
|
|
1608
1695
|
});
|
|
1609
1696
|
}
|
|
1610
1697
|
|
|
1611
|
-
mapToObject(data, Class, source_property, store_property, property) {
|
|
1698
|
+
mapToObject(data, Class, source_property, store_property, property, args, type, mapping_dept, level, columns) {
|
|
1612
1699
|
var _this15 = this;
|
|
1613
1700
|
|
|
1614
1701
|
return _asyncToGenerator(function* () {
|
|
1615
1702
|
var _this15$_ctx;
|
|
1616
1703
|
|
|
1617
1704
|
// ⚡ Get profiler for proper async context forking
|
|
1618
|
-
var p = (_this15$_ctx = _this15[_ctx]) == null ? void 0 : _this15$_ctx.profiler;
|
|
1705
|
+
var p = (_this15$_ctx = _this15[_ctx]) == null ? void 0 : _this15$_ctx.profiler; // create a array of all columns in args.columns skipping the first_segment of the Column string and pull out all the columns of where the new first segment matches source_property
|
|
1706
|
+
// Create a set of columns where the first segment matches source_property
|
|
1707
|
+
|
|
1708
|
+
var columnArray = [];
|
|
1709
|
+
|
|
1710
|
+
if (columns) {
|
|
1711
|
+
columns.split(',').forEach(col => {
|
|
1712
|
+
var parts = col.trim().split("."); // remove the first segment
|
|
1713
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1714
|
+
|
|
1715
|
+
var firstPart = parts[0]; // Remove backticks if present
|
|
1716
|
+
|
|
1717
|
+
var cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`') ? firstPart.slice(1, -1) : firstPart;
|
|
1718
|
+
|
|
1719
|
+
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1720
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1721
|
+
// Remove backticks from each column segment, if present, before joining
|
|
1722
|
+
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith('`') && segment.endsWith('`') ? segment.slice(1, -1) : segment).join("."));
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1619
1726
|
|
|
1620
1727
|
var original_is_array = _.isArray(data);
|
|
1621
1728
|
|
|
@@ -1631,8 +1738,18 @@ class SpiceModel {
|
|
|
1631
1738
|
var ids = [];
|
|
1632
1739
|
|
|
1633
1740
|
_.each(data, result => {
|
|
1634
|
-
|
|
1635
|
-
|
|
1741
|
+
var value = result[source_property]; // Check if value is in the empty string key (column aliasing issue)
|
|
1742
|
+
|
|
1743
|
+
if ((value === undefined || _.isObject(value) && _.isEmpty(value)) && result[''] && result[''][source_property]) {
|
|
1744
|
+
value = result[''][source_property];
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
if (_.isString(value) && value != "") {
|
|
1748
|
+
// Value is a raw ID string
|
|
1749
|
+
ids = _.union(ids, [value]);
|
|
1750
|
+
} else if (_.isObject(value) && _.isString(value.id) && value.id != "") {
|
|
1751
|
+
// Value is already a joined object with an id field
|
|
1752
|
+
ids = _.union(ids, [value.id]);
|
|
1636
1753
|
}
|
|
1637
1754
|
}); // Build the path for child models
|
|
1638
1755
|
|
|
@@ -1644,15 +1761,18 @@ class SpiceModel {
|
|
|
1644
1761
|
function () {
|
|
1645
1762
|
var _ref16 = _asyncToGenerator(function* () {
|
|
1646
1763
|
return yield Promise.allSettled(_.map(classes, obj => {
|
|
1647
|
-
|
|
1764
|
+
var objInstance = new obj(_extends({}, _this15[_args], {
|
|
1648
1765
|
skip_cache: _this15[_skip_cache],
|
|
1649
1766
|
_level: _this15[_level] + 1,
|
|
1650
1767
|
mapping_dept: _this15[_mapping_dept],
|
|
1651
1768
|
mapping_dept_exempt: _this15[_mapping_dept_exempt],
|
|
1769
|
+
_columns: columnArray.join(','),
|
|
1652
1770
|
_current_path: childPath
|
|
1653
|
-
}))
|
|
1771
|
+
}));
|
|
1772
|
+
return objInstance.getMulti({
|
|
1654
1773
|
skip_hooks: true,
|
|
1655
|
-
ids: ids
|
|
1774
|
+
ids: ids,
|
|
1775
|
+
columns: columnArray
|
|
1656
1776
|
});
|
|
1657
1777
|
}));
|
|
1658
1778
|
});
|
|
@@ -1673,12 +1793,26 @@ class SpiceModel {
|
|
|
1673
1793
|
}
|
|
1674
1794
|
|
|
1675
1795
|
var ug = _.flatten(_.compact(_.map(returned_all, returned_obj => {
|
|
1676
|
-
if (returned_obj.status == "fulfilled")
|
|
1796
|
+
if (returned_obj.status == "fulfilled") {
|
|
1797
|
+
return returned_obj.value;
|
|
1798
|
+
}
|
|
1677
1799
|
})));
|
|
1800
|
+
/* if(source_property == "group") {
|
|
1801
|
+
console.log("Returned All", source_property, store_property, ug);
|
|
1802
|
+
} */
|
|
1803
|
+
|
|
1678
1804
|
|
|
1679
1805
|
data = _.map(data, result => {
|
|
1806
|
+
var sourceValue = result[source_property]; // Check if value is in the empty string key (column aliasing issue)
|
|
1807
|
+
|
|
1808
|
+
if ((sourceValue === undefined || _.isObject(sourceValue) && _.isEmpty(sourceValue)) && result[''] && result[''][source_property]) {
|
|
1809
|
+
sourceValue = result[''][source_property];
|
|
1810
|
+
} // Get the ID to match against - either a string ID or the id property of an object
|
|
1811
|
+
|
|
1812
|
+
|
|
1813
|
+
var sourceId = _.isString(sourceValue) ? sourceValue : _.isObject(sourceValue) ? sourceValue.id : null;
|
|
1680
1814
|
var result_found = _.find(ug, g => {
|
|
1681
|
-
return g.id ==
|
|
1815
|
+
return g.id == sourceId;
|
|
1682
1816
|
}) || {};
|
|
1683
1817
|
result[store_property] = result_found;
|
|
1684
1818
|
return result;
|
|
@@ -1689,7 +1823,7 @@ class SpiceModel {
|
|
|
1689
1823
|
})();
|
|
1690
1824
|
}
|
|
1691
1825
|
|
|
1692
|
-
mapToObjectArray(data, Class, source_property, store_property, property) {
|
|
1826
|
+
mapToObjectArray(data, Class, source_property, store_property, property, args, type, mapping_dept, level, columns) {
|
|
1693
1827
|
var _this16 = this;
|
|
1694
1828
|
|
|
1695
1829
|
return _asyncToGenerator(function* () {
|
|
@@ -1697,6 +1831,24 @@ class SpiceModel {
|
|
|
1697
1831
|
|
|
1698
1832
|
// ⚡ Get profiler for proper async context forking
|
|
1699
1833
|
var p = (_this16$_ctx = _this16[_ctx]) == null ? void 0 : _this16$_ctx.profiler;
|
|
1834
|
+
var columnArray = [];
|
|
1835
|
+
|
|
1836
|
+
if (columns) {
|
|
1837
|
+
columns.split(',').forEach(col => {
|
|
1838
|
+
var parts = col.trim().split("."); // remove the first segment
|
|
1839
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1840
|
+
|
|
1841
|
+
var firstPart = parts[0]; // Remove backticks if present
|
|
1842
|
+
|
|
1843
|
+
var cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`') ? firstPart.slice(1, -1) : firstPart;
|
|
1844
|
+
|
|
1845
|
+
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1846
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1847
|
+
// Remove backticks from each column segment, if present, before joining
|
|
1848
|
+
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith('`') && segment.endsWith('`') ? segment.slice(1, -1) : segment).join("."));
|
|
1849
|
+
}
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1700
1852
|
|
|
1701
1853
|
var original_is_array = _.isArray(data);
|
|
1702
1854
|
|
|
@@ -1718,9 +1870,18 @@ class SpiceModel {
|
|
|
1718
1870
|
|
|
1719
1871
|
if (_.isString(result[source_property])) {
|
|
1720
1872
|
value = [result[source_property]];
|
|
1721
|
-
}
|
|
1873
|
+
} // Extract IDs - handle both string IDs and objects with id property
|
|
1722
1874
|
|
|
1723
|
-
|
|
1875
|
+
|
|
1876
|
+
var items = _.compact(_.map(value, obj => {
|
|
1877
|
+
if (_.isString(obj) && obj != "") {
|
|
1878
|
+
return obj;
|
|
1879
|
+
} else if (_.isObject(obj) && _.isString(obj.id) && obj.id != "") {
|
|
1880
|
+
return obj.id;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
return null;
|
|
1884
|
+
}));
|
|
1724
1885
|
|
|
1725
1886
|
ids = _.union(ids, items);
|
|
1726
1887
|
}); // Build the path for child models
|
|
@@ -1741,10 +1902,12 @@ class SpiceModel {
|
|
|
1741
1902
|
_level: _this16[_level] + 1,
|
|
1742
1903
|
mapping_dept: _this16[_mapping_dept],
|
|
1743
1904
|
mapping_dept_exempt: _this16[_mapping_dept_exempt],
|
|
1905
|
+
_columns: columnArray.join(','),
|
|
1744
1906
|
_current_path: childPath
|
|
1745
1907
|
})).getMulti({
|
|
1746
1908
|
skip_hooks: true,
|
|
1747
|
-
ids: ids
|
|
1909
|
+
ids: ids,
|
|
1910
|
+
columns: columnArray
|
|
1748
1911
|
});
|
|
1749
1912
|
}));
|
|
1750
1913
|
});
|
|
@@ -1778,7 +1941,11 @@ class SpiceModel {
|
|
|
1778
1941
|
return;
|
|
1779
1942
|
}
|
|
1780
1943
|
|
|
1781
|
-
result[store_property] = _.map(result[source_property],
|
|
1944
|
+
result[store_property] = _.map(result[source_property], item => {
|
|
1945
|
+
// Get the ID to match - either a string ID or the id property of an object
|
|
1946
|
+
var itemId = _.isString(item) ? item : _.isObject(item) ? item.id : null;
|
|
1947
|
+
return _.find(returned_objects, p => p.id === itemId);
|
|
1948
|
+
});
|
|
1782
1949
|
result[store_property] = _.reject(result[store_property], obj => obj === null || obj === undefined);
|
|
1783
1950
|
});
|
|
1784
1951
|
}
|
|
@@ -1830,11 +1997,11 @@ class SpiceModel {
|
|
|
1830
1997
|
_this17.addModifier({
|
|
1831
1998
|
when: properties[i].map.when || "read",
|
|
1832
1999
|
execute: function () {
|
|
1833
|
-
var _execute = _asyncToGenerator(function* (data) {
|
|
1834
|
-
return yield _this17.mapToObject(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i, properties[i].map.destination || i, properties[i]);
|
|
2000
|
+
var _execute = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns) {
|
|
2001
|
+
return yield _this17.mapToObject(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i, properties[i].map.destination || i, properties[i], args, type, mapping_dept, level, columns);
|
|
1835
2002
|
});
|
|
1836
2003
|
|
|
1837
|
-
function execute(_x) {
|
|
2004
|
+
function execute(_x, _x2, _x3, _x4, _x5, _x6, _x7, _x8) {
|
|
1838
2005
|
return _execute.apply(this, arguments);
|
|
1839
2006
|
}
|
|
1840
2007
|
|
|
@@ -1851,11 +2018,11 @@ class SpiceModel {
|
|
|
1851
2018
|
_this17.addModifier({
|
|
1852
2019
|
when: properties[i].map.when || "read",
|
|
1853
2020
|
execute: function () {
|
|
1854
|
-
var _execute2 = _asyncToGenerator(function* (data) {
|
|
1855
|
-
return yield _this17.mapToObjectArray(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i, properties[i].map.destination || i, properties[i]);
|
|
2021
|
+
var _execute2 = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns) {
|
|
2022
|
+
return yield _this17.mapToObjectArray(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i, properties[i].map.destination || i, properties[i], args, type, mapping_dept, level, columns);
|
|
1856
2023
|
});
|
|
1857
2024
|
|
|
1858
|
-
function execute(
|
|
2025
|
+
function execute(_x9, _x10, _x11, _x12, _x13, _x14, _x15, _x16) {
|
|
1859
2026
|
return _execute2.apply(this, arguments);
|
|
1860
2027
|
}
|
|
1861
2028
|
|
|
@@ -1921,7 +2088,7 @@ class SpiceModel {
|
|
|
1921
2088
|
var modifier = modifiers[i];
|
|
1922
2089
|
|
|
1923
2090
|
try {
|
|
1924
|
-
var result = yield modifier(data, old_data, _this18[_ctx], _this18.type); // Guard against modifiers that return undefined
|
|
2091
|
+
var result = yield modifier(data, old_data, _this18[_ctx], _this18.type, args, _this18[_mapping_dept], _this18[_level], _this18[_columns]); // Guard against modifiers that return undefined
|
|
1925
2092
|
|
|
1926
2093
|
if (result !== undefined) {
|
|
1927
2094
|
data = result;
|
|
@@ -1966,7 +2133,7 @@ class SpiceModel {
|
|
|
1966
2133
|
return (_this18$props$key2 = _this18.props[key]) == null ? void 0 : _this18$props$key2.hide;
|
|
1967
2134
|
}); // Combine default props to remove.
|
|
1968
2135
|
|
|
1969
|
-
var propsToClean = ["deleted", "type", ...path_to_be_removed, ...hiddenProps];
|
|
2136
|
+
var propsToClean = ["deleted", "type", "collection", ...path_to_be_removed, ...hiddenProps];
|
|
1970
2137
|
data = data.map(item => _.omit(item, propsToClean));
|
|
1971
2138
|
} // Return in the original format (array or single object).
|
|
1972
2139
|
|
package/package.json
CHANGED
package/src/models/SpiceModel.js
CHANGED
|
@@ -15,6 +15,7 @@ var SDate = require("sonover-date"),
|
|
|
15
15
|
_props = Symbol(),
|
|
16
16
|
_args = Symbol(),
|
|
17
17
|
_hooks = Symbol(),
|
|
18
|
+
_columns = Symbol(),
|
|
18
19
|
_disable_lifecycle_events = Symbol(),
|
|
19
20
|
_external_modifier_loaded = Symbol(),
|
|
20
21
|
_skip_cache = Symbol(),
|
|
@@ -62,6 +63,7 @@ export default class SpiceModel {
|
|
|
62
63
|
this[_skip_cache] = args?.args?.skip_cache || false;
|
|
63
64
|
this[_level] = args?.args?._level || 0;
|
|
64
65
|
this[_current_path] = args?.args?._current_path || "";
|
|
66
|
+
this[_columns] = args?.args?._columns || "";
|
|
65
67
|
this[_hooks] = {
|
|
66
68
|
create: {
|
|
67
69
|
before: [],
|
|
@@ -528,6 +530,41 @@ export default class SpiceModel {
|
|
|
528
530
|
let key = `get::${this.type}::${args.id}${args.columns ? `::${args.columns}` : ""}`;
|
|
529
531
|
let results = {};
|
|
530
532
|
|
|
533
|
+
// Extract nestings from columns if specified
|
|
534
|
+
const nestings = this.extractNestings(args?.columns || "", this.type);
|
|
535
|
+
|
|
536
|
+
// Build join metadata and prepare columns
|
|
537
|
+
this.buildJoinMetadata(nestings, args);
|
|
538
|
+
let columns = args.columns;
|
|
539
|
+
let columnArray = [];
|
|
540
|
+
if (columns) {
|
|
541
|
+
columns.split(',').forEach(col => {
|
|
542
|
+
|
|
543
|
+
const parts = col.trim().split(".")// remove the first segment
|
|
544
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
545
|
+
const firstPart = parts[0];
|
|
546
|
+
// Remove backticks if present
|
|
547
|
+
const cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`')
|
|
548
|
+
? firstPart.slice(1, -1)
|
|
549
|
+
: firstPart;
|
|
550
|
+
|
|
551
|
+
//if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
552
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
553
|
+
// Remove backticks from each column segment, if present, before joining
|
|
554
|
+
columnArray.push(
|
|
555
|
+
parts
|
|
556
|
+
.slice(1)
|
|
557
|
+
.map(segment =>
|
|
558
|
+
segment && segment.startsWith('`') && segment.endsWith('`')
|
|
559
|
+
? segment.slice(1, -1)
|
|
560
|
+
: segment
|
|
561
|
+
)
|
|
562
|
+
.join(".")
|
|
563
|
+
);
|
|
564
|
+
// }
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
531
568
|
if (this.shouldUseCache(this.type)) {
|
|
532
569
|
// Retrieve the cached results
|
|
533
570
|
const cached_results = await this.getCacheProviderObject(
|
|
@@ -537,16 +574,15 @@ export default class SpiceModel {
|
|
|
537
574
|
const isCacheEmpty = cached_results?.value === undefined;
|
|
538
575
|
// Check if the cached result should be refreshed
|
|
539
576
|
const shouldRefresh = await this.shouldForceRefresh(cached_results);
|
|
540
|
-
// Force a refresh for "workflow" type if needed
|
|
541
577
|
|
|
542
578
|
if (isCacheEmpty || shouldRefresh) {
|
|
543
579
|
// Retrieve from the database and update cache
|
|
544
580
|
if (p) {
|
|
545
581
|
results = await p.track(`${this.type}.get.database`, async () => {
|
|
546
|
-
return await this.database.get(args.id);
|
|
582
|
+
return await this.database.get(args.id, { columns: columnArray });
|
|
547
583
|
});
|
|
548
584
|
} else {
|
|
549
|
-
results = await this.database.get(args.id);
|
|
585
|
+
results = await this.database.get(args.id, { columns: columnArray });
|
|
550
586
|
}
|
|
551
587
|
await this.getCacheProviderObject(this.type).set(
|
|
552
588
|
key,
|
|
@@ -561,10 +597,10 @@ export default class SpiceModel {
|
|
|
561
597
|
// Directly fetch from the database if caching is disabled
|
|
562
598
|
if (p) {
|
|
563
599
|
results = await p.track(`${this.type}.get.database`, async () => {
|
|
564
|
-
return await this.database.get(args.id);
|
|
600
|
+
return await this.database.get(args.id, { columns: columnArray });
|
|
565
601
|
});
|
|
566
602
|
} else {
|
|
567
|
-
results = await this.database.get(args.id);
|
|
603
|
+
results = await this.database.get(args.id, { columns: columnArray });
|
|
568
604
|
}
|
|
569
605
|
}
|
|
570
606
|
|
|
@@ -636,7 +672,7 @@ export default class SpiceModel {
|
|
|
636
672
|
await this.run_hook(this, "list", "before");
|
|
637
673
|
}
|
|
638
674
|
_.remove(args.ids, (o) => o == undefined);
|
|
639
|
-
let key = `multi-get::${this.type}::${_.join(args.ids, "|")}`;
|
|
675
|
+
let key = `multi-get::${this.type}::${_.join(args.ids, "|")}:${args.columns}`;
|
|
640
676
|
let results = [];
|
|
641
677
|
if (args.ids.length > 0) {
|
|
642
678
|
if (this.shouldUseCache(this.type)) {
|
|
@@ -648,7 +684,7 @@ export default class SpiceModel {
|
|
|
648
684
|
cached_results?.value === undefined ||
|
|
649
685
|
(await this.shouldForceRefresh(cached_results))
|
|
650
686
|
) {
|
|
651
|
-
results = await this.database.multi_get(args.ids, true);
|
|
687
|
+
results = await this.database.multi_get(args.ids, {keep_type:true, columns:args.columns.length > 0 && args.columns != ""?[...args.columns, 'type']:[]});
|
|
652
688
|
this.getCacheProviderObject(this.type).set(
|
|
653
689
|
key,
|
|
654
690
|
{ value: results, time: new Date().getTime() },
|
|
@@ -656,7 +692,7 @@ export default class SpiceModel {
|
|
|
656
692
|
);
|
|
657
693
|
}
|
|
658
694
|
} else {
|
|
659
|
-
results = await this.database.multi_get(args.ids, true);
|
|
695
|
+
results = await this.database.multi_get(args.ids, {keep_type:true, columns:args.columns.length> 0 && args.columns != ""?[...args.columns, 'type']:[]});
|
|
660
696
|
}
|
|
661
697
|
}
|
|
662
698
|
_.remove(results, (o) => o.type != this.type);
|
|
@@ -668,11 +704,11 @@ export default class SpiceModel {
|
|
|
668
704
|
args,
|
|
669
705
|
await this.propsToBeRemoved(results)
|
|
670
706
|
);
|
|
671
|
-
}
|
|
707
|
+
}
|
|
672
708
|
|
|
673
709
|
if (args.skip_hooks != true) {
|
|
674
710
|
await this.run_hook(results, "list", "after", args.context);
|
|
675
|
-
}
|
|
711
|
+
}
|
|
676
712
|
|
|
677
713
|
return results;
|
|
678
714
|
};
|
|
@@ -981,6 +1017,13 @@ export default class SpiceModel {
|
|
|
981
1017
|
return explicitAs ? `${qualified} AS ${q(explicitAs)}` : qualified;
|
|
982
1018
|
}
|
|
983
1019
|
|
|
1020
|
+
// Check if alias has a map - if so, simplify to root column only (raw ID)
|
|
1021
|
+
const prop = this.props[alias];
|
|
1022
|
+
if (prop?.map) {
|
|
1023
|
+
// Return base table qualified root column, ignoring the .field part
|
|
1024
|
+
return `${q(this.type)}.${q(alias)}`;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
984
1027
|
if (arraySet.has(alias)) {
|
|
985
1028
|
let proj = this.buildArrayProjection(alias, field);
|
|
986
1029
|
if (explicitAs && explicitAs !== `${alias}_${field}`) {
|
|
@@ -1027,7 +1070,8 @@ export default class SpiceModel {
|
|
|
1027
1070
|
return col;
|
|
1028
1071
|
});
|
|
1029
1072
|
|
|
1030
|
-
|
|
1073
|
+
// Deduplicate columns (e.g., when multiple mapped dot-notations share the same root)
|
|
1074
|
+
return _.join(_.uniq(_.compact(out)), ",");
|
|
1031
1075
|
}
|
|
1032
1076
|
|
|
1033
1077
|
filterResultsByColumns(data, columns) {
|
|
@@ -1065,22 +1109,33 @@ export default class SpiceModel {
|
|
|
1065
1109
|
|
|
1066
1110
|
extractNestings(string, localType) {
|
|
1067
1111
|
let returnVal = [];
|
|
1112
|
+
|
|
1113
|
+
// First, extract loop variables and embedded arrays from ANY/EVERY expressions
|
|
1114
|
+
// These should be EXCLUDED from join candidates
|
|
1115
|
+
let anyEveryRegex = /(ANY|EVERY)\s+(\w+)\s+IN\s+`?(\w+)`?/gi;
|
|
1116
|
+
let anyEveryMatch;
|
|
1117
|
+
const loopVariables = new Set();
|
|
1118
|
+
const embeddedArrayFields = new Set();
|
|
1119
|
+
|
|
1120
|
+
while ((anyEveryMatch = anyEveryRegex.exec(string)) !== null) {
|
|
1121
|
+
loopVariables.add(anyEveryMatch[2]); // e.g., "p"
|
|
1122
|
+
embeddedArrayFields.add(anyEveryMatch[3]); // e.g., "permissions"
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// Now extract dot notation patterns, but skip loop variables and embedded arrays
|
|
1068
1126
|
let regex = /(`?\w+`?)\.(`?\w+`?)/g;
|
|
1069
1127
|
let match;
|
|
1070
1128
|
|
|
1071
1129
|
while ((match = regex.exec(string)) !== null) {
|
|
1072
1130
|
let first = match[1].replace(/`/g, "");
|
|
1073
|
-
if
|
|
1131
|
+
// Skip if it's the local type, a loop variable from ANY/EVERY, or an embedded array field
|
|
1132
|
+
if (first !== localType && !loopVariables.has(first) && !embeddedArrayFields.has(first)) {
|
|
1074
1133
|
returnVal.push(first);
|
|
1075
1134
|
}
|
|
1076
1135
|
}
|
|
1077
1136
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
while ((queryMatch = queryRegex.exec(string)) !== null) {
|
|
1082
|
-
returnVal.push(queryMatch[2]);
|
|
1083
|
-
}
|
|
1137
|
+
// DO NOT add embedded array fields from ANY/EVERY expressions
|
|
1138
|
+
// They iterate over document's embedded array, not join to another collection
|
|
1084
1139
|
|
|
1085
1140
|
return [...new Set(returnVal)];
|
|
1086
1141
|
}
|
|
@@ -1106,6 +1161,61 @@ export default class SpiceModel {
|
|
|
1106
1161
|
return parts.join(" ");
|
|
1107
1162
|
}
|
|
1108
1163
|
|
|
1164
|
+
/**
|
|
1165
|
+
* Builds join metadata from nestings for SQL joins and prepares columns.
|
|
1166
|
+
* @param {string[]} nestings - Array of alias names extracted from query/columns/sort
|
|
1167
|
+
* @param {Object} args - Arguments object containing columns (will be mutated with prepared columns)
|
|
1168
|
+
* @returns {Object} - { mappedNestings, protectedAliases, arrayAliases }
|
|
1169
|
+
*/
|
|
1170
|
+
buildJoinMetadata(nestings, args) {
|
|
1171
|
+
// Decide which aliases we can join: only when map.type===MODEL AND reference is a STRING keyspace.
|
|
1172
|
+
const mappedNestings = _.compact(
|
|
1173
|
+
_.uniq(nestings).map((alias) => {
|
|
1174
|
+
const prop = this.props[alias];
|
|
1175
|
+
if (!prop?.map || prop.map.type !== MapType.MODEL) return null;
|
|
1176
|
+
|
|
1177
|
+
const ref = prop.map.reference;
|
|
1178
|
+
if (typeof ref !== "string") {
|
|
1179
|
+
// reference is a class/function/array-of-classes → no SQL join; serializer will handle it
|
|
1180
|
+
return null;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const is_array =
|
|
1184
|
+
prop.type === "array" ||
|
|
1185
|
+
prop.type === Array ||
|
|
1186
|
+
prop.type === DataType.ARRAY;
|
|
1187
|
+
|
|
1188
|
+
return {
|
|
1189
|
+
alias,
|
|
1190
|
+
reference: ref.toLowerCase(), // keyspace to join
|
|
1191
|
+
is_array,
|
|
1192
|
+
type: prop.type,
|
|
1193
|
+
value_field: prop.map.value_field,
|
|
1194
|
+
destination: prop.map.destination || alias,
|
|
1195
|
+
};
|
|
1196
|
+
})
|
|
1197
|
+
);
|
|
1198
|
+
|
|
1199
|
+
const protectedAliases = mappedNestings.map((m) => m.alias);
|
|
1200
|
+
const arrayAliases = mappedNestings
|
|
1201
|
+
.filter((m) => m.is_array)
|
|
1202
|
+
.map((m) => m.alias);
|
|
1203
|
+
|
|
1204
|
+
// Columns: first prepare (prefix base table, rewrite array alias.field → ARRAY proj),
|
|
1205
|
+
// then normalize names and add default aliases
|
|
1206
|
+
//console.log("Columns in BuildJoinMetadata", args.columns);
|
|
1207
|
+
this[_columns] = `${args.columns}`;
|
|
1208
|
+
args.columns = this.prepColumns(
|
|
1209
|
+
args.columns,
|
|
1210
|
+
protectedAliases,
|
|
1211
|
+
arrayAliases
|
|
1212
|
+
);
|
|
1213
|
+
|
|
1214
|
+
args.columns = this.fixColumnName(args.columns, protectedAliases);
|
|
1215
|
+
//console.log("Columns in BuildJoinMetadata after fixColumnName", args.columns);
|
|
1216
|
+
return { mappedNestings, protectedAliases, arrayAliases };
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1109
1219
|
/* removeSpaceAndSpecialCharacters(str) {
|
|
1110
1220
|
return str.replace(/[^a-zA-Z0-9]/g, "");
|
|
1111
1221
|
} */
|
|
@@ -1157,11 +1267,11 @@ export default class SpiceModel {
|
|
|
1157
1267
|
|
|
1158
1268
|
// For joined table columns, add default alias <table_col> if none
|
|
1159
1269
|
if (tableName && tableName !== this.type) {
|
|
1160
|
-
let newAlias = explicitAlias || `${tableName}
|
|
1270
|
+
let newAlias = explicitAlias || `${tableName}`;
|
|
1161
1271
|
if (!explicitAlias) {
|
|
1162
1272
|
if (aliasTracker.hasOwnProperty(newAlias)) {
|
|
1163
1273
|
aliasTracker[newAlias]++;
|
|
1164
|
-
newAlias = `${newAlias}
|
|
1274
|
+
newAlias = `${newAlias}`;
|
|
1165
1275
|
} else {
|
|
1166
1276
|
aliasTracker[newAlias] = 0;
|
|
1167
1277
|
}
|
|
@@ -1169,7 +1279,12 @@ export default class SpiceModel {
|
|
|
1169
1279
|
}
|
|
1170
1280
|
}
|
|
1171
1281
|
|
|
1172
|
-
return
|
|
1282
|
+
// If column is already qualified with base table (e.g., `user`.`field`), return as-is
|
|
1283
|
+
if (tableName === this.type && match) {
|
|
1284
|
+
return col;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
return `\`${col}\``;
|
|
1173
1288
|
});
|
|
1174
1289
|
|
|
1175
1290
|
return _.join(_.compact(out), ", ");
|
|
@@ -1187,52 +1302,13 @@ export default class SpiceModel {
|
|
|
1187
1302
|
// Find alias tokens from query/columns/sort
|
|
1188
1303
|
const nestings = [
|
|
1189
1304
|
...this.extractNestings(args?.query || "", this.type),
|
|
1190
|
-
|
|
1305
|
+
//...this.extractNestings(args?.columns || "", this.type),
|
|
1191
1306
|
...this.extractNestings(args?.sort || "", this.type),
|
|
1192
1307
|
];
|
|
1193
1308
|
|
|
1194
|
-
//
|
|
1195
|
-
const mappedNestings =
|
|
1196
|
-
|
|
1197
|
-
const prop = this.props[alias];
|
|
1198
|
-
if (!prop?.map || prop.map.type !== MapType.MODEL) return null;
|
|
1199
|
-
|
|
1200
|
-
const ref = prop.map.reference;
|
|
1201
|
-
if (typeof ref !== "string") {
|
|
1202
|
-
// reference is a class/function/array-of-classes → no SQL join; serializer will handle it
|
|
1203
|
-
return null;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
const is_array =
|
|
1207
|
-
prop.type === "array" ||
|
|
1208
|
-
prop.type === Array ||
|
|
1209
|
-
prop.type === DataType.ARRAY;
|
|
1210
|
-
|
|
1211
|
-
return {
|
|
1212
|
-
alias,
|
|
1213
|
-
reference: ref.toLowerCase(), // keyspace to join
|
|
1214
|
-
is_array,
|
|
1215
|
-
type: prop.type,
|
|
1216
|
-
value_field: prop.map.value_field,
|
|
1217
|
-
destination: prop.map.destination || alias,
|
|
1218
|
-
};
|
|
1219
|
-
})
|
|
1220
|
-
);
|
|
1221
|
-
|
|
1222
|
-
const protectedAliases = mappedNestings.map((m) => m.alias);
|
|
1223
|
-
const arrayAliases = mappedNestings
|
|
1224
|
-
.filter((m) => m.is_array)
|
|
1225
|
-
.map((m) => m.alias);
|
|
1226
|
-
|
|
1227
|
-
// Columns: first prepare (prefix base table, rewrite array alias.field → ARRAY proj),
|
|
1228
|
-
// then normalize names and add default aliases
|
|
1229
|
-
args.columns = this.prepColumns(
|
|
1230
|
-
args.columns,
|
|
1231
|
-
protectedAliases,
|
|
1232
|
-
arrayAliases
|
|
1233
|
-
);
|
|
1234
|
-
args.columns = this.fixColumnName(args.columns, protectedAliases);
|
|
1235
|
-
|
|
1309
|
+
// Build join metadata and prepare columns
|
|
1310
|
+
const { mappedNestings } = this.buildJoinMetadata(nestings, args);
|
|
1311
|
+
|
|
1236
1312
|
// Build JOIN/NEST from the mapped keyspaces
|
|
1237
1313
|
args._join = this.createJoinSection(mappedNestings);
|
|
1238
1314
|
|
|
@@ -1299,7 +1375,7 @@ export default class SpiceModel {
|
|
|
1299
1375
|
"read",
|
|
1300
1376
|
{},
|
|
1301
1377
|
args,
|
|
1302
|
-
await this.propsToBeRemoved(results.data)
|
|
1378
|
+
await this.propsToBeRemoved(results.data),
|
|
1303
1379
|
);
|
|
1304
1380
|
}
|
|
1305
1381
|
|
|
@@ -1434,10 +1510,39 @@ export default class SpiceModel {
|
|
|
1434
1510
|
});
|
|
1435
1511
|
}
|
|
1436
1512
|
|
|
1437
|
-
async mapToObject(data, Class, source_property, store_property, property) {
|
|
1513
|
+
async mapToObject(data, Class, source_property, store_property, property, args, type, mapping_dept, level, columns) {
|
|
1438
1514
|
// ⚡ Get profiler for proper async context forking
|
|
1439
1515
|
const p = this[_ctx]?.profiler;
|
|
1440
|
-
|
|
1516
|
+
// create a array of all columns in args.columns skipping the first_segment of the Column string and pull out all the columns of where the new first segment matches source_property
|
|
1517
|
+
// Create a set of columns where the first segment matches source_property
|
|
1518
|
+
let columnArray = [];
|
|
1519
|
+
if (columns) {
|
|
1520
|
+
columns.split(',').forEach(col => {
|
|
1521
|
+
|
|
1522
|
+
const parts = col.trim().split(".")// remove the first segment
|
|
1523
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1524
|
+
const firstPart = parts[0];
|
|
1525
|
+
// Remove backticks if present
|
|
1526
|
+
const cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`')
|
|
1527
|
+
? firstPart.slice(1, -1)
|
|
1528
|
+
: firstPart;
|
|
1529
|
+
|
|
1530
|
+
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1531
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1532
|
+
// Remove backticks from each column segment, if present, before joining
|
|
1533
|
+
columnArray.push(
|
|
1534
|
+
parts
|
|
1535
|
+
.slice(1)
|
|
1536
|
+
.map(segment =>
|
|
1537
|
+
segment && segment.startsWith('`') && segment.endsWith('`')
|
|
1538
|
+
? segment.slice(1, -1)
|
|
1539
|
+
: segment
|
|
1540
|
+
)
|
|
1541
|
+
.join(".")
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1441
1546
|
let original_is_array = _.isArray(data);
|
|
1442
1547
|
if (!original_is_array) {
|
|
1443
1548
|
data = Array.of(data);
|
|
@@ -1448,11 +1553,19 @@ export default class SpiceModel {
|
|
|
1448
1553
|
|
|
1449
1554
|
let ids = [];
|
|
1450
1555
|
_.each(data, (result) => {
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
) {
|
|
1455
|
-
|
|
1556
|
+
let value = result[source_property];
|
|
1557
|
+
|
|
1558
|
+
// Check if value is in the empty string key (column aliasing issue)
|
|
1559
|
+
if ((value === undefined || (_.isObject(value) && _.isEmpty(value))) && result[''] && result[''][source_property]) {
|
|
1560
|
+
value = result[''][source_property];
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
if (_.isString(value) && value != "") {
|
|
1564
|
+
// Value is a raw ID string
|
|
1565
|
+
ids = _.union(ids, [value]);
|
|
1566
|
+
} else if (_.isObject(value) && _.isString(value.id) && value.id != "") {
|
|
1567
|
+
// Value is already a joined object with an id field
|
|
1568
|
+
ids = _.union(ids, [value.id]);
|
|
1456
1569
|
}
|
|
1457
1570
|
});
|
|
1458
1571
|
|
|
@@ -1466,16 +1579,20 @@ export default class SpiceModel {
|
|
|
1466
1579
|
const fetchRelated = async () => {
|
|
1467
1580
|
return await Promise.allSettled(
|
|
1468
1581
|
_.map(classes, (obj) => {
|
|
1469
|
-
|
|
1582
|
+
let objInstance = new obj({
|
|
1470
1583
|
...this[_args],
|
|
1471
1584
|
skip_cache: this[_skip_cache],
|
|
1472
1585
|
_level: this[_level] + 1,
|
|
1473
1586
|
mapping_dept: this[_mapping_dept],
|
|
1474
1587
|
mapping_dept_exempt: this[_mapping_dept_exempt],
|
|
1588
|
+
_columns: columnArray.join(','),
|
|
1475
1589
|
_current_path: childPath,
|
|
1476
|
-
})
|
|
1590
|
+
})
|
|
1591
|
+
|
|
1592
|
+
return objInstance.getMulti({
|
|
1477
1593
|
skip_hooks: true,
|
|
1478
1594
|
ids: ids,
|
|
1595
|
+
columns:columnArray,
|
|
1479
1596
|
});
|
|
1480
1597
|
})
|
|
1481
1598
|
);
|
|
@@ -1495,15 +1612,30 @@ export default class SpiceModel {
|
|
|
1495
1612
|
let ug = _.flatten(
|
|
1496
1613
|
_.compact(
|
|
1497
1614
|
_.map(returned_all, (returned_obj) => {
|
|
1498
|
-
if (returned_obj.status == "fulfilled")
|
|
1615
|
+
if (returned_obj.status == "fulfilled") {
|
|
1616
|
+
return returned_obj.value;
|
|
1617
|
+
}
|
|
1499
1618
|
})
|
|
1500
1619
|
)
|
|
1501
1620
|
);
|
|
1502
1621
|
|
|
1622
|
+
/* if(source_property == "group") {
|
|
1623
|
+
console.log("Returned All", source_property, store_property, ug);
|
|
1624
|
+
} */
|
|
1625
|
+
|
|
1503
1626
|
data = _.map(data, (result) => {
|
|
1627
|
+
let sourceValue = result[source_property];
|
|
1628
|
+
|
|
1629
|
+
// Check if value is in the empty string key (column aliasing issue)
|
|
1630
|
+
if ((sourceValue === undefined || (_.isObject(sourceValue) && _.isEmpty(sourceValue))) && result[''] && result[''][source_property]) {
|
|
1631
|
+
sourceValue = result[''][source_property];
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// Get the ID to match against - either a string ID or the id property of an object
|
|
1635
|
+
const sourceId = _.isString(sourceValue) ? sourceValue : (_.isObject(sourceValue) ? sourceValue.id : null);
|
|
1504
1636
|
let result_found =
|
|
1505
1637
|
_.find(ug, (g) => {
|
|
1506
|
-
return g.id ==
|
|
1638
|
+
return g.id == sourceId;
|
|
1507
1639
|
}) || {};
|
|
1508
1640
|
result[store_property] = result_found;
|
|
1509
1641
|
return result;
|
|
@@ -1517,11 +1649,41 @@ export default class SpiceModel {
|
|
|
1517
1649
|
Class,
|
|
1518
1650
|
source_property,
|
|
1519
1651
|
store_property,
|
|
1520
|
-
property
|
|
1652
|
+
property,
|
|
1653
|
+
args, type, mapping_dept, level, columns
|
|
1521
1654
|
) {
|
|
1522
1655
|
// ⚡ Get profiler for proper async context forking
|
|
1523
1656
|
const p = this[_ctx]?.profiler;
|
|
1524
1657
|
|
|
1658
|
+
let columnArray = [];
|
|
1659
|
+
if (columns) {
|
|
1660
|
+
columns.split(',').forEach(col => {
|
|
1661
|
+
|
|
1662
|
+
const parts = col.trim().split(".")// remove the first segment
|
|
1663
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1664
|
+
const firstPart = parts[0];
|
|
1665
|
+
// Remove backticks if present
|
|
1666
|
+
const cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`')
|
|
1667
|
+
? firstPart.slice(1, -1)
|
|
1668
|
+
: firstPart;
|
|
1669
|
+
|
|
1670
|
+
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1671
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1672
|
+
// Remove backticks from each column segment, if present, before joining
|
|
1673
|
+
columnArray.push(
|
|
1674
|
+
parts
|
|
1675
|
+
.slice(1)
|
|
1676
|
+
.map(segment =>
|
|
1677
|
+
segment && segment.startsWith('`') && segment.endsWith('`')
|
|
1678
|
+
? segment.slice(1, -1)
|
|
1679
|
+
: segment
|
|
1680
|
+
)
|
|
1681
|
+
.join(".")
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1525
1687
|
let original_is_array = _.isArray(data);
|
|
1526
1688
|
if (!original_is_array) {
|
|
1527
1689
|
data = Array.of(data);
|
|
@@ -1540,7 +1702,15 @@ export default class SpiceModel {
|
|
|
1540
1702
|
value = [result[source_property]];
|
|
1541
1703
|
}
|
|
1542
1704
|
|
|
1543
|
-
|
|
1705
|
+
// Extract IDs - handle both string IDs and objects with id property
|
|
1706
|
+
let items = _.compact(_.map(value, (obj) => {
|
|
1707
|
+
if (_.isString(obj) && obj != "") {
|
|
1708
|
+
return obj;
|
|
1709
|
+
} else if (_.isObject(obj) && _.isString(obj.id) && obj.id != "") {
|
|
1710
|
+
return obj.id;
|
|
1711
|
+
}
|
|
1712
|
+
return null;
|
|
1713
|
+
}));
|
|
1544
1714
|
ids = _.union(ids, items);
|
|
1545
1715
|
});
|
|
1546
1716
|
|
|
@@ -1562,10 +1732,12 @@ export default class SpiceModel {
|
|
|
1562
1732
|
_level: this[_level] + 1,
|
|
1563
1733
|
mapping_dept: this[_mapping_dept],
|
|
1564
1734
|
mapping_dept_exempt: this[_mapping_dept_exempt],
|
|
1735
|
+
_columns: columnArray.join(','),
|
|
1565
1736
|
_current_path: childPath,
|
|
1566
1737
|
}).getMulti({
|
|
1567
1738
|
skip_hooks: true,
|
|
1568
1739
|
ids: ids,
|
|
1740
|
+
columns:columnArray,
|
|
1569
1741
|
});
|
|
1570
1742
|
})
|
|
1571
1743
|
);
|
|
@@ -1600,9 +1772,11 @@ export default class SpiceModel {
|
|
|
1600
1772
|
return;
|
|
1601
1773
|
}
|
|
1602
1774
|
|
|
1603
|
-
result[store_property] = _.map(result[source_property], (
|
|
1604
|
-
|
|
1605
|
-
|
|
1775
|
+
result[store_property] = _.map(result[source_property], (item) => {
|
|
1776
|
+
// Get the ID to match - either a string ID or the id property of an object
|
|
1777
|
+
const itemId = _.isString(item) ? item : (_.isObject(item) ? item.id : null);
|
|
1778
|
+
return _.find(returned_objects, (p) => p.id === itemId);
|
|
1779
|
+
});
|
|
1606
1780
|
result[store_property] = _.reject(
|
|
1607
1781
|
result[store_property],
|
|
1608
1782
|
(obj) => obj === null || obj === undefined
|
|
@@ -1640,7 +1814,7 @@ export default class SpiceModel {
|
|
|
1640
1814
|
case "string": {
|
|
1641
1815
|
this.addModifier({
|
|
1642
1816
|
when: properties[i].map.when || "read",
|
|
1643
|
-
execute: async (data) => {
|
|
1817
|
+
execute: async (data, old_data, ctx, type, args, mapping_dept, level, columns) => {
|
|
1644
1818
|
return await this.mapToObject(
|
|
1645
1819
|
data,
|
|
1646
1820
|
_.isString(properties[i].map.reference) ?
|
|
@@ -1648,7 +1822,12 @@ export default class SpiceModel {
|
|
|
1648
1822
|
: properties[i].map.reference,
|
|
1649
1823
|
i,
|
|
1650
1824
|
properties[i].map.destination || i,
|
|
1651
|
-
properties[i]
|
|
1825
|
+
properties[i],
|
|
1826
|
+
args,
|
|
1827
|
+
type,
|
|
1828
|
+
mapping_dept,
|
|
1829
|
+
level,
|
|
1830
|
+
columns
|
|
1652
1831
|
);
|
|
1653
1832
|
},
|
|
1654
1833
|
});
|
|
@@ -1658,7 +1837,7 @@ export default class SpiceModel {
|
|
|
1658
1837
|
case "array": {
|
|
1659
1838
|
this.addModifier({
|
|
1660
1839
|
when: properties[i].map.when || "read",
|
|
1661
|
-
execute: async (data) => {
|
|
1840
|
+
execute: async (data, old_data, ctx, type, args, mapping_dept, level, columns) => {
|
|
1662
1841
|
return await this.mapToObjectArray(
|
|
1663
1842
|
data,
|
|
1664
1843
|
_.isString(properties[i].map.reference) ?
|
|
@@ -1666,7 +1845,12 @@ export default class SpiceModel {
|
|
|
1666
1845
|
: properties[i].map.reference,
|
|
1667
1846
|
i,
|
|
1668
1847
|
properties[i].map.destination || i,
|
|
1669
|
-
properties[i]
|
|
1848
|
+
properties[i],
|
|
1849
|
+
args,
|
|
1850
|
+
type,
|
|
1851
|
+
mapping_dept,
|
|
1852
|
+
level,
|
|
1853
|
+
columns
|
|
1670
1854
|
);
|
|
1671
1855
|
},
|
|
1672
1856
|
});
|
|
@@ -1676,7 +1860,7 @@ export default class SpiceModel {
|
|
|
1676
1860
|
break;
|
|
1677
1861
|
}
|
|
1678
1862
|
case MapType.LOOKUP: {
|
|
1679
|
-
break;
|
|
1863
|
+
break;
|
|
1680
1864
|
}
|
|
1681
1865
|
}
|
|
1682
1866
|
}
|
|
@@ -1704,7 +1888,7 @@ export default class SpiceModel {
|
|
|
1704
1888
|
for (let i = 0; i < modifiers.length; i++) {
|
|
1705
1889
|
const modifier = modifiers[i];
|
|
1706
1890
|
try {
|
|
1707
|
-
const result = await modifier(data, old_data, this[_ctx], this.type);
|
|
1891
|
+
const result = await modifier(data, old_data, this[_ctx], this.type, args, this[_mapping_dept], this[_level], this[_columns]);
|
|
1708
1892
|
// Guard against modifiers that return undefined
|
|
1709
1893
|
if (result !== undefined) {
|
|
1710
1894
|
data = result;
|
|
@@ -1754,6 +1938,7 @@ export default class SpiceModel {
|
|
|
1754
1938
|
const propsToClean = [
|
|
1755
1939
|
"deleted",
|
|
1756
1940
|
"type",
|
|
1941
|
+
"collection",
|
|
1757
1942
|
...path_to_be_removed,
|
|
1758
1943
|
...hiddenProps,
|
|
1759
1944
|
];
|
package/,
DELETED
|
File without changes
|