spice-js 2.7.17 → 2.7.19
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 +136 -58
- package/package.json +1 -1
- package/src/models/SpiceModel.js +377 -160
- package/tests/models/SpiceModel.test.js +156 -0
- package/src/models/SpiceModel.js.bak +0 -2186
|
@@ -502,27 +502,29 @@ class SpiceModel {
|
|
|
502
502
|
var key = "get::" + _this4.type + "::" + args.id + (args.columns ? "::" + args.columns : "");
|
|
503
503
|
var results = {};
|
|
504
504
|
|
|
505
|
+
// Filter out id, meta().id, and any column ending with .id (e.g., dependents.id)
|
|
506
|
+
if (args.columns) {
|
|
507
|
+
args.columns = args.columns.split(",").map(col => col.trim()).filter(col => col !== "").filter(col => {
|
|
508
|
+
var cleaned = col.replace(/`/g, "").toLowerCase();
|
|
509
|
+
return cleaned !== "id" && cleaned !== "meta().id" && !cleaned.endsWith(".id");
|
|
510
|
+
}).join(",");
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Save filtered columns before buildJoinMetadata modifies them
|
|
514
|
+
var originalColumns = args.columns;
|
|
515
|
+
|
|
505
516
|
// Extract nestings from columns if specified
|
|
506
517
|
var nestings = _this4.extractNestings(((_args9 = args) == null ? void 0 : _args9.columns) || "", _this4.type);
|
|
507
518
|
|
|
508
519
|
// Build join metadata and prepare columns
|
|
509
520
|
_this4.buildJoinMetadata(nestings, args);
|
|
510
|
-
|
|
521
|
+
|
|
522
|
+
// Use original (filtered) columns for extracting base column names
|
|
523
|
+
var columns = originalColumns;
|
|
511
524
|
var columnArray = [];
|
|
512
525
|
if (columns) {
|
|
513
|
-
columns.split(
|
|
514
|
-
|
|
515
|
-
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
516
|
-
var firstPart = parts[0];
|
|
517
|
-
// Remove backticks if present
|
|
518
|
-
var cleanFirstPart = firstPart && firstPart.startsWith('`') && firstPart.endsWith('`') ? firstPart.slice(1, -1) : firstPart;
|
|
519
|
-
|
|
520
|
-
//if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
521
|
-
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
522
|
-
// Remove backticks from each column segment, if present, before joining
|
|
523
|
-
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith('`') && segment.endsWith('`') ? segment.slice(1, -1) : segment).join("."));
|
|
524
|
-
// }
|
|
525
|
-
});
|
|
526
|
+
var rawColumns = columns.split(",").map(col => col.trim()).filter(col => col !== "").map(col => col.replace(/`/g, ""));
|
|
527
|
+
columnArray = [...new Set(_this4.extractBaseColumns(rawColumns).filter(col => col && col !== ""))];
|
|
526
528
|
}
|
|
527
529
|
if (_this4.shouldUseCache(_this4.type)) {
|
|
528
530
|
// Retrieve the cached results
|
|
@@ -644,7 +646,7 @@ class SpiceModel {
|
|
|
644
646
|
if ((cached_results == null ? void 0 : cached_results.value) === undefined || (yield _this6.shouldForceRefresh(cached_results))) {
|
|
645
647
|
results = yield _this6.database.multi_get(args.ids, {
|
|
646
648
|
keep_type: true,
|
|
647
|
-
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [..._this6.extractBaseColumns(args.columns),
|
|
649
|
+
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [..._this6.extractBaseColumns(args.columns), "type"] : []
|
|
648
650
|
});
|
|
649
651
|
_this6.getCacheProviderObject(_this6.type).set(key, {
|
|
650
652
|
value: results,
|
|
@@ -654,7 +656,7 @@ class SpiceModel {
|
|
|
654
656
|
} else {
|
|
655
657
|
results = yield _this6.database.multi_get(args.ids, {
|
|
656
658
|
keep_type: true,
|
|
657
|
-
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [..._this6.extractBaseColumns(args.columns),
|
|
659
|
+
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [..._this6.extractBaseColumns(args.columns), "type"] : []
|
|
658
660
|
});
|
|
659
661
|
}
|
|
660
662
|
}
|
|
@@ -955,36 +957,47 @@ class SpiceModel {
|
|
|
955
957
|
var col = (raw || "").trim();
|
|
956
958
|
if (col === "" || col === "meta().id") return undefined;
|
|
957
959
|
if (/^\s*ARRAY\s+/i.test(col) || /\w+\s*\(/.test(col)) return col;
|
|
960
|
+
|
|
961
|
+
// If the first segment is a mapped model property, always project the
|
|
962
|
+
// root mapped field (supports deep paths like dependents.passports.holder).
|
|
963
|
+
var deepMappedPathMatch = col.match(/^\s*`?(\w+)`?(?:\.`?\w+`?)+(?:\s+AS\s+`?([\w]+)`?)?\s*$/i);
|
|
964
|
+
if (deepMappedPathMatch) {
|
|
965
|
+
var _this$props$alias;
|
|
966
|
+
var alias = deepMappedPathMatch[1];
|
|
967
|
+
if (alias !== this.type && ((_this$props$alias = this.props[alias]) == null ? void 0 : _this$props$alias.map)) {
|
|
968
|
+
return q(this.type) + "." + q(alias);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
958
971
|
var m = col.match(/^\s*`?(\w+)`?\.`?(\w+)`?(?:\s+AS\s+`?([\w]+)`?)?\s*$/i);
|
|
959
972
|
if (m) {
|
|
960
|
-
var
|
|
973
|
+
var _alias = m[1];
|
|
961
974
|
var field = m[2];
|
|
962
975
|
var explicitAs = m[3];
|
|
963
976
|
|
|
964
977
|
// If alias matches this.type, don't prepend again
|
|
965
|
-
if (
|
|
966
|
-
var _qualified = q(
|
|
978
|
+
if (_alias === this.type) {
|
|
979
|
+
var _qualified = q(_alias) + "." + q(field);
|
|
967
980
|
return explicitAs ? _qualified + " AS " + q(explicitAs) : _qualified;
|
|
968
981
|
}
|
|
969
982
|
|
|
970
983
|
// Check if alias has a map - if so, simplify to root column only (raw ID)
|
|
971
|
-
var prop = this.props[
|
|
984
|
+
var prop = this.props[_alias];
|
|
972
985
|
if (prop == null ? void 0 : prop.map) {
|
|
973
986
|
// Return base table qualified root column, ignoring the .field part
|
|
974
|
-
return q(this.type) + "." + q(
|
|
987
|
+
return q(this.type) + "." + q(_alias);
|
|
975
988
|
}
|
|
976
|
-
if (arraySet.has(
|
|
977
|
-
var proj = this.buildArrayProjection(
|
|
978
|
-
if (explicitAs && explicitAs !==
|
|
989
|
+
if (arraySet.has(_alias)) {
|
|
990
|
+
var proj = this.buildArrayProjection(_alias, field);
|
|
991
|
+
if (explicitAs && explicitAs !== _alias + "_" + field) {
|
|
979
992
|
proj = proj.replace(/AS\s+`[^`]+`$/i, "AS " + q(explicitAs));
|
|
980
993
|
}
|
|
981
994
|
return proj;
|
|
982
995
|
}
|
|
983
|
-
if (protectedSet.has(
|
|
984
|
-
var aliased = q(
|
|
996
|
+
if (protectedSet.has(_alias)) {
|
|
997
|
+
var aliased = q(_alias) + "." + (field.startsWith("`") ? field : q(field));
|
|
985
998
|
return explicitAs ? aliased + " AS " + q(explicitAs) : aliased;
|
|
986
999
|
}
|
|
987
|
-
var qualified = q(this.type) + "." + q(
|
|
1000
|
+
var qualified = q(this.type) + "." + q(_alias) + "." + q(field);
|
|
988
1001
|
return explicitAs ? qualified + " AS " + q(explicitAs) : qualified;
|
|
989
1002
|
}
|
|
990
1003
|
var looksProtected = [...protectedSet].some(a => col === a || col === q(a) || col.startsWith(a + ".") || col.startsWith(q(a) + "."));
|
|
@@ -1030,9 +1043,14 @@ class SpiceModel {
|
|
|
1030
1043
|
if (aliasMatch) {
|
|
1031
1044
|
return aliasMatch[1].trim();
|
|
1032
1045
|
}
|
|
1033
|
-
// Otherwise,
|
|
1046
|
+
// Otherwise, for dot-notation, keep the first segment after removing
|
|
1047
|
+
// the base model prefix (e.g. user.group.name -> group).
|
|
1034
1048
|
if (col.includes(".")) {
|
|
1035
|
-
|
|
1049
|
+
var pathParts = col.split(".").map(part => part.trim()).filter(part => part !== "");
|
|
1050
|
+
if (pathParts[0] === this.type && pathParts.length > 1) {
|
|
1051
|
+
pathParts = pathParts.slice(1);
|
|
1052
|
+
}
|
|
1053
|
+
return pathParts[0];
|
|
1036
1054
|
}
|
|
1037
1055
|
return col;
|
|
1038
1056
|
});
|
|
@@ -1142,7 +1160,7 @@ class SpiceModel {
|
|
|
1142
1160
|
// then normalize names and add default aliases
|
|
1143
1161
|
//console.log("Columns in BuildJoinMetadata", args.columns);
|
|
1144
1162
|
|
|
1145
|
-
this[_columns] = (_args$columns = args.columns) != null ? _args$columns :
|
|
1163
|
+
this[_columns] = (_args$columns = args.columns) != null ? _args$columns : "";
|
|
1146
1164
|
args.columns = this.prepColumns(args.columns, protectedAliases, arrayAliases);
|
|
1147
1165
|
args.columns = this.fixColumnName(args.columns, protectedAliases);
|
|
1148
1166
|
//console.log("Columns in BuildJoinMetadata after fixColumnName", args.columns);
|
|
@@ -1237,6 +1255,17 @@ class SpiceModel {
|
|
|
1237
1255
|
if (args.mapping_dept) _this10[_mapping_dept] = args.mapping_dept;
|
|
1238
1256
|
if (args.mapping_dept_exempt) _this10[_mapping_dept_exempt] = args.mapping_dept_exempt;
|
|
1239
1257
|
|
|
1258
|
+
// Filter out id, meta().id, and any column ending with .id (e.g., dependents.id)
|
|
1259
|
+
if (args.columns) {
|
|
1260
|
+
args.columns = args.columns.split(",").map(col => col.trim()).filter(col => col !== "").filter(col => {
|
|
1261
|
+
var cleaned = col.replace(/`/g, "").toLowerCase();
|
|
1262
|
+
return cleaned !== "id" && cleaned !== "meta().id" && !cleaned.endsWith(".id");
|
|
1263
|
+
}).join(",");
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
// Save filtered columns before buildJoinMetadata modifies them
|
|
1267
|
+
var originalColumns = args.columns;
|
|
1268
|
+
|
|
1240
1269
|
// Find alias tokens from query/columns/sort
|
|
1241
1270
|
var nestings = [..._this10.extractNestings(((_args10 = args) == null ? void 0 : _args10.query) || "", _this10.type),
|
|
1242
1271
|
//...this.extractNestings(args?.columns || "", this.type),
|
|
@@ -1279,14 +1308,14 @@ class SpiceModel {
|
|
|
1279
1308
|
var isEmpty = (cached == null ? void 0 : cached.value) === undefined;
|
|
1280
1309
|
var refresh = yield _this10.shouldForceRefresh(cached);
|
|
1281
1310
|
if (isEmpty || refresh) {
|
|
1282
|
-
results = yield _this10.fetchResults(args, query);
|
|
1311
|
+
results = yield _this10.fetchResults(args, query, mappedNestings);
|
|
1283
1312
|
_this10.getCacheProviderObject(_this10.type).set(cacheKey, {
|
|
1284
1313
|
value: results,
|
|
1285
1314
|
time: new Date().getTime()
|
|
1286
1315
|
}, _this10.getCacheConfig(_this10.type));
|
|
1287
1316
|
}
|
|
1288
1317
|
} else {
|
|
1289
|
-
results = yield _this10.fetchResults(args, query);
|
|
1318
|
+
results = yield _this10.fetchResults(args, query, mappedNestings);
|
|
1290
1319
|
}
|
|
1291
1320
|
|
|
1292
1321
|
// Serializer still handles class-based refs and value_field
|
|
@@ -1319,7 +1348,36 @@ class SpiceModel {
|
|
|
1319
1348
|
}
|
|
1320
1349
|
})();
|
|
1321
1350
|
}
|
|
1322
|
-
|
|
1351
|
+
correctColumns(columns, mappedNestings) {
|
|
1352
|
+
// Preserve normal columns and only rewrite mapped alias dot-paths
|
|
1353
|
+
// to the root mapped field on the base resource.
|
|
1354
|
+
if (!columns || typeof columns !== "string") return columns;
|
|
1355
|
+
var mappedAliasSet = new Set((mappedNestings || []).map(m => m.alias));
|
|
1356
|
+
var isMappedAlias = alias => {
|
|
1357
|
+
var _this$props, _this$props$alias2;
|
|
1358
|
+
return !!((_this$props = this.props) == null ? void 0 : (_this$props$alias2 = _this$props[alias]) == null ? void 0 : _this$props$alias2.map);
|
|
1359
|
+
};
|
|
1360
|
+
var normalized = columns.split(",").map(col => col.trim()).filter(col => col !== "").map(col => {
|
|
1361
|
+
var cleanCol = col.replace(/`/g, "").trim();
|
|
1362
|
+
var parts = cleanCol.split(".");
|
|
1363
|
+
var firstSegment = parts[0];
|
|
1364
|
+
var secondSegment = parts[1];
|
|
1365
|
+
var mappedAlias = null;
|
|
1366
|
+
if (isMappedAlias(firstSegment)) {
|
|
1367
|
+
mappedAlias = firstSegment;
|
|
1368
|
+
} else if (firstSegment === this.type && secondSegment && isMappedAlias(secondSegment)) {
|
|
1369
|
+
mappedAlias = secondSegment;
|
|
1370
|
+
} else if (mappedAliasSet.has(firstSegment)) {
|
|
1371
|
+
mappedAlias = firstSegment;
|
|
1372
|
+
}
|
|
1373
|
+
if (mappedAlias) {
|
|
1374
|
+
return "`" + this.type + "`.`" + mappedAlias + "`";
|
|
1375
|
+
}
|
|
1376
|
+
return col;
|
|
1377
|
+
});
|
|
1378
|
+
return _.join(_.uniq(_.compact(normalized)), ",");
|
|
1379
|
+
}
|
|
1380
|
+
fetchResults(args, query, mappedNestings) {
|
|
1323
1381
|
var _this11 = this;
|
|
1324
1382
|
return _asyncToGenerator(function* () {
|
|
1325
1383
|
var _this11$_ctx;
|
|
@@ -1332,7 +1390,8 @@ class SpiceModel {
|
|
|
1332
1390
|
} else if (args.is_full_text === "true") {
|
|
1333
1391
|
return yield _this11.database.full_text_search(_this11.type, query || "", args.limit, args.offset, args._join);
|
|
1334
1392
|
} else {
|
|
1335
|
-
var
|
|
1393
|
+
var correctedColumns = _this11.correctColumns(args.columns, mappedNestings);
|
|
1394
|
+
var result = yield _this11.database.search(_this11.type, correctedColumns || args.columns || "", query || "", args.limit, args.offset, args.sort, args.do_count, args.statement_consistent, args._join);
|
|
1336
1395
|
return result;
|
|
1337
1396
|
}
|
|
1338
1397
|
});
|
|
@@ -1431,16 +1490,16 @@ class SpiceModel {
|
|
|
1431
1490
|
// Create a set of columns where the first segment matches source_property
|
|
1432
1491
|
var columnArray = [];
|
|
1433
1492
|
if (columns) {
|
|
1434
|
-
columns.split(
|
|
1493
|
+
columns.split(",").forEach(col => {
|
|
1435
1494
|
var parts = col.trim().split("."); // remove the first segment
|
|
1436
1495
|
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1437
1496
|
var firstPart = parts[0];
|
|
1438
1497
|
// Remove backticks if present
|
|
1439
|
-
var cleanFirstPart = firstPart && firstPart.startsWith(
|
|
1498
|
+
var cleanFirstPart = firstPart && firstPart.startsWith("`") && firstPart.endsWith("`") ? firstPart.slice(1, -1) : firstPart;
|
|
1440
1499
|
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1441
1500
|
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1442
1501
|
// Remove backticks from each column segment, if present, before joining
|
|
1443
|
-
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith(
|
|
1502
|
+
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith("`") && segment.endsWith("`") ? segment.slice(1, -1) : segment).join("."));
|
|
1444
1503
|
}
|
|
1445
1504
|
});
|
|
1446
1505
|
}
|
|
@@ -1456,8 +1515,8 @@ class SpiceModel {
|
|
|
1456
1515
|
var value = result[source_property];
|
|
1457
1516
|
|
|
1458
1517
|
// Check if value is in the empty string key (column aliasing issue)
|
|
1459
|
-
if ((value === undefined || _.isObject(value) && _.isEmpty(value)) && result[
|
|
1460
|
-
value = result[
|
|
1518
|
+
if ((value === undefined || _.isObject(value) && _.isEmpty(value)) && result[""] && result[""][source_property]) {
|
|
1519
|
+
value = result[""][source_property];
|
|
1461
1520
|
}
|
|
1462
1521
|
if (_.isString(value) && value != "") {
|
|
1463
1522
|
// Value is a raw ID string
|
|
@@ -1480,7 +1539,7 @@ class SpiceModel {
|
|
|
1480
1539
|
_level: _this13[_level] + 1,
|
|
1481
1540
|
mapping_dept: _this13[_mapping_dept],
|
|
1482
1541
|
mapping_dept_exempt: _this13[_mapping_dept_exempt],
|
|
1483
|
-
_columns: columnArray.join(
|
|
1542
|
+
_columns: columnArray.join(","),
|
|
1484
1543
|
_current_path: childPath
|
|
1485
1544
|
}));
|
|
1486
1545
|
return objInstance.getMulti({
|
|
@@ -1516,8 +1575,8 @@ class SpiceModel {
|
|
|
1516
1575
|
var sourceValue = result[source_property];
|
|
1517
1576
|
|
|
1518
1577
|
// Check if value is in the empty string key (column aliasing issue)
|
|
1519
|
-
if ((sourceValue === undefined || _.isObject(sourceValue) && _.isEmpty(sourceValue)) && result[
|
|
1520
|
-
sourceValue = result[
|
|
1578
|
+
if ((sourceValue === undefined || _.isObject(sourceValue) && _.isEmpty(sourceValue)) && result[""] && result[""][source_property]) {
|
|
1579
|
+
sourceValue = result[""][source_property];
|
|
1521
1580
|
}
|
|
1522
1581
|
|
|
1523
1582
|
// Get the ID to match against - either a string ID or the id property of an object
|
|
@@ -1540,16 +1599,16 @@ class SpiceModel {
|
|
|
1540
1599
|
var p = (_this14$_ctx = _this14[_ctx]) == null ? void 0 : _this14$_ctx.profiler;
|
|
1541
1600
|
var columnArray = [];
|
|
1542
1601
|
if (columns) {
|
|
1543
|
-
columns.split(
|
|
1602
|
+
columns.split(",").forEach(col => {
|
|
1544
1603
|
var parts = col.trim().split("."); // remove the first segment
|
|
1545
1604
|
// Also match if parts[0] is source_property or '`' + source_property + '`'
|
|
1546
1605
|
var firstPart = parts[0];
|
|
1547
1606
|
// Remove backticks if present
|
|
1548
|
-
var cleanFirstPart = firstPart && firstPart.startsWith(
|
|
1607
|
+
var cleanFirstPart = firstPart && firstPart.startsWith("`") && firstPart.endsWith("`") ? firstPart.slice(1, -1) : firstPart;
|
|
1549
1608
|
if (parts.length > 0 && (firstPart === source_property || cleanFirstPart === source_property)) {
|
|
1550
1609
|
// Use cleanFirstPart for the map key to handle both cases consistently
|
|
1551
1610
|
// Remove backticks from each column segment, if present, before joining
|
|
1552
|
-
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith(
|
|
1611
|
+
columnArray.push(parts.slice(1).map(segment => segment && segment.startsWith("`") && segment.endsWith("`") ? segment.slice(1, -1) : segment).join("."));
|
|
1553
1612
|
}
|
|
1554
1613
|
});
|
|
1555
1614
|
}
|
|
@@ -1561,12 +1620,16 @@ class SpiceModel {
|
|
|
1561
1620
|
if (isExempt || _this14[_level] + 1 < _this14[_mapping_dept]) {
|
|
1562
1621
|
var ids = [];
|
|
1563
1622
|
_.each(data, result => {
|
|
1564
|
-
var value = [];
|
|
1565
|
-
|
|
1566
|
-
|
|
1623
|
+
var value = result[source_property];
|
|
1624
|
+
|
|
1625
|
+
// Some list/select projections place fields under an empty-string key.
|
|
1626
|
+
if ((value === undefined || _.isObject(value) && _.isEmpty(value)) && result[""] && result[""][source_property] !== undefined) {
|
|
1627
|
+
value = result[""][source_property];
|
|
1567
1628
|
}
|
|
1568
|
-
if (_.isString(
|
|
1569
|
-
value = [
|
|
1629
|
+
if (_.isString(value)) {
|
|
1630
|
+
value = [value];
|
|
1631
|
+
} else if (!_.isArray(value)) {
|
|
1632
|
+
value = [];
|
|
1570
1633
|
}
|
|
1571
1634
|
|
|
1572
1635
|
// Extract IDs - handle both string IDs and objects with id property
|
|
@@ -1594,7 +1657,7 @@ class SpiceModel {
|
|
|
1594
1657
|
_level: _this14[_level] + 1,
|
|
1595
1658
|
mapping_dept: _this14[_mapping_dept],
|
|
1596
1659
|
mapping_dept_exempt: _this14[_mapping_dept_exempt],
|
|
1597
|
-
_columns: columnArray.join(
|
|
1660
|
+
_columns: columnArray.join(","),
|
|
1598
1661
|
_current_path: childPath
|
|
1599
1662
|
})).getMulti({
|
|
1600
1663
|
skip_hooks: true,
|
|
@@ -1619,14 +1682,29 @@ class SpiceModel {
|
|
|
1619
1682
|
if (returned_obj.status == "fulfilled") return returned_obj.value;
|
|
1620
1683
|
})));
|
|
1621
1684
|
_.each(data, result => {
|
|
1685
|
+
var sourceValue = result[source_property];
|
|
1686
|
+
var hasFallbackSource = result[""] && result[""][source_property] !== undefined;
|
|
1622
1687
|
if (_.isString(result[store_property])) {
|
|
1623
1688
|
result[store_property] = [result[store_property]];
|
|
1624
1689
|
}
|
|
1625
|
-
if (!_.has(result, source_property)) {
|
|
1690
|
+
if (!_.has(result, source_property) && !hasFallbackSource) {
|
|
1691
|
+
if (!_.isArray(result[store_property])) {
|
|
1692
|
+
result[store_property] = [];
|
|
1693
|
+
}
|
|
1626
1694
|
result[source_property] = [];
|
|
1627
1695
|
return;
|
|
1628
1696
|
}
|
|
1629
|
-
|
|
1697
|
+
|
|
1698
|
+
// Match mapToObject behavior for projected rows that use result[""].
|
|
1699
|
+
if ((sourceValue === undefined || _.isObject(sourceValue) && _.isEmpty(sourceValue)) && hasFallbackSource) {
|
|
1700
|
+
sourceValue = result[""][source_property];
|
|
1701
|
+
}
|
|
1702
|
+
if (_.isString(sourceValue)) {
|
|
1703
|
+
sourceValue = [sourceValue];
|
|
1704
|
+
} else if (!_.isArray(sourceValue)) {
|
|
1705
|
+
sourceValue = [];
|
|
1706
|
+
}
|
|
1707
|
+
result[store_property] = _.map(sourceValue, item => {
|
|
1630
1708
|
// Get the ID to match - either a string ID or the id property of an object
|
|
1631
1709
|
var itemId = _.isString(item) ? item : _.isObject(item) ? item.id : null;
|
|
1632
1710
|
return _.find(returned_objects, p => p.id === itemId);
|
|
@@ -1669,7 +1747,7 @@ class SpiceModel {
|
|
|
1669
1747
|
extractBaseColumns(columns) {
|
|
1670
1748
|
if (!columns || !Array.isArray(columns)) return columns;
|
|
1671
1749
|
return [...new Set(columns.map(col => {
|
|
1672
|
-
var firstDot = col.indexOf(
|
|
1750
|
+
var firstDot = col.indexOf(".");
|
|
1673
1751
|
return firstDot > -1 ? col.substring(0, firstDot) : col;
|
|
1674
1752
|
}))];
|
|
1675
1753
|
}
|
|
@@ -1683,14 +1761,14 @@ class SpiceModel {
|
|
|
1683
1761
|
*/
|
|
1684
1762
|
isFieldInColumns(fieldName, columns) {
|
|
1685
1763
|
// No columns filter = include all
|
|
1686
|
-
if (!columns || columns ===
|
|
1687
|
-
var tokens = columns.split(
|
|
1764
|
+
if (!columns || columns === "") return true;
|
|
1765
|
+
var tokens = columns.split(",");
|
|
1688
1766
|
for (var col of tokens) {
|
|
1689
1767
|
var trimmed = col.trim();
|
|
1690
1768
|
// Check if this column starts with the field name (exact match or nested like "fieldName.subfield")
|
|
1691
|
-
var firstPart = trimmed.split(
|
|
1769
|
+
var firstPart = trimmed.split(".")[0];
|
|
1692
1770
|
// Handle backtick-wrapped column names
|
|
1693
|
-
var cleanFirstPart = firstPart.startsWith(
|
|
1771
|
+
var cleanFirstPart = firstPart.startsWith("`") && firstPart.endsWith("`") ? firstPart.slice(1, -1) : firstPart;
|
|
1694
1772
|
if (cleanFirstPart === fieldName) {
|
|
1695
1773
|
return true;
|
|
1696
1774
|
}
|