spice-js 2.7.29 → 2.7.31

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.
@@ -7,9 +7,9 @@ var _ResourceLifecycleTriggered = _interopRequireDefault(require("../events/even
7
7
  var _Security = require("../utility/Security");
8
8
  var _fix = require("../utility/fix");
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) { ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } } return n; }, _extends.apply(null, arguments); }
10
11
  function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
11
12
  function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
12
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) { ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } } return n; }, _extends.apply(null, arguments); }
13
13
  var co = require("co");
14
14
  var regeneratorRuntime = require("regenerator-runtime");
15
15
  var SDate = require("sonover-date"),
@@ -27,11 +27,76 @@ var SDate = require("sonover-date"),
27
27
  _serializers = Symbol(),
28
28
  _level = Symbol(),
29
29
  _mapping_dept = Symbol(),
30
+ _mapping_dept_scalar = Symbol(),
31
+ _mapping_dept_array = Symbol(),
32
+ _mapping_concurrency = Symbol(),
33
+ _skip_mapped_serialization = Symbol(),
30
34
  _mapping_dept_exempt = Symbol(),
31
35
  _current_path = Symbol();
32
-
33
- //const _type = Symbol("type");
34
-
36
+ var GLOBAL_MAPPING_CONCURRENCY = Math.max(1, Number(process.env.SPICE_MAPPING_GLOBAL_CONCURRENCY) || 32);
37
+ var activeGlobalMappings = 0;
38
+ var globalMappingWaiters = [];
39
+ function normalizeConcurrency(value, fallback) {
40
+ if (fallback === void 0) {
41
+ fallback = 1;
42
+ }
43
+ var parsed = Number(value);
44
+ return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;
45
+ }
46
+ function acquireGlobalMappingSlot() {
47
+ return _acquireGlobalMappingSlot.apply(this, arguments);
48
+ }
49
+ function _acquireGlobalMappingSlot() {
50
+ _acquireGlobalMappingSlot = _asyncToGenerator(function* () {
51
+ var queuedAt = process.hrtime.bigint();
52
+ if (activeGlobalMappings < GLOBAL_MAPPING_CONCURRENCY) {
53
+ activeGlobalMappings += 1;
54
+ } else {
55
+ yield new Promise(resolve => globalMappingWaiters.push(resolve));
56
+ }
57
+ return {
58
+ active: activeGlobalMappings,
59
+ waitMs: Number(process.hrtime.bigint() - queuedAt) / 1e6,
60
+ release() {
61
+ var next = globalMappingWaiters.shift();
62
+ if (next) {
63
+ next();
64
+ } else {
65
+ activeGlobalMappings -= 1;
66
+ }
67
+ }
68
+ };
69
+ });
70
+ return _acquireGlobalMappingSlot.apply(this, arguments);
71
+ }
72
+ function runWithConcurrency(_x, _x2, _x3) {
73
+ return _runWithConcurrency.apply(this, arguments);
74
+ } //const _type = Symbol("type");
75
+ function _runWithConcurrency() {
76
+ _runWithConcurrency = _asyncToGenerator(function* (items, concurrency, worker) {
77
+ var results = new Array(items.length);
78
+ var nextIndex = 0;
79
+ function runWorker() {
80
+ return _runWorker.apply(this, arguments);
81
+ }
82
+ function _runWorker() {
83
+ _runWorker = _asyncToGenerator(function* () {
84
+ while (nextIndex < items.length) {
85
+ var index = nextIndex;
86
+ nextIndex += 1;
87
+ results[index] = yield worker(items[index], index);
88
+ }
89
+ });
90
+ return _runWorker.apply(this, arguments);
91
+ }
92
+ var workerCount = Math.min(concurrency, items.length);
93
+ yield Promise.all(Array.from({
94
+ length: workerCount
95
+ }, () => runWorker()));
96
+ return results;
97
+ });
98
+ return _runWithConcurrency.apply(this, arguments);
99
+ }
35
100
  var that;
