@routier/core 0.7.0 → 0.8.0

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.
Files changed (47) hide show
  1. package/dist/codegen/blocks.d.ts +17 -1
  2. package/dist/codegen/handlers/types.d.ts +13 -5
  3. package/dist/codegen/index.cjs +28 -0
  4. package/dist/codegen/index.cjs.map +1 -1
  5. package/dist/codegen/index.js +28 -0
  6. package/dist/codegen/index.js.map +1 -1
  7. package/dist/collections/MemoryDataCollection.d.ts +2 -4
  8. package/dist/collections/index.cjs +127 -15
  9. package/dist/collections/index.cjs.map +1 -1
  10. package/dist/collections/index.js +127 -15
  11. package/dist/collections/index.js.map +1 -1
  12. package/dist/expressions/index.cjs +226 -4
  13. package/dist/expressions/index.cjs.map +1 -1
  14. package/dist/expressions/index.js +228 -5
  15. package/dist/expressions/index.js.map +1 -1
  16. package/dist/expressions/parser.d.ts +42 -1
  17. package/dist/index.cjs +753 -345
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.js +756 -345
  20. package/dist/index.js.map +1 -1
  21. package/dist/plugins/EphemeralDataPlugin.d.ts +8 -0
  22. package/dist/plugins/index.cjs +566 -49
  23. package/dist/plugins/index.cjs.map +1 -1
  24. package/dist/plugins/index.js +566 -48
  25. package/dist/plugins/index.js.map +1 -1
  26. package/dist/plugins/query/QueryOptionsCollection.d.ts +15 -5
  27. package/dist/plugins/query/index.d.ts +1 -0
  28. package/dist/plugins/query/renames.d.ts +27 -0
  29. package/dist/plugins/query/types.d.ts +15 -1
  30. package/dist/plugins/translators/SqlTranslator.d.ts +15 -0
  31. package/dist/schema/SchemaDefinition.d.ts +8 -0
  32. package/dist/schema/changeTracker.d.ts +10 -0
  33. package/dist/schema/index.cjs +291 -274
  34. package/dist/schema/index.cjs.map +1 -1
  35. package/dist/schema/index.d.ts +1 -0
  36. package/dist/schema/index.js +294 -276
  37. package/dist/schema/index.js.map +1 -1
  38. package/dist/schema/types.d.ts +8 -7
  39. package/dist/schema/utils/storageDates.d.ts +25 -0
  40. package/dist/transfer/index.cjs.map +1 -1
  41. package/dist/transfer/index.js.map +1 -1
  42. package/dist/utilities/index.cjs +74 -29
  43. package/dist/utilities/index.cjs.map +1 -1
  44. package/dist/utilities/index.js +74 -29
  45. package/dist/utilities/index.js.map +1 -1
  46. package/package.json +2 -2
  47. package/dist/codegen/utils.d.ts +0 -22
package/dist/index.cjs CHANGED
@@ -465,6 +465,14 @@ class FunctionFactoryBuilder extends ContainerBlock {
465
465
  this._params.push(...params);
466
466
  return this;
467
467
  }
468
+ /**
469
+ * Adds a factory parameter carrying `value` and returns its name, for generated code to
470
+ * refer to. See `CodeBuilder.bind` for why values travel this way.
471
+ */ bind(value) {
472
+ const parameter = this.createParameter(value);
473
+ this._params.push(parameter);
474
+ return parameter.name;
475
+ }
468
476
  return() {
469
477
  this._return = true;
470
478
  return this;
@@ -580,6 +588,26 @@ class IfBuilder extends ContainerBlock {
580
588
  }
581
589
  }
