spice-js 2.7.3 → 2.7.5
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 +36 -155
- package/package.json +1 -1
- package/src/models/SpiceModel.js +41 -137
|
@@ -54,7 +54,6 @@ if (!Promise.allSettled) {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
class SpiceModel {
|
|
57
|
-
// ⚡ Static caches for performance optimization
|
|
58
57
|
constructor(args) {
|
|
59
58
|
if (args === void 0) {
|
|
60
59
|
args = {};
|
|
@@ -1559,54 +1558,6 @@ class SpiceModel {
|
|
|
1559
1558
|
}
|
|
1560
1559
|
|
|
1561
1560
|
return true;
|
|
1562
|
-
} // ⚡ OPTIMIZED: Cache defaults metadata per model type
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
getDefaultsMetadata(type) {
|
|
1566
|
-
var cacheKey = this.type + "::" + type;
|
|
1567
|
-
|
|
1568
|
-
if (!SpiceModel._defaultsCache[cacheKey]) {
|
|
1569
|
-
var staticDefaults = {};
|
|
1570
|
-
var dynamicDefaults = []; // Pre-compute once per model type
|
|
1571
|
-
|
|
1572
|
-
for (var key in this.props) {
|
|
1573
|
-
var _this$props$key, _this$props$key$defau;
|
|
1574
|
-
|
|
1575
|
-
var def = (_this$props$key = this.props[key]) == null ? void 0 : (_this$props$key$defau = _this$props$key.defaults) == null ? void 0 : _this$props$key$defau[type];
|
|
1576
|
-
|
|
1577
|
-
if (def !== undefined) {
|
|
1578
|
-
if (_.isFunction(def)) {
|
|
1579
|
-
dynamicDefaults.push({
|
|
1580
|
-
key,
|
|
1581
|
-
fn: def
|
|
1582
|
-
});
|
|
1583
|
-
} else {
|
|
1584
|
-
staticDefaults[key] = def;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
SpiceModel._defaultsCache[cacheKey] = {
|
|
1590
|
-
staticDefaults,
|
|
1591
|
-
dynamicDefaults,
|
|
1592
|
-
hasDefaults: Object.keys(staticDefaults).length > 0 || dynamicDefaults.length > 0
|
|
1593
|
-
};
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
return SpiceModel._defaultsCache[cacheKey];
|
|
1597
|
-
} // ⚡ OPTIMIZED: Cache hidden props per model type
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
getHiddenProps() {
|
|
1601
|
-
if (!SpiceModel._hiddenPropsCache[this.type]) {
|
|
1602
|
-
SpiceModel._hiddenPropsCache[this.type] = Object.keys(this.props).filter(key => {
|
|
1603
|
-
var _this$props$key2;
|
|
1604
|
-
|
|
1605
|
-
return (_this$props$key2 = this.props[key]) == null ? void 0 : _this$props$key2.hide;
|
|
1606
|
-
});
|
|
1607
|
-
}
|
|
1608
|
-
|
|
1609
|
-
return SpiceModel._hiddenPropsCache[this.type];
|
|
1610
1561
|
} // Check if a field is exempt from mapping depth limits
|
|
1611
1562
|
// Supports deep references like "group.permissions"
|
|
1612
1563
|
|
|
@@ -1816,18 +1767,11 @@ class SpiceModel {
|
|
|
1816
1767
|
addModifier(_ref18) {
|
|
1817
1768
|
var {
|
|
1818
1769
|
when,
|
|
1819
|
-
execute
|
|
1820
|
-
field = null,
|
|
1821
|
-
sourceField = null
|
|
1770
|
+
execute
|
|
1822
1771
|
} = _ref18;
|
|
1823
1772
|
|
|
1824
1773
|
if (this[_serializers][when]) {
|
|
1825
|
-
|
|
1826
|
-
this[_serializers][when]["modifiers"].push({
|
|
1827
|
-
execute,
|
|
1828
|
-
field,
|
|
1829
|
-
sourceField
|
|
1830
|
-
});
|
|
1774
|
+
this[_serializers][when]["modifiers"].push(execute);
|
|
1831
1775
|
}
|
|
1832
1776
|
}
|
|
1833
1777
|
|
|
@@ -1856,21 +1800,15 @@ class SpiceModel {
|
|
|
1856
1800
|
switch (properties[i].map.type) {
|
|
1857
1801
|
case _2.MapType.MODEL:
|
|
1858
1802
|
{
|
|
1859
|
-
var destinationField = properties[i].map.destination || i;
|
|
1860
|
-
|
|
1861
1803
|
switch (properties[i].type) {
|
|
1862
1804
|
case String:
|
|
1863
1805
|
case "string":
|
|
1864
1806
|
{
|
|
1865
1807
|
_this17.addModifier({
|
|
1866
1808
|
when: properties[i].map.when || "read",
|
|
1867
|
-
field: destinationField,
|
|
1868
|
-
// ⚡ Track which field this modifier populates
|
|
1869
|
-
sourceField: i,
|
|
1870
|
-
// ⚡ Track source property for column filtering
|
|
1871
1809
|
execute: function () {
|
|
1872
1810
|
var _execute = _asyncToGenerator(function* (data) {
|
|
1873
|
-
return yield _this17.mapToObject(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i,
|
|
1811
|
+
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]);
|
|
1874
1812
|
});
|
|
1875
1813
|
|
|
1876
1814
|
function execute(_x) {
|
|
@@ -1889,13 +1827,9 @@ class SpiceModel {
|
|
|
1889
1827
|
{
|
|
1890
1828
|
_this17.addModifier({
|
|
1891
1829
|
when: properties[i].map.when || "read",
|
|
1892
|
-
field: destinationField,
|
|
1893
|
-
// ⚡ Track which field this modifier populates
|
|
1894
|
-
sourceField: i,
|
|
1895
|
-
// ⚡ Track source property for column filtering
|
|
1896
1830
|
execute: function () {
|
|
1897
1831
|
var _execute2 = _asyncToGenerator(function* (data) {
|
|
1898
|
-
return yield _this17.mapToObjectArray(data, _.isString(properties[i].map.reference) ? spice.models[properties[i].map.reference] : properties[i].map.reference, i,
|
|
1832
|
+
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]);
|
|
1899
1833
|
});
|
|
1900
1834
|
|
|
1901
1835
|
function execute(_x2) {
|
|
@@ -1924,42 +1858,6 @@ class SpiceModel {
|
|
|
1924
1858
|
for (var i in properties) {
|
|
1925
1859
|
_loop(i);
|
|
1926
1860
|
}
|
|
1927
|
-
} // ⚡ Parse columns string into a Set for fast lookup
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
parseRequestedColumns(columns) {
|
|
1931
|
-
if (!columns || columns === "") return null; // Handle array of columns (convert to string)
|
|
1932
|
-
|
|
1933
|
-
if (Array.isArray(columns)) {
|
|
1934
|
-
columns = columns.join(",");
|
|
1935
|
-
} // Must be a string to parse
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
if (typeof columns !== "string") return null; // Extract field names from column specifications
|
|
1939
|
-
// Handles: "field", "`field`", "table.field", "`table`.`field`", "expr AS alias"
|
|
1940
|
-
|
|
1941
|
-
var fields = new Set();
|
|
1942
|
-
var columnList = columns.split(",").map(c => c.trim());
|
|
1943
|
-
|
|
1944
|
-
for (var col of columnList) {
|
|
1945
|
-
// Check for AS alias
|
|
1946
|
-
var aliasMatch = col.match(/\s+AS\s+`?([\w]+)`?$/i);
|
|
1947
|
-
|
|
1948
|
-
if (aliasMatch) {
|
|
1949
|
-
fields.add(aliasMatch[1]);
|
|
1950
|
-
continue;
|
|
1951
|
-
} // Get the last part after dots (the field name)
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
var parts = col.replace(/`/g, "").split(".");
|
|
1955
|
-
var fieldName = parts[parts.length - 1];
|
|
1956
|
-
|
|
1957
|
-
if (fieldName && fieldName !== "*") {
|
|
1958
|
-
fields.add(fieldName);
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
|
|
1962
|
-
return fields.size > 0 ? fields : null;
|
|
1963
1861
|
}
|
|
1964
1862
|
|
|
1965
1863
|
do_serialize(data, type, old_data, args, path_to_be_removed) {
|
|
@@ -1991,30 +1889,24 @@ class SpiceModel {
|
|
|
1991
1889
|
_this18.addExternalModifiers(_this18.type);
|
|
1992
1890
|
|
|
1993
1891
|
_this18[_external_modifier_loaded] = true;
|
|
1994
|
-
} //
|
|
1892
|
+
} // Cache the modifiers lookup for the specified type.
|
|
1995
1893
|
|
|
1996
1894
|
|
|
1997
|
-
var
|
|
1895
|
+
var modifiers = ((_this18$_serializers = _this18[_serializers]) == null ? void 0 : (_this18$_serializers$ = _this18$_serializers[type]) == null ? void 0 : _this18$_serializers$.modifiers) || [];
|
|
1998
1896
|
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
for (var modifier of modifiers) {
|
|
2003
|
-
// Skip field-specific modifiers if columns specified and field is not requested
|
|
2004
|
-
if (requestedColumns && modifier.field && !requestedColumns.has(modifier.field) && !(modifier.sourceField && requestedColumns.has(modifier.sourceField))) {
|
|
2005
|
-
continue;
|
|
2006
|
-
}
|
|
1897
|
+
for (var i = 0; i < modifiers.length; i++) {
|
|
1898
|
+
var modifier = modifiers[i];
|
|
2007
1899
|
|
|
2008
1900
|
try {
|
|
2009
|
-
|
|
2010
|
-
var executeFn = typeof modifier === "function" ? modifier : modifier.execute;
|
|
2011
|
-
var result = yield executeFn(data, old_data, _this18[_ctx], _this18.type); // Only assign if modifier returned a value to prevent data corruption
|
|
1901
|
+
var result = yield modifier(data, old_data, _this18[_ctx], _this18.type); // Guard against modifiers that return undefined
|
|
2012
1902
|
|
|
2013
1903
|
if (result !== undefined) {
|
|
2014
1904
|
data = result;
|
|
1905
|
+
} else {
|
|
1906
|
+
console.warn("Modifier #" + i + " for type=" + _this18.type + " returned undefined, keeping previous data");
|
|
2015
1907
|
}
|
|
2016
1908
|
} catch (error) {
|
|
2017
|
-
console.error("Modifier error in do_serialize:", error.stack);
|
|
1909
|
+
console.error("Modifier error in do_serialize (type=" + _this18.type + ", modifier #" + i + "):", error instanceof Error ? error.stack : "Non-Error thrown: " + JSON.stringify(error));
|
|
2018
1910
|
}
|
|
2019
1911
|
} // Ensure data is always an array for consistent processing.
|
|
2020
1912
|
|
|
@@ -2023,42 +1915,33 @@ class SpiceModel {
|
|
|
2023
1915
|
|
|
2024
1916
|
if (!originalIsArray) {
|
|
2025
1917
|
data = [data];
|
|
2026
|
-
} //
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
var {
|
|
2030
|
-
staticDefaults,
|
|
2031
|
-
dynamicDefaults,
|
|
2032
|
-
hasDefaults
|
|
2033
|
-
} = _this18.getDefaultsMetadata(type);
|
|
2034
|
-
|
|
2035
|
-
if (hasDefaults) {
|
|
2036
|
-
data = data.map(item => {
|
|
2037
|
-
// Apply static defaults first (fast - no function calls)
|
|
2038
|
-
var result = _.defaults({}, item, staticDefaults); // Only compute dynamic defaults if there are any
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
for (var {
|
|
2042
|
-
key,
|
|
2043
|
-
fn
|
|
2044
|
-
} of dynamicDefaults) {
|
|
2045
|
-
if (result[key] === undefined) {
|
|
2046
|
-
result[key] = fn({
|
|
2047
|
-
old_data: data,
|
|
2048
|
-
new_data: old_data
|
|
2049
|
-
});
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
1918
|
+
} // Compute the defaults from properties using reduce.
|
|
2052
1919
|
|
|
2053
|
-
return result;
|
|
2054
|
-
});
|
|
2055
|
-
} // If type is "read", clean the data by omitting certain props.
|
|
2056
1920
|
|
|
1921
|
+
var defaults = Object.keys(_this18.props).reduce((acc, key) => {
|
|
1922
|
+
var _this18$props$key, _this18$props$key$def;
|
|
1923
|
+
|
|
1924
|
+
var def = (_this18$props$key = _this18.props[key]) == null ? void 0 : (_this18$props$key$def = _this18$props$key.defaults) == null ? void 0 : _this18$props$key$def[type];
|
|
1925
|
+
|
|
1926
|
+
if (def !== undefined) {
|
|
1927
|
+
acc[key] = _.isFunction(def) ? def({
|
|
1928
|
+
old_data: data,
|
|
1929
|
+
new_data: old_data
|
|
1930
|
+
}) : def;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
return acc;
|
|
1934
|
+
}, {}); // Merge defaults into each object.
|
|
1935
|
+
|
|
1936
|
+
data = data.map(item => _.defaults(item, defaults)); // If type is "read", clean the data by omitting certain props.
|
|
2057
1937
|
|
|
2058
1938
|
if (type === "read") {
|
|
2059
|
-
//
|
|
2060
|
-
var hiddenProps = _this18.
|
|
1939
|
+
// Collect hidden properties from schema.
|
|
1940
|
+
var hiddenProps = Object.keys(_this18.props).filter(key => {
|
|
1941
|
+
var _this18$props$key2;
|
|
2061
1942
|
|
|
1943
|
+
return (_this18$props$key2 = _this18.props[key]) == null ? void 0 : _this18$props$key2.hide;
|
|
1944
|
+
}); // Combine default props to remove.
|
|
2062
1945
|
|
|
2063
1946
|
var propsToClean = ["deleted", "type", ...path_to_be_removed, ...hiddenProps];
|
|
2064
1947
|
data = data.map(item => _.omit(item, propsToClean));
|
|
@@ -2082,7 +1965,7 @@ class SpiceModel {
|
|
|
2082
1965
|
|
|
2083
1966
|
return yield doSerialize();
|
|
2084
1967
|
} catch (error) {
|
|
2085
|
-
console.error("Error in do_serialize:", error.stack);
|
|
1968
|
+
console.error("Error in do_serialize:", error instanceof Error ? error.stack : "Non-Error thrown: " + JSON.stringify(error));
|
|
2086
1969
|
throw error;
|
|
2087
1970
|
}
|
|
2088
1971
|
})();
|
|
@@ -2090,6 +1973,4 @@ class SpiceModel {
|
|
|
2090
1973
|
|
|
2091
1974
|
}
|
|
2092
1975
|
|
|
2093
|
-
exports.default = SpiceModel;
|
|
2094
|
-
SpiceModel._defaultsCache = {};
|
|
2095
|
-
SpiceModel._hiddenPropsCache = {};
|
|
1976
|
+
exports.default = SpiceModel;
|
package/package.json
CHANGED
package/src/models/SpiceModel.js
CHANGED
|
@@ -44,10 +44,6 @@ if (!Promise.allSettled) {
|
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
46
|
export default class SpiceModel {
|
|
47
|
-
// ⚡ Static caches for performance optimization
|
|
48
|
-
static _defaultsCache = {};
|
|
49
|
-
static _hiddenPropsCache = {};
|
|
50
|
-
|
|
51
47
|
constructor(args = {}) {
|
|
52
48
|
try {
|
|
53
49
|
var dbtype =
|
|
@@ -1391,47 +1387,6 @@ export default class SpiceModel {
|
|
|
1391
1387
|
return true;
|
|
1392
1388
|
}
|
|
1393
1389
|
|
|
1394
|
-
// ⚡ OPTIMIZED: Cache defaults metadata per model type
|
|
1395
|
-
getDefaultsMetadata(type) {
|
|
1396
|
-
const cacheKey = `${this.type}::${type}`;
|
|
1397
|
-
|
|
1398
|
-
if (!SpiceModel._defaultsCache[cacheKey]) {
|
|
1399
|
-
const staticDefaults = {};
|
|
1400
|
-
const dynamicDefaults = [];
|
|
1401
|
-
|
|
1402
|
-
// Pre-compute once per model type
|
|
1403
|
-
for (const key in this.props) {
|
|
1404
|
-
const def = this.props[key]?.defaults?.[type];
|
|
1405
|
-
if (def !== undefined) {
|
|
1406
|
-
if (_.isFunction(def)) {
|
|
1407
|
-
dynamicDefaults.push({ key, fn: def });
|
|
1408
|
-
} else {
|
|
1409
|
-
staticDefaults[key] = def;
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
SpiceModel._defaultsCache[cacheKey] = {
|
|
1415
|
-
staticDefaults,
|
|
1416
|
-
dynamicDefaults,
|
|
1417
|
-
hasDefaults:
|
|
1418
|
-
Object.keys(staticDefaults).length > 0 || dynamicDefaults.length > 0,
|
|
1419
|
-
};
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
|
-
return SpiceModel._defaultsCache[cacheKey];
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
// ⚡ OPTIMIZED: Cache hidden props per model type
|
|
1426
|
-
getHiddenProps() {
|
|
1427
|
-
if (!SpiceModel._hiddenPropsCache[this.type]) {
|
|
1428
|
-
SpiceModel._hiddenPropsCache[this.type] = Object.keys(this.props).filter(
|
|
1429
|
-
(key) => this.props[key]?.hide
|
|
1430
|
-
);
|
|
1431
|
-
}
|
|
1432
|
-
return SpiceModel._hiddenPropsCache[this.type];
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
1390
|
// Check if a field is exempt from mapping depth limits
|
|
1436
1391
|
// Supports deep references like "group.permissions"
|
|
1437
1392
|
isFieldExempt(source_property) {
|
|
@@ -1634,14 +1589,9 @@ export default class SpiceModel {
|
|
|
1634
1589
|
return original_is_array ? data : data[0];
|
|
1635
1590
|
}
|
|
1636
1591
|
|
|
1637
|
-
addModifier({ when, execute
|
|
1592
|
+
addModifier({ when, execute }) {
|
|
1638
1593
|
if (this[_serializers][when]) {
|
|
1639
|
-
|
|
1640
|
-
this[_serializers][when]["modifiers"].push({
|
|
1641
|
-
execute,
|
|
1642
|
-
field,
|
|
1643
|
-
sourceField,
|
|
1644
|
-
});
|
|
1594
|
+
this[_serializers][when]["modifiers"].push(execute);
|
|
1645
1595
|
}
|
|
1646
1596
|
}
|
|
1647
1597
|
|
|
@@ -1662,14 +1612,11 @@ export default class SpiceModel {
|
|
|
1662
1612
|
if (properties[i].map) {
|
|
1663
1613
|
switch (properties[i].map.type) {
|
|
1664
1614
|
case MapType.MODEL: {
|
|
1665
|
-
const destinationField = properties[i].map.destination || i;
|
|
1666
1615
|
switch (properties[i].type) {
|
|
1667
1616
|
case String:
|
|
1668
1617
|
case "string": {
|
|
1669
1618
|
this.addModifier({
|
|
1670
1619
|
when: properties[i].map.when || "read",
|
|
1671
|
-
field: destinationField, // ⚡ Track which field this modifier populates
|
|
1672
|
-
sourceField: i, // ⚡ Track source property for column filtering
|
|
1673
1620
|
execute: async (data) => {
|
|
1674
1621
|
return await this.mapToObject(
|
|
1675
1622
|
data,
|
|
@@ -1677,7 +1624,7 @@ export default class SpiceModel {
|
|
|
1677
1624
|
spice.models[properties[i].map.reference]
|
|
1678
1625
|
: properties[i].map.reference,
|
|
1679
1626
|
i,
|
|
1680
|
-
|
|
1627
|
+
properties[i].map.destination || i,
|
|
1681
1628
|
properties[i]
|
|
1682
1629
|
);
|
|
1683
1630
|
},
|
|
@@ -1688,8 +1635,6 @@ export default class SpiceModel {
|
|
|
1688
1635
|
case "array": {
|
|
1689
1636
|
this.addModifier({
|
|
1690
1637
|
when: properties[i].map.when || "read",
|
|
1691
|
-
field: destinationField, // ⚡ Track which field this modifier populates
|
|
1692
|
-
sourceField: i, // ⚡ Track source property for column filtering
|
|
1693
1638
|
execute: async (data) => {
|
|
1694
1639
|
return await this.mapToObjectArray(
|
|
1695
1640
|
data,
|
|
@@ -1697,7 +1642,7 @@ export default class SpiceModel {
|
|
|
1697
1642
|
spice.models[properties[i].map.reference]
|
|
1698
1643
|
: properties[i].map.reference,
|
|
1699
1644
|
i,
|
|
1700
|
-
|
|
1645
|
+
properties[i].map.destination || i,
|
|
1701
1646
|
properties[i]
|
|
1702
1647
|
);
|
|
1703
1648
|
},
|
|
@@ -1715,41 +1660,6 @@ export default class SpiceModel {
|
|
|
1715
1660
|
}
|
|
1716
1661
|
}
|
|
1717
1662
|
|
|
1718
|
-
// ⚡ Parse columns string into a Set for fast lookup
|
|
1719
|
-
parseRequestedColumns(columns) {
|
|
1720
|
-
if (!columns || columns === "") return null;
|
|
1721
|
-
|
|
1722
|
-
// Handle array of columns (convert to string)
|
|
1723
|
-
if (Array.isArray(columns)) {
|
|
1724
|
-
columns = columns.join(",");
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
// Must be a string to parse
|
|
1728
|
-
if (typeof columns !== "string") return null;
|
|
1729
|
-
// Extract field names from column specifications
|
|
1730
|
-
// Handles: "field", "`field`", "table.field", "`table`.`field`", "expr AS alias"
|
|
1731
|
-
const fields = new Set();
|
|
1732
|
-
const columnList = columns.split(",").map((c) => c.trim());
|
|
1733
|
-
|
|
1734
|
-
for (const col of columnList) {
|
|
1735
|
-
// Check for AS alias
|
|
1736
|
-
const aliasMatch = col.match(/\s+AS\s+`?([\w]+)`?$/i);
|
|
1737
|
-
if (aliasMatch) {
|
|
1738
|
-
fields.add(aliasMatch[1]);
|
|
1739
|
-
continue;
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
|
-
// Get the last part after dots (the field name)
|
|
1743
|
-
const parts = col.replace(/`/g, "").split(".");
|
|
1744
|
-
const fieldName = parts[parts.length - 1];
|
|
1745
|
-
if (fieldName && fieldName !== "*") {
|
|
1746
|
-
fields.add(fieldName);
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
return fields.size > 0 ? fields : null;
|
|
1751
|
-
}
|
|
1752
|
-
|
|
1753
1663
|
async do_serialize(data, type, old_data, args, path_to_be_removed = []) {
|
|
1754
1664
|
// Profiling: use track() for proper async context forking
|
|
1755
1665
|
const p = this[_ctx]?.profiler;
|
|
@@ -1766,35 +1676,27 @@ export default class SpiceModel {
|
|
|
1766
1676
|
this[_external_modifier_loaded] = true;
|
|
1767
1677
|
}
|
|
1768
1678
|
|
|
1769
|
-
// ⚡ OPTIMIZED: Parse requested columns for selective modifier execution
|
|
1770
|
-
const requestedColumns = this.parseRequestedColumns(args?.columns);
|
|
1771
|
-
|
|
1772
1679
|
// Cache the modifiers lookup for the specified type.
|
|
1773
1680
|
const modifiers = this[_serializers]?.[type]?.modifiers || [];
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
for (const modifier of modifiers) {
|
|
1777
|
-
// Skip field-specific modifiers if columns specified and field is not requested
|
|
1778
|
-
if (
|
|
1779
|
-
requestedColumns &&
|
|
1780
|
-
modifier.field &&
|
|
1781
|
-
!requestedColumns.has(modifier.field) &&
|
|
1782
|
-
!(modifier.sourceField && requestedColumns.has(modifier.sourceField))
|
|
1783
|
-
) {
|
|
1784
|
-
continue;
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1681
|
+
for (let i = 0; i < modifiers.length; i++) {
|
|
1682
|
+
const modifier = modifiers[i];
|
|
1787
1683
|
try {
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
typeof modifier === "function" ? modifier : modifier.execute;
|
|
1791
|
-
const result = await executeFn(data, old_data, this[_ctx], this.type);
|
|
1792
|
-
// Only assign if modifier returned a value to prevent data corruption
|
|
1684
|
+
const result = await modifier(data, old_data, this[_ctx], this.type);
|
|
1685
|
+
// Guard against modifiers that return undefined
|
|
1793
1686
|
if (result !== undefined) {
|
|
1794
1687
|
data = result;
|
|
1688
|
+
} else {
|
|
1689
|
+
console.warn(
|
|
1690
|
+
`Modifier #${i} for type=${this.type} returned undefined, keeping previous data`
|
|
1691
|
+
);
|
|
1795
1692
|
}
|
|
1796
1693
|
} catch (error) {
|
|
1797
|
-
console.error(
|
|
1694
|
+
console.error(
|
|
1695
|
+
`Modifier error in do_serialize (type=${this.type}, modifier #${i}):`,
|
|
1696
|
+
error instanceof Error ?
|
|
1697
|
+
error.stack
|
|
1698
|
+
: `Non-Error thrown: ${JSON.stringify(error)}`
|
|
1699
|
+
);
|
|
1798
1700
|
}
|
|
1799
1701
|
}
|
|
1800
1702
|
|
|
@@ -1804,30 +1706,27 @@ export default class SpiceModel {
|
|
|
1804
1706
|
data = [data];
|
|
1805
1707
|
}
|
|
1806
1708
|
|
|
1807
|
-
//
|
|
1808
|
-
const
|
|
1809
|
-
this.
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
if (result[key] === undefined) {
|
|
1819
|
-
result[key] = fn({ old_data: data, new_data: old_data });
|
|
1820
|
-
}
|
|
1821
|
-
}
|
|
1709
|
+
// Compute the defaults from properties using reduce.
|
|
1710
|
+
const defaults = Object.keys(this.props).reduce((acc, key) => {
|
|
1711
|
+
const def = this.props[key]?.defaults?.[type];
|
|
1712
|
+
if (def !== undefined) {
|
|
1713
|
+
acc[key] =
|
|
1714
|
+
_.isFunction(def) ?
|
|
1715
|
+
def({ old_data: data, new_data: old_data })
|
|
1716
|
+
: def;
|
|
1717
|
+
}
|
|
1718
|
+
return acc;
|
|
1719
|
+
}, {});
|
|
1822
1720
|
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
}
|
|
1721
|
+
// Merge defaults into each object.
|
|
1722
|
+
data = data.map((item) => _.defaults(item, defaults));
|
|
1826
1723
|
|
|
1827
1724
|
// If type is "read", clean the data by omitting certain props.
|
|
1828
1725
|
if (type === "read") {
|
|
1829
|
-
//
|
|
1830
|
-
const hiddenProps = this.
|
|
1726
|
+
// Collect hidden properties from schema.
|
|
1727
|
+
const hiddenProps = Object.keys(this.props).filter(
|
|
1728
|
+
(key) => this.props[key]?.hide
|
|
1729
|
+
);
|
|
1831
1730
|
// Combine default props to remove.
|
|
1832
1731
|
const propsToClean = [
|
|
1833
1732
|
"deleted",
|
|
@@ -1850,7 +1749,12 @@ export default class SpiceModel {
|
|
|
1850
1749
|
}
|
|
1851
1750
|
return await doSerialize();
|
|
1852
1751
|
} catch (error) {
|
|
1853
|
-
console.error(
|
|
1752
|
+
console.error(
|
|
1753
|
+
"Error in do_serialize:",
|
|
1754
|
+
error instanceof Error ?
|
|
1755
|
+
error.stack
|
|
1756
|
+
: `Non-Error thrown: ${JSON.stringify(error)}`
|
|
1757
|
+
);
|
|
1854
1758
|
throw error;
|
|
1855
1759
|
}
|
|
1856
1760
|
}
|