36
101
  if (!Promise.allSettled) {
37
102
  Promise.allSettled = promises => Promise.all(promises.map((promise, i) => promise.then(value => ({
@@ -48,21 +113,29 @@ class SpiceModel {
48
113
  args = {};
49
114
  }
50
115
  try {
51
- var _args2, _args2$args, _args3, _args3$args, _args$args, _args4, _args4$args, _args5, _args5$args, _args6, _args6$args, _args7, _args7$args, _args8, _args8$args;
116
+ var _args2, _modelArgs$ctx, _modelArgs$ctx$state, _ref, _ref2, _modelArgs$mapping_de, _ref3, _ref4, _modelArgs$mapping_de2, _modelArgs$mapping_co, _ref5, _modelArgs$skip_mappe, _args$args, _args3, _args3$args, _args4, _args4$args, _args5, _args5$args, _args6, _args6$args, _args7, _args7$args;
117
+ var modelArgs = ((_args2 = args) == null ? void 0 : _args2.args) || {};
118
+ var requestProfile = (modelArgs == null ? void 0 : (_modelArgs$ctx = modelArgs.ctx) == null ? void 0 : (_modelArgs$ctx$state = _modelArgs$ctx.state) == null ? void 0 : _modelArgs$ctx$state.read_profile) || {};
119
+ var defaultMappingDept = process.env.MAPPING_DEPT || 3;
120
+ var legacyMappingDept = modelArgs.mapping_dept !== undefined && modelArgs.mapping_dept !== null ? modelArgs.mapping_dept : undefined;
52
121
  var dbtype = spice.config.database.connections[args.connection].type || "couchbase";
53
122
  var Database = require("spice-" + dbtype);
54
- this[_mapping_dept] = ((_args2 = args) == null ? void 0 : (_args2$args = _args2.args) == null ? void 0 : _args2$args.mapping_dept) || process.env.MAPPING_DEPT || 3;
55
- this[_mapping_dept_exempt] = ((_args3 = args) == null ? void 0 : (_args3$args = _args3.args) == null ? void 0 : _args3$args.mapping_dept_exempt) || [];
123
+ this[_mapping_dept] = legacyMappingDept != null ? legacyMappingDept : defaultMappingDept;
124
+ this[_mapping_dept_scalar] = (_ref = (_ref2 = (_modelArgs$mapping_de = modelArgs.mapping_dept_scalar) != null ? _modelArgs$mapping_de : legacyMappingDept) != null ? _ref2 : requestProfile.mapping_dept_scalar) != null ? _ref : defaultMappingDept;
125
+ this[_mapping_dept_array] = (_ref3 = (_ref4 = (_modelArgs$mapping_de2 = modelArgs.mapping_dept_array) != null ? _modelArgs$mapping_de2 : legacyMappingDept) != null ? _ref4 : requestProfile.mapping_dept_array) != null ? _ref3 : defaultMappingDept;
126
+ this[_mapping_concurrency] = normalizeConcurrency((_modelArgs$mapping_co = modelArgs.mapping_concurrency) != null ? _modelArgs$mapping_co : requestProfile.mapping_concurrency);
127
+ this[_skip_mapped_serialization] = (_ref5 = (_modelArgs$skip_mappe = modelArgs.skip_mapped_serialization) != null ? _modelArgs$skip_mappe : requestProfile.skip_mapped_serialization) != null ? _ref5 : false;
128
+ this[_mapping_dept_exempt] = modelArgs.mapping_dept_exempt || [];
56
129
  this.type = "";
57
130
  this.collection = args.connection;
58
131
  this[_args] = args.args;
59
132
  this[_external_modifier_loaded] = false;
60
133
  this[_disable_lifecycle_events] = ((_args$args = args.args) == null ? void 0 : _args$args.disable_lifecycle_events) || false;
61
- this[_ctx] = (_args4 = args) == null ? void 0 : (_args4$args = _args4.args) == null ? void 0 : _args4$args.ctx;
62
- this[_skip_cache] = ((_args5 = args) == null ? void 0 : (_args5$args = _args5.args) == null ? void 0 : _args5$args.skip_cache) || false;
63
- this[_level] = ((_args6 = args) == null ? void 0 : (_args6$args = _args6.args) == null ? void 0 : _args6$args._level) || 0;
64
- this[_current_path] = ((_args7 = args) == null ? void 0 : (_args7$args = _args7.args) == null ? void 0 : _args7$args._current_path) || "";
65
- this[_columns] = ((_args8 = args) == null ? void 0 : (_args8$args = _args8.args) == null ? void 0 : _args8$args._columns) || "";
134
+ this[_ctx] = (_args3 = args) == null ? void 0 : (_args3$args = _args3.args) == null ? void 0 : _args3$args.ctx;
135
+ this[_skip_cache] = ((_args4 = args) == null ? void 0 : (_args4$args = _args4.args) == null ? void 0 : _args4$args.skip_cache) || false;
136
+ this[_level] = ((_args5 = args) == null ? void 0 : (_args5$args = _args5.args) == null ? void 0 : _args5$args._level) || 0;
137
+ this[_current_path] = ((_args6 = args) == null ? void 0 : (_args6$args = _args6.args) == null ? void 0 : _args6$args._current_path) || "";
138
+ this[_columns] = ((_args7 = args) == null ? void 0 : (_args7$args = _args7.args) == null ? void 0 : _args7$args._columns) || "";
66
139
  this[_hooks] = {
67
140
  create: {
68
141
  before: [],
@@ -209,6 +282,32 @@ class SpiceModel {
209
282
  }
210
283
  // }
211
284
  }
285
+ applyMappingDepthArgs(args) {
286
+ if (args === void 0) {
287
+ args = {};
288
+ }
289
+ var hasLegacyDepth = args.mapping_dept !== undefined && args.mapping_dept !== null;
290
+ if (hasLegacyDepth) {
291
+ this[_mapping_dept] = args.mapping_dept;
292
+ this[_mapping_dept_scalar] = args.mapping_dept;
293
+ this[_mapping_dept_array] = args.mapping_dept;
294
+ }
295
+ if (args.mapping_dept_scalar !== undefined && args.mapping_dept_scalar !== null) {
296
+ this[_mapping_dept_scalar] = args.mapping_dept_scalar;
297
+ }
298
+ if (args.mapping_dept_array !== undefined && args.mapping_dept_array !== null) {
299
+ this[_mapping_dept_array] = args.mapping_dept_array;
300
+ }
301
+ if (args.skip_mapped_serialization !== undefined) {
302
+ this[_skip_mapped_serialization] = args.skip_mapped_serialization;
303
+ }
304
+ if (args.mapping_concurrency !== undefined) {
305
+ this[_mapping_concurrency] = normalizeConcurrency(args.mapping_concurrency, this[_mapping_concurrency]);
306
+ }
307
+ if (args.mapping_dept_exempt) {
308
+ this[_mapping_dept_exempt] = args.mapping_dept_exempt;
309
+ }
310
+ }
212
311
  get database() {
213
312
  return this[_database];
214
313
  }
@@ -250,13 +349,13 @@ class SpiceModel {
250
349
  return [];
251
350
  })();
252
351
  }
253
- createValidationString(_ref) {
352
+ createValidationString(_ref6) {
254
353
  var {
255
354
  property_name,
256
355
  props,
257
356
  operation,
258
357
  complete
259
- } = _ref;
358
+ } = _ref6;
260
359
  var operationExempt = {
261
360
  PUT: ["required", "unique"]
262
361
  };
@@ -487,14 +586,13 @@ class SpiceModel {
487
586
  // Profiling: use track() for proper async context forking
488
587
  var p = (_this4$_ctx = _this4[_ctx]) == null ? void 0 : _this4$_ctx.profiler;
489
588
  var doGet = /*#__PURE__*/function () {
490
- var _ref2 = _asyncToGenerator(function* () {
491
- if (args.mapping_dept) _this4[_mapping_dept] = args.mapping_dept;
492
- if (args.mapping_dept_exempt) _this4[_mapping_dept_exempt] = args.mapping_dept_exempt;
589
+ var _ref7 = _asyncToGenerator(function* () {
493
590
  if (!args) {
494
591
  args = {};
495
592
  }
593
+ _this4.applyMappingDepthArgs(args);
496
594
  if (_.isString(args.id)) {
497
- var _args9, _results, _results2, _results3, _results4, _results5, _results6;
595
+ var _args8, _results, _results2, _results3, _results4, _results5, _results6;
498
596
  if (args.skip_hooks !== true) {
499
597
  yield _this4.run_hook(args, "get", "before");
500
598
  }
@@ -514,7 +612,7 @@ class SpiceModel {
514
612
  var originalColumns = args.columns;
515
613
 
516
614
  // Extract nestings from columns if specified
517
- var nestings = _this4.extractNestings(((_args9 = args) == null ? void 0 : _args9.columns) || "", _this4.type);
615
+ var nestings = _this4.extractNestings(((_args8 = args) == null ? void 0 : _args8.columns) || "", _this4.type);
518
616
 
519
617
  // Build join metadata and prepare columns
520
618
  _this4.buildJoinMetadata(nestings, args);
@@ -597,14 +695,14 @@ class SpiceModel {
597
695
  }
598
696
  });
599
697
  return function doGet() {
600
- return _ref2.apply(this, arguments);
698
+ return _ref7.apply(this, arguments);
601
699
  };
602
700
  }();
603
701
  try {
604
702
  if (p) {
605
- var _args0;
703
+ var _args9;
606
704
  return yield p.track(_this4.type + ".get", doGet, {
607
- id: (_args0 = args) == null ? void 0 : _args0.id
705
+ id: (_args9 = args) == null ? void 0 : _args9.id
608
706
  });
609
707
  }
610
708
  return yield doGet();
@@ -632,14 +730,15 @@ class SpiceModel {
632
730
  // ⚡ Profiling: use track() for proper async context forking
633
731
  var p = (_this6$_ctx = _this6[_ctx]) == null ? void 0 : _this6$_ctx.profiler;
634
732
  var doGetMulti = /*#__PURE__*/function () {
635
- var _ref5 = _asyncToGenerator(function* () {
733
+ var _ref0 = _asyncToGenerator(function* () {
636
734
  if (!args) {
637
735
  args = {};
638
736
  }
737
+ _this6.applyMappingDepthArgs(args);
639
738
  if (args.skip_hooks != true) {
640
739
  yield _this6.run_hook(_this6, "list", "before");
641
740
  }
642
- _.remove(args.ids, o => o == undefined);
741
+ args.ids = _.uniq(_.filter(args.ids || [], id => _.isString(id) && id.length > 0));
643
742
  var key = "multi-get::" + _this6.type + "::" + _.join(args.ids, "|") + ":" + args.columns;
644
743
  var results = [];
645
744
  if (args.ids.length > 0) {
@@ -673,14 +772,14 @@ class SpiceModel {
673
772
  return results;
674
773
  });
675
774
  return function doGetMulti() {
676
- return _ref5.apply(this, arguments);
775
+ return _ref0.apply(this, arguments);
677
776
  };
678
777
  }();
679
778
  try {
680
779
  if (p) {
681
- var _args1, _args1$ids;
780
+ var _args0, _args0$ids;
682
781
  return yield p.track(_this6.type + ".getMulti", doGetMulti, {
683
- ids_count: ((_args1 = args) == null ? void 0 : (_args1$ids = _args1.ids) == null ? void 0 : _args1$ids.length) || 0
782
+ ids_count: ((_args0 = args) == null ? void 0 : (_args0$ids = _args0.ids) == null ? void 0 : _args0$ids.length) || 0
684
783
  });
685
784
  }
686
785
  return yield doGetMulti();
@@ -729,7 +828,7 @@ class SpiceModel {
729
828
  // Profiling: use track() for proper async context forking
730
829
  var p = (_this8$_ctx = _this8[_ctx]) == null ? void 0 : _this8$_ctx.profiler;
731
830
  var doUpdate = /*#__PURE__*/function () {
732
- var _ref6 = _asyncToGenerator(function* () {
831
+ var _ref1 = _asyncToGenerator(function* () {
733
832
  _this8.updated_at = new SDate().now();
734
833
  var results = yield _this8.database.get(args.id);
735
834
  var item_exist = yield _this8.exist(results);
@@ -773,7 +872,7 @@ class SpiceModel {
773
872
  });
774
873
  });
775
874
  return function doUpdate() {
776
- return _ref6.apply(this, arguments);
875
+ return _ref1.apply(this, arguments);
777
876
  };
778
877
  }();
779
878
  try {
@@ -799,7 +898,7 @@ class SpiceModel {
799
898
  // Profiling: use track() for proper async context forking
800
899
  var p = (_this9$_ctx = _this9[_ctx]) == null ? void 0 : _this9$_ctx.profiler;
801
900
  var doCreate = /*#__PURE__*/function () {
802
- var _ref8 = _asyncToGenerator(function* () {
901
+ var _ref11 = _asyncToGenerator(function* () {
803
902
  var form;
804
903
  _this9.created_at = new SDate().now();
805
904
  args = _.defaults(args, {
@@ -845,7 +944,7 @@ class SpiceModel {
845
944
  });
846
945
  });
847
946
  return function doCreate() {
848
- return _ref8.apply(this, arguments);
947
+ return _ref11.apply(this, arguments);
849
948
  };
850
949
  }();
851
950
  try {
@@ -883,7 +982,7 @@ class SpiceModel {
883
982
  // Profiling: use track() for proper async context forking
884
983
  var p = (_this1$_ctx = _this1[_ctx]) == null ? void 0 : _this1$_ctx.profiler;
885
984
  var doDelete = /*#__PURE__*/function () {
886
- var _ref0 = _asyncToGenerator(function* () {
985
+ var _ref13 = _asyncToGenerator(function* () {
887
986
  var item_exist = yield _this1.exist(args.id);
888
987
  if (!item_exist) {
889
988
  throw new Error(_this1.type + " does not exist.");
@@ -894,7 +993,7 @@ class SpiceModel {
894
993
  }
895
994
  var delete_response = {};
896
995
  var dbOperation = /*#__PURE__*/function () {
897
- var _ref1 = _asyncToGenerator(function* () {
996
+ var _ref14 = _asyncToGenerator(function* () {
898
997
  if (args.hard) {
899
998
  delete_response = yield _this1.database.delete(args.id);
900
999
  _this1.setMonitor();
@@ -905,7 +1004,7 @@ class SpiceModel {
905
1004
  }
906
1005
  });
907
1006
  return function dbOperation() {
908
- return _ref1.apply(this, arguments);
1007
+ return _ref14.apply(this, arguments);
909
1008
  };
910
1009
  }();
911
1010
  if (p) {
@@ -921,7 +1020,7 @@ class SpiceModel {
921
1020
  return {};
922
1021
  });
923
1022
  return function doDelete() {
924
- return _ref0.apply(this, arguments);
1023
+ return _ref13.apply(this, arguments);
925
1024
  };
926
1025
  }();
927
1026
  try {
@@ -1111,12 +1210,12 @@ class SpiceModel {
1111
1210
  }
1112
1211
  createJoinSection(mappedNestings) {
1113
1212
  if (!mappedNestings || mappedNestings.length === 0) return "";
1114
- return mappedNestings.map(_ref10 => {
1213
+ return mappedNestings.map(_ref15 => {
1115
1214
  var {
1116
1215
  alias,
1117
1216
  reference,
1118
1217
  is_array
1119
- } = _ref10;
1218
+ } = _ref15;
1120
1219
  var keyspace = (0, _fix.fixCollection)(reference);
1121
1220
  if (is_array === true) {
1122
1221
  return "LEFT NEST `" + keyspace + "` AS `" + alias + "` ON KEYS `" + this.type + "`.`" + alias + "`";
@@ -1261,10 +1360,9 @@ class SpiceModel {
1261
1360
  // Profiling: use track() for proper async context forking
1262
1361
  var p = (_this10$_ctx = _this10[_ctx]) == null ? void 0 : _this10$_ctx.profiler;
1263
1362
  var doList = /*#__PURE__*/function () {
1264
- var _ref11 = _asyncToGenerator(function* () {
1265
- var _args10, _args11;
1266
- if (args.mapping_dept) _this10[_mapping_dept] = args.mapping_dept;
1267
- if (args.mapping_dept_exempt) _this10[_mapping_dept_exempt] = args.mapping_dept_exempt;
1363
+ var _ref16 = _asyncToGenerator(function* () {
1364
+ var _args1, _args10;
1365
+ _this10.applyMappingDepthArgs(args);
1268
1366
 
1269
1367
  // Filter out id, meta().id, and any column ending with .id (e.g., dependents.id)
1270
1368
  if (args.columns) {
@@ -1278,9 +1376,9 @@ class SpiceModel {
1278
1376
  var originalColumns = args.columns;
1279
1377
 
1280
1378
  // Find alias tokens from query/columns/sort
1281
- var nestings = [..._this10.extractNestings(((_args10 = args) == null ? void 0 : _args10.query) || "", _this10.type),
1379
+ var nestings = [..._this10.extractNestings(((_args1 = args) == null ? void 0 : _args1.query) || "", _this10.type),
1282
1380
  //...this.extractNestings(args?.columns || "", this.type),
1283
- ..._this10.extractNestings(((_args11 = args) == null ? void 0 : _args11.sort) || "", _this10.type)];
1381
+ ..._this10.extractNestings(((_args10 = args) == null ? void 0 : _args10.sort) || "", _this10.type)];
1284
1382
 
1285
1383
  // Build join metadata and prepare columns
1286
1384
  var {
@@ -1341,15 +1439,15 @@ class SpiceModel {
1341
1439
  return results;
1342
1440
  });
1343
1441
  return function doList() {
1344
- return _ref11.apply(this, arguments);
1442
+ return _ref16.apply(this, arguments);
1345
1443
  };
1346
1444
  }();
1347
1445
  try {
1348
1446
  if (p) {
1349
- var _args12, _args13;
1447
+ var _args11, _args12;
1350
1448
  return yield p.track(_this10.type + ".list", doList, {
1351
- limit: (_args12 = args) == null ? void 0 : _args12.limit,
1352
- offset: (_args13 = args) == null ? void 0 : _args13.offset
1449
+ limit: (_args11 = args) == null ? void 0 : _args11.limit,
1450
+ offset: (_args12 = args) == null ? void 0 : _args12.offset
1353
1451
  });
1354
1452
  }
1355
1453
  return yield doList();
@@ -1395,8 +1493,9 @@ class SpiceModel {
1395
1493
  // Profiling: use track() for proper async context forking
1396
1494
  var p = (_this11$_ctx = _this11[_ctx]) == null ? void 0 : _this11$_ctx.profiler;
1397
1495
  var doFetch = /*#__PURE__*/function () {
1398
- var _ref12 = _asyncToGenerator(function* () {
1496
+ var _ref17 = _asyncToGenerator(function* () {
1399
1497
  if (args.is_custom_query === "true" && args.ids.length > 0) {
1498
+ console.log("Fetching results from database", _this11.type, args, query, mappedNestings);
1400
1499
  return yield _this11.database.query(query);
1401
1500
  } else if (args.is_full_text === "true") {
1402
1501
  return yield _this11.database.full_text_search(_this11.type, query || "", args.limit, args.offset, args._join);
@@ -1407,7 +1506,7 @@ class SpiceModel {
1407
1506
  }
1408
1507
  });
1409
1508
  return function doFetch() {
1410
- return _ref12.apply(this, arguments);
1509
+ return _ref17.apply(this, arguments);
1411
1510
  };
1412
1511
  }();
1413
1512
  if (p) {
@@ -1416,12 +1515,12 @@ class SpiceModel {
1416
1515
  return yield doFetch();
1417
1516
  })();
1418
1517
  }
1419
- addHook(_ref13) {
1518
+ addHook(_ref18) {
1420
1519
  var {
1421
1520
  operation,
1422
1521
  when,
1423
1522
  execute
1424
- } = _ref13;
1523
+ } = _ref18;
1425
1524
  this[_hooks][operation][when].push(execute);
1426
1525
  }
1427
1526
  run_hook(data, op, when, old_data) {
@@ -1519,7 +1618,8 @@ class SpiceModel {
1519
1618
  data = Array.of(data);
1520
1619
  }
1521
1620
  var isExempt = _this13.isFieldExempt(source_property);
1522
- if (isExempt || _this13[_level] + 1 < _this13[_mapping_dept]) {
1621
+ var activeMappingDept = type === "read" ? _this13[_mapping_dept_scalar] : _this13[_mapping_dept];
1622
+ if (isExempt || _this13[_level] + 1 < activeMappingDept) {
1523
1623
  var classes = _.compact(_.isArray(Class) ? Class : [Class]);
1524
1624
  var ids = [];
1525
1625
  _.each(data, result => {
@@ -1543,12 +1643,16 @@ class SpiceModel {
1543
1643
 
1544
1644
  // ⚡ Wrap in profiler track() to ensure proper async context for child operations
1545
1645
  var fetchRelated = /*#__PURE__*/function () {
1546
- var _ref14 = _asyncToGenerator(function* () {
1646
+ var _ref19 = _asyncToGenerator(function* () {
1547
1647
  return yield Promise.allSettled(_.map(classes, obj => {
1548
1648
  var objInstance = new obj(_extends({}, _this13[_args], {
1549
1649
  skip_cache: _this13[_skip_cache],
1550
1650
  _level: _this13[_level] + 1,
1551
1651
  mapping_dept: _this13[_mapping_dept],
1652
+ mapping_dept_scalar: _this13[_mapping_dept_scalar],
1653
+ mapping_dept_array: _this13[_mapping_dept_array],
1654
+ mapping_concurrency: _this13[_mapping_concurrency],
1655
+ skip_mapped_serialization: _this13[_skip_mapped_serialization],
1552
1656
  mapping_dept_exempt: _this13[_mapping_dept_exempt],
1553
1657
  _columns: columnArray.join(","),
1554
1658
  _current_path: childPath
@@ -1556,12 +1660,13 @@ class SpiceModel {
1556
1660
  return objInstance.getMulti({
1557
1661
  skip_hooks: true,
1558
1662
  ids: ids,
1559
- columns: columnArray
1663
+ columns: columnArray,
1664
+ skip_read_serialize: _this13[_skip_mapped_serialization]
1560
1665
  });
1561
1666
  }));
1562
1667
  });
1563
1668
  return function fetchRelated() {
1564
- return _ref14.apply(this, arguments);
1669
+ return _ref19.apply(this, arguments);
1565
1670
  };
1566
1671
  }();
1567
1672
  var returned_all;
@@ -1628,7 +1733,8 @@ class SpiceModel {
1628
1733
  data = Array.of(data);
1629
1734
  }
1630
1735
  var isExempt = _this14.isFieldExempt(source_property);
1631
- if (isExempt || _this14[_level] + 1 < _this14[_mapping_dept]) {
1736
+ var activeMappingDept = type === "read" ? _this14[_mapping_dept_array] : _this14[_mapping_dept];
1737
+ if (isExempt || _this14[_level] + 1 < activeMappingDept) {
1632
1738
  var ids = [];
1633
1739
  _.each(data, result => {
1634
1740
  var value = result[source_property];
@@ -1661,24 +1767,29 @@ class SpiceModel {
1661
1767
 
1662
1768
  // ⚡ Wrap in profiler track() to ensure proper async context for child operations
1663
1769
  var fetchRelated = /*#__PURE__*/function () {
1664
- var _ref15 = _asyncToGenerator(function* () {
1770
+ var _ref20 = _asyncToGenerator(function* () {
1665
1771
  return yield Promise.allSettled(_.map(classes, obj => {
1666
1772
  return new obj(_extends({}, _this14[_args], {
1667
1773
  skip_cache: _this14[_skip_cache],
1668
1774
  _level: _this14[_level] + 1,
1669
1775
  mapping_dept: _this14[_mapping_dept],
1776
+ mapping_dept_scalar: _this14[_mapping_dept_scalar],
1777
+ mapping_dept_array: _this14[_mapping_dept_array],
1778
+ mapping_concurrency: _this14[_mapping_concurrency],
1779
+ skip_mapped_serialization: _this14[_skip_mapped_serialization],
1670
1780
  mapping_dept_exempt: _this14[_mapping_dept_exempt],
1671
1781
  _columns: columnArray.join(","),
1672
1782
  _current_path: childPath
1673
1783
  })).getMulti({
1674
1784
  skip_hooks: true,
1675
1785
  ids: ids,
1676
- columns: columnArray
1786
+ columns: columnArray,
1787
+ skip_read_serialize: _this14[_skip_mapped_serialization]
1677
1788
  });
1678
1789
  }));
1679
1790
  });
1680
1791
  return function fetchRelated() {
1681
- return _ref15.apply(this, arguments);
1792
+ return _ref20.apply(this, arguments);
1682
1793
  };
1683
1794
  }();
1684
1795
  var returned_all;
@@ -1726,12 +1837,22 @@ class SpiceModel {
1726
1837
  return original_is_array ? data : data[0];
1727
1838
  })();
1728
1839
  }
1729
- addModifier(_ref16) {
1840
+ addModifier(_ref21) {
1730
1841
  var {
1731
1842
  when,
1732
- execute
1733
- } = _ref16;
1843
+ execute,
1844
+ kind,
1845
+ source_property,
1846
+ store_property
1847
+ } = _ref21;
1734
1848
  if (this[_serializers][when]) {
1849
+ if (kind) {
1850
+ execute.spiceModifier = {
1851
+ kind,
1852
+ source_property,
1853
+ store_property
1854
+ };
1855
+ }
1735
1856
  this[_serializers][when]["modifiers"].push(execute);
1736
1857
  }
1737
1858
  }
@@ -1799,15 +1920,18 @@ class SpiceModel {
1799
1920
  {
1800
1921
  _this15.addModifier({
1801
1922
  when: properties[i].map.when || "read",
1923
+ kind: "relationship_map",
1924
+ source_property: i,
1925
+ store_property: properties[i].map.destination || i,
1802
1926
  execute: function () {
1803
- var _execute = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns) {
1927
+ var _execute = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns, serializationType) {
1804
1928
  // Skip if columns are specified but this field isn't included
1805
1929
  if (!_this15.isFieldInColumns(i, columns)) {
1806
1930
  return data;
1807
1931
  }
1808
- return yield _this15.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], args, type, mapping_dept, level, columns);
1932
+ return yield _this15.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], args, serializationType, mapping_dept, level, columns);
1809
1933
  });
1810
- function execute(_x, _x2, _x3, _x4, _x5, _x6, _x7, _x8) {
1934
+ function execute(_x4, _x5, _x6, _x7, _x8, _x9, _x0, _x1, _x10) {
1811
1935
  return _execute.apply(this, arguments);
1812
1936
  }
1813
1937
  return execute;
@@ -1820,15 +1944,18 @@ class SpiceModel {
1820
1944
  {
1821
1945
  _this15.addModifier({
1822
1946
  when: properties[i].map.when || "read",
1947
+ kind: "relationship_map",
1948
+ source_property: i,
1949
+ store_property: properties[i].map.destination || i,
1823
1950
  execute: function () {
1824
- var _execute2 = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns) {
1951
+ var _execute2 = _asyncToGenerator(function* (data, old_data, ctx, type, args, mapping_dept, level, columns, serializationType) {
1825
1952
  // Skip if columns are specified but this field isn't included
1826
1953
  if (!_this15.isFieldInColumns(i, columns)) {
1827
1954
  return data;
1828
1955
  }
1829
- return yield _this15.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], args, type, mapping_dept, level, columns);
1956
+ return yield _this15.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], args, serializationType, mapping_dept, level, columns);
1830
1957
  });
1831
- function execute(_x9, _x0, _x1, _x10, _x11, _x12, _x13, _x14) {
1958
+ function execute(_x11, _x12, _x13, _x14, _x15, _x16, _x17, _x18, _x19) {
1832
1959
  return _execute2.apply(this, arguments);
1833
1960
  }
1834
1961
  return execute;
@@ -1860,7 +1987,7 @@ class SpiceModel {
1860
1987
  // Profiling: use track() for proper async context forking
1861
1988
  var p = (_this16$_ctx = _this16[_ctx]) == null ? void 0 : _this16$_ctx.profiler;
1862
1989
  var doSerialize = /*#__PURE__*/function () {
1863
- var _ref17 = _asyncToGenerator(function* () {
1990
+ var _ref22 = _asyncToGenerator(function* () {
1864
1991
  var _this16$_serializers, _this16$_serializers$;
1865
1992
  // Early exit if serialization should not run.
1866
1993
  if (!_this16.shouldSerializerRun(args, type)) {
@@ -1875,19 +2002,117 @@ class SpiceModel {
1875
2002
 
1876
2003
  // Cache the modifiers lookup for the specified type.
1877
2004
  var modifiers = ((_this16$_serializers = _this16[_serializers]) == null ? void 0 : (_this16$_serializers$ = _this16$_serializers[type]) == null ? void 0 : _this16$_serializers$.modifiers) || [];
1878
- for (var i = 0; i < modifiers.length; i++) {
1879
- var modifier = modifiers[i];
1880
- try {
1881
- var result = yield modifier(data, old_data, _this16[_ctx], _this16.type, args, _this16[_mapping_dept], _this16[_level], _this16[_columns]);
1882
- // Guard against modifiers that return undefined
1883
- if (result !== undefined) {
1884
- data = result;
1885
- } else {
1886
- console.warn("Modifier #" + i + " for type=" + _this16.type + " returned undefined, keeping previous data");
2005
+ var invokeModifier = /*#__PURE__*/function () {
2006
+ var _ref23 = _asyncToGenerator(function* (modifier, index, inputData) {
2007
+ try {
2008
+ var result = yield modifier(inputData, old_data, _this16[_ctx], _this16.type, args, _this16[_mapping_dept], _this16[_level], _this16[_columns], type);
2009
+ if (result !== undefined) {
2010
+ return {
2011
+ hasValue: true,
2012
+ value: result
2013
+ };
2014
+ }
2015
+ console.warn("Modifier #" + index + " for type=" + _this16.type + " returned undefined, keeping previous data");
2016
+ } catch (error) {
2017
+ console.error("Modifier error in do_serialize (type=" + _this16.type + ", modifier #" + index + "):", error instanceof Error ? error.stack : "Non-Error thrown: " + JSON.stringify(error));
1887
2018
  }
1888
- } catch (error) {
1889
- console.error("Modifier error in do_serialize (type=" + _this16.type + ", modifier #" + i + "):", error instanceof Error ? error.stack : "Non-Error thrown: " + JSON.stringify(error));
2019
+ return {
2020
+ hasValue: false
2021
+ };
2022
+ });
2023
+ return function invokeModifier(_x20, _x21, _x22) {
2024
+ return _ref23.apply(this, arguments);
2025
+ };
2026
+ }();
2027
+ var modifierIndex = 0;
2028
+ var _loop2 = function* _loop2() {
2029
+ var _modifier$spiceModifi;
2030
+ var modifier = modifiers[modifierIndex];
2031
+ var canRunRelationshipMapsConcurrently = type === "read" && _this16[_level] === 0 && _this16[_mapping_concurrency] > 1 && (modifier == null ? void 0 : (_modifier$spiceModifi = modifier.spiceModifier) == null ? void 0 : _modifier$spiceModifi.kind) === "relationship_map";
2032
+ if (!canRunRelationshipMapsConcurrently) {
2033
+ var result = yield invokeModifier(modifier, modifierIndex, data);
2034
+ if (result.hasValue) data = result.value;
2035
+ modifierIndex += 1;
2036
+ return "continue";
2037
+ }
2038
+ var group = [];
2039
+ var destinations = new Set();
2040
+ while (modifierIndex < modifiers.length) {
2041
+ var candidate = modifiers[modifierIndex];
2042
+ var metadata = candidate == null ? void 0 : candidate.spiceModifier;
2043
+ if ((metadata == null ? void 0 : metadata.kind) !== "relationship_map") break;
2044
+ if (metadata.store_property && destinations.has(metadata.store_property)) {
2045
+ break;
2046
+ }
2047
+ if (metadata.store_property) {
2048
+ destinations.add(metadata.store_property);
2049
+ }
2050
+ group.push({
2051
+ modifier: candidate,
2052
+ index: modifierIndex,
2053
+ metadata
2054
+ });
2055
+ modifierIndex += 1;
1890
2056
  }
2057
+ var groupQueuedAt = process.hrtime.bigint();
2058
+ var activeRequestMappings = 0;
2059
+ var executeGroup = /*#__PURE__*/function () {
2060
+ var _ref24 = _asyncToGenerator(function* () {
2061
+ return yield runWithConcurrency(group, _this16[_mapping_concurrency], /*#__PURE__*/function () {
2062
+ var _ref25 = _asyncToGenerator(function* (entry) {
2063
+ var requestQueueWaitMs = Number(process.hrtime.bigint() - groupQueuedAt) / 1e6;
2064
+ var globalSlot = yield acquireGlobalMappingSlot();
2065
+ activeRequestMappings += 1;
2066
+ var profileMetadata = {
2067
+ source_property: entry.metadata.source_property,
2068
+ store_property: entry.metadata.store_property,
2069
+ request_queue_wait_ms: Math.round(requestQueueWaitMs * 100) / 100,
2070
+ global_queue_wait_ms: Math.round(globalSlot.waitMs * 100) / 100,
2071
+ active_request_mappings: activeRequestMappings,
2072
+ request_limit: _this16[_mapping_concurrency],
2073
+ active_global_mappings: globalSlot.active,
2074
+ global_limit: GLOBAL_MAPPING_CONCURRENCY
2075
+ };
2076
+ try {
2077
+ var execute = /*#__PURE__*/function () {
2078
+ var _ref26 = _asyncToGenerator(function* () {
2079
+ return yield invokeModifier(entry.modifier, entry.index, data);
2080
+ });
2081
+ return function execute() {
2082
+ return _ref26.apply(this, arguments);
2083
+ };
2084
+ }();
2085
+ if (p) {
2086
+ return yield p.track(_this16.type + ".map.concurrent." + entry.metadata.source_property, execute, profileMetadata);
2087
+ }
2088
+ return yield execute();
2089
+ } finally {
2090
+ activeRequestMappings -= 1;
2091
+ globalSlot.release();
2092
+ }
2093
+ });
2094
+ return function (_x23) {
2095
+ return _ref25.apply(this, arguments);
2096
+ };
2097
+ }());
2098
+ });
2099
+ return function executeGroup() {
2100
+ return _ref24.apply(this, arguments);
2101
+ };
2102
+ }();
2103
+ var groupMetadata = {
2104
+ map_count: group.length,
2105
+ request_limit: _this16[_mapping_concurrency],
2106
+ global_limit: GLOBAL_MAPPING_CONCURRENCY
2107
+ };
2108
+ var groupResults = p ? yield p.track(_this16.type + ".map.concurrent", executeGroup, groupMetadata) : yield executeGroup();
2109
+ for (var _result of groupResults) {
2110
+ if (_result == null ? void 0 : _result.hasValue) data = _result.value;
2111
+ }
2112
+ };
2113
+ while (modifierIndex < modifiers.length) {
2114
+ var _ret = yield* _loop2();
2115
+ if (_ret === "continue") continue;
1891
2116
  }
1892
2117
 
1893
2118
  // Ensure data is always an array for consistent processing.
@@ -1928,7 +2153,7 @@ class SpiceModel {
1928
2153
  return originalIsArray ? data : data[0];
1929
2154
  });
1930
2155
  return function doSerialize() {
1931
- return _ref17.apply(this, arguments);
2156
+ return _ref22.apply(this, arguments);
1932
2157
  };
1933
2158
  }();
1934
2159
  try {