spice-js 2.7.2 → 2.7.4
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 +186 -240
- package/package.json +1 -1
- package/src/models/SpiceModel.js +101 -171
|
@@ -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 = {};
|
|
@@ -704,50 +703,75 @@ class SpiceModel {
|
|
|
704
703
|
var _this6 = this;
|
|
705
704
|
|
|
706
705
|
return _asyncToGenerator(function* () {
|
|
707
|
-
|
|
708
|
-
if (!args) {
|
|
709
|
-
args = {};
|
|
710
|
-
}
|
|
706
|
+
var _this6$_ctx;
|
|
711
707
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
708
|
+
// ⚡ Profiling: use track() for proper async context forking
|
|
709
|
+
var p = (_this6$_ctx = _this6[_ctx]) == null ? void 0 : _this6$_ctx.profiler;
|
|
710
|
+
|
|
711
|
+
var doGetMulti =
|
|
712
|
+
/*#__PURE__*/
|
|
713
|
+
function () {
|
|
714
|
+
var _ref5 = _asyncToGenerator(function* () {
|
|
715
|
+
if (!args) {
|
|
716
|
+
args = {};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (args.skip_hooks != true) {
|
|
720
|
+
yield _this6.run_hook(_this6, "list", "before");
|
|
721
|
+
}
|
|
715
722
|
|
|
716
|
-
|
|
723
|
+
_.remove(args.ids, o => o == undefined);
|
|
717
724
|
|
|
718
|
-
|
|
725
|
+
var key = "multi-get::" + _this6.type + "::" + _.join(args.ids, "|");
|
|
719
726
|
|
|
720
|
-
|
|
727
|
+
var results = [];
|
|
721
728
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
729
|
+
if (args.ids.length > 0) {
|
|
730
|
+
if (_this6.shouldUseCache(_this6.type)) {
|
|
731
|
+
var cached_results = yield _this6.getCacheProviderObject(_this6.type).get(key);
|
|
732
|
+
results = cached_results == null ? void 0 : cached_results.value;
|
|
726
733
|
|
|
727
|
-
|
|
728
|
-
|
|
734
|
+
if ((cached_results == null ? void 0 : cached_results.value) === undefined || (yield _this6.shouldForceRefresh(cached_results))) {
|
|
735
|
+
results = yield _this6.database.multi_get(args.ids, true);
|
|
729
736
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
737
|
+
_this6.getCacheProviderObject(_this6.type).set(key, {
|
|
738
|
+
value: results,
|
|
739
|
+
time: new Date().getTime()
|
|
740
|
+
}, _this6.getCacheConfig(_this6.type));
|
|
741
|
+
}
|
|
742
|
+
} else {
|
|
743
|
+
results = yield _this6.database.multi_get(args.ids, true);
|
|
734
744
|
}
|
|
735
|
-
} else {
|
|
736
|
-
results = yield _this6.database.multi_get(args.ids, true);
|
|
737
745
|
}
|
|
738
|
-
}
|
|
739
746
|
|
|
740
|
-
|
|
747
|
+
_.remove(results, o => o.type != _this6.type);
|
|
741
748
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
749
|
+
if (args.skip_read_serialize != true && args.skip_serialize != true) {
|
|
750
|
+
results = yield _this6.do_serialize(results, "read", {}, args, (yield _this6.propsToBeRemoved(results)));
|
|
751
|
+
}
|
|
745
752
|
|
|
746
|
-
|
|
747
|
-
|
|
753
|
+
if (args.skip_hooks != true) {
|
|
754
|
+
yield _this6.run_hook(results, "list", "after", args.context);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
return results;
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
return function doGetMulti() {
|
|
761
|
+
return _ref5.apply(this, arguments);
|
|
762
|
+
};
|
|
763
|
+
}();
|
|
764
|
+
|
|
765
|
+
try {
|
|
766
|
+
if (p) {
|
|
767
|
+
var _args9, _args9$ids;
|
|
768
|
+
|
|
769
|
+
return yield p.track(_this6.type + ".getMulti", doGetMulti, {
|
|
770
|
+
ids_count: ((_args9 = args) == null ? void 0 : (_args9$ids = _args9.ids) == null ? void 0 : _args9$ids.length) || 0
|
|
771
|
+
});
|
|
748
772
|
}
|
|
749
773
|
|
|
750
|
-
return
|
|
774
|
+
return yield doGetMulti();
|
|
751
775
|
} catch (e) {
|
|
752
776
|
console.warn(e.stack);
|
|
753
777
|
throw e;
|
|
@@ -796,7 +820,7 @@ class SpiceModel {
|
|
|
796
820
|
var doUpdate =
|
|
797
821
|
/*#__PURE__*/
|
|
798
822
|
function () {
|
|
799
|
-
var
|
|
823
|
+
var _ref6 = _asyncToGenerator(function* () {
|
|
800
824
|
_this8.updated_at = new SDate().now();
|
|
801
825
|
var results = yield _this8.database.get(args.id);
|
|
802
826
|
var item_exist = yield _this8.exist(results);
|
|
@@ -855,7 +879,7 @@ class SpiceModel {
|
|
|
855
879
|
});
|
|
856
880
|
|
|
857
881
|
return function doUpdate() {
|
|
858
|
-
return
|
|
882
|
+
return _ref6.apply(this, arguments);
|
|
859
883
|
};
|
|
860
884
|
}();
|
|
861
885
|
|
|
@@ -890,7 +914,7 @@ class SpiceModel {
|
|
|
890
914
|
var doCreate =
|
|
891
915
|
/*#__PURE__*/
|
|
892
916
|
function () {
|
|
893
|
-
var
|
|
917
|
+
var _ref8 = _asyncToGenerator(function* () {
|
|
894
918
|
var form;
|
|
895
919
|
_this9.created_at = new SDate().now();
|
|
896
920
|
args = _.defaults(args, {
|
|
@@ -950,7 +974,7 @@ class SpiceModel {
|
|
|
950
974
|
});
|
|
951
975
|
|
|
952
976
|
return function doCreate() {
|
|
953
|
-
return
|
|
977
|
+
return _ref8.apply(this, arguments);
|
|
954
978
|
};
|
|
955
979
|
}();
|
|
956
980
|
|
|
@@ -1000,7 +1024,7 @@ class SpiceModel {
|
|
|
1000
1024
|
var doDelete =
|
|
1001
1025
|
/*#__PURE__*/
|
|
1002
1026
|
function () {
|
|
1003
|
-
var
|
|
1027
|
+
var _ref10 = _asyncToGenerator(function* () {
|
|
1004
1028
|
var item_exist = yield _this11.exist(args.id);
|
|
1005
1029
|
|
|
1006
1030
|
if (!item_exist) {
|
|
@@ -1018,7 +1042,7 @@ class SpiceModel {
|
|
|
1018
1042
|
var dbOperation =
|
|
1019
1043
|
/*#__PURE__*/
|
|
1020
1044
|
function () {
|
|
1021
|
-
var
|
|
1045
|
+
var _ref11 = _asyncToGenerator(function* () {
|
|
1022
1046
|
if (args.hard) {
|
|
1023
1047
|
delete_response = yield _this11.database.delete(args.id);
|
|
1024
1048
|
|
|
@@ -1031,7 +1055,7 @@ class SpiceModel {
|
|
|
1031
1055
|
});
|
|
1032
1056
|
|
|
1033
1057
|
return function dbOperation() {
|
|
1034
|
-
return
|
|
1058
|
+
return _ref11.apply(this, arguments);
|
|
1035
1059
|
};
|
|
1036
1060
|
}();
|
|
1037
1061
|
|
|
@@ -1049,7 +1073,7 @@ class SpiceModel {
|
|
|
1049
1073
|
});
|
|
1050
1074
|
|
|
1051
1075
|
return function doDelete() {
|
|
1052
|
-
return
|
|
1076
|
+
return _ref10.apply(this, arguments);
|
|
1053
1077
|
};
|
|
1054
1078
|
}();
|
|
1055
1079
|
|
|
@@ -1218,12 +1242,12 @@ class SpiceModel {
|
|
|
1218
1242
|
|
|
1219
1243
|
createJoinSection(mappedNestings) {
|
|
1220
1244
|
if (!mappedNestings || mappedNestings.length === 0) return "";
|
|
1221
|
-
return mappedNestings.map((
|
|
1245
|
+
return mappedNestings.map((_ref12) => {
|
|
1222
1246
|
var {
|
|
1223
1247
|
alias,
|
|
1224
1248
|
reference,
|
|
1225
1249
|
is_array
|
|
1226
|
-
} =
|
|
1250
|
+
} = _ref12;
|
|
1227
1251
|
var keyspace = (0, _fix.fixCollection)(reference);
|
|
1228
1252
|
|
|
1229
1253
|
if (is_array === true) {
|
|
@@ -1319,13 +1343,13 @@ class SpiceModel {
|
|
|
1319
1343
|
var doList =
|
|
1320
1344
|
/*#__PURE__*/
|
|
1321
1345
|
function () {
|
|
1322
|
-
var
|
|
1323
|
-
var
|
|
1346
|
+
var _ref13 = _asyncToGenerator(function* () {
|
|
1347
|
+
var _args10, _args11, _args12;
|
|
1324
1348
|
|
|
1325
1349
|
if (args.mapping_dept) _this12[_mapping_dept] = args.mapping_dept;
|
|
1326
1350
|
if (args.mapping_dept_exempt) _this12[_mapping_dept_exempt] = args.mapping_dept_exempt; // Find alias tokens from query/columns/sort
|
|
1327
1351
|
|
|
1328
|
-
var nestings = [..._this12.extractNestings(((
|
|
1352
|
+
var nestings = [..._this12.extractNestings(((_args10 = args) == null ? void 0 : _args10.query) || "", _this12.type), ..._this12.extractNestings(((_args11 = args) == null ? void 0 : _args11.columns) || "", _this12.type), ..._this12.extractNestings(((_args12 = args) == null ? void 0 : _args12.sort) || "", _this12.type)]; // Decide which aliases we can join: only when map.type===MODEL AND reference is a STRING keyspace.
|
|
1329
1353
|
|
|
1330
1354
|
var mappedNestings = _.compact(_.uniq(nestings).map(alias => {
|
|
1331
1355
|
var prop = _this12.props[alias];
|
|
@@ -1416,17 +1440,17 @@ class SpiceModel {
|
|
|
1416
1440
|
});
|
|
1417
1441
|
|
|
1418
1442
|
return function doList() {
|
|
1419
|
-
return
|
|
1443
|
+
return _ref13.apply(this, arguments);
|
|
1420
1444
|
};
|
|
1421
1445
|
}();
|
|
1422
1446
|
|
|
1423
1447
|
try {
|
|
1424
1448
|
if (p) {
|
|
1425
|
-
var
|
|
1449
|
+
var _args13, _args14;
|
|
1426
1450
|
|
|
1427
1451
|
return yield p.track(_this12.type + ".list", doList, {
|
|
1428
|
-
limit: (
|
|
1429
|
-
offset: (
|
|
1452
|
+
limit: (_args13 = args) == null ? void 0 : _args13.limit,
|
|
1453
|
+
offset: (_args14 = args) == null ? void 0 : _args14.offset
|
|
1430
1454
|
});
|
|
1431
1455
|
}
|
|
1432
1456
|
|
|
@@ -1450,7 +1474,7 @@ class SpiceModel {
|
|
|
1450
1474
|
var doFetch =
|
|
1451
1475
|
/*#__PURE__*/
|
|
1452
1476
|
function () {
|
|
1453
|
-
var
|
|
1477
|
+
var _ref14 = _asyncToGenerator(function* () {
|
|
1454
1478
|
if (args.is_custom_query === "true" && args.ids.length > 0) {
|
|
1455
1479
|
return yield _this13.database.query(query);
|
|
1456
1480
|
} else if (args.is_full_text === "true") {
|
|
@@ -1462,7 +1486,7 @@ class SpiceModel {
|
|
|
1462
1486
|
});
|
|
1463
1487
|
|
|
1464
1488
|
return function doFetch() {
|
|
1465
|
-
return
|
|
1489
|
+
return _ref14.apply(this, arguments);
|
|
1466
1490
|
};
|
|
1467
1491
|
}();
|
|
1468
1492
|
|
|
@@ -1474,12 +1498,12 @@ class SpiceModel {
|
|
|
1474
1498
|
})();
|
|
1475
1499
|
}
|
|
1476
1500
|
|
|
1477
|
-
addHook(
|
|
1501
|
+
addHook(_ref15) {
|
|
1478
1502
|
var {
|
|
1479
1503
|
operation,
|
|
1480
1504
|
when,
|
|
1481
1505
|
execute
|
|
1482
|
-
} =
|
|
1506
|
+
} = _ref15;
|
|
1483
1507
|
|
|
1484
1508
|
this[_hooks][operation][when].push(execute);
|
|
1485
1509
|
}
|
|
@@ -1534,54 +1558,6 @@ class SpiceModel {
|
|
|
1534
1558
|
}
|
|
1535
1559
|
|
|
1536
1560
|
return true;
|
|
1537
|
-
} // ⚡ OPTIMIZED: Cache defaults metadata per model type
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
getDefaultsMetadata(type) {
|
|
1541
|
-
var cacheKey = this.type + "::" + type;
|
|
1542
|
-
|
|
1543
|
-
if (!SpiceModel._defaultsCache[cacheKey]) {
|
|
1544
|
-
var staticDefaults = {};
|
|
1545
|
-
var dynamicDefaults = []; // Pre-compute once per model type
|
|
1546
|
-
|
|
1547
|
-
for (var key in this.props) {
|
|
1548
|
-
var _this$props$key, _this$props$key$defau;
|
|
1549
|
-
|
|
1550
|
-
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];
|
|
1551
|
-
|
|
1552
|
-
if (def !== undefined) {
|
|
1553
|
-
if (_.isFunction(def)) {
|
|
1554
|
-
dynamicDefaults.push({
|
|
1555
|
-
key,
|
|
1556
|
-
fn: def
|
|
1557
|
-
});
|
|
1558
|
-
} else {
|
|
1559
|
-
staticDefaults[key] = def;
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
|
|
1564
|
-
SpiceModel._defaultsCache[cacheKey] = {
|
|
1565
|
-
staticDefaults,
|
|
1566
|
-
dynamicDefaults,
|
|
1567
|
-
hasDefaults: Object.keys(staticDefaults).length > 0 || dynamicDefaults.length > 0
|
|
1568
|
-
};
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
return SpiceModel._defaultsCache[cacheKey];
|
|
1572
|
-
} // ⚡ OPTIMIZED: Cache hidden props per model type
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
getHiddenProps() {
|
|
1576
|
-
if (!SpiceModel._hiddenPropsCache[this.type]) {
|
|
1577
|
-
SpiceModel._hiddenPropsCache[this.type] = Object.keys(this.props).filter(key => {
|
|
1578
|
-
var _this$props$key2;
|
|
1579
|
-
|
|
1580
|
-
return (_this$props$key2 = this.props[key]) == null ? void 0 : _this$props$key2.hide;
|
|
1581
|
-
});
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
return SpiceModel._hiddenPropsCache[this.type];
|
|
1585
1561
|
} // Check if a field is exempt from mapping depth limits
|
|
1586
1562
|
// Supports deep references like "group.permissions"
|
|
1587
1563
|
|
|
@@ -1613,6 +1589,11 @@ class SpiceModel {
|
|
|
1613
1589
|
var _this15 = this;
|
|
1614
1590
|
|
|
1615
1591
|
return _asyncToGenerator(function* () {
|
|
1592
|
+
var _this15$_ctx;
|
|
1593
|
+
|
|
1594
|
+
// ⚡ Get profiler for proper async context forking
|
|
1595
|
+
var p = (_this15$_ctx = _this15[_ctx]) == null ? void 0 : _this15$_ctx.profiler;
|
|
1596
|
+
|
|
1616
1597
|
var original_is_array = _.isArray(data);
|
|
1617
1598
|
|
|
1618
1599
|
if (!original_is_array) {
|
|
@@ -1633,19 +1614,40 @@ class SpiceModel {
|
|
|
1633
1614
|
}); // Build the path for child models
|
|
1634
1615
|
|
|
1635
1616
|
|
|
1636
|
-
var childPath = _this15[_current_path] ? _this15[_current_path] + "." + source_property : source_property;
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1617
|
+
var childPath = _this15[_current_path] ? _this15[_current_path] + "." + source_property : source_property; // ⚡ Wrap in profiler track() to ensure proper async context for child operations
|
|
1618
|
+
|
|
1619
|
+
var fetchRelated =
|
|
1620
|
+
/*#__PURE__*/
|
|
1621
|
+
function () {
|
|
1622
|
+
var _ref16 = _asyncToGenerator(function* () {
|
|
1623
|
+
return yield Promise.allSettled(_.map(classes, obj => {
|
|
1624
|
+
return new obj(_extends({}, _this15[_args], {
|
|
1625
|
+
skip_cache: _this15[_skip_cache],
|
|
1626
|
+
_level: _this15[_level] + 1,
|
|
1627
|
+
mapping_dept: _this15[_mapping_dept],
|
|
1628
|
+
mapping_dept_exempt: _this15[_mapping_dept_exempt],
|
|
1629
|
+
_current_path: childPath
|
|
1630
|
+
})).getMulti({
|
|
1631
|
+
skip_hooks: true,
|
|
1632
|
+
ids: ids
|
|
1633
|
+
});
|
|
1634
|
+
}));
|
|
1647
1635
|
});
|
|
1648
|
-
|
|
1636
|
+
|
|
1637
|
+
return function fetchRelated() {
|
|
1638
|
+
return _ref16.apply(this, arguments);
|
|
1639
|
+
};
|
|
1640
|
+
}();
|
|
1641
|
+
|
|
1642
|
+
var returned_all;
|
|
1643
|
+
|
|
1644
|
+
if (p && ids.length > 0) {
|
|
1645
|
+
returned_all = yield p.track(_this15.type + ".map." + source_property, fetchRelated, {
|
|
1646
|
+
ids_count: ids.length
|
|
1647
|
+
});
|
|
1648
|
+
} else {
|
|
1649
|
+
returned_all = yield fetchRelated();
|
|
1650
|
+
}
|
|
1649
1651
|
|
|
1650
1652
|
var ug = _.flatten(_.compact(_.map(returned_all, returned_obj => {
|
|
1651
1653
|
if (returned_obj.status == "fulfilled") return returned_obj.value;
|
|
@@ -1668,6 +1670,11 @@ class SpiceModel {
|
|
|
1668
1670
|
var _this16 = this;
|
|
1669
1671
|
|
|
1670
1672
|
return _asyncToGenerator(function* () {
|
|
1673
|
+
var _this16$_ctx;
|
|
1674
|
+
|
|
1675
|
+
// ⚡ Get profiler for proper async context forking
|
|
1676
|
+
var p = (_this16$_ctx = _this16[_ctx]) == null ? void 0 : _this16$_ctx.profiler;
|
|
1677
|
+
|
|
1671
1678
|
var original_is_array = _.isArray(data);
|
|
1672
1679
|
|
|
1673
1680
|
if (!original_is_array) {
|
|
@@ -1698,28 +1705,45 @@ class SpiceModel {
|
|
|
1698
1705
|
|
|
1699
1706
|
var childPath = _this16[_current_path] ? _this16[_current_path] + "." + source_property : source_property;
|
|
1700
1707
|
|
|
1701
|
-
var classes = _.compact(_.isArray(Class) ? Class : [Class]);
|
|
1708
|
+
var classes = _.compact(_.isArray(Class) ? Class : [Class]); // ⚡ Wrap in profiler track() to ensure proper async context for child operations
|
|
1709
|
+
|
|
1710
|
+
|
|
1711
|
+
var fetchRelated =
|
|
1712
|
+
/*#__PURE__*/
|
|
1713
|
+
function () {
|
|
1714
|
+
var _ref17 = _asyncToGenerator(function* () {
|
|
1715
|
+
return yield Promise.allSettled(_.map(classes, obj => {
|
|
1716
|
+
return new obj(_extends({}, _this16[_args], {
|
|
1717
|
+
skip_cache: _this16[_skip_cache],
|
|
1718
|
+
_level: _this16[_level] + 1,
|
|
1719
|
+
mapping_dept: _this16[_mapping_dept],
|
|
1720
|
+
mapping_dept_exempt: _this16[_mapping_dept_exempt],
|
|
1721
|
+
_current_path: childPath
|
|
1722
|
+
})).getMulti({
|
|
1723
|
+
skip_hooks: true,
|
|
1724
|
+
ids: ids
|
|
1725
|
+
});
|
|
1726
|
+
}));
|
|
1727
|
+
});
|
|
1702
1728
|
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1729
|
+
return function fetchRelated() {
|
|
1730
|
+
return _ref17.apply(this, arguments);
|
|
1731
|
+
};
|
|
1732
|
+
}();
|
|
1733
|
+
|
|
1734
|
+
var returned_all;
|
|
1735
|
+
|
|
1736
|
+
if (p && ids.length > 0) {
|
|
1737
|
+
returned_all = yield p.track(_this16.type + ".mapArray." + source_property, fetchRelated, {
|
|
1738
|
+
ids_count: ids.length
|
|
1713
1739
|
});
|
|
1714
|
-
}
|
|
1740
|
+
} else {
|
|
1741
|
+
returned_all = yield fetchRelated();
|
|
1742
|
+
}
|
|
1715
1743
|
|
|
1716
1744
|
var returned_objects = _.flatten(_.compact(_.map(returned_all, returned_obj => {
|
|
1717
1745
|
if (returned_obj.status == "fulfilled") return returned_obj.value;
|
|
1718
1746
|
})));
|
|
1719
|
-
/* let returned_objects = await new Class().getMulti({
|
|
1720
|
-
ids: ids,
|
|
1721
|
-
}); */
|
|
1722
|
-
|
|
1723
1747
|
|
|
1724
1748
|
_.each(data, result => {
|
|
1725
1749
|
if (_.isString(result[store_property])) {
|
|
@@ -1740,21 +1764,14 @@ class SpiceModel {
|
|
|
1740
1764
|
})();
|
|
1741
1765
|
}
|
|
1742
1766
|
|
|
1743
|
-
addModifier(
|
|
1767
|
+
addModifier(_ref18) {
|
|
1744
1768
|
var {
|
|
1745
1769
|
when,
|
|
1746
|
-
execute
|
|
1747
|
-
|
|
1748
|
-
sourceField = null
|
|
1749
|
-
} = _ref15;
|
|
1770
|
+
execute
|
|
1771
|
+
} = _ref18;
|
|
1750
1772
|
|
|
1751
1773
|
if (this[_serializers][when]) {
|
|
1752
|
-
|
|
1753
|
-
this[_serializers][when]["modifiers"].push({
|
|
1754
|
-
execute,
|
|
1755
|
-
field,
|
|
1756
|
-
sourceField
|
|
1757
|
-
});
|
|
1774
|
+
this[_serializers][when]["modifiers"].push(execute);
|
|
1758
1775
|
}
|
|
1759
1776
|
}
|
|
1760
1777
|
|
|
@@ -1783,21 +1800,15 @@ class SpiceModel {
|
|
|
1783
1800
|
switch (properties[i].map.type) {
|
|
1784
1801
|
case _2.MapType.MODEL:
|
|
1785
1802
|
{
|
|
1786
|
-
var destinationField = properties[i].map.destination || i;
|
|
1787
|
-
|
|
1788
1803
|
switch (properties[i].type) {
|
|
1789
1804
|
case String:
|
|
1790
1805
|
case "string":
|
|
1791
1806
|
{
|
|
1792
1807
|
_this17.addModifier({
|
|
1793
1808
|
when: properties[i].map.when || "read",
|
|
1794
|
-
field: destinationField,
|
|
1795
|
-
// ⚡ Track which field this modifier populates
|
|
1796
|
-
sourceField: i,
|
|
1797
|
-
// ⚡ Track source property for column filtering
|
|
1798
1809
|
execute: function () {
|
|
1799
1810
|
var _execute = _asyncToGenerator(function* (data) {
|
|
1800
|
-
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]);
|
|
1801
1812
|
});
|
|
1802
1813
|
|
|
1803
1814
|
function execute(_x) {
|
|
@@ -1816,13 +1827,9 @@ class SpiceModel {
|
|
|
1816
1827
|
{
|
|
1817
1828
|
_this17.addModifier({
|
|
1818
1829
|
when: properties[i].map.when || "read",
|
|
1819
|
-
field: destinationField,
|
|
1820
|
-
// ⚡ Track which field this modifier populates
|
|
1821
|
-
sourceField: i,
|
|
1822
|
-
// ⚡ Track source property for column filtering
|
|
1823
1830
|
execute: function () {
|
|
1824
1831
|
var _execute2 = _asyncToGenerator(function* (data) {
|
|
1825
|
-
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]);
|
|
1826
1833
|
});
|
|
1827
1834
|
|
|
1828
1835
|
function execute(_x2) {
|
|
@@ -1851,42 +1858,6 @@ class SpiceModel {
|
|
|
1851
1858
|
for (var i in properties) {
|
|
1852
1859
|
_loop(i);
|
|
1853
1860
|
}
|
|
1854
|
-
} // ⚡ Parse columns string into a Set for fast lookup
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
parseRequestedColumns(columns) {
|
|
1858
|
-
if (!columns || columns === "") return null; // Handle array of columns (convert to string)
|
|
1859
|
-
|
|
1860
|
-
if (Array.isArray(columns)) {
|
|
1861
|
-
columns = columns.join(",");
|
|
1862
|
-
} // Must be a string to parse
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
if (typeof columns !== "string") return null; // Extract field names from column specifications
|
|
1866
|
-
// Handles: "field", "`field`", "table.field", "`table`.`field`", "expr AS alias"
|
|
1867
|
-
|
|
1868
|
-
var fields = new Set();
|
|
1869
|
-
var columnList = columns.split(",").map(c => c.trim());
|
|
1870
|
-
|
|
1871
|
-
for (var col of columnList) {
|
|
1872
|
-
// Check for AS alias
|
|
1873
|
-
var aliasMatch = col.match(/\s+AS\s+`?([\w]+)`?$/i);
|
|
1874
|
-
|
|
1875
|
-
if (aliasMatch) {
|
|
1876
|
-
fields.add(aliasMatch[1]);
|
|
1877
|
-
continue;
|
|
1878
|
-
} // Get the last part after dots (the field name)
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
var parts = col.replace(/`/g, "").split(".");
|
|
1882
|
-
var fieldName = parts[parts.length - 1];
|
|
1883
|
-
|
|
1884
|
-
if (fieldName && fieldName !== "*") {
|
|
1885
|
-
fields.add(fieldName);
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
return fields.size > 0 ? fields : null;
|
|
1890
1861
|
}
|
|
1891
1862
|
|
|
1892
1863
|
do_serialize(data, type, old_data, args, path_to_be_removed) {
|
|
@@ -1905,7 +1876,7 @@ class SpiceModel {
|
|
|
1905
1876
|
var doSerialize =
|
|
1906
1877
|
/*#__PURE__*/
|
|
1907
1878
|
function () {
|
|
1908
|
-
var
|
|
1879
|
+
var _ref19 = _asyncToGenerator(function* () {
|
|
1909
1880
|
var _this18$_serializers, _this18$_serializers$;
|
|
1910
1881
|
|
|
1911
1882
|
// Early exit if serialization should not run.
|
|
@@ -1918,28 +1889,14 @@ class SpiceModel {
|
|
|
1918
1889
|
_this18.addExternalModifiers(_this18.type);
|
|
1919
1890
|
|
|
1920
1891
|
_this18[_external_modifier_loaded] = true;
|
|
1921
|
-
} //
|
|
1922
|
-
|
|
1892
|
+
} // Cache the modifiers lookup for the specified type.
|
|
1923
1893
|
|
|
1924
|
-
var requestedColumns = _this18.parseRequestedColumns(args == null ? void 0 : args.columns); // Cache the modifiers lookup for the specified type.
|
|
1925
1894
|
|
|
1926
|
-
|
|
1927
|
-
var modifiers = ((_this18$_serializers = _this18[_serializers]) == null ? void 0 : (_this18$_serializers$ = _this18$_serializers[type]) == null ? void 0 : _this18$_serializers$.modifiers) || []; // Run modifiers serially
|
|
1895
|
+
var modifiers = ((_this18$_serializers = _this18[_serializers]) == null ? void 0 : (_this18$_serializers$ = _this18$_serializers[type]) == null ? void 0 : _this18$_serializers$.modifiers) || [];
|
|
1928
1896
|
|
|
1929
1897
|
for (var modifier of modifiers) {
|
|
1930
|
-
// Skip field-specific modifiers if columns specified and field is not requested
|
|
1931
|
-
if (requestedColumns && modifier.field && !requestedColumns.has(modifier.field) && !(modifier.sourceField && requestedColumns.has(modifier.sourceField))) {
|
|
1932
|
-
continue;
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
1898
|
try {
|
|
1936
|
-
|
|
1937
|
-
var executeFn = typeof modifier === "function" ? modifier : modifier.execute;
|
|
1938
|
-
var result = yield executeFn(data, old_data, _this18[_ctx], _this18.type); // Only assign if modifier returned a value to prevent data corruption
|
|
1939
|
-
|
|
1940
|
-
if (result !== undefined) {
|
|
1941
|
-
data = result;
|
|
1942
|
-
}
|
|
1899
|
+
data = yield modifier(data, old_data, _this18[_ctx], _this18.type);
|
|
1943
1900
|
} catch (error) {
|
|
1944
1901
|
console.error("Modifier error in do_serialize:", error.stack);
|
|
1945
1902
|
}
|
|
@@ -1950,42 +1907,33 @@ class SpiceModel {
|
|
|
1950
1907
|
|
|
1951
1908
|
if (!originalIsArray) {
|
|
1952
1909
|
data = [data];
|
|
1953
|
-
} //
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
var {
|
|
1957
|
-
staticDefaults,
|
|
1958
|
-
dynamicDefaults,
|
|
1959
|
-
hasDefaults
|
|
1960
|
-
} = _this18.getDefaultsMetadata(type);
|
|
1961
|
-
|
|
1962
|
-
if (hasDefaults) {
|
|
1963
|
-
data = data.map(item => {
|
|
1964
|
-
// Apply static defaults first (fast - no function calls)
|
|
1965
|
-
var result = _.defaults({}, item, staticDefaults); // Only compute dynamic defaults if there are any
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
for (var {
|
|
1969
|
-
key,
|
|
1970
|
-
fn
|
|
1971
|
-
} of dynamicDefaults) {
|
|
1972
|
-
if (result[key] === undefined) {
|
|
1973
|
-
result[key] = fn({
|
|
1974
|
-
old_data: data,
|
|
1975
|
-
new_data: old_data
|
|
1976
|
-
});
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1910
|
+
} // Compute the defaults from properties using reduce.
|
|
1979
1911
|
|
|
1980
|
-
return result;
|
|
1981
|
-
});
|
|
1982
|
-
} // If type is "read", clean the data by omitting certain props.
|
|
1983
1912
|
|
|
1913
|
+
var defaults = Object.keys(_this18.props).reduce((acc, key) => {
|
|
1914
|
+
var _this18$props$key, _this18$props$key$def;
|
|
1915
|
+
|
|
1916
|
+
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];
|
|
1917
|
+
|
|
1918
|
+
if (def !== undefined) {
|
|
1919
|
+
acc[key] = _.isFunction(def) ? def({
|
|
1920
|
+
old_data: data,
|
|
1921
|
+
new_data: old_data
|
|
1922
|
+
}) : def;
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
return acc;
|
|
1926
|
+
}, {}); // Merge defaults into each object.
|
|
1927
|
+
|
|
1928
|
+
data = data.map(item => _.defaults(item, defaults)); // If type is "read", clean the data by omitting certain props.
|
|
1984
1929
|
|
|
1985
1930
|
if (type === "read") {
|
|
1986
|
-
//
|
|
1987
|
-
var hiddenProps = _this18.
|
|
1931
|
+
// Collect hidden properties from schema.
|
|
1932
|
+
var hiddenProps = Object.keys(_this18.props).filter(key => {
|
|
1933
|
+
var _this18$props$key2;
|
|
1988
1934
|
|
|
1935
|
+
return (_this18$props$key2 = _this18.props[key]) == null ? void 0 : _this18$props$key2.hide;
|
|
1936
|
+
}); // Combine default props to remove.
|
|
1989
1937
|
|
|
1990
1938
|
var propsToClean = ["deleted", "type", ...path_to_be_removed, ...hiddenProps];
|
|
1991
1939
|
data = data.map(item => _.omit(item, propsToClean));
|
|
@@ -1996,7 +1944,7 @@ class SpiceModel {
|
|
|
1996
1944
|
});
|
|
1997
1945
|
|
|
1998
1946
|
return function doSerialize() {
|
|
1999
|
-
return
|
|
1947
|
+
return _ref19.apply(this, arguments);
|
|
2000
1948
|
};
|
|
2001
1949
|
}();
|
|
2002
1950
|
|
|
@@ -2017,6 +1965,4 @@ class SpiceModel {
|
|
|
2017
1965
|
|
|
2018
1966
|
}
|
|
2019
1967
|
|
|
2020
|
-
exports.default = SpiceModel;
|
|
2021
|
-
SpiceModel._defaultsCache = {};
|
|
2022
|
-
SpiceModel._hiddenPropsCache = {};
|
|
1968
|
+
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 =
|
|
@@ -606,7 +602,10 @@ export default class SpiceModel {
|
|
|
606
602
|
}
|
|
607
603
|
|
|
608
604
|
async getMulti(args) {
|
|
609
|
-
|
|
605
|
+
// ⚡ Profiling: use track() for proper async context forking
|
|
606
|
+
const p = this[_ctx]?.profiler;
|
|
607
|
+
|
|
608
|
+
const doGetMulti = async () => {
|
|
610
609
|
if (!args) {
|
|
611
610
|
args = {};
|
|
612
611
|
}
|
|
@@ -653,6 +652,15 @@ export default class SpiceModel {
|
|
|
653
652
|
}
|
|
654
653
|
|
|
655
654
|
return results;
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
try {
|
|
658
|
+
if (p) {
|
|
659
|
+
return await p.track(`${this.type}.getMulti`, doGetMulti, {
|
|
660
|
+
ids_count: args?.ids?.length || 0,
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
return await doGetMulti();
|
|
656
664
|
} catch (e) {
|
|
657
665
|
console.warn(e.stack);
|
|
658
666
|
throw e;
|
|
@@ -1379,47 +1387,6 @@ export default class SpiceModel {
|
|
|
1379
1387
|
return true;
|
|
1380
1388
|
}
|
|
1381
1389
|
|
|
1382
|
-
// ⚡ OPTIMIZED: Cache defaults metadata per model type
|
|
1383
|
-
getDefaultsMetadata(type) {
|
|
1384
|
-
const cacheKey = `${this.type}::${type}`;
|
|
1385
|
-
|
|
1386
|
-
if (!SpiceModel._defaultsCache[cacheKey]) {
|
|
1387
|
-
const staticDefaults = {};
|
|
1388
|
-
const dynamicDefaults = [];
|
|
1389
|
-
|
|
1390
|
-
// Pre-compute once per model type
|
|
1391
|
-
for (const key in this.props) {
|
|
1392
|
-
const def = this.props[key]?.defaults?.[type];
|
|
1393
|
-
if (def !== undefined) {
|
|
1394
|
-
if (_.isFunction(def)) {
|
|
1395
|
-
dynamicDefaults.push({ key, fn: def });
|
|
1396
|
-
} else {
|
|
1397
|
-
staticDefaults[key] = def;
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
SpiceModel._defaultsCache[cacheKey] = {
|
|
1403
|
-
staticDefaults,
|
|
1404
|
-
dynamicDefaults,
|
|
1405
|
-
hasDefaults:
|
|
1406
|
-
Object.keys(staticDefaults).length > 0 || dynamicDefaults.length > 0,
|
|
1407
|
-
};
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
return SpiceModel._defaultsCache[cacheKey];
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
// ⚡ OPTIMIZED: Cache hidden props per model type
|
|
1414
|
-
getHiddenProps() {
|
|
1415
|
-
if (!SpiceModel._hiddenPropsCache[this.type]) {
|
|
1416
|
-
SpiceModel._hiddenPropsCache[this.type] = Object.keys(this.props).filter(
|
|
1417
|
-
(key) => this.props[key]?.hide
|
|
1418
|
-
);
|
|
1419
|
-
}
|
|
1420
|
-
return SpiceModel._hiddenPropsCache[this.type];
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
1390
|
// Check if a field is exempt from mapping depth limits
|
|
1424
1391
|
// Supports deep references like "group.permissions"
|
|
1425
1392
|
isFieldExempt(source_property) {
|
|
@@ -1445,6 +1412,9 @@ export default class SpiceModel {
|
|
|
1445
1412
|
}
|
|
1446
1413
|
|
|
1447
1414
|
async mapToObject(data, Class, source_property, store_property, property) {
|
|
1415
|
+
// ⚡ Get profiler for proper async context forking
|
|
1416
|
+
const p = this[_ctx]?.profiler;
|
|
1417
|
+
|
|
1448
1418
|
let original_is_array = _.isArray(data);
|
|
1449
1419
|
if (!original_is_array) {
|
|
1450
1420
|
data = Array.of(data);
|
|
@@ -1469,21 +1439,36 @@ export default class SpiceModel {
|
|
|
1469
1439
|
`${this[_current_path]}.${source_property}`
|
|
1470
1440
|
: source_property;
|
|
1471
1441
|
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1442
|
+
// ⚡ Wrap in profiler track() to ensure proper async context for child operations
|
|
1443
|
+
const fetchRelated = async () => {
|
|
1444
|
+
return await Promise.allSettled(
|
|
1445
|
+
_.map(classes, (obj) => {
|
|
1446
|
+
return new obj({
|
|
1447
|
+
...this[_args],
|
|
1448
|
+
skip_cache: this[_skip_cache],
|
|
1449
|
+
_level: this[_level] + 1,
|
|
1450
|
+
mapping_dept: this[_mapping_dept],
|
|
1451
|
+
mapping_dept_exempt: this[_mapping_dept_exempt],
|
|
1452
|
+
_current_path: childPath,
|
|
1453
|
+
}).getMulti({
|
|
1454
|
+
skip_hooks: true,
|
|
1455
|
+
ids: ids,
|
|
1456
|
+
});
|
|
1457
|
+
})
|
|
1458
|
+
);
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
var returned_all;
|
|
1462
|
+
if (p && ids.length > 0) {
|
|
1463
|
+
returned_all = await p.track(
|
|
1464
|
+
`${this.type}.map.${source_property}`,
|
|
1465
|
+
fetchRelated,
|
|
1466
|
+
{ ids_count: ids.length }
|
|
1467
|
+
);
|
|
1468
|
+
} else {
|
|
1469
|
+
returned_all = await fetchRelated();
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1487
1472
|
let ug = _.flatten(
|
|
1488
1473
|
_.compact(
|
|
1489
1474
|
_.map(returned_all, (returned_obj) => {
|
|
@@ -1511,6 +1496,9 @@ export default class SpiceModel {
|
|
|
1511
1496
|
store_property,
|
|
1512
1497
|
property
|
|
1513
1498
|
) {
|
|
1499
|
+
// ⚡ Get profiler for proper async context forking
|
|
1500
|
+
const p = this[_ctx]?.profiler;
|
|
1501
|
+
|
|
1514
1502
|
let original_is_array = _.isArray(data);
|
|
1515
1503
|
if (!original_is_array) {
|
|
1516
1504
|
data = Array.of(data);
|
|
@@ -1540,21 +1528,36 @@ export default class SpiceModel {
|
|
|
1540
1528
|
: source_property;
|
|
1541
1529
|
|
|
1542
1530
|
let classes = _.compact(_.isArray(Class) ? Class : [Class]);
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1531
|
+
|
|
1532
|
+
// ⚡ Wrap in profiler track() to ensure proper async context for child operations
|
|
1533
|
+
const fetchRelated = async () => {
|
|
1534
|
+
return await Promise.allSettled(
|
|
1535
|
+
_.map(classes, (obj) => {
|
|
1536
|
+
return new obj({
|
|
1537
|
+
...this[_args],
|
|
1538
|
+
skip_cache: this[_skip_cache],
|
|
1539
|
+
_level: this[_level] + 1,
|
|
1540
|
+
mapping_dept: this[_mapping_dept],
|
|
1541
|
+
mapping_dept_exempt: this[_mapping_dept_exempt],
|
|
1542
|
+
_current_path: childPath,
|
|
1543
|
+
}).getMulti({
|
|
1544
|
+
skip_hooks: true,
|
|
1545
|
+
ids: ids,
|
|
1546
|
+
});
|
|
1547
|
+
})
|
|
1548
|
+
);
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
var returned_all;
|
|
1552
|
+
if (p && ids.length > 0) {
|
|
1553
|
+
returned_all = await p.track(
|
|
1554
|
+
`${this.type}.mapArray.${source_property}`,
|
|
1555
|
+
fetchRelated,
|
|
1556
|
+
{ ids_count: ids.length }
|
|
1557
|
+
);
|
|
1558
|
+
} else {
|
|
1559
|
+
returned_all = await fetchRelated();
|
|
1560
|
+
}
|
|
1558
1561
|
|
|
1559
1562
|
var returned_objects = _.flatten(
|
|
1560
1563
|
_.compact(
|
|
@@ -1564,9 +1567,6 @@ export default class SpiceModel {
|
|
|
1564
1567
|
)
|
|
1565
1568
|
);
|
|
1566
1569
|
|
|
1567
|
-
/* let returned_objects = await new Class().getMulti({
|
|
1568
|
-
ids: ids,
|
|
1569
|
-
}); */
|
|
1570
1570
|
_.each(data, (result) => {
|
|
1571
1571
|
if (_.isString(result[store_property])) {
|
|
1572
1572
|
result[store_property] = [result[store_property]];
|
|
@@ -1589,14 +1589,9 @@ export default class SpiceModel {
|
|
|
1589
1589
|
return original_is_array ? data : data[0];
|
|
1590
1590
|
}
|
|
1591
1591
|
|
|
1592
|
-
addModifier({ when, execute
|
|
1592
|
+
addModifier({ when, execute }) {
|
|
1593
1593
|
if (this[_serializers][when]) {
|
|
1594
|
-
|
|
1595
|
-
this[_serializers][when]["modifiers"].push({
|
|
1596
|
-
execute,
|
|
1597
|
-
field,
|
|
1598
|
-
sourceField,
|
|
1599
|
-
});
|
|
1594
|
+
this[_serializers][when]["modifiers"].push(execute);
|
|
1600
1595
|
}
|
|
1601
1596
|
}
|
|
1602
1597
|
|
|
@@ -1617,14 +1612,11 @@ export default class SpiceModel {
|
|
|
1617
1612
|
if (properties[i].map) {
|
|
1618
1613
|
switch (properties[i].map.type) {
|
|
1619
1614
|
case MapType.MODEL: {
|
|
1620
|
-
const destinationField = properties[i].map.destination || i;
|
|
1621
1615
|
switch (properties[i].type) {
|
|
1622
1616
|
case String:
|
|
1623
1617
|
case "string": {
|
|
1624
1618
|
this.addModifier({
|
|
1625
1619
|
when: properties[i].map.when || "read",
|
|
1626
|
-
field: destinationField, // ⚡ Track which field this modifier populates
|
|
1627
|
-
sourceField: i, // ⚡ Track source property for column filtering
|
|
1628
1620
|
execute: async (data) => {
|
|
1629
1621
|
return await this.mapToObject(
|
|
1630
1622
|
data,
|
|
@@ -1632,7 +1624,7 @@ export default class SpiceModel {
|
|
|
1632
1624
|
spice.models[properties[i].map.reference]
|
|
1633
1625
|
: properties[i].map.reference,
|
|
1634
1626
|
i,
|
|
1635
|
-
|
|
1627
|
+
properties[i].map.destination || i,
|
|
1636
1628
|
properties[i]
|
|
1637
1629
|
);
|
|
1638
1630
|
},
|
|
@@ -1643,8 +1635,6 @@ export default class SpiceModel {
|
|
|
1643
1635
|
case "array": {
|
|
1644
1636
|
this.addModifier({
|
|
1645
1637
|
when: properties[i].map.when || "read",
|
|
1646
|
-
field: destinationField, // ⚡ Track which field this modifier populates
|
|
1647
|
-
sourceField: i, // ⚡ Track source property for column filtering
|
|
1648
1638
|
execute: async (data) => {
|
|
1649
1639
|
return await this.mapToObjectArray(
|
|
1650
1640
|
data,
|
|
@@ -1652,7 +1642,7 @@ export default class SpiceModel {
|
|
|
1652
1642
|
spice.models[properties[i].map.reference]
|
|
1653
1643
|
: properties[i].map.reference,
|
|
1654
1644
|
i,
|
|
1655
|
-
|
|
1645
|
+
properties[i].map.destination || i,
|
|
1656
1646
|
properties[i]
|
|
1657
1647
|
);
|
|
1658
1648
|
},
|
|
@@ -1670,41 +1660,6 @@ export default class SpiceModel {
|
|
|
1670
1660
|
}
|
|
1671
1661
|
}
|
|
1672
1662
|
|
|
1673
|
-
// ⚡ Parse columns string into a Set for fast lookup
|
|
1674
|
-
parseRequestedColumns(columns) {
|
|
1675
|
-
if (!columns || columns === "") return null;
|
|
1676
|
-
|
|
1677
|
-
// Handle array of columns (convert to string)
|
|
1678
|
-
if (Array.isArray(columns)) {
|
|
1679
|
-
columns = columns.join(",");
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
// Must be a string to parse
|
|
1683
|
-
if (typeof columns !== "string") return null;
|
|
1684
|
-
// Extract field names from column specifications
|
|
1685
|
-
// Handles: "field", "`field`", "table.field", "`table`.`field`", "expr AS alias"
|
|
1686
|
-
const fields = new Set();
|
|
1687
|
-
const columnList = columns.split(",").map((c) => c.trim());
|
|
1688
|
-
|
|
1689
|
-
for (const col of columnList) {
|
|
1690
|
-
// Check for AS alias
|
|
1691
|
-
const aliasMatch = col.match(/\s+AS\s+`?([\w]+)`?$/i);
|
|
1692
|
-
if (aliasMatch) {
|
|
1693
|
-
fields.add(aliasMatch[1]);
|
|
1694
|
-
continue;
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
// Get the last part after dots (the field name)
|
|
1698
|
-
const parts = col.replace(/`/g, "").split(".");
|
|
1699
|
-
const fieldName = parts[parts.length - 1];
|
|
1700
|
-
if (fieldName && fieldName !== "*") {
|
|
1701
|
-
fields.add(fieldName);
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
return fields.size > 0 ? fields : null;
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
1663
|
async do_serialize(data, type, old_data, args, path_to_be_removed = []) {
|
|
1709
1664
|
// Profiling: use track() for proper async context forking
|
|
1710
1665
|
const p = this[_ctx]?.profiler;
|
|
@@ -1721,33 +1676,11 @@ export default class SpiceModel {
|
|
|
1721
1676
|
this[_external_modifier_loaded] = true;
|
|
1722
1677
|
}
|
|
1723
1678
|
|
|
1724
|
-
// ⚡ OPTIMIZED: Parse requested columns for selective modifier execution
|
|
1725
|
-
const requestedColumns = this.parseRequestedColumns(args?.columns);
|
|
1726
|
-
|
|
1727
1679
|
// Cache the modifiers lookup for the specified type.
|
|
1728
1680
|
const modifiers = this[_serializers]?.[type]?.modifiers || [];
|
|
1729
|
-
|
|
1730
|
-
// Run modifiers serially
|
|
1731
1681
|
for (const modifier of modifiers) {
|
|
1732
|
-
// Skip field-specific modifiers if columns specified and field is not requested
|
|
1733
|
-
if (
|
|
1734
|
-
requestedColumns &&
|
|
1735
|
-
modifier.field &&
|
|
1736
|
-
!requestedColumns.has(modifier.field) &&
|
|
1737
|
-
!(modifier.sourceField && requestedColumns.has(modifier.sourceField))
|
|
1738
|
-
) {
|
|
1739
|
-
continue;
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
1682
|
try {
|
|
1743
|
-
|
|
1744
|
-
const executeFn =
|
|
1745
|
-
typeof modifier === "function" ? modifier : modifier.execute;
|
|
1746
|
-
const result = await executeFn(data, old_data, this[_ctx], this.type);
|
|
1747
|
-
// Only assign if modifier returned a value to prevent data corruption
|
|
1748
|
-
if (result !== undefined) {
|
|
1749
|
-
data = result;
|
|
1750
|
-
}
|
|
1683
|
+
data = await modifier(data, old_data, this[_ctx], this.type);
|
|
1751
1684
|
} catch (error) {
|
|
1752
1685
|
console.error("Modifier error in do_serialize:", error.stack);
|
|
1753
1686
|
}
|
|
@@ -1759,30 +1692,27 @@ export default class SpiceModel {
|
|
|
1759
1692
|
data = [data];
|
|
1760
1693
|
}
|
|
1761
1694
|
|
|
1762
|
-
//
|
|
1763
|
-
const
|
|
1764
|
-
this.
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
if (result[key] === undefined) {
|
|
1774
|
-
result[key] = fn({ old_data: data, new_data: old_data });
|
|
1775
|
-
}
|
|
1776
|
-
}
|
|
1695
|
+
// Compute the defaults from properties using reduce.
|
|
1696
|
+
const defaults = Object.keys(this.props).reduce((acc, key) => {
|
|
1697
|
+
const def = this.props[key]?.defaults?.[type];
|
|
1698
|
+
if (def !== undefined) {
|
|
1699
|
+
acc[key] =
|
|
1700
|
+
_.isFunction(def) ?
|
|
1701
|
+
def({ old_data: data, new_data: old_data })
|
|
1702
|
+
: def;
|
|
1703
|
+
}
|
|
1704
|
+
return acc;
|
|
1705
|
+
}, {});
|
|
1777
1706
|
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
}
|
|
1707
|
+
// Merge defaults into each object.
|
|
1708
|
+
data = data.map((item) => _.defaults(item, defaults));
|
|
1781
1709
|
|
|
1782
1710
|
// If type is "read", clean the data by omitting certain props.
|
|
1783
1711
|
if (type === "read") {
|
|
1784
|
-
//
|
|
1785
|
-
const hiddenProps = this.
|
|
1712
|
+
// Collect hidden properties from schema.
|
|
1713
|
+
const hiddenProps = Object.keys(this.props).filter(
|
|
1714
|
+
(key) => this.props[key]?.hide
|
|
1715
|
+
);
|
|
1786
1716
|
// Combine default props to remove.
|
|
1787
1717
|
const propsToClean = [
|
|
1788
1718
|
"deleted",
|