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.
@@ -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
- this[_serializers][when]["modifiers"].push(execute);
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, properties[i].map.destination || i, properties[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, properties[i].map.destination || i, properties[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
- } // Cache the modifiers lookup for the specified type.
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
- data = yield modifier(data, old_data, _this18[_ctx], _this18.type);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spice-js",
3
- "version": "2.6.73",
3
+ "version": "2.6.74",
4
4
  "description": "spice",
5
5
  "main": "build/index.js",
6
6
  "repository": {
@@ -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
- let key = `get::${this.type}::${args.id}`;
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
- this[_serializers][when]["modifiers"].push(execute);
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
- properties[i].map.destination || i,
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
- properties[i].map.destination || i,
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
- data = await modifier(data, old_data, this[_ctx], this.type);
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
  }