spice-js 2.7.13 → 2.7.15
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 +40 -12
- package/package.json +1 -1
- package/src/models/SpiceModel.js +37 -12
|
@@ -791,7 +791,7 @@ class SpiceModel {
|
|
|
791
791
|
if ((cached_results == null ? void 0 : cached_results.value) === undefined || (yield _this6.shouldForceRefresh(cached_results))) {
|
|
792
792
|
results = yield _this6.database.multi_get(args.ids, {
|
|
793
793
|
keep_type: true,
|
|
794
|
-
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [...args.columns, 'type'] : []
|
|
794
|
+
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [..._this6.extractBaseColumns(args.columns), 'type'] : []
|
|
795
795
|
});
|
|
796
796
|
|
|
797
797
|
_this6.getCacheProviderObject(_this6.type).set(key, {
|
|
@@ -802,7 +802,7 @@ class SpiceModel {
|
|
|
802
802
|
} else {
|
|
803
803
|
results = yield _this6.database.multi_get(args.ids, {
|
|
804
804
|
keep_type: true,
|
|
805
|
-
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [...args.columns, 'type'] : []
|
|
805
|
+
columns: args.columns && args.columns.length > 0 && args.columns != "" ? [..._this6.extractBaseColumns(args.columns), 'type'] : []
|
|
806
806
|
});
|
|
807
807
|
}
|
|
808
808
|
}
|
|
@@ -1290,34 +1290,42 @@ class SpiceModel {
|
|
|
1290
1290
|
}
|
|
1291
1291
|
|
|
1292
1292
|
extractNestings(string, localType) {
|
|
1293
|
-
var returnVal = []; //
|
|
1294
|
-
//
|
|
1293
|
+
var returnVal = []; // Extract loop variables from ANY/EVERY expressions
|
|
1294
|
+
// Loop variables (e.g., "vote" in "EVERY vote IN committee_votes") should be excluded
|
|
1295
|
+
// But the collection being iterated (e.g., "committee_votes") should be INCLUDED
|
|
1296
|
+
// if it's a joinable mapped property - buildJoinMetadata will filter non-joinables
|
|
1295
1297
|
|
|
1296
1298
|
var anyEveryRegex = /(ANY|EVERY)\s+(\w+)\s+IN\s+`?(\w+)`?/gi;
|
|
1297
1299
|
var anyEveryMatch;
|
|
1298
1300
|
var loopVariables = new Set();
|
|
1299
|
-
var
|
|
1301
|
+
var anyEveryCollections = new Set();
|
|
1300
1302
|
|
|
1301
1303
|
while ((anyEveryMatch = anyEveryRegex.exec(string)) !== null) {
|
|
1302
|
-
loopVariables.add(anyEveryMatch[2]); // e.g., "
|
|
1304
|
+
loopVariables.add(anyEveryMatch[2]); // e.g., "vote" - exclude from nestings
|
|
1303
1305
|
|
|
1304
|
-
|
|
1305
|
-
} // Now extract dot notation patterns, but skip loop variables
|
|
1306
|
+
anyEveryCollections.add(anyEveryMatch[3]); // e.g., "committee_votes" - include in nestings
|
|
1307
|
+
} // Now extract dot notation patterns, but skip loop variables
|
|
1306
1308
|
|
|
1307
1309
|
|
|
1308
1310
|
var regex = /(`?\w+`?)\.(`?\w+`?)/g;
|
|
1309
1311
|
var match;
|
|
1310
1312
|
|
|
1311
1313
|
while ((match = regex.exec(string)) !== null) {
|
|
1312
|
-
var first = match[1].replace(/`/g, ""); // Skip if it's the local type
|
|
1314
|
+
var first = match[1].replace(/`/g, ""); // Skip if it's the local type or a loop variable from ANY/EVERY
|
|
1313
1315
|
|
|
1314
|
-
if (first !== localType && !loopVariables.has(first)
|
|
1316
|
+
if (first !== localType && !loopVariables.has(first)) {
|
|
1315
1317
|
returnVal.push(first);
|
|
1316
1318
|
}
|
|
1317
|
-
} //
|
|
1318
|
-
//
|
|
1319
|
+
} // Add collections from ANY/EVERY expressions as potential nestings
|
|
1320
|
+
// buildJoinMetadata will filter out non-joinable ones (embedded arrays vs mapped collections)
|
|
1319
1321
|
|
|
1320
1322
|
|
|
1323
|
+
for (var collection of anyEveryCollections) {
|
|
1324
|
+
if (collection !== localType) {
|
|
1325
|
+
returnVal.push(collection);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1321
1329
|
return [...new Set(returnVal)];
|
|
1322
1330
|
}
|
|
1323
1331
|
|
|
@@ -1460,6 +1468,11 @@ class SpiceModel {
|
|
|
1460
1468
|
|
|
1461
1469
|
if (tableName === this.type && match) {
|
|
1462
1470
|
return col;
|
|
1471
|
+
} // If column is already backtick-quoted, return as-is
|
|
1472
|
+
|
|
1473
|
+
|
|
1474
|
+
if (col.startsWith("`") && col.endsWith("`")) {
|
|
1475
|
+
return col;
|
|
1463
1476
|
}
|
|
1464
1477
|
|
|
1465
1478
|
return "`" + col + "`";
|
|
@@ -1989,6 +2002,21 @@ class SpiceModel {
|
|
|
1989
2002
|
that.addModifier(modifier);
|
|
1990
2003
|
});
|
|
1991
2004
|
}
|
|
2005
|
+
/**
|
|
2006
|
+
* Extracts the first segment of each column path for database queries.
|
|
2007
|
+
* e.g., ["name", "permissions.permission"] → ["name", "permissions"]
|
|
2008
|
+
* @param {string[]} columns - Array of column paths
|
|
2009
|
+
* @returns {string[]} - Array of base column names (deduplicated)
|
|
2010
|
+
*/
|
|
2011
|
+
|
|
2012
|
+
|
|
2013
|
+
extractBaseColumns(columns) {
|
|
2014
|
+
if (!columns || !Array.isArray(columns)) return columns;
|
|
2015
|
+
return [...new Set(columns.map(col => {
|
|
2016
|
+
var firstDot = col.indexOf('.');
|
|
2017
|
+
return firstDot > -1 ? col.substring(0, firstDot) : col;
|
|
2018
|
+
}))];
|
|
2019
|
+
}
|
|
1992
2020
|
/**
|
|
1993
2021
|
* Checks if a field is present in the columns string.
|
|
1994
2022
|
* Used to skip modifier execution when the field isn't requested.
|
package/package.json
CHANGED
package/src/models/SpiceModel.js
CHANGED
|
@@ -684,7 +684,7 @@ export default class SpiceModel {
|
|
|
684
684
|
cached_results?.value === undefined ||
|
|
685
685
|
(await this.shouldForceRefresh(cached_results))
|
|
686
686
|
) {
|
|
687
|
-
results = await this.database.multi_get(args.ids, {keep_type:true, columns:args.columns && args.columns.length > 0 && args.columns != ""?[...args.columns, 'type']:[]});
|
|
687
|
+
results = await this.database.multi_get(args.ids, {keep_type:true, columns:args.columns && args.columns.length > 0 && args.columns != ""?[...this.extractBaseColumns(args.columns), 'type']:[]});
|
|
688
688
|
this.getCacheProviderObject(this.type).set(
|
|
689
689
|
key,
|
|
690
690
|
{ value: results, time: new Date().getTime() },
|
|
@@ -692,7 +692,7 @@ export default class SpiceModel {
|
|
|
692
692
|
);
|
|
693
693
|
}
|
|
694
694
|
} else {
|
|
695
|
-
results = await this.database.multi_get(args.ids, {keep_type:true, columns:args.columns && args.columns.length > 0 && args.columns != ""?[...args.columns, 'type']:[]});
|
|
695
|
+
results = await this.database.multi_get(args.ids, {keep_type:true, columns:args.columns && args.columns.length > 0 && args.columns != ""?[...this.extractBaseColumns(args.columns), 'type']:[]});
|
|
696
696
|
}
|
|
697
697
|
}
|
|
698
698
|
_.remove(results, (o) => o.type != this.type);
|
|
@@ -1110,32 +1110,39 @@ export default class SpiceModel {
|
|
|
1110
1110
|
extractNestings(string, localType) {
|
|
1111
1111
|
let returnVal = [];
|
|
1112
1112
|
|
|
1113
|
-
//
|
|
1114
|
-
//
|
|
1113
|
+
// Extract loop variables from ANY/EVERY expressions
|
|
1114
|
+
// Loop variables (e.g., "vote" in "EVERY vote IN committee_votes") should be excluded
|
|
1115
|
+
// But the collection being iterated (e.g., "committee_votes") should be INCLUDED
|
|
1116
|
+
// if it's a joinable mapped property - buildJoinMetadata will filter non-joinables
|
|
1115
1117
|
let anyEveryRegex = /(ANY|EVERY)\s+(\w+)\s+IN\s+`?(\w+)`?/gi;
|
|
1116
1118
|
let anyEveryMatch;
|
|
1117
1119
|
const loopVariables = new Set();
|
|
1118
|
-
const
|
|
1120
|
+
const anyEveryCollections = new Set();
|
|
1119
1121
|
|
|
1120
1122
|
while ((anyEveryMatch = anyEveryRegex.exec(string)) !== null) {
|
|
1121
|
-
loopVariables.add(anyEveryMatch[2]); // e.g., "
|
|
1122
|
-
|
|
1123
|
+
loopVariables.add(anyEveryMatch[2]); // e.g., "vote" - exclude from nestings
|
|
1124
|
+
anyEveryCollections.add(anyEveryMatch[3]); // e.g., "committee_votes" - include in nestings
|
|
1123
1125
|
}
|
|
1124
1126
|
|
|
1125
|
-
// Now extract dot notation patterns, but skip loop variables
|
|
1127
|
+
// Now extract dot notation patterns, but skip loop variables
|
|
1126
1128
|
let regex = /(`?\w+`?)\.(`?\w+`?)/g;
|
|
1127
1129
|
let match;
|
|
1128
1130
|
|
|
1129
1131
|
while ((match = regex.exec(string)) !== null) {
|
|
1130
1132
|
let first = match[1].replace(/`/g, "");
|
|
1131
|
-
// Skip if it's the local type
|
|
1132
|
-
if (first !== localType && !loopVariables.has(first)
|
|
1133
|
+
// Skip if it's the local type or a loop variable from ANY/EVERY
|
|
1134
|
+
if (first !== localType && !loopVariables.has(first)) {
|
|
1133
1135
|
returnVal.push(first);
|
|
1134
1136
|
}
|
|
1135
1137
|
}
|
|
1136
1138
|
|
|
1137
|
-
//
|
|
1138
|
-
//
|
|
1139
|
+
// Add collections from ANY/EVERY expressions as potential nestings
|
|
1140
|
+
// buildJoinMetadata will filter out non-joinable ones (embedded arrays vs mapped collections)
|
|
1141
|
+
for (const collection of anyEveryCollections) {
|
|
1142
|
+
if (collection !== localType) {
|
|
1143
|
+
returnVal.push(collection);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1139
1146
|
|
|
1140
1147
|
return [...new Set(returnVal)];
|
|
1141
1148
|
}
|
|
@@ -1292,6 +1299,10 @@ export default class SpiceModel {
|
|
|
1292
1299
|
return col;
|
|
1293
1300
|
}
|
|
1294
1301
|
|
|
1302
|
+
// If column is already backtick-quoted, return as-is
|
|
1303
|
+
if (col.startsWith("`") && col.endsWith("`")) {
|
|
1304
|
+
return col;
|
|
1305
|
+
}
|
|
1295
1306
|
return `\`${col}\``;
|
|
1296
1307
|
});
|
|
1297
1308
|
|
|
@@ -1813,6 +1824,20 @@ export default class SpiceModel {
|
|
|
1813
1824
|
});
|
|
1814
1825
|
}
|
|
1815
1826
|
|
|
1827
|
+
/**
|
|
1828
|
+
* Extracts the first segment of each column path for database queries.
|
|
1829
|
+
* e.g., ["name", "permissions.permission"] → ["name", "permissions"]
|
|
1830
|
+
* @param {string[]} columns - Array of column paths
|
|
1831
|
+
* @returns {string[]} - Array of base column names (deduplicated)
|
|
1832
|
+
*/
|
|
1833
|
+
extractBaseColumns(columns) {
|
|
1834
|
+
if (!columns || !Array.isArray(columns)) return columns;
|
|
1835
|
+
return [...new Set(columns.map(col => {
|
|
1836
|
+
const firstDot = col.indexOf('.');
|
|
1837
|
+
return firstDot > -1 ? col.substring(0, firstDot) : col;
|
|
1838
|
+
}))];
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1816
1841
|
/**
|
|
1817
1842
|
* Checks if a field is present in the columns string.
|
|
1818
1843
|
* Used to skip modifier execution when the field isn't requested.
|