spice-js 2.7.8 → 2.7.10
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 +291 -84
- package/package.json +1 -1
- package/src/models/SpiceModel.js +308 -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
|
-
}
|
|
1317
|
+
} // DO NOT add embedded array fields from ANY/EVERY expressions
|
|
1318
|
+
// They iterate over document's embedded array, not join to another collection
|
|
1255
1319
|
|
|
1256
|
-
var queryRegex = /(ANY|EVERY)\s+\w+\s+IN\s+`?(\w+)`?/g;
|
|
1257
|
-
var queryMatch;
|
|
1258
|
-
|
|
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,55 @@ 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
|
+
var _args$columns;
|
|
1357
|
+
|
|
1358
|
+
// Decide which aliases we can join: only when map.type===MODEL AND reference is a STRING keyspace.
|
|
1359
|
+
var mappedNestings = _.compact(_.uniq(nestings).map(alias => {
|
|
1360
|
+
var prop = this.props[alias];
|
|
1361
|
+
if (!(prop == null ? void 0 : prop.map) || prop.map.type !== _2.MapType.MODEL) return null;
|
|
1362
|
+
var ref = prop.map.reference;
|
|
1363
|
+
|
|
1364
|
+
if (typeof ref !== "string") {
|
|
1365
|
+
// reference is a class/function/array-of-classes → no SQL join; serializer will handle it
|
|
1366
|
+
return null;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
var is_array = prop.type === "array" || prop.type === Array || prop.type === _2.DataType.ARRAY;
|
|
1370
|
+
return {
|
|
1371
|
+
alias,
|
|
1372
|
+
reference: ref.toLowerCase(),
|
|
1373
|
+
// keyspace to join
|
|
1374
|
+
is_array,
|
|
1375
|
+
type: prop.type,
|
|
1376
|
+
value_field: prop.map.value_field,
|
|
1377
|
+
destination: prop.map.destination || alias
|
|
1378
|
+
};
|
|
1379
|
+
}));
|
|
1380
|
+
|
|
1381
|
+
var protectedAliases = mappedNestings.map(m => m.alias);
|
|
1382
|
+
var arrayAliases = mappedNestings.filter(m => m.is_array).map(m => m.alias); // Columns: first prepare (prefix base table, rewrite array alias.field → ARRAY proj),
|
|
1383
|
+
// then normalize names and add default aliases
|
|
1384
|
+
//console.log("Columns in BuildJoinMetadata", args.columns);
|
|
1385
|
+
|
|
1386
|
+
this[_columns] = (_args$columns = args.columns) != null ? _args$columns : '';
|
|
1387
|
+
args.columns = this.prepColumns(args.columns, protectedAliases, arrayAliases);
|
|
1388
|
+
args.columns = this.fixColumnName(args.columns, protectedAliases); //console.log("Columns in BuildJoinMetadata after fixColumnName", args.columns);
|
|
1389
|
+
|
|
1390
|
+
return {
|
|
1391
|
+
mappedNestings,
|
|
1392
|
+
protectedAliases,
|
|
1393
|
+
arrayAliases
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1289
1396
|
/* removeSpaceAndSpecialCharacters(str) {
|
|
1290
1397
|
return str.replace(/[^a-zA-Z0-9]/g, "");
|
|
1291
1398
|
} */
|
|
@@ -1331,21 +1438,26 @@ class SpiceModel {
|
|
|
1331
1438
|
|
|
1332
1439
|
|
|
1333
1440
|
if (tableName && tableName !== this.type) {
|
|
1334
|
-
var newAlias = explicitAlias ||
|
|
1441
|
+
var newAlias = explicitAlias || "" + tableName;
|
|
1335
1442
|
|
|
1336
1443
|
if (!explicitAlias) {
|
|
1337
1444
|
if (aliasTracker.hasOwnProperty(newAlias)) {
|
|
1338
1445
|
aliasTracker[newAlias]++;
|
|
1339
|
-
newAlias =
|
|
1446
|
+
newAlias = "" + newAlias;
|
|
1340
1447
|
} else {
|
|
1341
1448
|
aliasTracker[newAlias] = 0;
|
|
1342
1449
|
}
|
|
1343
1450
|
|
|
1344
1451
|
return colWithoutAlias + " AS `" + newAlias + "`";
|
|
1345
1452
|
}
|
|
1453
|
+
} // If column is already qualified with base table (e.g., `user`.`field`), return as-is
|
|
1454
|
+
|
|
1455
|
+
|
|
1456
|
+
if (tableName === this.type && match) {
|
|
1457
|
+
return col;
|
|
1346
1458
|
}
|
|
1347
1459
|
|
|
1348
|
-
return col;
|
|
1460
|
+
return "`" + col + "`";
|
|
1349
1461
|
});
|
|
1350
1462
|
return _.join(_.compact(out), ", ");
|
|
1351
1463
|
}
|
|
@@ -1367,41 +1479,18 @@ class SpiceModel {
|
|
|
1367
1479
|
/*#__PURE__*/
|
|
1368
1480
|
function () {
|
|
1369
1481
|
var _ref13 = _asyncToGenerator(function* () {
|
|
1370
|
-
var
|
|
1482
|
+
var _args12, _args13;
|
|
1371
1483
|
|
|
1372
1484
|
if (args.mapping_dept) _this12[_mapping_dept] = args.mapping_dept;
|
|
1373
1485
|
if (args.mapping_dept_exempt) _this12[_mapping_dept_exempt] = args.mapping_dept_exempt; // Find alias tokens from query/columns/sort
|
|
1374
1486
|
|
|
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
|
-
}));
|
|
1487
|
+
var nestings = [..._this12.extractNestings(((_args12 = args) == null ? void 0 : _args12.query) || "", _this12.type), //...this.extractNestings(args?.columns || "", this.type),
|
|
1488
|
+
..._this12.extractNestings(((_args13 = args) == null ? void 0 : _args13.sort) || "", _this12.type)]; // Build join metadata and prepare columns
|
|
1398
1489
|
|
|
1399
|
-
var
|
|
1400
|
-
|
|
1401
|
-
//
|
|
1490
|
+
var {
|
|
1491
|
+
mappedNestings
|
|
1492
|
+
} = _this12.buildJoinMetadata(nestings, args); // Build JOIN/NEST from the mapped keyspaces
|
|
1402
1493
|
|
|
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
1494
|
|
|
1406
1495
|
args._join = _this12.createJoinSection(mappedNestings); // WHERE
|
|
1407
1496
|
|
|
@@ -1469,11 +1558,11 @@ class SpiceModel {
|
|
|
1469
1558
|
|
|
1470
1559
|
try {
|
|
1471
1560
|
if (p) {
|
|
1472
|
-
var
|
|
1561
|
+
var _args14, _args15;
|
|
1473
1562
|
|
|
1474
1563
|
return yield p.track(_this12.type + ".list", doList, {
|
|
1475
|
-
limit: (
|
|
1476
|
-
offset: (
|
|
1564
|
+
limit: (_args14 = args) == null ? void 0 : _args14.limit,
|
|
1565
|
+
offset: (_args15 = args) == null ? void 0 : _args15.offset
|
|
1477
1566
|
});
|
|
1478
1567
|
}
|
|
1479
1568
|
|
|
@@ -1608,14 +1697,34 @@ class SpiceModel {
|
|
|
1608
1697
|
});
|
|
1609
1698
|
}
|
|
1610
1699
|
|
|
1611
|
-
mapToObject(data, Class, source_property, store_property, property) {
|
|
1700
|
+
mapToObject(data, Class, source_property, store_property, property, args, type, mapping_dept, level, columns) {
|
|
1612
1701
|
var _this15 = this;
|
|
1613
1702
|
|
|
1614
1703
|
return _asyncToGenerator(function* () {
|
|
1615
1704
|
var _this15$_ctx;
|
|
1616
1705
|
|
|
1617
1706
|
// ⚡ Get profiler for proper async context forking
|
|
1618
|
-
var p = (_this15$_ctx = _this15[_ctx]) == null ? void 0 : _this15$_ctx.profiler;
|
|
1707
|
+
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
|
|
1708
|
+
// Create a set of columns where the first segment matches source_property
|
|
1709
|
+
|
|
1710
|
+
var columnArray = [];
|
|
1711
|
+
|
|
1712
|
+
if (columns) {
|
|
1713
|
+
columns.split(',').forEach(col => {
|
|
1714
|
+
var parts = col.trim().split("."); // remove the first segment
|
|
1715
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1716
|
+
|
|
1717
|
+
var firstPart = parts[0]; // Remove backticks if present
|
|
1718
|
+
|
|
1719
|
+
var cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`') ? firstPart.slice(1, -1) : firstPart;
|
|
1720
|
+
|
|
1721
|
+
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1722
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1723
|
+
// Remove backticks from each column segment, if present, before joining
|
|
1724
|
+
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith('`') && segment.endsWith('`') ? segment.slice(1, -1) : segment).join("."));
|
|
1725
|
+
}
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1619
1728
|
|
|
1620
1729
|
var original_is_array = _.isArray(data);
|
|
1621
1730
|
|
|
@@ -1631,8 +1740,18 @@ class SpiceModel {
|
|
|
1631
1740
|
var ids = [];
|
|
1632
1741
|
|
|
1633
1742
|
_.each(data, result => {
|
|
1634
|
-
|
|
1635
|
-
|
|
1743
|
+
var value = result[source_property]; // Check if value is in the empty string key (column aliasing issue)
|
|
1744
|
+
|
|
1745
|
+
if ((value === undefined || _.isObject(value) && _.isEmpty(value)) && result[''] && result[''][source_property]) {
|
|
1746
|
+
value = result[''][source_property];
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
if (_.isString(value) && value != "") {
|
|
1750
|
+
// Value is a raw ID string
|
|
1751
|
+
ids = _.union(ids, [value]);
|
|
1752
|
+
} else if (_.isObject(value) && _.isString(value.id) && value.id != "") {
|
|
1753
|
+
// Value is already a joined object with an id field
|
|
1754
|
+
ids = _.union(ids, [value.id]);
|
|
1636
1755
|
}
|
|
1637
1756
|
}); // Build the path for child models
|
|
1638
1757
|
|
|
@@ -1644,15 +1763,18 @@ class SpiceModel {
|
|
|
1644
1763
|
function () {
|
|
1645
1764
|
var _ref16 = _asyncToGenerator(function* () {
|
|
1646
1765
|
return yield Promise.allSettled(_.map(classes, obj => {
|
|
1647
|
-
|
|
1766
|
+
var objInstance = new obj(_extends({}, _this15[_args], {
|
|
1648
1767
|
skip_cache: _this15[_skip_cache],
|
|
1649
1768
|
_level: _this15[_level] + 1,
|
|
1650
1769
|
mapping_dept: _this15[_mapping_dept],
|
|
1651
1770
|
mapping_dept_exempt: _this15[_mapping_dept_exempt],
|
|
1771
|
+
_columns: columnArray.join(','),
|
|
1652
1772
|
_current_path: childPath
|
|
1653
|
-
}))
|
|
1773
|
+
}));
|
|
1774
|
+
return objInstance.getMulti({
|
|
1654
1775
|
skip_hooks: true,
|
|
1655
|
-
ids: ids
|
|
1776
|
+
ids: ids,
|
|
1777
|
+
columns: columnArray
|
|
1656
1778
|
});
|
|
1657
1779
|
}));
|
|
1658
1780
|
});
|
|
@@ -1673,12 +1795,26 @@ class SpiceModel {
|
|
|
1673
1795
|
}
|
|
1674
1796
|
|
|
1675
1797
|
var ug = _.flatten(_.compact(_.map(returned_all, returned_obj => {
|
|
1676
|
-
if (returned_obj.status == "fulfilled")
|
|
1798
|
+
if (returned_obj.status == "fulfilled") {
|
|
1799
|
+
return returned_obj.value;
|
|
1800
|
+
}
|
|
1677
1801
|
})));
|
|
1802
|
+
/* if(source_property == "group") {
|
|
1803
|
+
console.log("Returned All", source_property, store_property, ug);
|
|
1804
|
+
} */
|
|
1805
|
+
|
|
1678
1806
|
|
|
1679
1807
|
data = _.map(data, result => {
|
|
1808
|
+
var sourceValue = result[source_property]; // Check if value is in the empty string key (column aliasing issue)
|
|
1809
|
+
|
|
1810
|
+
if ((sourceValue === undefined || _.isObject(sourceValue) && _.isEmpty(sourceValue)) && result[''] && result[''][source_property]) {
|
|
1811
|
+
sourceValue = result[''][source_property];
|
|
1812
|
+
} // Get the ID to match against - either a string ID or the id property of an object
|
|
1813
|
+
|
|
1814
|
+
|
|
1815
|
+
var sourceId = _.isString(sourceValue) ? sourceValue : _.isObject(sourceValue) ? sourceValue.id : null;
|
|
1680
1816
|
var result_found = _.find(ug, g => {
|
|
1681
|
-
return g.id ==
|
|
1817
|
+
return g.id == sourceId;
|
|
1682
1818
|
}) || {};
|
|
1683
1819
|
result[store_property] = result_found;
|
|
1684
1820
|
return result;
|
|
@@ -1689,7 +1825,7 @@ class SpiceModel {
|
|
|
1689
1825
|
})();
|
|
1690
1826
|
}
|
|
1691
1827
|
|
|
1692
|
-
mapToObjectArray(data, Class, source_property, store_property, property) {
|
|
1828
|
+
mapToObjectArray(data, Class, source_property, store_property, property, args, type, mapping_dept, level, columns) {
|
|
1693
1829
|
var _this16 = this;
|
|
1694
1830
|
|
|
1695
1831
|
return _asyncToGenerator(function* () {
|
|
@@ -1697,6 +1833,24 @@ class SpiceModel {
|
|
|
1697
1833
|
|
|
1698
1834
|
// ⚡ Get profiler for proper async context forking
|
|
1699
1835
|
var p = (_this16$_ctx = _this16[_ctx]) == null ? void 0 : _this16$_ctx.profiler;
|
|
1836
|
+
var columnArray = [];
|
|
1837
|
+
|
|
1838
|
+
if (columns) {
|
|
1839
|
+
columns.split(',').forEach(col => {
|
|
1840
|
+
var parts = col.trim().split("."); // remove the first segment
|
|
1841
|
+
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1842
|
+
|
|
1843
|
+
var firstPart = parts[0]; // Remove backticks if present
|
|
1844
|
+
|
|
1845
|
+
var cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`') ? firstPart.slice(1, -1) : firstPart;
|
|
1846
|
+
|
|
1847
|
+
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1848
|
+
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1849
|
+
// Remove backticks from each column segment, if present, before joining
|
|
1850
|
+
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith('`') && segment.endsWith('`') ? segment.slice(1, -1) : segment).join("."));
|
|
1851
|
+
}
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1700
1854
|
|
|
1701
1855
|
var original_is_array = _.isArray(data);
|
|
1702
1856
|
|
|
@@ -1718,9 +1872,18 @@ class SpiceModel {
|
|
|
1718
1872
|
|
|
1719
1873
|
if (_.isString(result[source_property])) {
|
|
1720
1874
|
value = [result[source_property]];
|
|
1721
|
-
}
|
|
1875
|
+
} // Extract IDs - handle both string IDs and objects with id property
|
|
1876
|
+
|
|
1722
1877
|
|
|
1723
|
-
var items = _.
|
|
1878
|
+
var items = _.compact(_.map(value, obj => {
|
|
1879
|
+
if (_.isString(obj) && obj != "") {
|
|
1880
|
+
return obj;
|
|
1881
|
+
} else if (_.isObject(obj) && _.isString(obj.id) && obj.id != "") {
|
|
1882
|
+
return obj.id;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
return null;
|
|
1886
|
+
}));
|
|
1724
1887
|
|
|
1725
1888
|
ids = _.union(ids, items);
|
|
1726
1889
|
}); // Build the path for child models
|
|
@@ -1741,10 +1904,12 @@ class SpiceModel {
|
|
|
1741
1904
|
_level: _this16[_level] + 1,
|
|
1742
1905
|
mapping_dept: _this16[_mapping_dept],
|
|
1743
1906
|
mapping_dept_exempt: _this16[_mapping_dept_exempt],
|
|
1907
|
+
_columns: columnArray.join(','),
|
|
1744
1908
|
_current_path: childPath
|
|
1745
1909
|
})).getMulti({
|
|
1746
1910
|
skip_hooks: true,
|
|
1747
|
-
ids: ids
|
|
1911
|
+
ids: ids,
|
|
1912
|
+
columns: columnArray
|
|
1748
1913
|
});
|
|
1749
1914
|
}));
|
|
1750
1915
|
});
|
|
@@ -1778,7 +1943,11 @@ class SpiceModel {
|
|
|
1778
1943
|
return;
|
|
1779
1944
|
}
|
|
1780
1945
|
|
|
1781
|
-
result[store_property] = _.map(result[source_property],
|
|
1946
|
+
result[store_property] = _.map(result[source_property], item => {
|
|
1947
|
+
// Get the ID to match - either a string ID or the id property of an object
|
|
1948
|
+
var itemId = _.isString(item) ? item : _.isObject(item) ? item.id : null;
|
|
1949
|
+
return _.find(returned_objects, p => p.id === itemId);
|
|
1950
|
+
});
|
|
1782
1951
|
result[store_property] = _.reject(result[store_property], obj => obj === null || obj === undefined);
|
|
1783
1952
|
});
|
|
1784
1953
|
}
|
|
@@ -1814,6 +1983,34 @@ class SpiceModel {
|
|
|
1814
1983
|
that.addModifier(modifier);
|
|
1815
1984
|
});
|
|
1816
1985
|
}
|
|
1986
|
+
/**
|
|
1987
|
+
* Checks if a field is present in the columns string.
|
|
1988
|
+
* Used to skip modifier execution when the field isn't requested.
|
|
1989
|
+
* @param {string} fieldName - The field name to check for
|
|
1990
|
+
* @param {string} columns - Comma-separated column string
|
|
1991
|
+
* @returns {boolean} - True if field is in columns or columns is empty (fetch all)
|
|
1992
|
+
*/
|
|
1993
|
+
|
|
1994
|
+
|
|
1995
|
+
isFieldInColumns(fieldName, columns) {
|
|
1996
|
+
// No columns filter = include all
|
|
1997
|
+
if (!columns || columns === '') return true;
|
|
1998
|
+
var tokens = columns.split(',');
|
|
1999
|
+
|
|
2000
|
+
for (var col of tokens) {
|
|
2001
|
+
var trimmed = col.trim(); // Check if this column starts with the field name (exact match or nested like "fieldName.subfield")
|
|
2002
|
+
|
|
2003
|
+
var firstPart = trimmed.split('.')[0]; // Handle backtick-wrapped column names
|
|
2004
|
+
|
|
2005
|
+
var cleanFirstPart = firstPart.startsWith('`') && firstPart.endsWith('`') ? firstPart.slice(1, -1) : firstPart;
|
|
2006
|
+
|
|
2007
|
+
if (cleanFirstPart === fieldName) {
|
|
2008
|
+
return true;
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
return false;
|
|
2013
|
+
}
|
|
1817
2014
|
|
|
1818
2015
|
createMofifier(properties) {
|
|
1819
2016
|
var _this17 = this;
|
|
@@ -1830,11 +2027,16 @@ class SpiceModel {
|
|
|
1830
2027
|
_this17.addModifier({
|
|
1831
2028
|
when: properties[i].map.when || "read",
|
|
1832
2029
|
execute: function () {
|
|
1833
|
-
var _execute = _asyncToGenerator(function* (data) {
|
|
1834
|
-
|
|
2030
|
+
var _execute = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns) {
|
|
2031
|
+
// Skip if columns are specified but this field isn't included
|
|
2032
|
+
if (!_this17.isFieldInColumns(i, columns)) {
|
|
2033
|
+
return data;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
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
2037
|
});
|
|
1836
2038
|
|
|
1837
|
-
function execute(_x) {
|
|
2039
|
+
function execute(_x, _x2, _x3, _x4, _x5, _x6, _x7, _x8) {
|
|
1838
2040
|
return _execute.apply(this, arguments);
|
|
1839
2041
|
}
|
|
1840
2042
|
|
|
@@ -1851,11 +2053,16 @@ class SpiceModel {
|
|
|
1851
2053
|
_this17.addModifier({
|
|
1852
2054
|
when: properties[i].map.when || "read",
|
|
1853
2055
|
execute: function () {
|
|
1854
|
-
var _execute2 = _asyncToGenerator(function* (data) {
|
|
1855
|
-
|
|
2056
|
+
var _execute2 = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns) {
|
|
2057
|
+
// Skip if columns are specified but this field isn't included
|
|
2058
|
+
if (!_this17.isFieldInColumns(i, columns)) {
|
|
2059
|
+
return data;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
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
2063
|
});
|
|
1857
2064
|
|
|
1858
|
-
function execute(
|
|
2065
|
+
function execute(_x9, _x10, _x11, _x12, _x13, _x14, _x15, _x16) {
|
|
1859
2066
|
return _execute2.apply(this, arguments);
|
|
1860
2067
|
}
|
|
1861
2068
|
|
|
@@ -1921,7 +2128,7 @@ class SpiceModel {
|
|
|
1921
2128
|
var modifier = modifiers[i];
|
|
1922
2129
|
|
|
1923
2130
|
try {
|
|
1924
|
-
var result = yield modifier(data, old_data, _this18[_ctx], _this18.type); // Guard against modifiers that return undefined
|
|
2131
|
+
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
2132
|
|
|
1926
2133
|
if (result !== undefined) {
|
|
1927
2134
|
data = result;
|
|
@@ -1966,7 +2173,7 @@ class SpiceModel {
|
|
|
1966
2173
|
return (_this18$props$key2 = _this18.props[key]) == null ? void 0 : _this18$props$key2.hide;
|
|
1967
2174
|
}); // Combine default props to remove.
|
|
1968
2175
|
|
|
1969
|
-
var propsToClean = ["deleted", "type", ...path_to_be_removed, ...hiddenProps];
|
|
2176
|
+
var propsToClean = ["deleted", "type", "collection", ...path_to_be_removed, ...hiddenProps];
|
|
1970
2177
|
data = data.map(item => _.omit(item, propsToClean));
|
|
1971
2178
|
} // Return in the original format (array or single object).
|
|
1972
2179
|
|
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
|
|
@@ -1630,6 +1804,34 @@ export default class SpiceModel {
|
|
|
1630
1804
|
});
|
|
1631
1805
|
}
|
|
1632
1806
|
|
|
1807
|
+
/**
|
|
1808
|
+
* Checks if a field is present in the columns string.
|
|
1809
|
+
* Used to skip modifier execution when the field isn't requested.
|
|
1810
|
+
* @param {string} fieldName - The field name to check for
|
|
1811
|
+
* @param {string} columns - Comma-separated column string
|
|
1812
|
+
* @returns {boolean} - True if field is in columns or columns is empty (fetch all)
|
|
1813
|
+
*/
|
|
1814
|
+
isFieldInColumns(fieldName, columns) {
|
|
1815
|
+
// No columns filter = include all
|
|
1816
|
+
if (!columns || columns === '') return true;
|
|
1817
|
+
|
|
1818
|
+
const tokens = columns.split(',');
|
|
1819
|
+
for (const col of tokens) {
|
|
1820
|
+
const trimmed = col.trim();
|
|
1821
|
+
// Check if this column starts with the field name (exact match or nested like "fieldName.subfield")
|
|
1822
|
+
const firstPart = trimmed.split('.')[0];
|
|
1823
|
+
// Handle backtick-wrapped column names
|
|
1824
|
+
const cleanFirstPart = firstPart.startsWith('`') && firstPart.endsWith('`')
|
|
1825
|
+
? firstPart.slice(1, -1)
|
|
1826
|
+
: firstPart;
|
|
1827
|
+
|
|
1828
|
+
if (cleanFirstPart === fieldName) {
|
|
1829
|
+
return true;
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
return false;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1633
1835
|
createMofifier(properties) {
|
|
1634
1836
|
for (let i in properties) {
|
|
1635
1837
|
if (properties[i].map) {
|
|
@@ -1640,7 +1842,11 @@ export default class SpiceModel {
|
|
|
1640
1842
|
case "string": {
|
|
1641
1843
|
this.addModifier({
|
|
1642
1844
|
when: properties[i].map.when || "read",
|
|
1643
|
-
execute: async (data) => {
|
|
1845
|
+
execute: async (data, old_data, ctx, type, args, mapping_dept, level, columns) => {
|
|
1846
|
+
// Skip if columns are specified but this field isn't included
|
|
1847
|
+
if (!this.isFieldInColumns(i, columns)) {
|
|
1848
|
+
return data;
|
|
1849
|
+
}
|
|
1644
1850
|
return await this.mapToObject(
|
|
1645
1851
|
data,
|
|
1646
1852
|
_.isString(properties[i].map.reference) ?
|
|
@@ -1648,7 +1854,12 @@ export default class SpiceModel {
|
|
|
1648
1854
|
: properties[i].map.reference,
|
|
1649
1855
|
i,
|
|
1650
1856
|
properties[i].map.destination || i,
|
|
1651
|
-
properties[i]
|
|
1857
|
+
properties[i],
|
|
1858
|
+
args,
|
|
1859
|
+
type,
|
|
1860
|
+
mapping_dept,
|
|
1861
|
+
level,
|
|
1862
|
+
columns
|
|
1652
1863
|
);
|
|
1653
1864
|
},
|
|
1654
1865
|
});
|
|
@@ -1658,7 +1869,11 @@ export default class SpiceModel {
|
|
|
1658
1869
|
case "array": {
|
|
1659
1870
|
this.addModifier({
|
|
1660
1871
|
when: properties[i].map.when || "read",
|
|
1661
|
-
execute: async (data) => {
|
|
1872
|
+
execute: async (data, old_data, ctx, type, args, mapping_dept, level, columns) => {
|
|
1873
|
+
// Skip if columns are specified but this field isn't included
|
|
1874
|
+
if (!this.isFieldInColumns(i, columns)) {
|
|
1875
|
+
return data;
|
|
1876
|
+
}
|
|
1662
1877
|
return await this.mapToObjectArray(
|
|
1663
1878
|
data,
|
|
1664
1879
|
_.isString(properties[i].map.reference) ?
|
|
@@ -1666,7 +1881,12 @@ export default class SpiceModel {
|
|
|
1666
1881
|
: properties[i].map.reference,
|
|
1667
1882
|
i,
|
|
1668
1883
|
properties[i].map.destination || i,
|
|
1669
|
-
properties[i]
|
|
1884
|
+
properties[i],
|
|
1885
|
+
args,
|
|
1886
|
+
type,
|
|
1887
|
+
mapping_dept,
|
|
1888
|
+
level,
|
|
1889
|
+
columns
|
|
1670
1890
|
);
|
|
1671
1891
|
},
|
|
1672
1892
|
});
|
|
@@ -1676,7 +1896,7 @@ export default class SpiceModel {
|
|
|
1676
1896
|
break;
|
|
1677
1897
|
}
|
|
1678
1898
|
case MapType.LOOKUP: {
|
|
1679
|
-
break;
|
|
1899
|
+
break;
|
|
1680
1900
|
}
|
|
1681
1901
|
}
|
|
1682
1902
|
}
|
|
@@ -1704,7 +1924,7 @@ export default class SpiceModel {
|
|
|
1704
1924
|
for (let i = 0; i < modifiers.length; i++) {
|
|
1705
1925
|
const modifier = modifiers[i];
|
|
1706
1926
|
try {
|
|
1707
|
-
const result = await modifier(data, old_data, this[_ctx], this.type);
|
|
1927
|
+
const result = await modifier(data, old_data, this[_ctx], this.type, args, this[_mapping_dept], this[_level], this[_columns]);
|
|
1708
1928
|
// Guard against modifiers that return undefined
|
|
1709
1929
|
if (result !== undefined) {
|
|
1710
1930
|
data = result;
|
|
@@ -1754,6 +1974,7 @@ export default class SpiceModel {
|
|
|
1754
1974
|
const propsToClean = [
|
|
1755
1975
|
"deleted",
|
|
1756
1976
|
"type",
|
|
1977
|
+
"collection",
|
|
1757
1978
|
...path_to_be_removed,
|
|
1758
1979
|
...hiddenProps,
|
|
1759
1980
|
];
|
package/,
DELETED
|
File without changes
|