582
590
  class CodeBuilder extends ContainerBlock {
591
+ _bindings = [];
592
+ /**
593
+ * Makes `value` available to the generated function under the returned name.
594
+ *
595
+ * Generated code must never reach a runtime value by its source name or by pasting its
596
+ * source text: a minifier renames the declaration and cannot see inside the generated
597
+ * string, and pasted source loses the scope it closed over (#40, #46). A binding is passed
598
+ * in as a real value when the function is compiled, so it survives any bundler.
599
+ */ bind(value, name = `binding${this._bindings.length}`) {
600
+ this._bindings.push({
601
+ name,
602
+ value
603
+ });
604
+ return name;
605
+ }
606
+ getBindings() {
607
+ return [
608
+ ...this._bindings
609
+ ];
610
+ }
583
611
  toString() {
584
612
  return this._lines.map((line)=>typeof line === 'string' ? this.indent(line) : line.toString()).join('\n\n');
585
613
  }
@@ -914,6 +942,8 @@ class IdSet {
914
942
 
915
943
  // EXTERNAL MODULE: ./src/schema/types.ts
916
944
  var types = __webpack_require__(537);
945
+ // EXTERNAL MODULE: ./src/schema/utils/storageDates.ts
946
+ var storageDates = __webpack_require__(894);
917
947
  // EXTERNAL MODULE: ./src/results/Result.ts
918
948
  var Result = __webpack_require__(718);
919
949
  // EXTERNAL MODULE: ./src/utilities/uuid.ts
@@ -979,29 +1009,17 @@ class MemoryDataCollection {
979
1009
  }
980
1010
  throw new Error(`Id Property '${property.name}' must be string or number, found '${property.type}'`);
981
1011
  }
982
- _dateColumns;
983
- /** Date columns, by the name a stored record uses. Nested dates live inside a JSON column. */ get dateColumns() {
984
- if (this._dateColumns == null) {
985
- this._dateColumns = this.schema.properties.filter((property)=>property.type === types/* .SchemaTypes.Date */.L.Date && property.getAssignmentPath().includes(".") === false).map((property)=>property.getResolvedName());
986
- }
987
- return this._dateColumns;
988
- }
989
1012
  /**
990
1013
  * The record this collection keeps.
991
1014
  *
992
1015
  * A copy, so a caller holding the entity cannot write into the store afterwards. Dates are held
993
- * as Dates: a predicate compares a Date, and a stored ISO string never matches one.
1016
+ * as Dates, at the root, in objects and in arrays: a predicate compares a Date, and a stored ISO
1017
+ * string never matches one. A durable subclass hydrates parsed JSON through here too.
994
1018
  */ toStored(item) {
995
- const columns = this.dateColumns;
996
1019
  const stored = {
997
1020
  ...item
998
1021
  };
999
- for(let i = 0, length = columns.length; i < length; i++){
1000
- const value = stored[columns[i]];
1001
- if (typeof value === "string") {
1002
- stored[columns[i]] = new Date(value);
1003
- }
1004
- }
1022
+ (0,storageDates/* .getStorageDateReviver */.T)(this.schema)?.(stored);
1005
1023
  return stored;
1006
1024
  }
1007
1025
  seed(items) {
@@ -1821,6 +1839,7 @@ __webpack_require__.d(__webpack_exports__, {
1821
1839
  getProperties: () => (/* reexport safe */ _utils__rspack_import_5.oY),
1822
1840
  operandValue: () => (/* reexport safe */ _evaluate__rspack_import_1.Vv),
1823
1841
  parseFragment: () => (/* reexport safe */ _parser__rspack_import_3.oH),
1842
+ parseSelector: () => (/* reexport safe */ _parser__rspack_import_3.Pl),
1824
1843
  peelCalls: () => (/* reexport safe */ _utils__rspack_import_5.CC),
1825
1844
  renderCallAsJs: () => (/* reexport safe */ _callSource__rspack_import_0.a),
1826
1845
  toExpression: () => (/* reexport safe */ _parser__rspack_import_3.MY),
@@ -1847,6 +1866,7 @@ __webpack_require__.d(__webpack_exports__, {
1847
1866
  91(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1848
1867
  __webpack_require__.d(__webpack_exports__, {
1849
1868
  MY: () => (toExpression),
1869
+ Pl: () => (parseSelector),
1850
1870
  oH: () => (parseFragment),
1851
1871
  pg: () => (combineExpressions)
1852
1872
  });
@@ -1855,6 +1875,7 @@ __webpack_require__.d(__webpack_exports__, {
1855
1875
  /* import */ var _schema__rspack_import_2 = __webpack_require__(537);
1856
1876
  /* import */ var _evaluate__rspack_import_3 = __webpack_require__(379);
1857
1877
  /* import */ var _fold__rspack_import_4 = __webpack_require__(43);
1878
+ /* import */ var _utils__rspack_import_6 = __webpack_require__(63);
1858
1879
  /* import */ var _types__rspack_import_1 = __webpack_require__(27);
1859
1880
 
1860
1881
 
@@ -1862,6 +1883,7 @@ __webpack_require__.d(__webpack_exports__, {
1862
1883
 
1863
1884
 
1864
1885
 
1886
+
1865
1887
  // Error message constants
1866
1888
  const ERROR_MESSAGES = {
1867
1889
  PROPERTY_NOT_FOUND: (path)=>`Error parsing query, could not find PropertyInfo for path: ${path}`,
@@ -2469,6 +2491,9 @@ const COALESCE_OPERATORS = sourceKeyed({
2469
2491
  // A comparison always names a schema property, so the condition alone settles it
2470
2492
  return true;
2471
2493
  }
2494
+ if (operand.kind === "opaque") {
2495
+ return operand.reads.some(containsProperty);
2496
+ }
2472
2497
  return operand.kind === "arithmetic" && (containsProperty(operand.left) || containsProperty(operand.right) || operand.extra != null && containsProperty(operand.extra));
2473
2498
  };
2474
2499
  const DECLARATION_KEYWORDS = new Set([
@@ -2646,13 +2671,18 @@ const resolveParamPath = (paramsName, path, data)=>{
2646
2671
  scope;
2647
2672
  paramsName;
2648
2673
  params;
2674
+ /**
2675
+ * Whether this parses a value selector rather than a filter, and so reads a call it has no node for
2676
+ * as an `OpaqueOperand` instead of refusing it.
2677
+ */ readsValues;
2649
2678
  /** Set when a param value shaped the tree itself (e.g. x[p.name]) — such templates cannot be cached. */ structurallyDependsOnParams = false;
2650
- constructor(schema, stream, scope, paramsName, params){
2679
+ constructor(schema, stream, scope, paramsName, params, readsValues = false){
2651
2680
  this.schema = schema;
2652
2681
  this.stream = stream;
2653
2682
  this.scope = scope;
2654
2683
  this.paramsName = paramsName;
2655
2684
  this.params = params;
2685
+ this.readsValues = readsValues;
2656
2686
  }
2657
2687
  parse() {
2658
2688
  const expression = this.parseOr();
@@ -2674,6 +2704,71 @@ const resolveParamPath = (paramsName, path, data)=>{
2674
2704
  }
2675
2705
  return answer;
2676
2706
  }
2707
+ /**
2708
+ * What a value selector returns: one value, or the fields of an object literal.
2709
+ *
2710
+ * A block body is read only when it does nothing but return, which is what a transpiler makes of an
2711
+ * arrow function. Anything more is refused, and the caller falls back to running the function.
2712
+ */ parseSelector() {
2713
+ const block = this.stream.matchPunctuation("{");
2714
+ if (block) {
2715
+ const keyword = this.stream.next();
2716
+ if (keyword.kind !== "identifier" || keyword.value !== "return") {
2717
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a selector block that does more than return"));
2718
+ }
2719
+ }
2720
+ const selected = this.stream.isPunctuation("{") ? this.parseObjectLiteral() : this.stream.isPunctuation("(") && this.stream.isPunctuation("{", 1) ? this.parseBracketedObjectLiteral() : this.parseInterpolation();
2721
+ if (block) {
2722
+ this.stream.matchPunctuation(";");
2723
+ this.stream.expectPunctuation("}");
2724
+ }
2725
+ if (!this.stream.isAtEnd) {
2726
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`unexpected token '${this.stream.peek()?.value}'`));
2727
+ }
2728
+ return selected;
2729
+ }
2730
+ /** `({ … })`, the arrow body that returns an object. */ parseBracketedObjectLiteral() {
2731
+ this.stream.expectPunctuation("(");
2732
+ const fields = this.parseObjectLiteral();
2733
+ this.stream.expectPunctuation(")");
2734
+ return fields;
2735
+ }
2736
+ /**
2737
+ * The fields of an object literal, each one value.
2738
+ *
2739
+ * A field's value is read without a top-level conditional, which needs brackets here: the look-ahead
2740
+ * for a `?` does not stop at the comma that ends the field.
2741
+ */ parseObjectLiteral() {
2742
+ this.stream.expectPunctuation("{");
2743
+ const fields = [];
2744
+ while(!this.stream.matchPunctuation("}")){
2745
+ const key = this.stream.next();
2746
+ if (key.kind !== "identifier" && key.kind !== "string") {
2747
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED(`the object key '${key.value}'`));
2748
+ }
2749
+ fields.push({
2750
+ name: key.value,
2751
+ operand: this.stream.matchPunctuation(":") ? this.parseValue() : this.parseShorthand(key)
2752
+ });
2753
+ if (!this.stream.matchPunctuation(",")) {
2754
+ this.stream.expectPunctuation("}");
2755
+ break;
2756
+ }
2757
+ }
2758
+ return fields;
2759
+ }
2760
+ /** `{ name }`, which reads what the parameter list bound `name` to. */ parseShorthand(key) {
2761
+ const binding = key.kind === "identifier" ? this.scope.get(key.value) : undefined;
2762
+ if (binding == null || binding.kind === "inlined") {
2763
+ throw new Error(ERROR_MESSAGES.VARIABLE_VALUE(key.value));
2764
+ }
2765
+ return this.parseChain({
2766
+ kind: binding.kind,
2767
+ path: [
2768
+ ...binding.path
2769
+ ]
2770
+ });
2771
+ }
2677
2772
  /** The expression a `{ … }` block answers with. */ parseBlock() {
2678
2773
  this.stream.expectPunctuation("{");
2679
2774
  const answer = this.parseStatements();
@@ -2937,7 +3032,7 @@ const resolveParamPath = (paramsName, path, data)=>{
2937
3032
  * A structural dependence found inside propagates outward: the template it belongs to cannot be
2938
3033
  * cached either.
2939
3034
  */ parseNested(source) {
2940
- const nested = new ExpressionParser(this.schema, new TokenStream(tokenize(source)), this.scope, this.paramsName, this.params);
3035
+ const nested = new ExpressionParser(this.schema, new TokenStream(tokenize(source)), this.scope, this.paramsName, this.params, this.readsValues);
2941
3036
  const operand = nested.parseInterpolation();
2942
3037
  // Leftover tokens mean the interpolation held something this reads only part of. Silently
2943
3038
  // keeping the part it understood is the worst outcome available: `${x.age > 5 ? "a" : "b"}`
@@ -3229,7 +3324,7 @@ const resolveParamPath = (paramsName, path, data)=>{
3229
3324
  if (argument.kind === "method-call") {
3230
3325
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("nested method call inside .includes()"));
3231
3326
  }
3232
- if (argument.kind === "arithmetic" || argument.kind === "conditional") {
3327
+ if (argument.kind === "arithmetic" || argument.kind === "conditional" || argument.kind === "opaque") {
3233
3328
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("arithmetic inside .includes()"));
3234
3329
  }
3235
3330
  return {
@@ -3323,7 +3418,7 @@ const resolveParamPath = (paramsName, path, data)=>{
3323
3418
  if (argument.kind === "method-call") {
3324
3419
  throw new Error(ERROR_MESSAGES.UNSUPPORTED(`nested method call inside .${method}()`));
3325
3420
  }
3326
- if (argument.kind === "arithmetic" || argument.kind === "conditional") {
3421
+ if (argument.kind === "arithmetic" || argument.kind === "conditional" || argument.kind === "opaque") {
3327
3422
  throw new Error(ERROR_MESSAGES.UNSUPPORTED(`arithmetic inside .${method}()`));
3328
3423
  }
3329
3424
  return {
@@ -3333,9 +3428,20 @@ const resolveParamPath = (paramsName, path, data)=>{
3333
3428
  argument
3334
3429
  };
3335
3430
  }
3431
+ if (this.readsValues) {
3432
+ return this.withGroupCall(this.opaqueCall(this.resolveChain(options.kind, path, transformer, locale)));
3433
+ }
3336
3434
  throw new Error(ERROR_MESSAGES.UNSUPPORTED(`method '.${method}()'`));
3337
3435
  }
3338
3436
  if (transformer != null) {
3437
+ if (this.readsValues) {
3438
+ return this.withGroupCall({
3439
+ kind: "opaque",
3440
+ reads: [
3441
+ this.resolveChain(options.kind, path, transformer, locale)
3442
+ ]
3443
+ });
3444
+ }
3339
3445
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("property access after a transform method"));
3340
3446
  }
3341
3447
  path.push(segment.value);
@@ -3480,10 +3586,39 @@ const resolveParamPath = (paramsName, path, data)=>{
3480
3586
  argument
3481
3587
  };
3482
3588
  }
3589
+ // Any other member or call of a value, which a selector reads through
3590
+ if (this.readsValues) {
3591
+ this.stream.next();
3592
+ this.stream.next();
3593
+ receiver = this.stream.isPunctuation("(") ? this.opaqueCall(receiver) : {
3594
+ kind: "opaque",
3595
+ reads: [
3596
+ receiver
3597
+ ]
3598
+ };
3599
+ continue;
3600
+ }
3483
3601
  break;
3484
3602
  }
3485
3603
  return receiver;
3486
3604
  }
3605
+ /** A call with no node of its own, from its `(`, kept for what its receiver and arguments read. */ opaqueCall(receiver) {
3606
+ const reads = [
3607
+ receiver
3608
+ ];
3609
+ this.stream.expectPunctuation("(");
3610
+ while(!this.stream.matchPunctuation(")")){
3611
+ reads.push(this.parseValue());
3612
+ if (!this.stream.matchPunctuation(",")) {
3613
+ this.stream.expectPunctuation(")");
3614
+ break;
3615
+ }
3616
+ }
3617
+ return {
3618
+ kind: "opaque",
3619
+ reads
3620
+ };
3621
+ }
3487
3622
  withValueTransformer(operand) {
3488
3623
  if (this.stream.isPunctuation(".")) {
3489
3624
  const method = this.stream.peek(1);
@@ -3517,6 +3652,10 @@ const resolveParamPath = (paramsName, path, data)=>{
3517
3652
  if (right.kind === "method-call") {
3518
3653
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("method call on the right side of a comparison"));
3519
3654
  }
3655
+ // A comparison is a tree a backend renders, and this operand has no node in one
3656
+ if (left.kind === "opaque" || right.kind === "opaque") {
3657
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a call with no expression form inside a comparison"));
3658
+ }
3520
3659
  if (needsBrackets(left) || needsBrackets(right)) {
3521
3660
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("a bitwise or nullish operator compared without brackets, which JavaScript reads the other way round"));
3522
3661
  }
@@ -3730,6 +3869,9 @@ const resolveParamPath = (paramsName, path, data)=>{
3730
3869
  if (operand.kind === "method-call") {
3731
3870
  throw new Error(ERROR_MESSAGES.UNSUPPORTED("a method call inside arithmetic"));
3732
3871
  }
3872
+ if (operand.kind === "opaque") {
3873
+ throw new Error(ERROR_MESSAGES.UNSUPPORTED("a call with no expression form inside arithmetic"));
3874
+ }
3733
3875
  return this.createValueExpression(operand, null, /* applyConverter */ false);
3734
3876
  }
3735
3877
  createPropertyExpression(operand) {
@@ -4065,6 +4207,104 @@ const toExpression = (schema, fn, params)=>{
4065
4207
  return _types__rspack_import_1/* .Expression.notParsable */.r4.notParsable(refusalOf(error));
4066
4208
  }
4067
4209
  };
4210
+ const collectReads = (operand, into)=>{
4211
+ switch(operand.kind){
4212
+ case "property":
4213
+ into.add(operand.property);
4214
+ return;
4215
+ case "method-call":
4216
+ collectReads(operand.target, into);
4217
+ collectReads(operand.argument, into);
4218
+ return;
4219
+ case "arithmetic":
4220
+ collectReads(operand.left, into);
4221
+ collectReads(operand.right, into);
4222
+ if (operand.extra != null) {
4223
+ collectReads(operand.extra, into);
4224
+ }
4225
+ return;
4226
+ case "conditional":
4227
+ for (const property of (0,_utils__rspack_import_6/* .getProperties */.oY)(operand.condition)){
4228
+ into.add(property);
4229
+ }
4230
+ collectReads(operand.whenTrue, into);
4231
+ collectReads(operand.whenFalse, into);
4232
+ return;
4233
+ case "opaque":
4234
+ for (const read of operand.reads){
4235
+ collectReads(read, into);
4236
+ }
4237
+ return;
4238
+ }
4239
+ };
4240
+ const selectedValue = (operand)=>{
4241
+ const found = new Set();
4242
+ collectReads(operand, found);
4243
+ const reads = [
4244
+ ...found
4245
+ ];
4246
+ return {
4247
+ property: reads.length === 1 ? reads[0] : null,
4248
+ reads,
4249
+ isDirectProperty: operand.kind === "property" && operand.transformer == null
4250
+ };
4251
+ };
4252
+ // Keyed like the template cache. A selector takes no params, so every result is cacheable
4253
+ const selectorCache = new WeakMap();
4254
+ /**
4255
+ * Reads a sort, map, group or `nearest` selector with the grammar filters use, for what its value is
4256
+ * read from.
4257
+ *
4258
+ * Not for evaluating it: the caller's function stays the value, and nothing here renders one. A plugin
4259
+ * decides from the result whether it can run the option. One that orders or projects by column cannot
4260
+ * run a value that is not the property itself, and one that runs the function over stored rows cannot
4261
+ * run it over a renamed property.
4262
+ *
4263
+ * So the grammar is wider here than for a filter. A call it has no node for, such as `getFullYear()`,
4264
+ * is kept for the operands it reads rather than refused, since the function it came from still runs.
4265
+ *
4266
+ * `not-parsable` is not logged. The option runs as it did before the selector was parsed.
4267
+ *
4268
+ * Cached by function source per schema, like `toExpression`. The result is shared, so it is read-only.
4269
+ */ const parseSelector = (schema, selector)=>{
4270
+ const source = selector.toString();
4271
+ let bySource = selectorCache.get(schema);
4272
+ const cached = bySource?.get(source);
4273
+ if (cached != null) {
4274
+ return cached;
4275
+ }
4276
+ let parsed;
4277
+ try {
4278
+ const shape = resolveFunctionShape(source, false);
4279
+ const parser = new ExpressionParser(schema, new TokenStream(tokenize(shape.body)), shape.scope, null, undefined, true);
4280
+ const selected = parser.parseSelector();
4281
+ parsed = Array.isArray(selected) ? {
4282
+ kind: "object",
4283
+ fields: selected.map((field)=>({
4284
+ name: field.name,
4285
+ ...selectedValue(field.operand)
4286
+ }))
4287
+ } : {
4288
+ kind: "value",
4289
+ value: selectedValue(selected)
4290
+ };
4291
+ } catch (error) {
4292
+ parsed = {
4293
+ kind: "not-parsable",
4294
+ reason: refusalOf(error)
4295
+ };
4296
+ }
4297
+ if (bySource == null) {
4298
+ bySource = new Map();
4299
+ selectorCache.set(schema, bySource);
4300
+ }
4301
+ // Stryker disable next-line all: the same resource bound as the template cache's
4302
+ if (bySource.size >= MAX_CACHED_TEMPLATES_PER_SCHEMA) {
4303
+ bySource.clear();
4304
+ }
4305
+ bySource.set(source, parsed);
4306
+ return parsed;
4307
+ }; // #endregion
4068
4308
 
4069
4309
 
4070
4310
  },
@@ -4801,7 +5041,7 @@ var TrampolinePipeline = __webpack_require__(416);
4801
5041
 
4802
5042
 
4803
5043
  },
4804
- 640(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
5044
+ 756(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
4805
5045
 
4806
5046
  // EXPORTS
4807
5047
  __webpack_require__.d(__webpack_exports__, {
@@ -4813,6 +5053,7 @@ __webpack_require__.d(__webpack_exports__, {
4813
5053
  CacheDbPlugin: () => (/* reexport */ CacheDbPlugin),
4814
5054
  Query: () => (/* reexport */ Query),
4815
5055
  splitSendableOptions: () => (/* reexport */ splitSendableOptions),
5056
+ withInnerSide: () => (/* reexport */ withInnerSide),
4816
5057
  executeJoin: () => (/* reexport */ executeJoin),
4817
5058
  formatExplanation: () => (/* reexport */ formatExplanation),
4818
5059
  parameteriseDocument: () => (/* reexport */ parameteriseDocument),
@@ -4843,13 +5084,13 @@ __webpack_require__.d(__webpack_exports__, {
4843
5084
  readJoinKey: () => (/* reexport */ readJoinKey),
4844
5085
  loadJoinInnerSide: () => (/* reexport */ loadJoinInnerSide),
4845
5086
  DataTranslator: () => (/* reexport */ DataTranslator),
5087
+ reportRenamedProperties: () => (/* reexport */ reportRenamedProperties),
4846
5088
  serializeBulkPersist: () => (/* reexport */ serializeBulkPersist),
4847
- toEntityShape: () => (/* reexport */ toEntityShape),
4848
5089
  TelemetryDbPlugin: () => (/* reexport */ TelemetryDbPlugin),
4849
- withExecutedQueries: () => (/* reexport */ withExecutedQueries),
5090
+ toEntityShape: () => (/* reexport */ toEntityShape),
4850
5091
  createRequestHandler: () => (/* reexport */ createRequestHandler),
4851
5092
  SqlTranslator: () => (/* reexport */ SqlTranslator),
4852
- withInnerSide: () => (/* reexport */ withInnerSide),
5093
+ withExecutedQueries: () => (/* reexport */ withExecutedQueries),
4853
5094
  QueryOrdering: () => (/* reexport */ types_QueryOrdering),
4854
5095
  describeFilterAsJs: () => (/* reexport */ describeFilterAsJs),
4855
5096
  serializeQueryOptions: () => (/* reexport */ serializeQueryOptions),
@@ -5823,9 +6064,12 @@ class JsonTranslator extends DataTranslator {
5823
6064
  }
5824
6065
  }
5825
6066
 
6067
+ // EXTERNAL MODULE: ./src/schema/utils/storageDates.ts
6068
+ var storageDates = __webpack_require__(894);
5826
6069
  ;// CONCATENATED MODULE: ./src/plugins/translators/SqlTranslator.ts
5827
6070
 
5828
6071
 
6072
+
5829
6073
  /**
5830
6074
  * A stored vector as a list of numbers, whatever the driver handed back.
5831
6075
  *
@@ -5854,6 +6098,31 @@ class SqlTranslator extends DataTranslator {
5854
6098
  super(query);
5855
6099
  this.pushedDown = pushedDown;
5856
6100
  }
6101
+ /**
6102
+ * Dates back as Dates, before the caller's selectors run over the rows.
6103
+ *
6104
+ * A `group` key and a `map` are the caller's lambdas, run here over rows as the engine returned them.
6105
+ * SQLite, D1 and libSQL hand a date back as the TEXT it was stored as, which has no `getFullYear()`
6106
+ * and groups apart from the Date the entity holds. Revived at storage paths and in place, which the
6107
+ * datastore's deserialization still reads, and after `decodeJsonColumns`, so a date inside a JSON
6108
+ * column is revived too. Only a string is converted, so an engine that returns a Date (PostgreSQL,
6109
+ * PGlite, MySQL) is left alone, and so is a row already revived.
6110
+ *
6111
+ * Not a joined statement's rows, which are tuples, each half already deserialized. Nor rows whose
6112
+ * `group` or `map` was handed back, which the datastore runs after deserializing them.
6113
+ */ translate(data) {
6114
+ const runsHere = (name)=>this.query.options.get(name).some((item)=>item.option.target === "database" && item.option.reason === "executed");
6115
+ if (this.pushedDown.join !== true && this.query.schema != null && Array.isArray(data) && (runsHere("group") || runsHere("map"))) {
6116
+ const reviveDates = (0,storageDates/* .getStorageDateReviver */.T)(this.query.schema);
6117
+ for(let i = 0, length = reviveDates == null ? 0 : data.length; i < length; i++){
6118
+ const row = data[i];
6119
+ if (row != null && typeof row === "object") {
6120
+ reviveDates(row);
6121
+ }
6122
+ }
6123
+ }
6124
+ return super.translate(data);
6125
+ }
5857
6126
  count(data, _) {
5858
6127
  if (Array.isArray(data) && data.length > 0) {
5859
6128
  // Count is returned as the property alias on the query.
@@ -6305,7 +6574,6 @@ const isParameter = (value)=>typeof value === "object" && value !== null && PARA
6305
6574
  */ const MEMORY_EXECUTION_EXPLANATIONS = {
6306
6575
  "not-parsable": "A filter could not be parsed into an expression tree, so it and every option after it run in memory.",
6307
6576
  "unmapped-property": "The property is not stored in the database, so it can only be read after deserialization.",
6308
- "renamed-property": "The property is stored under a different name, and selectors use the in-memory name, so it can only be read after deserialization.",
6309
6577
  "map-rename": "A map renames or drops properties, so every option after it refers to names the database does not have.",
6310
6578
  "after-nearest": "A similarity search orders and limits rows, and the plugin cannot report whether it performed the search, so every option after it runs in memory.",
6311
6579
  "after-join": "A join produces [outer, inner] tuples rather than entities, and the plugin cannot report how it joined, so every option after it runs in memory.",
@@ -6807,6 +7075,80 @@ const formatStep = (step, lines)=>{
6807
7075
  return lines.join("\n");
6808
7076
  };
6809
7077
 
7078
+ // EXTERNAL MODULE: ./src/expressions/utils.ts
7079
+ var utils = __webpack_require__(63);
7080
+ ;// CONCATENATED MODULE: ./src/plugins/query/renames.ts
7081
+
7082
+
7083
+ const PROPERTY_READING_OPTIONS = [
7084
+ "filter",
7085
+ "sort",
7086
+ "nearest",
7087
+ "map",
7088
+ "group"
7089
+ ];
7090
+ const namesRenamedProperty = (expression)=>{
7091
+ let found = false;
7092
+ if (expression == null) {
7093
+ return found;
7094
+ }
7095
+ (0,utils/* .forEach */.jJ)(expression, (node)=>{
7096
+ if ((0,assertions.isPropertyExpression)(node) && node.property.hasRenamedSegments) {
7097
+ found = true;
7098
+ return false;
7099
+ }
7100
+ return true;
7101
+ });
7102
+ return found;
7103
+ };
7104
+ const isRenamed = (property)=>property != null && property.hasRenamedSegments;
7105
+ /**
7106
+ * Whether a selector's value is read from a renamed property, whether it is that property or computed
7107
+ * from it: `r => r.dueDate.getTime()` reads `dueDate` all the same. Every property it reads when the
7108
+ * selector was parsed, and otherwise the property recorded for it.
7109
+ */ const readsRenamedValue = (value)=>value != null && (value.reads != null ? value.reads.some(isRenamed) : isRenamed(value.property));
7110
+ const readsRenamedField = (fields)=>fields != null && fields.some(readsRenamedValue);
7111
+ const readsRenamedProperty = (name, value)=>{
7112
+ switch(name){
7113
+ case "filter":
7114
+ return namesRenamedProperty(value.expression);
7115
+ case "map":
7116
+ // A projection reads each field it selects
7117
+ return readsRenamedField(value.fields);
7118
+ case "group":
7119
+ // A group reads its key, then copies every field of the row into its members: every schema
7120
+ // property, or what a `map` before it selected
7121
+ return readsRenamedValue(value.key) || readsRenamedField(value.fields);
7122
+ default:
7123
+ return readsRenamedValue(value);
7124
+ }
7125
+ };
7126
+ /**
7127
+ * Hands back every option over a property stored under a `.from()` name, for the datastore to run
7128
+ * in memory.
7129
+ *
7130
+ * Core keeps such an option with the database, because only the plugin knows whether its backend
7131
+ * reads storage names. One that translates the option — SQL renders the column from
7132
+ * `getResolvedName()` — needs nothing from here. One that runs the caller's lambda over rows as it
7133
+ * stores them reads a key the row does not have, and answers wrongly without an error: that plugin
7134
+ * calls this before it reads anything, and the datastore finishes the query after deserialization,
7135
+ * where the in-memory names exist.
7136
+ *
7137
+ * Reported as `missing-capability`: the backend cannot express the option as written, and like
7138
+ * every capability, that is only knowable by the plugin.
7139
+ *
7140
+ * @param names Which options to check, for a plugin that resolves some of them itself — Mongo renders
7141
+ * filters and sorts through the stored path, and runs `nearest`, `map` and `group` in JavaScript.
7142
+ */ const reportRenamedProperties = (options, names = PROPERTY_READING_OPTIONS)=>{
7143
+ for (const name of names){
7144
+ for (const item of options.get(name)){
7145
+ if (readsRenamedProperty(name, item.option.value)) {
7146
+ options.reportMissingCapability(item);
7147
+ }
7148
+ }
7149
+ }
7150
+ };
7151
+
6810
7152
  ;// CONCATENATED MODULE: ./src/plugins/query/types.ts
6811
7153
  var types_QueryOrdering = /*#__PURE__*/ function(QueryOrdering) {
6812
7154
  QueryOrdering["Descending"] = "desc";
@@ -6824,6 +7166,7 @@ var types_QueryOrdering = /*#__PURE__*/ function(QueryOrdering) {
6824
7166
 
6825
7167
 
6826
7168
 
7169
+
6827
7170
  // EXTERNAL MODULE: ./src/expressions/evaluate.ts
6828
7171
  var evaluate = __webpack_require__(379);
6829
7172
  // EXTERNAL MODULE: ./src/expressions/fold.ts
@@ -6837,6 +7180,9 @@ var fold = __webpack_require__(43);
6837
7180
  * Everything except `map` and `group`. Those two are defined BY a closure — the projection is the
6838
7181
  * option — and no data form of them exists to send. Nothing else needs its closure: a sort is a
6839
7182
  * property and a direction, a filter is an expression tree, `nearest` is a vector and a count.
7183
+ *
7184
+ * Except a sort or `nearest` whose selector computes its value, such as `x => x.name.length`. It is sent
7185
+ * as the property it reads, and the receiver would order by that instead. See `isSendable`.
6840
7186
  */ const SENDABLE = new Set([
6841
7187
  "skip",
6842
7188
  "take",
@@ -6850,6 +7196,7 @@ var fold = __webpack_require__(43);
6850
7196
  "sum",
6851
7197
  "distinct"
6852
7198
  ]);
7199
+ const isSendable = (name, value)=>SENDABLE.has(name) && (name !== "sort" && name !== "nearest" || value.isDirectProperty !== false);
6853
7200
  /**
6854
7201
  * Splits options into the PREFIX that can be sent and the remainder that cannot.
6855
7202
  *
@@ -6865,7 +7212,12 @@ var fold = __webpack_require__(43);
6865
7212
  const local = new QueryOptionsCollection/* .QueryOptionsCollection */.H();
6866
7213
  let stopped = false;
6867
7214
  options.forEach((option)=>{
6868
- if (stopped === false && SENDABLE.has(option.name) === false) {
7215
+ // Reported by the plugin, so it belongs to the datastore, and so does everything after it —
7216
+ // a report cascades to the end of the database phase, which keeps what is left a prefix
7217
+ if (option.target === "database" && option.reason !== "executed") {
7218
+ return;
7219
+ }
7220
+ if (stopped === false && isSendable(option.name, option.value) === false) {
6869
7221
  stopped = true;
6870
7222
  }
6871
7223
  (stopped ? local : sendable).add(option.name, option.value);
@@ -7732,6 +8084,15 @@ class EphemeralDataPlugin {
7732
8084
  */ get databaseName() {
7733
8085
  return this._databaseName;
7734
8086
  }
8087
+ /**
8088
+ * Whether the records this plugin holds are in storage shape, keyed by `from` names.
8089
+ *
8090
+ * True for every store of what the datastore serialized, which is why a renamed property is
8091
+ * reported and records are cloned and keyed by their storage names. The datastore's change probe
8092
+ * holds rows the broadcast has already deserialized, so it reads them by in-memory names instead.
8093
+ */ get holdsStorageShape() {
8094
+ return true;
8095
+ }
7735
8096
  /**
7736
8097
  * All-or-nothing across every collection in the save.
7737
8098
  *
@@ -7939,7 +8300,9 @@ class EphemeralDataPlugin {
7939
8300
  * join discards the surplus. Same pairs either way.
7940
8301
  */ resolveJoinInnerSide(event, outerKeys, done) {
7941
8302
  const joinOption = event.operation.options.getLast("join");
7942
- if (joinOption == null) {
8303
+ // Not reached when an option before it was reported: the datastore's own join branch pairs
8304
+ // the rows this read returns.
8305
+ if (joinOption == null || joinOption.reason !== "executed") {
7943
8306
  done({
7944
8307
  ok: "success"
7945
8308
  });
@@ -7966,7 +8329,7 @@ class EphemeralDataPlugin {
7966
8329
  const innerRows = [];
7967
8330
  // Records are held in STORAGE shape, so the key is read by its resolved column name.
7968
8331
  const innerKey = joinOption.value.innerKey;
7969
- const keyColumn = innerKey.property?.getResolvedName() ?? innerKey.propertyName;
8332
+ const keyColumn = this.holdsStorageShape ? innerKey.property?.getResolvedName() ?? innerKey.propertyName : innerKey.propertyName;
7970
8333
  for (const record of innerCollection.values()){
7971
8334
  if (outerKeys != null && outerKeys.has(record[keyColumn]) === false) {
7972
8335
  continue;
@@ -7995,7 +8358,7 @@ class EphemeralDataPlugin {
7995
8358
  * to fall back to `structuredClone`, which is roughly an order of magnitude slower and was paid
7996
8359
  * on EVERY read of EVERY schema that renames a property.
7997
8360
  */ recordCloner(schema) {
7998
- const hasRenamedProperties = schema.properties.some((property)=>property.from != null);
8361
+ const hasRenamedProperties = this.holdsStorageShape && schema.properties.some((property)=>property.from != null);
7999
8362
  return hasRenamedProperties ? schema.cloneStorage : schema.clone;
8000
8363
  }
8001
8364
  query(event, done) {
@@ -8007,6 +8370,12 @@ class EphemeralDataPlugin {
8007
8370
  const schema = operation.schema;
8008
8371
  const collection = this.resolveCollection(schema);
8009
8372
  const cloneRecord = this.recordCloner(schema);
8373
+ // Records are held in storage shape and every option below runs the caller's lambda
8374
+ // over them, so a `from` property is read by a name the record does not have. Handed
8375
+ // back, and the datastore runs it after deserialization.
8376
+ if (this.holdsStorageShape) {
8377
+ reportRenamedProperties(operation.options);
8378
+ }
8010
8379
  collection.load((r)=>{
8011
8380
  if (r.ok === Result/* .Result.ERROR */.Q.ERROR) {
8012
8381
  done(Result/* .PluginEventResult.error */.D.error(event.id, r.error));
@@ -8015,7 +8384,9 @@ class EphemeralDataPlugin {
8015
8384
  const orderedOptions = [];
8016
8385
  operation.options.forEach((o)=>orderedOptions.push(o));
8017
8386
  let leadingFilterCount = 0;
8018
- while(leadingFilterCount < orderedOptions.length && orderedOptions[leadingFilterCount].name === "filter"){
8387
+ // Stops at a reported filter too: the database phase ends there, and the datastore
8388
+ // runs it and everything after it.
8389
+ while(leadingFilterCount < orderedOptions.length && orderedOptions[leadingFilterCount].name === "filter" && orderedOptions[leadingFilterCount].reason === "executed"){
8019
8390
  leadingFilterCount++;
8020
8391
  }
8021
8392
  // Key-equality fast path: when a leading filter's parsed expression pins
@@ -8093,14 +8464,14 @@ class EphemeralDataPlugin {
8093
8464
  * that was never applied.
8094
8465
  *
8095
8466
  * Before the inner side, to match execution order.
8096
- */ const described = describeFilters(operation.options.get("filter").map((entry)=>entry.option.value));
8467
+ */ const described = describeFilters(operation.options.get("filter").filter((entry)=>entry.option.reason === "executed").map((entry)=>entry.option.value));
8097
8468
  event.executedQueries.push({
8098
8469
  text: `${operation.schema.collectionName}: scanned ${cloned.length} in-memory ` + `${cloned.length === 1 ? "record" : "records"}, filter ${described.text}`,
8099
8470
  parameters: described.parameters.length > 0 ? described.parameters : undefined
8100
8471
  });
8101
8472
  const joinOption = operation.options.getLast("join");
8102
- const outerKeys = joinOption == null ? null : distinctJoinKeys(cloned, joinOption.value.outerKey, joinOption.value.semiJoinKeyThreshold, {
8103
- storageShape: true
8473
+ const outerKeys = joinOption == null || joinOption.reason !== "executed" ? null : distinctJoinKeys(cloned, joinOption.value.outerKey, joinOption.value.semiJoinKeyThreshold, {
8474
+ storageShape: this.holdsStorageShape
8104
8475
  });
8105
8476
  this.resolveJoinInnerSide(event, outerKeys, (joinResult)=>{
8106
8477
  if (joinResult.ok === "error") {
@@ -8276,7 +8647,7 @@ class TelemetryDbPlugin {
8276
8647
  *
8277
8648
  * The clone is a real date and fails `instanceof Date`, which is what a caller checks. Mutated in
8278
8649
  * place because the clone is already private to this call.
8279
- */ const reviveDates = (value)=>{
8650
+ */ const CacheDbPlugin_reviveDates = (value)=>{
8280
8651
  if (value == null || typeof value !== "object") {
8281
8652
  return value;
8282
8653
  }
@@ -8285,12 +8656,12 @@ class TelemetryDbPlugin {
8285
8656
  }
8286
8657
  if (Array.isArray(value)) {
8287
8658
  for(let i = 0, length = value.length; i < length; i++){
8288
- value[i] = reviveDates(value[i]);
8659
+ value[i] = CacheDbPlugin_reviveDates(value[i]);
8289
8660
  }
8290
8661
  return value;
8291
8662
  }
8292
8663
  for (const key of Object.keys(value)){
8293
- value[key] = reviveDates(value[key]);
8664
+ value[key] = CacheDbPlugin_reviveDates(value[key]);
8294
8665
  }
8295
8666
  return value;
8296
8667
  };
@@ -8332,7 +8703,7 @@ class CacheDbPlugin {
8332
8703
  * the next update would be written UNCHECKED with no error anywhere.
8333
8704
  * Pinned by `datastore/src/collections/wrapperStacking.test.ts`.
8334
8705
  */ rebuild(entry) {
8335
- return new entry.construct(reviveDates(structuredClone(entry.value)), entry.isTransformed);
8706
+ return new entry.construct(CacheDbPlugin_reviveDates(structuredClone(entry.value)), entry.isTransformed);
8336
8707
  }
8337
8708
  query(event, done) {
8338
8709
  const key = this.keyFor(event);
@@ -8790,6 +9161,30 @@ const mismatchWarning = (expression)=>{
8790
9161
  const outcome = expression.negated ? "every row matches" : "no row matches";
8791
9162
  return `Routier: '${side.property.property.getAssignmentPath()}' is a ${side.expected}, and this filter ` + `compares it against ${describeLiteral(side.value.value)}, which is a ${typeof side.value.value}. ` + `A strict comparison between them is the same answer for every row, so ${outcome} and the filter ` + `runs in memory. https://routier.dev/guides/strict-comparison-types`;
8792
9163
  };
9164
+ /**
9165
+ * An item as one dispatch receives it: a new object, so a report written on it stays with that dispatch.
9166
+ *
9167
+ * A database option starts `executed` again, because a report is only an answer from the plugin that
9168
+ * made it. A memory option keeps the reason core planned it with. A join's inner options are copied the
9169
+ * same way, since a plugin can report on them too.
9170
+ */ const toDispatchItem = (item)=>{
9171
+ const option = item.option;
9172
+ const value = option.name === "join" ? {
9173
+ ...option.value,
9174
+ innerOptions: option.value.innerOptions.forDispatch()
9175
+ } : option.value;
9176
+ return {
9177
+ index: item.index,
9178
+ option: option.target === "database" ? {
9179
+ ...option,
9180
+ value,
9181
+ reason: "executed"
9182
+ } : {
9183
+ ...option,
9184
+ value
9185
+ }
9186
+ };
9187
+ };
8793
9188
  class QueryOptionsCollection {
8794
9189
  options = new Map();
8795
9190
  nextExecutionTarget = "database";
@@ -8828,7 +9223,7 @@ class QueryOptionsCollection {
8828
9223
  }
8829
9224
  }
8830
9225
  if (name === "filter") {
8831
- // Need to check for unmapped and renamed properties
9226
+ // Need to check for unmapped properties
8832
9227
  const filterValue = value;
8833
9228
  // A tautology (`x => true`) filters nothing — skip it entirely so
8834
9229
  // plugins never see it
@@ -8845,14 +9240,10 @@ class QueryOptionsCollection {
8845
9240
  this.cutOverToMemory("unmapped-property");
8846
9241
  return false;
8847
9242
  }
8848
- if ((0,_assertions__rspack_import_1.isPropertyExpression)(expression) && expression.property.hasRenamedSegments) {
8849
- // Cut over to memory execution: the plugin stores data under the
8850
- // `from` (storage) names, but filter selectors reference the
8851
- // in-memory names. Memory execution runs after deserialization,
8852
- // where the in-memory names exist
8853
- this.cutOverToMemory("renamed-property");
8854
- return false;
8855
- }
9243
+ // A renamed property stays with the database. Whether the backend can read a
9244
+ // `from` name is the plugin's to know, not this collection's: the property
9245
+ // travels with the option, and a plugin that cannot resolve it reports it
9246
+ // back see `reportRenamedProperties`
8856
9247
  if (comparesTypesThatCannotMatch(expression)) {
8857
9248
  _utilities__rspack_import_3/* .logger.warn */.vF.warn(mismatchWarning(expression));
8858
9249
  this.cutOverToMemory("predicate-error");
@@ -8864,26 +9255,19 @@ class QueryOptionsCollection {
8864
9255
  }
8865
9256
  if (name === "sort") {
8866
9257
  const sortValue = value;
8867
- // Same rule as filters: sort selectors reference in-memory names, which
8868
- // only exist after deserialization when the property is renamed or unmapped
9258
+ // Same rule as filters: an unmapped property only exists after deserialization. A
9259
+ // renamed one stays with the database, for the plugin to resolve or report
8869
9260
  if (sortValue.property != null && sortValue.property.isUnmapped) {
8870
9261
  this.cutOverToMemory("unmapped-property");
8871
- } else if (sortValue.property != null && sortValue.property.hasRenamedSegments) {
8872
- this.cutOverToMemory("renamed-property");
8873
9262
  }
8874
9263
  }
8875
9264
  if (name === "nearest") {
8876
9265
  const nearestValue = value;
8877
- // Same rule as sort, and for the same reason: the plugin stores the vector under
8878
- // the `from` name, and an unmapped property is not stored at all. Both are only
8879
- // readable after deserialization, which is where memory execution runs.
8880
- //
8881
- // This is also what lets every translator's in-memory fallback read the column by
8882
- // its resolved name — anything whose storage name differs never reaches them.
9266
+ // Same rule as sort, and for the same reason: an unmapped property is not stored at
9267
+ // all, so it is only readable after deserialization, which is where memory execution
9268
+ // runs. A vector stored under a `from` name is the plugin's to resolve or report.
8883
9269
  if (nearestValue.property != null && nearestValue.property.isUnmapped) {
8884
9270
  this.cutOverToMemory("unmapped-property");
8885
- } else if (nearestValue.property != null && nearestValue.property.hasRenamedSegments) {
8886
- this.cutOverToMemory("renamed-property");
8887
9271
  }
8888
9272
  }
8889
9273
  if ((name === "filter" || name === "sort") && (this.options.has("skip") || this.options.has("take"))) {
@@ -8990,6 +9374,9 @@ class QueryOptionsCollection {
8990
9374
  * the shared collection before executing. Without restoring, a re-executed terminal —
8991
9375
  * the whole point of a subscribed queryable — stacks its option a second time and
8992
9376
  * runs it over the first execution's scalar result.
9377
+ *
9378
+ * The item objects are shared with the snapshot. Nothing reports on them, because every
9379
+ * dispatch sends a `forDispatch` copy, so a restore brings back no reports.
8993
9380
  */ snapshot() {
8994
9381
  const options = new Map([
8995
9382
  ...this.options.entries()
@@ -9067,19 +9454,48 @@ class QueryOptionsCollection {
9067
9454
  }
9068
9455
  }
9069
9456
  /**
9070
- * Forgets what any previous dispatch reported.
9457
+ * A copy of the collection for one dispatch to a plugin, with nothing reported on it.
9071
9458
  *
9072
9459
  * Capability is answered per dispatch, so a report is only an answer for the execution that
9073
- * produced it. The items are shared with any snapshot, so a report mutated in place otherwise
9074
- * survives a restore and a second terminal on the same queryable replays options the plugin
9075
- * did run a `skip` applied twice, over rows already windowed.
9076
- */ forgetReports() {
9460
+ * produced it. Reports are written onto items, and the items of a queryable's collection
9461
+ * outlive any one execution: a snapshot shares them, and a subscription dispatches the same
9462
+ * query on every change. A report left on them replays options the plugin did run on the
9463
+ * next execution, such as a `skip` applied twice over rows already windowed, or hands a
9464
+ * renamed filter to memory that the engine could have run.
9465
+ *
9466
+ * Each item keeps its index, name, value and target. A half from `split`/`splitAt` is copied
9467
+ * with a copy of its origin, and its items are that copy's items, so a report on the half still
9468
+ * cascades over the whole dispatch without reaching the collection it was copied from.
9469
+ */ forDispatch() {
9470
+ if (this.origin == null) {
9471
+ return this.copyForDispatch().copy;
9472
+ }
9473
+ const { copy: root, copies } = this.origin.copyForDispatch();
9474
+ const half = new QueryOptionsCollection();
9077
9475
  this.resolveEnumeration();
9078
9476
  for (const item of this.enumeratedItems){
9079
- if (item.option.target === "database") {
9080
- item.option.reason = "executed";
9081
- }
9477
+ // An item added to the half after it was split has no counterpart in the origin
9478
+ half.adopt(copies.get(item) ?? toDispatchItem(item));
9082
9479
  }
9480
+ half.origin = root;
9481
+ return half;
9482
+ }
9483
+ copyForDispatch() {
9484
+ const copy = new QueryOptionsCollection();
9485
+ const copies = new Map();
9486
+ this.resolveEnumeration();
9487
+ for (const item of this.enumeratedItems){
9488
+ const copied = toDispatchItem(item);
9489
+ copies.set(item, copied);
9490
+ copy.adopt(copied);
9491
+ }
9492
+ copy.nextExecutionTarget = this.nextExecutionTarget;
9493
+ copy.nextExecutionReason = this.nextExecutionReason;
9494
+ copy.nextIndex = this.nextIndex;
9495
+ return {
9496
+ copy,
9497
+ copies
9498
+ };
9083
9499
  }
9084
9500
  /** The options the database did not run, in the order they were written. */ notExecuted() {
9085
9501
  this.resolveEnumeration();
@@ -9277,13 +9693,14 @@ function toPromise(fn) {
9277
9693
 
9278
9694
 
9279
9695
  },
9280
- 755(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
9696
+ 862(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
9281
9697
 
9282
9698
  // EXPORTS
9283
9699
  __webpack_require__.d(__webpack_exports__, {
9284
9700
  SchemaTransform: () => (/* reexport */ SchemaTransform),
9285
9701
  SchemaComputed: () => (/* reexport */ SchemaComputed),
9286
9702
  extractTypeInfo: () => (/* reexport */ extractTypeInfo),
9703
+ getStorageDateReviver: () => (/* reexport */ storageDates/* .getStorageDateReviver */.T),
9287
9704
  SchemaTracked: () => (/* reexport */ SchemaTracked),
9288
9705
  SchemaFile: () => (/* reexport */ SchemaFile),
9289
9706
  SchemaNumber: () => (/* reexport */ SchemaNumber),
@@ -9300,12 +9717,12 @@ __webpack_require__.d(__webpack_exports__, {
9300
9717
  SchemaArray: () => (/* reexport */ SchemaArray),
9301
9718
  SchemaKey: () => (/* reexport */ SchemaKey),
9302
9719
  SchemaOptional: () => (/* reexport */ SchemaOptional),
9303
- hasPrimitiveElements: () => (/* reexport */ hasPrimitiveElements),
9720
+ hasPrimitiveElements: () => (/* reexport */ propertyKind/* .hasPrimitiveElements */.L),
9304
9721
  SchemaDefault: () => (/* reexport */ SchemaDefault),
9305
9722
  SchemaIndex: () => (/* reexport */ SchemaIndex),
9306
9723
  SchemaVector: () => (/* reexport */ SchemaVector),
9307
9724
  HashType: () => (/* reexport */ types/* .HashType */.$),
9308
- isArrayValued: () => (/* reexport */ isArrayValued),
9725
+ isArrayValued: () => (/* reexport */ propertyKind/* .isArrayValued */.l),
9309
9726
  SchemaBase: () => (/* reexport */ SchemaBase),
9310
9727
  createStandardJsonSchemaProps: () => (/* reexport */ createStandardJsonSchemaProps),
9311
9728
  propertyInfoToJsonSchema: () => (/* reexport */ propertyInfoToJsonSchema),
@@ -10526,78 +10943,9 @@ class SlotPath {
10526
10943
 
10527
10944
  // EXTERNAL MODULE: ./src/errors/SchemaError.ts
10528
10945
  var SchemaError = __webpack_require__(131);
10529
- ;// CONCATENATED MODULE: ./src/codegen/utils.ts
10530
- /**
10531
- * Counts non-overlapping occurrences of a term in text.
10532
- *
10533
- * Behavior:
10534
- * - Case-sensitive matching
10535
- * - If the search term is composed entirely of word characters (A–Z, a–z, 0–9, _),
10536
- * enforce whole-word boundaries so "red" does not match inside "redder".
10537
- * - If the search term contains any non-word character (e.g. "=>", "()", "::"),
10538
- * match anywhere without boundary checks (useful for symbols).
10539
- * - Non-overlapping matches (after a hit, advances by term length)
10540
- * - Optimized single-character fast path; otherwise uses indexOf loop
10541
- *
10542
- * Examples:
10543
- * - countWordOccurance("red redder red", "red") => 2
10544
- * - countWordOccurance("()=>{}", "=>") => 1
10545
- * - countWordOccurance("aaaa", "aa") => 2 (non-overlapping)
10546
- *
10547
- * @param text The source text to scan
10548
- * @param word The term to match (must be non-empty)
10549
- * @returns The number of occurrences found
10550
- */ const countWordOccurance = (text, word)=>{
10551
- const wl = word.length;
10552
- const tl = text.length;
10553
- if (wl === 0 || wl > tl) return 0;
10554
- // Fast path for single-character words
10555
- if (wl === 1) {
10556
- let c = 0;
10557
- const code = word.charCodeAt(0);
10558
- for(let i = 0; i < tl; i++)if (text.charCodeAt(i) === code) c++;
10559
- return c;
10560
- }
10561
- let count = 0;
10562
- let i = 0;
10563
- function isWordCharCode(c) {
10564
- return c >= 48 && c <= 57 // 0-9
10565
- || c >= 65 && c <= 90 // A-Z
10566
- || c >= 97 && c <= 122 // a-z
10567
- || c === 95; // _
10568
- }
10569
- // Decide whether to enforce word boundaries based on the search term
10570
- let enforceWordBoundaries = true;
10571
- for(let k = 0; k < wl; k++){
10572
- const cc = word.charCodeAt(k);
10573
- if (!isWordCharCode(cc)) {
10574
- enforceWordBoundaries = false;
10575
- break;
10576
- }
10577
- }
10578
- while(true){
10579
- i = text.indexOf(word, i);
10580
- if (i === -1) break;
10581
- if (enforceWordBoundaries) {
10582
- const left = i - 1;
10583
- const right = i + wl;
10584
- const leftOk = left < 0 || !isWordCharCode(text.charCodeAt(left));
10585
- const rightOk = right >= tl || !isWordCharCode(text.charCodeAt(right));
10586
- if (leftOk && rightOk) count++;
10587
- } else {
10588
- // No boundary enforcement for symbol-containing terms
10589
- count++;
10590
- }
10591
- i += wl; // non-overlapping word matches
10592
- }
10593
- return count;
10594
- };
10595
-
10596
10946
  ;// CONCATENATED MODULE: ./src/codegen/handlers/types.ts
10597
10947
 
10598
10948
 
10599
-
10600
-
10601
10949
  /**
10602
10950
  * Terminal link for chains that apply only to a subset of properties (keys,
10603
10951
  * identities). Returning the builder marks every other property as
@@ -10773,34 +11121,16 @@ class PropertyInfoHandler {
10773
11121
  }
10774
11122
  enriched.property(`${property.name}: ${entitySelectorPath}`);
10775
11123
  }
10776
- toNamedFunction(stringifiedFunction, parent) {
10777
- const name = `_${(0,uuid/* .uuid */.u)()}`;
10778
- const builder = parent.function(name);
10779
- const occurences = countWordOccurance(stringifiedFunction, "=>");
10780
- if (occurences > 0) {
10781
- const split = stringifiedFunction.split("=>").map((w)=>w.trim());
10782
- const parameters = split[0].replace(/\(|\)/g, "").split(",");
10783
- let body = split[1];
10784
- if (occurences > 1) {
10785
- // we have a function that returns a function
10786
- const index = stringifiedFunction.indexOf("=>");
10787
- body = stringifiedFunction.slice(index + 2, stringifiedFunction.length);
10788
- }
10789
- if (body.startsWith("{") === true && body.endsWith("}")) {
10790
- // Remove brackets, wrapping function will have them
10791
- builder.appendBody(body.slice(1, body.length - 1));
10792
- return {
10793
- builder,
10794
- parameters
10795
- };
10796
- }
10797
- builder.appendBody(`return ${body};`);
10798
- return {
10799
- builder,
10800
- parameters
10801
- };
10802
- }
10803
- throw new Error("Only arrow functions are allowed in the schema definition: function () {} ---> () => {}");
11124
+ /**
11125
+ * Binds a function the schema author supplied (a default, a computed, a serializer) into
11126
+ * the generated code and returns the expression that calls it with `args`.
11127
+ *
11128
+ * The function is passed in by value rather than pasted in as source text. Pasted source
11129
+ * loses the scope it was written in, so a default that called an imported helper threw, and
11130
+ * it had to be parsed back apart, which only worked for arrows: a bundler that lowers arrows
11131
+ * to `function` expressions, or renames what they refer to, broke every schema (#46).
11132
+ */ emitBoundCall(target, fn, args) {
11133
+ return `${target.bind(fn)}(${args.join(", ")})`;
10804
11134
  }
10805
11135
  }
10806
11136
 
@@ -10960,28 +11290,21 @@ class EnrichmentPrimitiveHandler extends PropertyInfoHandler {
10960
11290
  class EnrichmentFunctionHandler extends PropertyInfoHandler {
10961
11291
  handle(property, builder) {
10962
11292
  if (property.functionBody != null && property.type === types/* .SchemaTypes.Function */.L.Function) {
10963
- const parameterNames = [
11293
+ const factory = builder.get("factory");
11294
+ const args = [
10964
11295
  "enriched",
10965
11296
  "collectionName"
10966
11297
  ];
10967
11298
  if (property.injected != null) {
10968
- const factory = builder.get("factory");
10969
- const parameter = factory.createParameter(property.injected);
10970
- factory.parameters(parameter);
10971
- parameterNames.push(parameter.name);
10972
- }
10973
- const declarationsSlot = builder.get("factory.function.declarations");
10974
- // Unwrap the functions to removing currying
10975
- const defaultFunctionWithParameters = this.toNamedFunction(property.functionBody.toString(), declarationsSlot);
10976
- defaultFunctionWithParameters.builder.parameters(...parameterNames.map((w, i)=>({
10977
- name: defaultFunctionWithParameters.parameters[i],
10978
- callName: w
10979
- })));
11299
+ args.push(factory.bind(property.injected));
11300
+ }
10980
11301
  const slot = builder.get("factory.function.assignment");
10981
11302
  const enrichedAssignmentPath = property.getAssignmentPath({
10982
11303
  parent: "enriched"
10983
11304
  });
10984
- slot.assign(enrichedAssignmentPath).value(defaultFunctionWithParameters.builder.toCallable());
11305
+ // The definition is curried: calling it with the entity returns the function the
11306
+ // property holds
11307
+ slot.assign(enrichedAssignmentPath).value(this.emitBoundCall(factory, property.functionBody, args));
10985
11308
  return builder;
10986
11309
  }
10987
11310
  return super.handle(property, builder);
@@ -11036,34 +11359,17 @@ class EnrichmentDefaultFunctionHandler extends PropertyInfoHandler {
11036
11359
  handle(property, builder) {
11037
11360
  if (property.defaultValue != null && typeof property.defaultValue === "function") {
11038
11361
  this.setEnrichedProperty(property, builder);
11039
- // we need to add the call for this function too, want to create an if
11040
- const declarationsSlot = builder.get("factory.function.declarations");
11041
- if (property.injected != null) {
11042
- const factory = builder.get("factory");
11043
- if (factory == null) {
11044
- throw new Error("Error building enricher, could not find slot for factory");
11045
- }
11046
- const parameter = factory.createParameter(property.injected);
11047
- factory.parameters(parameter);
11048
- const defaultFunctionWithParameters = this.toNamedFunction(property.defaultValue.toString(), declarationsSlot);
11049
- // This is ok, defaults can only inject one parameter anyways
11050
- defaultFunctionWithParameters.builder.parameters(...defaultFunctionWithParameters.parameters.map((w)=>({
11051
- name: w,
11052
- callName: parameter.name
11053
- })));
11054
- const ifsSlot = builder.get("factory.function.ifs");
11055
- const enrichedAssignmentPath = property.getAssignmentPath({
11056
- parent: "enriched"
11057
- });
11058
- ifsSlot.if(`${enrichedAssignmentPath} == null`).appendBody(`${enrichedAssignmentPath} = ${defaultFunctionWithParameters.builder.toCallable()}`);
11059
- return builder;
11060
- }
11061
- const defaultFunction = this.toNamedFunction(property.defaultValue.toString(), declarationsSlot);
11362
+ const factory = builder.get("factory");
11363
+ // Defaults take at most one argument: the injected value, when there is one
11364
+ const args = property.injected != null ? [
11365
+ factory.bind(property.injected)
11366
+ ] : [];
11367
+ const call = this.emitBoundCall(factory, property.defaultValue, args);
11062
11368
  const ifsSlot = builder.get("factory.function.ifs");
11063
11369
  const enrichedAssignmentPath = property.getAssignmentPath({
11064
11370
  parent: "enriched"
11065
11371
  });
11066
- ifsSlot.if(`${enrichedAssignmentPath} == null`).appendBody(`${enrichedAssignmentPath} = ${defaultFunction.builder.toCallable()}`);
11372
+ ifsSlot.if(`${enrichedAssignmentPath} == null`).appendBody(`${enrichedAssignmentPath} = ${call}`);
11067
11373
  return builder;
11068
11374
  }
11069
11375
  return super.handle(property, builder);
@@ -11076,22 +11382,15 @@ class EnrichmentDefaultFunctionHandler extends PropertyInfoHandler {
11076
11382
  class EnrichmentComputedValueHandler extends PropertyInfoHandler {
11077
11383
  handle(property, builder) {
11078
11384
  if (property.functionBody != null && property.type === types/* .SchemaTypes.Computed */.L.Computed) {
11079
- const parameterNames = [
11385
+ const factory = builder.get("factory");
11386
+ const args = [
11080
11387
  "enriched",
11081
11388
  "collectionName"
11082
11389
  ];
11083
11390
  if (property.injected != null) {
11084
- const factory = builder.get("factory");
11085
- const parameter = factory.createParameter(property.injected);
11086
- factory.parameters(parameter);
11087
- parameterNames.push(parameter.name);
11088
- }
11089
- const declarationsSlot = builder.get("factory.function.declarations");
11090
- const defaultFunctionWithParameters = this.toNamedFunction(property.functionBody.toString(), declarationsSlot);
11091
- defaultFunctionWithParameters.builder.parameters(...parameterNames.map((w, i)=>({
11092
- name: defaultFunctionWithParameters.parameters[i],
11093
- callName: w
11094
- })));
11391
+ args.push(factory.bind(property.injected));
11392
+ }
11393
+ const call = this.emitBoundCall(factory, property.functionBody, args);
11095
11394
  // Compute-once semantics for computed keys/identities: an existing value is
11096
11395
  // carried into the enriched literal and never recomputed — a key must stay
11097
11396
  // stable once assigned (content-hash ids would otherwise churn as the
@@ -11104,44 +11403,15 @@ class EnrichmentComputedValueHandler extends PropertyInfoHandler {
11104
11403
  const enrichedAssignmentPath = property.getAssignmentPath({
11105
11404
  parent: "enriched"
11106
11405
  });
11107
- ifsSlot.if(`${enrichedAssignmentPath} == null`).appendBody(`${enrichedAssignmentPath} = ${defaultFunctionWithParameters.builder.toCallable()}`);
11406
+ ifsSlot.if(`${enrichedAssignmentPath} == null`).appendBody(`${enrichedAssignmentPath} = ${call}`);
11108
11407
  return builder;
11109
11408
  }
11110
11409
  return super.handle(property, builder);
11111
11410
  }
11112
11411
  }
11113
11412
 
11114
- ;// CONCATENATED MODULE: ./src/schema/utils/propertyKind.ts
11115
-
11116
- /**
11117
- * Types whose runtime value is a JS array.
11118
- *
11119
- * `Array` and `Vector` are the same thing to every layer that copies, compares, hashes or
11120
- * freezes a value — a vector is a list of numbers and nothing more. They differ only where a
11121
- * backend chooses storage, which is the one place that should ask for `SchemaTypes.Vector` by
11122
- * name.
11123
- *
11124
- * This exists so adding a third array-shaped type is one edit rather than a hunt through
11125
- * twelve handlers. Missing one of those is silent in the worst way: a vector that clones by
11126
- * reference is shared with the change tracker's copy, so overwriting an embedding produces no
11127
- * diff and the save reports nothing to do.
11128
- */ const ARRAY_VALUED_TYPES = new Set([
11129
- types/* .SchemaTypes.Array */.L.Array,
11130
- types/* .SchemaTypes.Vector */.L.Vector
11131
- ]);
11132
- /** True when the property's value is a JS array and needs value rather than reference semantics. */ const isArrayValued = (type)=>ARRAY_VALUED_TYPES.has(type);
11133
- /**
11134
- * True when the property's elements are primitives, so a spread is a sufficient copy.
11135
- *
11136
- * A vector is always numbers, so it never needs the per-element deep copy an array of objects
11137
- * or dates does.
11138
- */ const PRIMITIVE_ELEMENT_TYPES = new Set([
11139
- types/* .SchemaTypes.String */.L.String,
11140
- types/* .SchemaTypes.Number */.L.Number,
11141
- types/* .SchemaTypes.Boolean */.L.Boolean
11142
- ]);
11143
- const hasPrimitiveElements = (type, elementType)=>type === types/* .SchemaTypes.Vector */.L.Vector || PRIMITIVE_ELEMENT_TYPES.has(elementType);
11144
-
11413
+ // EXTERNAL MODULE: ./src/schema/utils/propertyKind.ts
11414
+ var propertyKind = __webpack_require__(575);
11145
11415
  ;// CONCATENATED MODULE: ./src/codegen/handlers/enrichment/EnrichmentArrayHandler.ts
11146
11416
 
11147
11417
 
@@ -11151,7 +11421,7 @@ const hasPrimitiveElements = (type, elementType)=>type === types/* .SchemaTypes.
11151
11421
  * mark the root entity dirty instead of being silently lost on save.
11152
11422
  */ class EnrichmentArrayHandler extends PropertyInfoHandler {
11153
11423
  handle(property, builder) {
11154
- if (isArrayValued(property.type)) {
11424
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
11155
11425
  // Place the property in the enriched literal like any other leaf
11156
11426
  this.setEnrichedProperty(property, builder);
11157
11427
  const enrichedPath = property.getAssignmentPath({
@@ -11193,13 +11463,10 @@ class MergeDefaultFunctionHandler extends PropertyInfoHandler {
11193
11463
  // we are changing merge to be more like enrich so we can handle injections
11194
11464
  // we may need to change more. Need to move towards factories
11195
11465
  if (property.defaultValue != null && typeof property.defaultValue === "function") {
11196
- const defaultFunctionParameters = [];
11197
- if (property.injected != null) {
11198
- const factory = builder.get("factory");
11199
- const parameter = factory.createParameter(property.injected);
11200
- factory.parameters(parameter);
11201
- defaultFunctionParameters.push(parameter.name);
11202
- }
11466
+ const factory = builder.get("factory");
11467
+ const args = property.injected != null ? [
11468
+ factory.bind(property.injected)
11469
+ ] : [];
11203
11470
  // A defaulted property still merges from the source; the default only fills
11204
11471
  // the gap when neither side has a value
11205
11472
  this.emitMergeCopy(property, builder, {
@@ -11215,15 +11482,9 @@ class MergeDefaultFunctionHandler extends PropertyInfoHandler {
11215
11482
  const assignmentPath = property.getAssignmentPath({
11216
11483
  parent: "destination"
11217
11484
  });
11218
- const declarationsSlot = builder.get("factory.function.header");
11219
- const defaultFunctionWithParameters = this.toNamedFunction(property.defaultValue.toString(), declarationsSlot);
11220
- defaultFunctionWithParameters.builder.parameters(...defaultFunctionParameters.map((w, i)=>({
11221
- name: defaultFunctionWithParameters.parameters[i],
11222
- callName: w
11223
- })));
11224
11485
  const defaultIf = ifsSlot.if(`${selectorPath} == null`);
11225
11486
  this.emitDestinationAncestorGuards(property, defaultIf);
11226
- defaultIf.appendBody(`${assignmentPath} = ${defaultFunctionWithParameters.builder.toCallable()}`);
11487
+ defaultIf.appendBody(`${assignmentPath} = ${this.emitBoundCall(factory, property.defaultValue, args)}`);
11227
11488
  return builder;
11228
11489
  }
11229
11490
  return super.handle(property, builder);
@@ -11264,28 +11525,20 @@ class MergePrimitiveHandler extends PropertyInfoHandler {
11264
11525
  class MergeComputedValueHandler extends PropertyInfoHandler {
11265
11526
  handle(property, builder) {
11266
11527
  if (property.functionBody != null && property.type === types/* .SchemaTypes.Computed */.L.Computed) {
11267
- const parameterNames = [
11528
+ const factory = builder.get("factory");
11529
+ const args = [
11268
11530
  "source",
11269
11531
  "collectionName"
11270
11532
  ];
11271
11533
  if (property.injected != null) {
11272
- const factory = builder.get("factory");
11273
- const parameter = factory.createParameter(property.injected);
11274
- factory.parameters(parameter);
11275
- parameterNames.push(parameter.name);
11276
- }
11277
- const declarationsSlot = builder.get("factory.function.header");
11278
- const defaultFunctionWithParameters = this.toNamedFunction(property.functionBody.toString(), declarationsSlot);
11279
- defaultFunctionWithParameters.builder.parameters(...parameterNames.map((w, i)=>({
11280
- name: defaultFunctionWithParameters.parameters[i],
11281
- callName: w
11282
- })));
11534
+ args.push(factory.bind(property.injected));
11535
+ }
11283
11536
  const slot = builder.get("factory.function.assignments");
11284
11537
  const enrichedAssignmentPath = property.getAssignmentPath({
11285
11538
  parent: "destination"
11286
11539
  });
11287
11540
  // We want to recompute the value always in case there are changes
11288
- slot.assign(enrichedAssignmentPath).value(defaultFunctionWithParameters.builder.toCallable());
11541
+ slot.assign(enrichedAssignmentPath).value(this.emitBoundCall(factory, property.functionBody, args));
11289
11542
  return builder;
11290
11543
  }
11291
11544
  return super.handle(property, builder);
@@ -11358,7 +11611,7 @@ class MergeFunctionHandler extends PropertyInfoHandler {
11358
11611
  * reference is adopted as-is — same as the primitive copy this replaces.
11359
11612
  */ class MergeArrayHandler extends PropertyInfoHandler {
11360
11613
  handle(property, builder) {
11361
- if (isArrayValued(property.type)) {
11614
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
11362
11615
  const selectorPath = property.getSelectrorPath({
11363
11616
  parent: "source",
11364
11617
  assignmentType: "FORCE_NULLABLE_OR_OPTIONAL"
@@ -11695,7 +11948,7 @@ class CloneArrayHandler extends PropertyInfoHandler {
11695
11948
  super(), this.useFromPropertyName = useFromPropertyName;
11696
11949
  }
11697
11950
  handle(property, builder) {
11698
- if (isArrayValued(property.type)) {
11951
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
11699
11952
  // Arrays are leaf properties — they have no child PropertyInfos, so the
11700
11953
  // copy must happen here for every array, including nullable/optional ones.
11701
11954
  // The `!== undefined` guard below covers absent values; an explicit null is copied as
@@ -11721,7 +11974,7 @@ class CloneArrayHandler extends PropertyInfoHandler {
11721
11974
  // across merges), and a Proxy cannot pass a structured-clone boundary.
11722
11975
  const elementType = property.innerSchema?.type;
11723
11976
  let copyExpression;
11724
- if (hasPrimitiveElements(property.type, elementType)) {
11977
+ if ((0,propertyKind/* .hasPrimitiveElements */.L)(property.type, elementType)) {
11725
11978
  copyExpression = `[...${entitySelectorPath}]`;
11726
11979
  } else if (elementType === types/* .SchemaTypes.Date */.L.Date) {
11727
11980
  copyExpression = `${entitySelectorPath}.map(function (v) { return v == null ? v : new Date(v); })`;
@@ -11840,7 +12093,7 @@ class CloneObjectHandler extends PropertyInfoHandler {
11840
12093
  // Anything that copies by assignment. An array-valued property must not land here:
11841
12094
  // assigning the reference shares it with the source, which is the whole point of
11842
12095
  // CloneArrayHandler.
11843
- if (property.type != types/* .SchemaTypes.Object */.L.Object && isArrayValued(property.type) === false) {
12096
+ if (property.type != types/* .SchemaTypes.Object */.L.Object && (0,propertyKind/* .isArrayValued */.l)(property.type) === false) {
11844
12097
  const slot = builder.get("if");
11845
12098
  const useFromPropertyName = this.useFromPropertyName;
11846
12099
  const entitySelectorPath = property.getSelectrorPath({
@@ -11903,7 +12156,7 @@ class CloneHandlerBuilder {
11903
12156
 
11904
12157
  class CompareArrayHandler extends PropertyInfoHandler {
11905
12158
  handle(property, builder) {
11906
- if (isArrayValued(property.type)) {
12159
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
11907
12160
  let compare = builder.getOrDefault("result.variable.compare");
11908
12161
  const leftCompare = property.getSelectrorPath({
11909
12162
  parent: "a"
@@ -12198,7 +12451,6 @@ class DeserializeDeserializerHandler extends PropertyInfoHandler {
12198
12451
  handle(property, builder) {
12199
12452
  if (property.valueDeserializer != null) {
12200
12453
  let objectBuilder = builder.getOrDefault("result.variable.object");
12201
- const assignmentBuilder = builder.getOrDefault("functions");
12202
12454
  // Read the incoming record by `from` (storage) name
12203
12455
  const entitySelectorPath = property.getSelectrorPath({
12204
12456
  parent: "unserialized",
@@ -12211,18 +12463,16 @@ class DeserializeDeserializerHandler extends PropertyInfoHandler {
12211
12463
  name: "object"
12212
12464
  });
12213
12465
  }
12214
- const defaultFunctionWithParameters = this.toNamedFunction(property.valueDeserializer.toString(), assignmentBuilder);
12215
- defaultFunctionWithParameters.builder.parameters(...defaultFunctionWithParameters.parameters.map((_, i)=>({
12216
- name: defaultFunctionWithParameters.parameters[i],
12217
- callName: entitySelectorPath
12218
- })));
12466
+ const call = this.emitBoundCall(builder, property.valueDeserializer, [
12467
+ entitySelectorPath
12468
+ ]);
12219
12469
  if (property.parent == null) {
12220
- objectBuilder.property(`${property.name}: ${defaultFunctionWithParameters.builder.toCallable()}`);
12470
+ objectBuilder.property(`${property.name}: ${call}`);
12221
12471
  return builder;
12222
12472
  }
12223
12473
  const slotPath = new SlotPath(...property.getParentPathArray());
12224
12474
  objectBuilder = objectBuilder.get(slotPath.get());
12225
- objectBuilder.property(`${property.name}: ${defaultFunctionWithParameters.builder.toCallable()}`);
12475
+ objectBuilder.property(`${property.name}: ${call}`);
12226
12476
  return builder;
12227
12477
  }
12228
12478
  return super.handle(property, builder);
@@ -12248,7 +12498,7 @@ class DeserializeDeserializerHandler extends PropertyInfoHandler {
12248
12498
  return `[...${selector}]`;
12249
12499
  }
12250
12500
  handle(property, builder) {
12251
- if (isArrayValued(property.type)) {
12501
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
12252
12502
  const slotPath = new SlotPath("result.variable.object");
12253
12503
  // Create the result object when this is the first property iterated —
12254
12504
  // handler output cannot depend on schema property order
@@ -12489,7 +12739,7 @@ class HashComputedValueHandler extends PropertyInfoHandler {
12489
12739
  * objects would collapse every value to "[object Object]" and collide.
12490
12740
  */ class HashArrayHandler extends PropertyInfoHandler {
12491
12741
  handle(property, builder) {
12492
- if (isArrayValued(property.type)) {
12742
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
12493
12743
  let stringBuilder = builder.getOrDefault("hash-object-return.variable.string");
12494
12744
  const entitySelectorPath = property.getSelectrorPath({
12495
12745
  parent: "entity"
@@ -12654,7 +12904,7 @@ class EnableChangeTrackingObjectHandler extends PropertyInfoHandler {
12654
12904
  * mark the root entity dirty instead of being silently lost on save.
12655
12905
  */ class EnableChangeTrackingArrayHandler extends PropertyInfoHandler {
12656
12906
  handle(property, builder) {
12657
- if (isArrayValued(property.type)) {
12907
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
12658
12908
  const assignmentSlot = builder.get("assignment");
12659
12909
  const childSelectorPath = property.getSelectrorPath({
12660
12910
  parent: "entity"
@@ -12731,7 +12981,7 @@ class FreezeObjectHandler extends PropertyInfoHandler {
12731
12981
 
12732
12982
  class FreezeArrayHandler extends PropertyInfoHandler {
12733
12983
  handle(property, builder) {
12734
- if (isArrayValued(property.type)) {
12984
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
12735
12985
  const assignmentSlot = builder.get("assignment");
12736
12986
  const childSelectorPath = property.getSelectrorPath({
12737
12987
  parent: "entity"
@@ -12867,7 +13117,6 @@ class SerializeSerializerHandler extends PropertyInfoHandler {
12867
13117
  handle(property, builder) {
12868
13118
  if (property.valueSerializer != null) {
12869
13119
  const slot = builder.getOrDefault("if");
12870
- const assignmentBuilder = builder.getOrDefault("functions");
12871
13120
  // Serialize maps in-memory shape -> storage shape: read the entity by
12872
13121
  // property name, write the result by `from` (storage) name
12873
13122
  const entitySelectorPath = property.getSelectrorPath({
@@ -12877,17 +13126,15 @@ class SerializeSerializerHandler extends PropertyInfoHandler {
12877
13126
  parent: "result",
12878
13127
  useFromPropertyName: true
12879
13128
  });
12880
- const defaultFunctionWithParameters = this.toNamedFunction(property.valueSerializer.toString(), assignmentBuilder);
12881
- defaultFunctionWithParameters.builder.parameters(...defaultFunctionWithParameters.parameters.map((_, i)=>({
12882
- name: defaultFunctionWithParameters.parameters[i],
12883
- callName: entitySelectorPath
12884
- })));
13129
+ const call = this.emitBoundCall(builder, property.valueSerializer, [
13130
+ entitySelectorPath
13131
+ ]);
12885
13132
  if (property.parent == null) {
12886
- slot.if(`Object.hasOwn(entity, "${property.name}")`).appendBody(`${resultSelectorPath} = ${defaultFunctionWithParameters.builder.toCallable()}`);
13133
+ slot.if(`Object.hasOwn(entity, "${property.name}")`).appendBody(`${resultSelectorPath} = ${call}`);
12887
13134
  return builder;
12888
13135
  }
12889
13136
  // Nested serializer: same pattern as SerializeValueHandler — if block for parent existence, then assign via serializer
12890
- this.emitSerializeNestedAssignment(property, slot, defaultFunctionWithParameters.builder.toCallable());
13137
+ this.emitSerializeNestedAssignment(property, slot, call);
12891
13138
  return builder;
12892
13139
  }
12893
13140
  return super.handle(property, builder);
@@ -12946,7 +13193,7 @@ class SerializeComputedHandler extends PropertyInfoHandler {
12946
13193
  return `[...${selector}]`;
12947
13194
  }
12948
13195
  handle(property, builder) {
12949
- if (isArrayValued(property.type)) {
13196
+ if ((0,propertyKind/* .isArrayValued */.l)(property.type)) {
12950
13197
  const slot = builder.get("if");
12951
13198
  // Serialize maps in-memory shape -> storage shape: read the entity by
12952
13199
  // property name, write the result by `from` (storage) name
@@ -13850,8 +14097,8 @@ const arrayConverter = (property, context)=>{
13850
14097
  // Create the function using new Function()
13851
14098
  // If no parameters, call with just the body; otherwise spread the params
13852
14099
  const fn = params.length > 0 ? new Function(...params, functionBody) : new Function(functionBody);
13853
- // Wrap it so toString() returns the original arrow function string
13854
- // This is needed because the schema system validates that functions are arrow functions
14100
+ // Wrap it so toString() returns the original arrow function string, so
14101
+ // serializing the rehydrated schema writes the same functionSource again
13855
14102
  recreatedFn = Object.assign(fn, {
13856
14103
  toString: ()=>functionSource
13857
14104
  });
@@ -13860,7 +14107,7 @@ const arrayConverter = (property, context)=>{
13860
14107
  recreatedFn = ()=>{
13861
14108
  throw new Error(`Cannot recreate computed property ${computedProp.name}: ${e instanceof Error ? e.message : 'unknown error'}`);
13862
14109
  };
13863
- // Ensure toString returns an arrow function for validation
14110
+ // Keep functionSource re-parseable if this schema is serialized again
13864
14111
  Object.assign(recreatedFn, {
13865
14112
  toString: ()=>`() => { throw new Error("Cannot recreate computed property ${computedProp.name}"); }`
13866
14113
  });
@@ -13997,39 +14244,16 @@ class SetHandlerBuilder {
13997
14244
  }
13998
14245
  }
13999
14246
 
14000
- ;// CONCATENATED MODULE: ./src/schema/SchemaDefinition.ts
14001
-
14002
-
14003
-
14004
-
14005
-
14006
-
14007
-
14008
-
14009
-
14010
-
14011
-
14012
-
14013
-
14014
-
14015
-
14016
-
14017
-
14018
-
14019
-
14020
-
14021
-
14022
-
14023
-
14024
-
14025
-
14026
-
14027
- function assertPropertyHandled(generatorName, property, result) {
14028
- if (result == null) {
14029
- throw new Error(`Schema compilation failed: no '${generatorName}' code generator handles property '${property.getAssignmentPath()}' (type: ${property.type}). Add a handler for this property shape or mark it not applicable in the ${generatorName} chain.`);
14030
- }
14031
- }
14032
- function createChangeTracker() {
14247
+ ;// CONCATENATED MODULE: ./src/schema/changeTracker.ts
14248
+ /**
14249
+ * Builds the proxy factory that change-tracks an entity.
14250
+ *
14251
+ * Generated schema code receives the result as a bound value — a parameter of the generated
14252
+ * factory — and never refers to this module by name. Name references do not survive a minifier,
14253
+ * which renames the declaration but cannot see inside generated source text (#40, #46). The
14254
+ * returned function holds no per-entity state, so one per compiled schema is shared by every
14255
+ * entity it tracks.
14256
+ */ function createChangeTracker() {
14033
14257
  const DIRTY_ENTITY_MARKER = "isDirty";
14034
14258
  const CHANGES_ENTITY_KEY = "changes";
14035
14259
  const ORIGINAL_ENTITY_KEY = "original";
@@ -14128,6 +14352,40 @@ function createChangeTracker() {
14128
14352
  return new Proxy(entity, proxyHandler);
14129
14353
  };
14130
14354
  }
14355
+
14356
+ ;// CONCATENATED MODULE: ./src/schema/SchemaDefinition.ts
14357
+
14358
+
14359
+
14360
+
14361
+
14362
+
14363
+
14364
+
14365
+
14366
+
14367
+
14368
+
14369
+
14370
+
14371
+
14372
+
14373
+
14374
+
14375
+
14376
+
14377
+
14378
+
14379
+
14380
+
14381
+
14382
+
14383
+
14384
+ function assertPropertyHandled(generatorName, property, result) {
14385
+ if (result == null) {
14386
+ throw new Error(`Schema compilation failed: no '${generatorName}' code generator handles property '${property.getAssignmentPath()}' (type: ${property.type}). Add a handler for this property shape or mark it not applicable in the ${generatorName} chain.`);
14387
+ }
14388
+ }
14131
14389
  class SchemaDefinition extends SchemaBase {
14132
14390
  instance;
14133
14391
  type = types/* .SchemaTypes.Definition */.L.Definition;
@@ -14178,10 +14436,22 @@ class SchemaDefinition extends SchemaBase {
14178
14436
  throw e;
14179
14437
  }
14180
14438
  }
14181
- createFunction(builder, ...fnArgs) {
14439
+ /**
14440
+ * Compiles `builder` into a function taking `fnArgs`.
14441
+ *
14442
+ * A builder with bindings is compiled one level out: an outer function whose parameters are
14443
+ * the bindings, called once here with their values, returns the function that is kept. The
14444
+ * bound values become closure variables of that function, so the per-call cost is a context
14445
+ * read rather than anything resolved by name.
14446
+ */ createFunction(builder, ...fnArgs) {
14182
14447
  const body = builder.toString();
14448
+ const bindings = builder.getBindings();
14183
14449
  try {
14184
- return Function(...fnArgs, body);
14450
+ if (bindings.length === 0) {
14451
+ return Function(...fnArgs, body);
14452
+ }
14453
+ const outer = Function(...bindings.map((w)=>w.name), `return function(${fnArgs.join(", ")}) {\n${body}\n}`);
14454
+ return outer(...bindings.map((w)=>w.value));
14185
14455
  } catch (e) {
14186
14456
  logger/* .logger.error */.vF.error(`Error compiling schema function. Function Body: ${body}`);
14187
14457
  throw e;
@@ -14314,9 +14584,11 @@ class SchemaDefinition extends SchemaBase {
14314
14584
  const serializeHandler = serializeHandlerBuilder.build();
14315
14585
  const compareIdsHandler = compareIdsHandlerBuilder.build();
14316
14586
  const setHandlerHanlder = setHandlerBuilder.build();
14587
+ // Handed to the generated functions as a value, never embedded as source and called
14588
+ // by name — a minifier renames the declaration and breaks every schema (#40).
14589
+ const changeTracker = createChangeTracker();
14317
14590
  const changeTrackingCodeBuilder = new blocks/* .CodeBuilder */.Nl();
14318
- changeTrackingCodeBuilder.raw(`${createChangeTracker.toString()}`);
14319
- changeTrackingCodeBuilder.slot("declarations").variable("enableChangeTracking").value('createChangeTracker()');
14591
+ changeTrackingCodeBuilder.bind(changeTracker, "enableChangeTracking");
14320
14592
  // Nested proxies are installed by assigning through already-proxied parents;
14321
14593
  // pause tracking during setup so those writes don't register as changes
14322
14594
  changeTrackingCodeBuilder.slot("pause").raw('\tconst hadTracking = entity.__tracking__ != null;\n\tif (!hadTracking) { Object.defineProperty(entity, "__tracking__", { value: { changes: {}, isDirty: false, original: {}, isPaused: false }, configurable: true, writable: true, enumerable: false }); }\n\tconst wasPaused = entity.__tracking__.isPaused;\n\tentity.__tracking__.isPaused = true;');
@@ -14345,9 +14617,10 @@ class SchemaDefinition extends SchemaBase {
14345
14617
  }).parameters({
14346
14618
  name: "collectionName",
14347
14619
  value: this.collectionName
14620
+ }, {
14621
+ name: "changeTracker",
14622
+ value: changeTracker
14348
14623
  });
14349
- enricherFunctionRoot.slot("changeTracker").raw(`${createChangeTracker.toString()}`);
14350
- enricherFunctionRoot.slot("changeTrackerFunction").raw(`\tconst changeTracker = createChangeTracker();`);
14351
14624
  const enricherFunctionBody = enricherFunctionRoot.function(undefined, {
14352
14625
  name: "function"
14353
14626
  }).parameters("entity", "changeTrackingType").return();
@@ -14582,6 +14855,8 @@ class SchemaDefinition extends SchemaBase {
14582
14855
  enricherFunctionBody.get("append").insert(deserializeCodeBuilder.get("result"));
14583
14856
  enricherFunctionBody.get("append").insert(deserializeCodeBuilder.get("if"));
14584
14857
  enricherFunctionRoot.replace("function", new blocks/* .FunctionBuilder */.kF(undefined).parameters("unserialized", "changeTrackingType").return());
14858
+ // The deserialize slots moved in above call the deserializers bound on their own builder
14859
+ enricherFunctionRoot.parameters(...deserializeCodeBuilder.getBindings());
14585
14860
  const postProcessGenerator = this.createReturnFunction(enricherCodeBuilder);
14586
14861
  const postProcessParams = enricherFunctionRoot.getParameters();
14587
14862
  // Combine prepare and serialize
@@ -14590,6 +14865,10 @@ class SchemaDefinition extends SchemaBase {
14590
14865
  preprocessCodeBuilder.get("main").insert(serializeCodeBuilder.get("assignments"));
14591
14866
  preprocessCodeBuilder.get("main").insert(serializeCodeBuilder.get("functions"));
14592
14867
  preprocessCodeBuilder.get("main").insert(serializeCodeBuilder.get("if"));
14868
+ // Likewise the serialize slots call the serializers bound on the serialize builder
14869
+ for (const binding of serializeCodeBuilder.getBindings()){
14870
+ preprocessCodeBuilder.bind(binding.value, binding.name);
14871
+ }
14593
14872
  const getIdsFunction = this.createFunction(idSelectorCodeBuilder, "entity");
14594
14873
  const getHashTypeFunction = this.createFunction(hashTypeCodeBuilder, "entity");
14595
14874
  const prepareFunction = this.createFunction(prepareCodeBuilder, "entity");
@@ -15231,6 +15510,8 @@ const s = {
15231
15510
 
15232
15511
 
15233
15512
 
15513
+ // EXTERNAL MODULE: ./src/schema/utils/storageDates.ts
15514
+ var storageDates = __webpack_require__(894);
15234
15515
  ;// CONCATENATED MODULE: ./src/schema/index.ts
15235
15516
 
15236
15517
 
@@ -15244,6 +15525,7 @@ const s = {
15244
15525
 
15245
15526
 
15246
15527
 
15528
+
15247
15529
  },
15248
15530
  537(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
15249
15531
  __webpack_require__.d(__webpack_exports__, {
@@ -15280,6 +15562,129 @@ var HashType = /*#__PURE__*/ function(HashType) {
15280
15562
  }({});
15281
15563
 
15282
15564
 
15565
+ },
15566
+ 575(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
15567
+ __webpack_require__.d(__webpack_exports__, {
15568
+ L: () => (hasPrimitiveElements),
15569
+ l: () => (isArrayValued)
15570
+ });
15571
+ /* import */ var _types__rspack_import_0 = __webpack_require__(537);
15572
+
15573
+ /**
15574
+ * Types whose runtime value is a JS array.
15575
+ *
15576
+ * `Array` and `Vector` are the same thing to every layer that copies, compares, hashes or
15577
+ * freezes a value — a vector is a list of numbers and nothing more. They differ only where a
15578
+ * backend chooses storage, which is the one place that should ask for `SchemaTypes.Vector` by
15579
+ * name.
15580
+ *
15581
+ * This exists so adding a third array-shaped type is one edit rather than a hunt through
15582
+ * twelve handlers. Missing one of those is silent in the worst way: a vector that clones by
15583
+ * reference is shared with the change tracker's copy, so overwriting an embedding produces no
15584
+ * diff and the save reports nothing to do.
15585
+ */ const ARRAY_VALUED_TYPES = new Set([
15586
+ _types__rspack_import_0/* .SchemaTypes.Array */.L.Array,
15587
+ _types__rspack_import_0/* .SchemaTypes.Vector */.L.Vector
15588
+ ]);
15589
+ /** True when the property's value is a JS array and needs value rather than reference semantics. */ const isArrayValued = (type)=>ARRAY_VALUED_TYPES.has(type);
15590
+ /**
15591
+ * True when the property's elements are primitives, so a spread is a sufficient copy.
15592
+ *
15593
+ * A vector is always numbers, so it never needs the per-element deep copy an array of objects
15594
+ * or dates does.
15595
+ */ const PRIMITIVE_ELEMENT_TYPES = new Set([
15596
+ _types__rspack_import_0/* .SchemaTypes.String */.L.String,
15597
+ _types__rspack_import_0/* .SchemaTypes.Number */.L.Number,
15598
+ _types__rspack_import_0/* .SchemaTypes.Boolean */.L.Boolean
15599
+ ]);
15600
+ const hasPrimitiveElements = (type, elementType)=>type === _types__rspack_import_0/* .SchemaTypes.Vector */.L.Vector || PRIMITIVE_ELEMENT_TYPES.has(elementType);
15601
+
15602
+
15603
+ },
15604
+ 894(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
15605
+ __webpack_require__.d(__webpack_exports__, {
15606
+ T: () => (getStorageDateReviver)
15607
+ });
15608
+ /* import */ var _types__rspack_import_0 = __webpack_require__(537);
15609
+ /* import */ var _propertyKind__rspack_import_1 = __webpack_require__(575);
15610
+
15611
+
15612
+ const collectDatePaths = (properties, paths)=>{
15613
+ for (const property of properties){
15614
+ // The stored value belongs to whoever wrote it: a custom serializer, deserializer or
15615
+ // transform reads it back, and would be handed a Date it did not expect. Unmapped
15616
+ // properties are never stored.
15617
+ if (property.valueSerializer != null || property.valueDeserializer != null || property.transform != null || property.isUnmapped) {
15618
+ continue;
15619
+ }
15620
+ if (property.type === _types__rspack_import_0/* .SchemaTypes.Object */.L.Object) {
15621
+ collectDatePaths(property.children, paths);
15622
+ continue;
15623
+ }
15624
+ const isArray = (0,_propertyKind__rspack_import_1/* .isArrayValued */.l)(property.type) && property.innerSchema?.type === _types__rspack_import_0/* .SchemaTypes.Date */.L.Date;
15625
+ if (property.type !== _types__rspack_import_0/* .SchemaTypes.Date */.L.Date && isArray === false) {
15626
+ continue;
15627
+ }
15628
+ paths.push({
15629
+ segments: [
15630
+ ...property.getParentPathArray({
15631
+ useFromPropertyName: true
15632
+ }),
15633
+ property.getResolvedName()
15634
+ ],
15635
+ isArray
15636
+ });
15637
+ }
15638
+ };
15639
+ const reviveAt = (record, path)=>{
15640
+ const { segments } = path;
15641
+ let parent = record;
15642
+ for(let i = 0, length = segments.length - 1; i < length; i++){
15643
+ parent = parent[segments[i]];
15644
+ // An absent or null parent holds no date
15645
+ if (parent == null || typeof parent !== "object") {
15646
+ return;
15647
+ }
15648
+ }
15649
+ const key = segments[segments.length - 1];
15650
+ const value = parent[key];
15651
+ if (path.isArray === false) {
15652
+ if (typeof value === "string") {
15653
+ parent[key] = new Date(value);
15654
+ }
15655
+ return;
15656
+ }
15657
+ if (Array.isArray(value)) {
15658
+ for(let i = 0, length = value.length; i < length; i++){
15659
+ if (typeof value[i] === "string") {
15660
+ value[i] = new Date(value[i]);
15661
+ }
15662
+ }
15663
+ }
15664
+ };
15665
+ /** Per schema: `null` for a schema with no dates, so a caller can skip the pass. */ const revivers = new WeakMap();
15666
+ /**
15667
+ * The reviver for `schema`'s records, or `null` when it declares no dates.
15668
+ *
15669
+ * Built once per compiled schema. A read revives every row it returns, so the paths are resolved
15670
+ * here rather than per row.
15671
+ */ const getStorageDateReviver = (schema)=>{
15672
+ const cached = revivers.get(schema);
15673
+ if (cached !== undefined) {
15674
+ return cached;
15675
+ }
15676
+ const paths = [];
15677
+ collectDatePaths(schema.properties, paths);
15678
+ const reviver = paths.length === 0 ? null : (record)=>{
15679
+ for(let i = 0, length = paths.length; i < length; i++){
15680
+ reviveAt(record, paths[i]);
15681
+ }
15682
+ };
15683
+ revivers.set(schema, reviver);
15684
+ return reviver;
15685
+ };
15686
+
15687
+
15283
15688
  },
15284
15689
  76(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
15285
15690
  __webpack_require__.d(__webpack_exports__, {
@@ -15988,6 +16393,7 @@ __webpack_require__.d(__webpack_exports__, {
15988
16393
  formatExplanation: () => (/* reexport safe */ _plugins__rspack_import_7.formatExplanation),
15989
16394
  getLogLevel: () => (/* reexport safe */ _utilities__rspack_import_10.getLogLevel),
15990
16395
  getProperties: () => (/* reexport safe */ _expressions__rspack_import_4.getProperties),
16396
+ getStorageDateReviver: () => (/* reexport safe */ _schema__rspack_import_9.getStorageDateReviver),
15991
16397
  hasPrimitiveElements: () => (/* reexport safe */ _schema__rspack_import_9.hasPrimitiveElements),
15992
16398
  hash: () => (/* reexport safe */ _utilities__rspack_import_10.hash),
15993
16399
  hashJoin: () => (/* reexport safe */ _plugins__rspack_import_7.hashJoin),
@@ -16017,12 +16423,14 @@ __webpack_require__.d(__webpack_exports__, {
16017
16423
  parameter: () => (/* reexport safe */ _plugins__rspack_import_7.parameter),
16018
16424
  parameteriseDocument: () => (/* reexport safe */ _plugins__rspack_import_7.parameteriseDocument),
16019
16425
  parseFragment: () => (/* reexport safe */ _expressions__rspack_import_4.parseFragment),
16426
+ parseSelector: () => (/* reexport safe */ _expressions__rspack_import_4.parseSelector),
16020
16427
  peelCalls: () => (/* reexport safe */ _expressions__rspack_import_4.peelCalls),
16021
16428
  propertyInfoToJsonSchema: () => (/* reexport safe */ _schema__rspack_import_9.propertyInfoToJsonSchema),
16022
16429
  readJoinKey: () => (/* reexport safe */ _plugins__rspack_import_7.readJoinKey),
16023
16430
  rehydrateSchemaFromJsonSchema: () => (/* reexport safe */ _schema__rspack_import_9.rehydrateSchemaFromJsonSchema),
16024
16431
  rehydrateSchemaFromJsonString: () => (/* reexport safe */ _schema__rspack_import_9.rehydrateSchemaFromJsonString),
16025
16432
  renderCallAsJs: () => (/* reexport safe */ _expressions__rspack_import_4.renderCallAsJs),
16433
+ reportRenamedProperties: () => (/* reexport safe */ _plugins__rspack_import_7.reportRenamedProperties),
16026
16434
  resetLogLevel: () => (/* reexport safe */ _utilities__rspack_import_10.resetLogLevel),
16027
16435
  resolveBulkPersistChanges: () => (/* reexport safe */ _utilities__rspack_import_10.resolveBulkPersistChanges),
16028
16436
  s: () => (/* reexport safe */ _schema__rspack_import_9.s),
@@ -16053,9 +16461,9 @@ __webpack_require__.d(__webpack_exports__, {
16053
16461
  /* import */ var _expressions__rspack_import_4 = __webpack_require__(138);
16054
16462
  /* import */ var _performance__rspack_import_5 = __webpack_require__(971);
16055
16463
  /* import */ var _pipeline__rspack_import_6 = __webpack_require__(314);
16056
- /* import */ var _plugins__rspack_import_7 = __webpack_require__(640);
16464
+ /* import */ var _plugins__rspack_import_7 = __webpack_require__(756);
16057
16465
  /* import */ var _results__rspack_import_8 = __webpack_require__(264);
16058
- /* import */ var _schema__rspack_import_9 = __webpack_require__(755);
16466
+ /* import */ var _schema__rspack_import_9 = __webpack_require__(862);
16059
16467
  /* import */ var _utilities__rspack_import_10 = __webpack_require__(222);
16060
16468
 
16061
16469