spice-js 2.6.73 → 2.6.74
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 +65 -8
- package/package.json +1 -1
- package/src/models/SpiceModel.js +56 -6
|
@@ -584,9 +584,10 @@ class SpiceModel {
|
|
|
584
584
|
if (_.isString(args.id)) {
|
|
585
585
|
if (args.skip_hooks !== true) {
|
|
586
586
|
yield _this4.run_hook(args, "get", "before");
|
|
587
|
-
}
|
|
587
|
+
} // ⚡ Include columns in cache key if specified
|
|
588
|
+
|
|
588
589
|
|
|
589
|
-
var key = "get::" + _this4.type + "::" + args.id;
|
|
590
|
+
var key = "get::" + _this4.type + "::" + args.id + (args.columns ? "::" + args.columns : "");
|
|
590
591
|
var results = {};
|
|
591
592
|
|
|
592
593
|
if (_this4.shouldUseCache(_this4.type)) {
|
|
@@ -640,7 +641,13 @@ class SpiceModel {
|
|
|
640
641
|
|
|
641
642
|
if (results.deleted === undefined || results.deleted === false) {
|
|
642
643
|
if (args.skip_read_serialize !== true && args.skip_serialize !== true) {
|
|
644
|
+
// ⚡ Pass columns to do_serialize so it can skip irrelevant modifiers
|
|
643
645
|
results = yield _this4.do_serialize(results, "read", {}, args, (yield _this4.propsToBeRemoved(results)));
|
|
646
|
+
} // ⚡ OPTIMIZED: Filter results by columns if specified
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
if (args.columns) {
|
|
650
|
+
results = _this4.filterResultsByColumns([results], args.columns)[0];
|
|
644
651
|
}
|
|
645
652
|
|
|
646
653
|
if (args.skip_hooks !== true) {
|
|
@@ -1695,11 +1702,16 @@ class SpiceModel {
|
|
|
1695
1702
|
addModifier(_ref15) {
|
|
1696
1703
|
var {
|
|
1697
1704
|
when,
|
|
1698
|
-
execute
|
|
1705
|
+
execute,
|
|
1706
|
+
field = null
|
|
1699
1707
|
} = _ref15;
|
|
1700
1708
|
|
|
1701
1709
|
if (this[_serializers][when]) {
|
|
1702
|
-
|
|
1710
|
+
// Store as object with field info for column-based filtering
|
|
1711
|
+
this[_serializers][when]["modifiers"].push({
|
|
1712
|
+
execute,
|
|
1713
|
+
field
|
|
1714
|
+
});
|
|
1703
1715
|
}
|
|
1704
1716
|
}
|
|
1705
1717
|
|
|
@@ -1728,15 +1740,19 @@ class SpiceModel {
|
|
|
1728
1740
|
switch (properties[i].map.type) {
|
|
1729
1741
|
case _2.MapType.MODEL:
|
|
1730
1742
|
{
|
|
1743
|
+
var destinationField = properties[i].map.destination || i;
|
|
1744
|
+
|
|
1731
1745
|
switch (properties[i].type) {
|
|
1732
1746
|
case String:
|
|
1733
1747
|
case "string":
|
|
1734
1748
|
{
|
|
1735
1749
|
_this17.addModifier({
|
|
1736
1750
|
when: properties[i].map.when || "read",
|
|
1751
|
+
field: destinationField,
|
|
1752
|
+
// ⚡ Track which field this modifier populates
|
|
1737
1753
|
execute: function () {
|
|
1738
1754
|
var _execute = _asyncToGenerator(function* (data) {
|
|
1739
|
-
return yield _this17.mapToObject(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i,
|
|
1755
|
+
return yield _this17.mapToObject(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i, destinationField, properties[i]);
|
|
1740
1756
|
});
|
|
1741
1757
|
|
|
1742
1758
|
function execute(_x) {
|
|
@@ -1755,9 +1771,11 @@ class SpiceModel {
|
|
|
1755
1771
|
{
|
|
1756
1772
|
_this17.addModifier({
|
|
1757
1773
|
when: properties[i].map.when || "read",
|
|
1774
|
+
field: destinationField,
|
|
1775
|
+
// ⚡ Track which field this modifier populates
|
|
1758
1776
|
execute: function () {
|
|
1759
1777
|
var _execute2 = _asyncToGenerator(function* (data) {
|
|
1760
|
-
return yield _this17.mapToObjectArray(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i,
|
|
1778
|
+
return yield _this17.mapToObjectArray(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i, destinationField, properties[i]);
|
|
1761
1779
|
});
|
|
1762
1780
|
|
|
1763
1781
|
function execute(_x2) {
|
|
@@ -1786,6 +1804,35 @@ class SpiceModel {
|
|
|
1786
1804
|
for (var i in properties) {
|
|
1787
1805
|
_loop(i);
|
|
1788
1806
|
}
|
|
1807
|
+
} // ⚡ Parse columns string into a Set for fast lookup
|
|
1808
|
+
|
|
1809
|
+
|
|
1810
|
+
parseRequestedColumns(columns) {
|
|
1811
|
+
if (!columns || columns === "") return null; // Extract field names from column specifications
|
|
1812
|
+
// Handles: "field", "`field`", "table.field", "`table`.`field`", "expr AS alias"
|
|
1813
|
+
|
|
1814
|
+
var fields = new Set();
|
|
1815
|
+
var columnList = columns.split(",").map(c => c.trim());
|
|
1816
|
+
|
|
1817
|
+
for (var col of columnList) {
|
|
1818
|
+
// Check for AS alias
|
|
1819
|
+
var aliasMatch = col.match(/\s+AS\s+`?([\w]+)`?$/i);
|
|
1820
|
+
|
|
1821
|
+
if (aliasMatch) {
|
|
1822
|
+
fields.add(aliasMatch[1]);
|
|
1823
|
+
continue;
|
|
1824
|
+
} // Get the last part after dots (the field name)
|
|
1825
|
+
|
|
1826
|
+
|
|
1827
|
+
var parts = col.replace(/`/g, "").split(".");
|
|
1828
|
+
var fieldName = parts[parts.length - 1];
|
|
1829
|
+
|
|
1830
|
+
if (fieldName && fieldName !== "*") {
|
|
1831
|
+
fields.add(fieldName);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
return fields.size > 0 ? fields : null;
|
|
1789
1836
|
}
|
|
1790
1837
|
|
|
1791
1838
|
do_serialize(data, type, old_data, args, path_to_be_removed) {
|
|
@@ -1817,14 +1864,24 @@ class SpiceModel {
|
|
|
1817
1864
|
_this18.addExternalModifiers(_this18.type);
|
|
1818
1865
|
|
|
1819
1866
|
_this18[_external_modifier_loaded] = true;
|
|
1820
|
-
} //
|
|
1867
|
+
} // ⚡ OPTIMIZED: Parse requested columns for selective modifier execution
|
|
1868
|
+
|
|
1869
|
+
|
|
1870
|
+
var requestedColumns = _this18.parseRequestedColumns(args == null ? void 0 : args.columns); // Cache the modifiers lookup for the specified type.
|
|
1821
1871
|
|
|
1822
1872
|
|
|
1823
1873
|
var modifiers = ((_this18$_serializers = _this18[_serializers]) == null ? void 0 : (_this18$_serializers$ = _this18$_serializers[type]) == null ? void 0 : _this18$_serializers$.modifiers) || [];
|
|
1824
1874
|
|
|
1825
1875
|
for (var modifier of modifiers) {
|
|
1826
1876
|
try {
|
|
1827
|
-
|
|
1877
|
+
// ⚡ OPTIMIZED: Skip field-specific modifiers if columns specified and field not requested
|
|
1878
|
+
if (requestedColumns && modifier.field && !requestedColumns.has(modifier.field)) {
|
|
1879
|
+
continue; // Skip this modifier - field not in requested columns
|
|
1880
|
+
} // Execute modifier (supports both old function format and new object format)
|
|
1881
|
+
|
|
1882
|
+
|
|
1883
|
+
var executeFn = typeof modifier === "function" ? modifier : modifier.execute;
|
|
1884
|
+
data = yield executeFn(data, old_data, _this18[_ctx], _this18.type);
|
|
1828
1885
|
} catch (error) {
|
|
1829
1886
|
console.error("Modifier error in do_serialize:", error.stack);
|
|
1830
1887
|
}
|
package/package.json
CHANGED
package/src/models/SpiceModel.js
CHANGED
|
@@ -499,7 +499,8 @@ export default class SpiceModel {
|
|
|
499
499
|
if (args.skip_hooks !== true) {
|
|
500
500
|
await this.run_hook(args, "get", "before");
|
|
501
501
|
}
|
|
502
|
-
|
|
502
|
+
// ⚡ Include columns in cache key if specified
|
|
503
|
+
let key = `get::${this.type}::${args.id}${args.columns ? `::${args.columns}` : ""}`;
|
|
503
504
|
let results = {};
|
|
504
505
|
|
|
505
506
|
if (this.shouldUseCache(this.type)) {
|
|
@@ -553,6 +554,7 @@ export default class SpiceModel {
|
|
|
553
554
|
args.skip_read_serialize !== true &&
|
|
554
555
|
args.skip_serialize !== true
|
|
555
556
|
) {
|
|
557
|
+
// ⚡ Pass columns to do_serialize so it can skip irrelevant modifiers
|
|
556
558
|
results = await this.do_serialize(
|
|
557
559
|
results,
|
|
558
560
|
"read",
|
|
@@ -561,6 +563,12 @@ export default class SpiceModel {
|
|
|
561
563
|
await this.propsToBeRemoved(results)
|
|
562
564
|
);
|
|
563
565
|
}
|
|
566
|
+
|
|
567
|
+
// ⚡ OPTIMIZED: Filter results by columns if specified
|
|
568
|
+
if (args.columns) {
|
|
569
|
+
results = this.filterResultsByColumns([results], args.columns)[0];
|
|
570
|
+
}
|
|
571
|
+
|
|
564
572
|
if (args.skip_hooks !== true) {
|
|
565
573
|
await this.run_hook(results, "get", "after");
|
|
566
574
|
}
|
|
@@ -1533,9 +1541,10 @@ export default class SpiceModel {
|
|
|
1533
1541
|
return original_is_array ? data : data[0];
|
|
1534
1542
|
}
|
|
1535
1543
|
|
|
1536
|
-
addModifier({ when, execute }) {
|
|
1544
|
+
addModifier({ when, execute, field = null }) {
|
|
1537
1545
|
if (this[_serializers][when]) {
|
|
1538
|
-
|
|
1546
|
+
// Store as object with field info for column-based filtering
|
|
1547
|
+
this[_serializers][when]["modifiers"].push({ execute, field });
|
|
1539
1548
|
}
|
|
1540
1549
|
}
|
|
1541
1550
|
|
|
@@ -1556,11 +1565,13 @@ export default class SpiceModel {
|
|
|
1556
1565
|
if (properties[i].map) {
|
|
1557
1566
|
switch (properties[i].map.type) {
|
|
1558
1567
|
case MapType.MODEL: {
|
|
1568
|
+
const destinationField = properties[i].map.destination || i;
|
|
1559
1569
|
switch (properties[i].type) {
|
|
1560
1570
|
case String:
|
|
1561
1571
|
case "string": {
|
|
1562
1572
|
this.addModifier({
|
|
1563
1573
|
when: properties[i].map.when || "read",
|
|
1574
|
+
field: destinationField, // ⚡ Track which field this modifier populates
|
|
1564
1575
|
execute: async (data) => {
|
|
1565
1576
|
return await this.mapToObject(
|
|
1566
1577
|
data,
|
|
@@ -1568,7 +1579,7 @@ export default class SpiceModel {
|
|
|
1568
1579
|
spice.models[properties[i].map.reference]
|
|
1569
1580
|
: properties[i].map.reference,
|
|
1570
1581
|
i,
|
|
1571
|
-
|
|
1582
|
+
destinationField,
|
|
1572
1583
|
properties[i]
|
|
1573
1584
|
);
|
|
1574
1585
|
},
|
|
@@ -1579,6 +1590,7 @@ export default class SpiceModel {
|
|
|
1579
1590
|
case "array": {
|
|
1580
1591
|
this.addModifier({
|
|
1581
1592
|
when: properties[i].map.when || "read",
|
|
1593
|
+
field: destinationField, // ⚡ Track which field this modifier populates
|
|
1582
1594
|
execute: async (data) => {
|
|
1583
1595
|
return await this.mapToObjectArray(
|
|
1584
1596
|
data,
|
|
@@ -1586,7 +1598,7 @@ export default class SpiceModel {
|
|
|
1586
1598
|
spice.models[properties[i].map.reference]
|
|
1587
1599
|
: properties[i].map.reference,
|
|
1588
1600
|
i,
|
|
1589
|
-
|
|
1601
|
+
destinationField,
|
|
1590
1602
|
properties[i]
|
|
1591
1603
|
);
|
|
1592
1604
|
},
|
|
@@ -1604,6 +1616,34 @@ export default class SpiceModel {
|
|
|
1604
1616
|
}
|
|
1605
1617
|
}
|
|
1606
1618
|
|
|
1619
|
+
// ⚡ Parse columns string into a Set for fast lookup
|
|
1620
|
+
parseRequestedColumns(columns) {
|
|
1621
|
+
if (!columns || columns === "") return null;
|
|
1622
|
+
|
|
1623
|
+
// Extract field names from column specifications
|
|
1624
|
+
// Handles: "field", "`field`", "table.field", "`table`.`field`", "expr AS alias"
|
|
1625
|
+
const fields = new Set();
|
|
1626
|
+
const columnList = columns.split(",").map((c) => c.trim());
|
|
1627
|
+
|
|
1628
|
+
for (const col of columnList) {
|
|
1629
|
+
// Check for AS alias
|
|
1630
|
+
const aliasMatch = col.match(/\s+AS\s+`?([\w]+)`?$/i);
|
|
1631
|
+
if (aliasMatch) {
|
|
1632
|
+
fields.add(aliasMatch[1]);
|
|
1633
|
+
continue;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
// Get the last part after dots (the field name)
|
|
1637
|
+
const parts = col.replace(/`/g, "").split(".");
|
|
1638
|
+
const fieldName = parts[parts.length - 1];
|
|
1639
|
+
if (fieldName && fieldName !== "*") {
|
|
1640
|
+
fields.add(fieldName);
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
return fields.size > 0 ? fields : null;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1607
1647
|
async do_serialize(data, type, old_data, args, path_to_be_removed = []) {
|
|
1608
1648
|
// Profiling: use track() for proper async context forking
|
|
1609
1649
|
const p = this[_ctx]?.profiler;
|
|
@@ -1620,11 +1660,21 @@ export default class SpiceModel {
|
|
|
1620
1660
|
this[_external_modifier_loaded] = true;
|
|
1621
1661
|
}
|
|
1622
1662
|
|
|
1663
|
+
// ⚡ OPTIMIZED: Parse requested columns for selective modifier execution
|
|
1664
|
+
const requestedColumns = this.parseRequestedColumns(args?.columns);
|
|
1665
|
+
|
|
1623
1666
|
// Cache the modifiers lookup for the specified type.
|
|
1624
1667
|
const modifiers = this[_serializers]?.[type]?.modifiers || [];
|
|
1625
1668
|
for (const modifier of modifiers) {
|
|
1626
1669
|
try {
|
|
1627
|
-
|
|
1670
|
+
// ⚡ OPTIMIZED: Skip field-specific modifiers if columns specified and field not requested
|
|
1671
|
+
if (requestedColumns && modifier.field && !requestedColumns.has(modifier.field)) {
|
|
1672
|
+
continue; // Skip this modifier - field not in requested columns
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
// Execute modifier (supports both old function format and new object format)
|
|
1676
|
+
const executeFn = typeof modifier === "function" ? modifier : modifier.execute;
|
|
1677
|
+
data = await executeFn(data, old_data, this[_ctx], this.type);
|
|
1628
1678
|
} catch (error) {
|
|
1629
1679
|
console.error("Modifier error in do_serialize:", error.stack);
|
|
1630
1680
|
}
|