@bjornpagen/bumbledb 1.1.0 → 1.2.1

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 (152) hide show
  1. package/COOKBOOK.md +114 -11
  2. package/README.md +52 -9
  3. package/dist/capacity.d.ts +22 -59
  4. package/dist/capacity.d.ts.map +1 -1
  5. package/dist/capacity.js +66 -13
  6. package/dist/capacity.js.map +1 -1
  7. package/dist/changes.d.ts +26 -3
  8. package/dist/changes.d.ts.map +1 -1
  9. package/dist/changes.js +89 -44
  10. package/dist/changes.js.map +1 -1
  11. package/dist/closed.d.ts +23 -51
  12. package/dist/closed.d.ts.map +1 -1
  13. package/dist/closed.js +110 -168
  14. package/dist/closed.js.map +1 -1
  15. package/dist/codec.d.ts +4 -9
  16. package/dist/codec.d.ts.map +1 -1
  17. package/dist/codec.js +108 -183
  18. package/dist/codec.js.map +1 -1
  19. package/dist/compile.d.ts +16 -16
  20. package/dist/compile.d.ts.map +1 -1
  21. package/dist/compile.js +36 -15
  22. package/dist/compile.js.map +1 -1
  23. package/dist/db-native.d.ts +39 -0
  24. package/dist/db-native.d.ts.map +1 -1
  25. package/dist/db-native.js +8 -0
  26. package/dist/db-native.js.map +1 -1
  27. package/dist/db.d.ts +28 -8
  28. package/dist/db.d.ts.map +1 -1
  29. package/dist/db.js +91 -38
  30. package/dist/db.js.map +1 -1
  31. package/dist/errors.d.ts +11 -3
  32. package/dist/errors.d.ts.map +1 -1
  33. package/dist/errors.js +13 -1
  34. package/dist/errors.js.map +1 -1
  35. package/dist/face.d.ts +19 -25
  36. package/dist/face.d.ts.map +1 -1
  37. package/dist/face.js +30 -24
  38. package/dist/face.js.map +1 -1
  39. package/dist/fields.d.ts +13 -26
  40. package/dist/fields.d.ts.map +1 -1
  41. package/dist/fields.js +89 -116
  42. package/dist/fields.js.map +1 -1
  43. package/dist/immutable.d.ts +10 -0
  44. package/dist/immutable.d.ts.map +1 -0
  45. package/dist/immutable.js +75 -0
  46. package/dist/immutable.js.map +1 -0
  47. package/dist/index.d.ts +16 -12
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +5 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/internal/log.d.ts +2 -0
  52. package/dist/internal/log.d.ts.map +1 -1
  53. package/dist/internal/log.js +2 -0
  54. package/dist/internal/log.js.map +1 -1
  55. package/dist/law.d.ts +13 -11
  56. package/dist/law.d.ts.map +1 -1
  57. package/dist/law.js +1 -1
  58. package/dist/law.js.map +1 -1
  59. package/dist/lower.d.ts.map +1 -1
  60. package/dist/lower.js +11 -6
  61. package/dist/lower.js.map +1 -1
  62. package/dist/native.d.ts +1 -1
  63. package/dist/native.d.ts.map +1 -1
  64. package/dist/native.js.map +1 -1
  65. package/dist/query/atom.d.ts +1 -1
  66. package/dist/query/atom.d.ts.map +1 -1
  67. package/dist/query/atom.js.map +1 -1
  68. package/dist/query/description.d.ts +33 -0
  69. package/dist/query/description.d.ts.map +1 -0
  70. package/dist/query/description.js +302 -0
  71. package/dist/query/description.js.map +1 -0
  72. package/dist/query/find.d.ts +21 -6
  73. package/dist/query/find.d.ts.map +1 -1
  74. package/dist/query/find.js.map +1 -1
  75. package/dist/query/lower.d.ts +75 -10
  76. package/dist/query/lower.d.ts.map +1 -1
  77. package/dist/query/lower.js +132 -163
  78. package/dist/query/lower.js.map +1 -1
  79. package/dist/query/parse-ir.d.ts +7 -2
  80. package/dist/query/parse-ir.d.ts.map +1 -1
  81. package/dist/query/parse-ir.js +240 -53
  82. package/dist/query/parse-ir.js.map +1 -1
  83. package/dist/query/run.d.ts.map +1 -1
  84. package/dist/query/run.js +8 -10
  85. package/dist/query/run.js.map +1 -1
  86. package/dist/query/scope.d.ts +24 -16
  87. package/dist/query/scope.d.ts.map +1 -1
  88. package/dist/query/scope.js +5 -10
  89. package/dist/query/scope.js.map +1 -1
  90. package/dist/relation.d.ts +22 -48
  91. package/dist/relation.d.ts.map +1 -1
  92. package/dist/relation.js +30 -82
  93. package/dist/relation.js.map +1 -1
  94. package/dist/rows.d.ts +7 -4
  95. package/dist/rows.d.ts.map +1 -1
  96. package/dist/rows.js +44 -198
  97. package/dist/rows.js.map +1 -1
  98. package/dist/runtime-errors.d.ts +26 -2
  99. package/dist/runtime-errors.d.ts.map +1 -1
  100. package/dist/runtime-errors.js +43 -3
  101. package/dist/runtime-errors.js.map +1 -1
  102. package/dist/schema.d.ts +9 -1
  103. package/dist/schema.d.ts.map +1 -1
  104. package/dist/schema.js +85 -24
  105. package/dist/schema.js.map +1 -1
  106. package/dist/selection.d.ts +27 -0
  107. package/dist/selection.d.ts.map +1 -0
  108. package/dist/selection.js +104 -0
  109. package/dist/selection.js.map +1 -0
  110. package/dist/shape.d.ts +12 -12
  111. package/dist/shape.d.ts.map +1 -1
  112. package/dist/statements.d.ts +17 -52
  113. package/dist/statements.d.ts.map +1 -1
  114. package/dist/statements.js +92 -111
  115. package/dist/statements.js.map +1 -1
  116. package/dist/values.d.ts +25 -0
  117. package/dist/values.d.ts.map +1 -0
  118. package/dist/values.js +203 -0
  119. package/dist/values.js.map +1 -0
  120. package/pack-provenance.json +3 -3
  121. package/package.json +4 -4
  122. package/src/capacity.ts +93 -80
  123. package/src/changes.ts +183 -54
  124. package/src/closed.ts +161 -314
  125. package/src/codec.ts +116 -190
  126. package/src/compile.ts +56 -32
  127. package/src/db-native.ts +42 -0
  128. package/src/db.ts +134 -52
  129. package/src/errors.ts +16 -1
  130. package/src/face.ts +44 -74
  131. package/src/fields.ts +100 -146
  132. package/src/immutable.ts +76 -0
  133. package/src/index.ts +36 -29
  134. package/src/internal/log.ts +2 -0
  135. package/src/law.ts +21 -18
  136. package/src/lower.ts +13 -10
  137. package/src/native.ts +2 -0
  138. package/src/query/atom.ts +1 -0
  139. package/src/query/description.ts +394 -0
  140. package/src/query/find.ts +20 -7
  141. package/src/query/lower.ts +177 -187
  142. package/src/query/parse-ir.ts +247 -54
  143. package/src/query/run.ts +15 -9
  144. package/src/query/scope.ts +42 -33
  145. package/src/relation.ts +58 -142
  146. package/src/rows.ts +62 -205
  147. package/src/runtime-errors.ts +47 -3
  148. package/src/schema.ts +99 -29
  149. package/src/selection.ts +124 -0
  150. package/src/shape.ts +18 -12
  151. package/src/statements.ts +138 -189
  152. package/src/values.ts +223 -0
@@ -1,13 +1,15 @@
1
- import { sealedFieldsOf } from "#closed.ts";
1
+ import { membersAgree, sealedFieldsOf } from "#closed.ts";
2
2
  import { AuthoringError, SdkInvariantError } from "#errors.ts";
3
- import { assertDeclarationOrderKey, f64 as f64Field, isFloatIntervalValue, isIntervalValue, literalShapeError, rosterOf, u64 as u64Field } from "#fields.ts";
3
+ import { assertDeclarationOrderKey, f64 as f64Field, i64 as i64Field, isFloatIntervalValue, isIntervalValue, literalShapeError, rosterOf, rostersAgree, u64 as u64Field } from "#fields.ts";
4
+ import { snapshotData } from "#immutable.ts";
4
5
  import { allen, and, eq, ge, gt, le, lt, ne, not, or, pointIn } from "#query/atom.ts";
5
6
  import { computeFieldOf, computeVarsOf, isComputeExpr, MAX_COMPUTE_DEPTH } from "#query/compute.ts";
6
7
  import { count, max, mean, min, pack, sum } from "#query/find.ts";
7
8
  import { parseQueryIr } from "#query/parse-ir.ts";
8
9
  import { fieldAntiJoins, fieldJoins, headFieldJoins, importFacadeOf, importFacadeOfOwner, inferred, isImportedSource, isTerm, labelImport, makeParam, makeSetParam, renderFieldKind, term } from "#query/scope.ts";
9
10
  import { literalWireOf } from "#scalar.ts";
10
- import { Uuid } from "#uuid.ts";
11
+ import { schemaDescriptor, schemasAgree } from "#schema.ts";
12
+ import { arrayValue, recordValue, taggedValueOf } from "#values.ts";
11
13
  const termOps = Object.freeze({
12
14
  param: makeParam,
13
15
  inSet: makeSetParam,
@@ -36,8 +38,8 @@ const EMPTY_RULE = Object.freeze({
36
38
  });
37
39
  /**
38
40
  * The MINT slot of a variable, the runtime twin of {@link MintSlotOf}: (i)
39
- * verifies the mint owner is the schema's own member value — a variable
40
- * minted from a foreign relation is refused, naming its label — and (ii)
41
+ * verifies the mint owner agrees with the schema's ordered declaration — a
42
+ * conflicting declaration is refused, naming its label — and (ii)
41
43
  * returns the descriptor it was minted at plus the law-computed class read
42
44
  * off the schema's frozen class map. Because {@link fieldJoins} is an
43
45
  * equality, judging every binding position against this one slot makes all
@@ -50,16 +52,16 @@ function mintSlotOf(context, ref) {
50
52
  // the descriptor it projected and the carrier class that survived
51
53
  // the projection (aggregate outputs are bare derived scalars).
52
54
  const column = facade.columns.get(ref.column);
53
- if (column === undefined || facade.source.schema !== context.theory) {
55
+ if (column === undefined || !schemasAgree(facade.source.schema, context.theory)) {
54
56
  throw new AuthoringError({
55
57
  message: `the variable ${ref.label} was minted from a query template schema ${context.theory.name} does not own`
56
58
  });
57
59
  }
58
60
  return column.slot ?? { field: ref.field, class: undefined };
59
61
  }
60
- if (context.theory.relations[ref.owner.name] !== ref.owner) {
62
+ if (!membersAgree(context.theory.relations[ref.owner.name], ref.owner)) {
61
63
  throw new AuthoringError({
62
- message: `the variable ${ref.label} was minted from a relation schema ${context.theory.name} does not declare — mint variables with v() from the schema's own relations`
64
+ message: `the variable ${ref.label} was minted from a relation schema ${context.theory.name} does not declare — use an equivalent ordered declaration`
63
65
  });
64
66
  }
65
67
  return { field: ref.field, class: context.classes[ref.owner.name]?.[ref.column] };
@@ -82,7 +84,7 @@ function membershipSet(context, field, value) {
82
84
  });
83
85
  }
84
86
  const seen = new Set();
85
- const members = value.map(function memberName(member) {
87
+ const members = arrayValue(context, value, function memberName(context, member) {
86
88
  if (typeof member !== "string") {
87
89
  throw literalShapeError(context, `a ${roster.name} handle name (string)`, member);
88
90
  }
@@ -97,16 +99,23 @@ function membershipSet(context, field, value) {
97
99
  const key = [...members].sort();
98
100
  return { name: `∈ ${roster.name} ${JSON.stringify(key)}`, members: Object.freeze(members) };
99
101
  }
100
- function resolveBindings(context, label, relation, bindings, joins = fieldJoins) {
102
+ function queryRecord(context, input) {
103
+ return recordValue(context, input, typeof input === "object" && input !== null ? Object.keys(input) : []);
104
+ }
105
+ function resolveBindings(context, label, input, bindings, joins = fieldJoins) {
106
+ const relation = context.theory.relations[input.name];
107
+ if (relation === undefined || !membersAgree(relation, input)) {
108
+ throw new AuthoringError({
109
+ message: `${label}: schema ${context.theory.name} does not declare this ordered relation`
110
+ });
111
+ }
112
+ // Retain the schema-owned declaration, not mutable caller metadata.
101
113
  const entries = [];
102
114
  const vars = [];
103
115
  const uses = [];
104
116
  const relationClasses = context.classes[relation.name];
105
117
  const ordered = sealedFieldsOf(relation);
106
- for (const [fieldName, value] of Object.entries(bindings)) {
107
- if (value === undefined) {
108
- continue;
109
- }
118
+ for (const [fieldName, value] of Object.entries(queryRecord(label, bindings))) {
110
119
  const declared = ordered.find(function byName(candidate) {
111
120
  return candidate.name === fieldName;
112
121
  });
@@ -166,7 +175,10 @@ function resolveBindings(context, label, relation, bindings, joins = fieldJoins)
166
175
  }));
167
176
  }
168
177
  else {
169
- bound = Object.freeze({ kind: "literal", value });
178
+ bound = Object.freeze({
179
+ kind: "literal",
180
+ value: ownLiteral(`${label}.${fieldName}`, declared.field, value, "binding")
181
+ });
170
182
  }
171
183
  entries.push(Object.freeze({ field: fieldName, data: declared.field, class: fieldClass, term: bound }));
172
184
  }
@@ -211,9 +223,22 @@ function sideUses(op, side, sibling, uses) {
211
223
  }));
212
224
  }
213
225
  function condDataOf(cond, uses) {
226
+ queryRecord("query condition", cond);
214
227
  if (cond.cond === "cmp") {
215
- const lhs = cmpTermDataOf(cond.lhs);
216
- const rhs = cmpTermDataOf(cond.rhs);
228
+ let lhs = cmpTermDataOf(cond.lhs);
229
+ let rhs = cmpTermDataOf(cond.rhs);
230
+ if (lhs.kind === "literal" && rhs.kind === "var") {
231
+ lhs = Object.freeze({
232
+ kind: "literal",
233
+ value: ownLiteral("comparison literal", rhs.ref.field, lhs.value, cond.op)
234
+ });
235
+ }
236
+ if (rhs.kind === "literal" && lhs.kind === "var") {
237
+ rhs = Object.freeze({
238
+ kind: "literal",
239
+ value: ownLiteral("comparison literal", lhs.ref.field, rhs.value, cond.op)
240
+ });
241
+ }
217
242
  sideUses(cond.op, lhs, rhs, uses);
218
243
  sideUses(cond.op, rhs, lhs, uses);
219
244
  if (cond.op === "allen") {
@@ -233,7 +258,7 @@ function condDataOf(cond, uses) {
233
258
  return Object.freeze({ kind: "cmp", op: { kind: cond.op }, lhs, rhs });
234
259
  }
235
260
  if (cond.cond === "tree") {
236
- const children = cond.children.map(function lowerChild(child) {
261
+ const children = arrayValue("query condition children", cond.children, function lowerChild(_context, child) {
237
262
  return condDataOf(child, uses);
238
263
  });
239
264
  return Object.freeze({ kind: "tree", op: cond.op, children: Object.freeze(children) });
@@ -243,21 +268,16 @@ function condDataOf(cond, uses) {
243
268
  });
244
269
  }
245
270
  function advanceWhere(context, state, cond) {
271
+ queryRecord("query condition", cond);
246
272
  if (typeof cond !== "object" || cond === null || !("cond" in cond)) {
247
273
  throw new AuthoringError({ message: "where() takes a comparison, an and()/or() tree, or a negated atom" });
248
274
  }
249
275
  if (cond.cond === "notInterior") {
250
- const bindings = Object.fromEntries(Object.entries(cond.bindings ?? {}).filter(function defined([, value]) {
251
- return value !== undefined;
252
- }));
253
- return notInteriorAdvance(context, state, cond.name, bindings);
276
+ return notInteriorAdvance(context, state, cond.name, queryRecord("negated interior bindings", cond.bindings));
254
277
  }
255
278
  if (cond.cond === "not") {
256
279
  const relation = cond.relation;
257
- const bindings = Object.fromEntries(Object.entries(cond.bindings ?? {}).filter(function defined([, value]) {
258
- return value !== undefined;
259
- }));
260
- const resolved = resolveBindings(context, `negated relation ${relation.name}`, relation, bindings, fieldAntiJoins);
280
+ const resolved = resolveBindings(context, `negated relation ${relation.name}`, relation, cond.bindings, fieldAntiJoins);
261
281
  return Object.freeze({
262
282
  items: Object.freeze([...state.items, Object.freeze({ kind: "negated", atom: resolved.atom })]),
263
283
  bound: state.bound,
@@ -274,10 +294,7 @@ function advanceWhere(context, state, cond) {
274
294
  }
275
295
  function advanceInterior(state, target, bindings, kind) {
276
296
  const resolved = [];
277
- for (const [key, value] of Object.entries(bindings)) {
278
- if (value === undefined) {
279
- continue;
280
- }
297
+ for (const [key, value] of Object.entries(queryRecord(`interior ${target.name} bindings`, bindings))) {
281
298
  if (!isTerm(value) || value[term] !== "var") {
282
299
  throw new AuthoringError({
283
300
  message: `interior ${target.name}: position ${key} takes a variable — bind literals and params through where()/match()`
@@ -621,27 +638,42 @@ function interiorAdvance(context, state, name, bindings) {
621
638
  }
622
639
  const importEntries = new WeakMap();
623
640
  const importTables = new WeakSet();
641
+ const importOrigins = new WeakMap();
642
+ function snapshotQueryData(input) {
643
+ return snapshotData(input, (source, snapshot) => {
644
+ // Detached imports retain their authoring identity for deduplication.
645
+ if (importTables.has(source)) {
646
+ const table = snapshot;
647
+ importTables.add(table);
648
+ importOrigins.set(table, importOrigins.get(source) ?? source);
649
+ const inner = importInner.get(source);
650
+ if (inner !== undefined)
651
+ importInner.set(table, inner);
652
+ }
653
+ });
654
+ }
624
655
  function importEntryOf(context, imported) {
625
656
  const cached = importEntries.get(imported);
626
657
  if (cached !== undefined) {
627
- if (imported.schema !== context.theory) {
658
+ if (!schemasAgree(imported.schema, context.theory)) {
628
659
  throw new AuthoringError({
629
660
  message: `${contextLabel(context)}: the imported query belongs to schema ${imported.schema.name}, not ${context.theory.name} — templates compose within one schema`
630
661
  });
631
662
  }
632
663
  return cached;
633
664
  }
634
- if (imported.schema !== context.theory) {
665
+ if (!schemasAgree(imported.schema, context.theory)) {
635
666
  throw new AuthoringError({
636
667
  message: `${contextLabel(context)}: the imported query belongs to schema ${imported.schema.name}, not ${context.theory.name} — templates compose within one schema`
637
668
  });
638
669
  }
639
- if (imported.data.kind === "reach") {
670
+ const data = imported.data;
671
+ if (data.kind === "reach") {
640
672
  throw new AuthoringError({
641
673
  message: `${contextLabel(context)}: a recursive query is not importable as a relation expression yet — declare the recursion on the consuming query (C05 boundary, recorded)`
642
674
  });
643
675
  }
644
- const userParams = imported.data.params.filter(function userSupplied(entry) {
676
+ const userParams = data.params.filter(function userSupplied(entry) {
645
677
  return entry.membership === undefined;
646
678
  });
647
679
  if (userParams.length > 0) {
@@ -654,10 +686,10 @@ function importEntryOf(context, imported) {
654
686
  const facade = importFacadeOf(imported);
655
687
  const table = Object.freeze({
656
688
  name: facade.owner.name,
657
- finds: imported.data.finds,
658
- rules: imported.data.rules
689
+ finds: data.finds,
690
+ rules: data.rules
659
691
  });
660
- const entry = Object.freeze({ table, inner: imported.data.interiors });
692
+ const entry = Object.freeze({ table, inner: data.interiors });
661
693
  importEntries.set(imported, entry);
662
694
  importTables.add(table);
663
695
  importInner.set(table, entry.inner);
@@ -679,8 +711,9 @@ function referencedImports(interiors, rec, rules) {
679
711
  continue;
680
712
  }
681
713
  const target = item.target;
682
- if (importTables.has(target) && !seen.has(target)) {
683
- seen.add(target);
714
+ const origin = importOrigins.get(target) ?? target;
715
+ if (importTables.has(target) && !seen.has(origin)) {
716
+ seen.add(origin);
684
717
  out.push(target);
685
718
  }
686
719
  }
@@ -712,7 +745,8 @@ function spliceImports(interiors, rec, rules) {
712
745
  const names = new Set();
713
746
  const added = new Set();
714
747
  function add(table) {
715
- if (added.has(table)) {
748
+ const origin = importOrigins.get(table) ?? table;
749
+ if (added.has(origin)) {
716
750
  return;
717
751
  }
718
752
  if (names.has(table.name)) {
@@ -720,7 +754,7 @@ function spliceImports(interiors, rec, rules) {
720
754
  message: `query: the derived-table name ${table.name} appears twice after import splicing — rename the colliding interior (names are unique)`
721
755
  });
722
756
  }
723
- added.add(table);
757
+ added.add(origin);
724
758
  names.add(table.name);
725
759
  spliced.push(table);
726
760
  }
@@ -749,15 +783,13 @@ function notInteriorAdvance(context, state, name, bindings) {
749
783
  }
750
784
  function findColumns(context, entries) {
751
785
  const columns = [];
786
+ queryRecord("query find", entries);
752
787
  // Nonrecursive derived stages (interiors) may emit aggregate/computed
753
788
  // outputs (C05: "do not leave Interior.rules projection only"); ONLY the
754
789
  // recursive feedback cycle stays projection-only — no aggregate,
755
790
  // arithmetic-created value or negation flows through it.
756
791
  const recName = context.kind === "rec-base" || context.kind === "rec-arm" ? context.self.name : undefined;
757
792
  for (const [name, entry] of Object.entries(entries)) {
758
- if (entry === undefined) {
759
- continue;
760
- }
761
793
  if (recName !== undefined && !(isTerm(entry) && entry[term] === "var")) {
762
794
  throw new AuthoringError({
763
795
  message: `rec ${recName}: a rec head projects bound variables only — no aggregate or arithmetic-created value flows through the feedback cycle (compute over the finished set in the main rules)`
@@ -912,7 +944,7 @@ function paramRegistryOf(interiors, rec, rules) {
912
944
  if (existing.anchor !== undefined && use.anchor !== undefined) {
913
945
  const registered = rosterOf(existing.anchor);
914
946
  const anchored = rosterOf(use.anchor);
915
- if (registered !== anchored) {
947
+ if (!rostersAgree(registered, anchored)) {
916
948
  throw new AuthoringError({
917
949
  message: `query param ${use.name} is anchored at ${renderParamAnchor(registered)} and at ${renderParamAnchor(anchored)} — a closed-anchored param translates handle names through ONE roster (one name, one domain); name the params differently`
918
950
  });
@@ -984,7 +1016,7 @@ function alignedHeadOf(label, rules) {
984
1016
  }
985
1017
  rule.finds.forEach(function verifyClosedSlice(column, position) {
986
1018
  const lead = first.finds[position];
987
- if (lead !== undefined && column.closed !== lead.closed) {
1019
+ if (lead !== undefined && !rostersAgree(column.closed, lead.closed)) {
988
1020
  throw new AuthoringError({
989
1021
  message: `every rule of ${label} derives the same head — the head column ${lead.name} is ${renderClosedSlice(lead.closed)} in rule 0 but ${renderClosedSlice(column.closed)} in rule ${index} (one column decodes through one roster)`
990
1022
  });
@@ -1025,7 +1057,13 @@ function afterMainError(what) {
1025
1057
  message: `query: ${what} after a main rule is unwritable — declaration order is interiors, then rec, then main`
1026
1058
  });
1027
1059
  }
1028
- function makeRawQuery(theory, interiors, rec, rules) {
1060
+ function makeRawQuery(inputTheory, inputInteriors, inputRec, inputRules) {
1061
+ const { theory, interiors, rec, rules } = snapshotQueryData({
1062
+ theory: inputTheory,
1063
+ interiors: inputInteriors,
1064
+ rec: inputRec,
1065
+ rules: inputRules
1066
+ });
1029
1067
  const mergedFinds = alignedHeadOf("a query", rules);
1030
1068
  const first = rules[0];
1031
1069
  if (first === undefined) {
@@ -1053,8 +1091,12 @@ function makeRawQuery(theory, interiors, rec, rules) {
1053
1091
  params
1054
1092
  });
1055
1093
  const value = {
1056
- schema: theory,
1057
- data,
1094
+ get schema() {
1095
+ return snapshotData(theory);
1096
+ },
1097
+ get data() {
1098
+ return snapshotQueryData(data);
1099
+ },
1058
1100
  rule(build) {
1059
1101
  const built = build(makeRawScope({ kind: "query", classes: theory.classes, theory, ...env }));
1060
1102
  return makeRawQuery(theory, interiors, rec, [...rules, built.rule]);
@@ -1129,9 +1171,9 @@ function collectRec(theory, interiors, name, baseBuilds, recBuilds) {
1129
1171
  const sealedRec = [firstRec, ...rec.slice(1)];
1130
1172
  const recData = Object.freeze({
1131
1173
  name,
1132
- finds: sealedFinds,
1133
- base: sealedBase,
1134
- rec: sealedRec
1174
+ finds: Object.freeze(sealedFinds),
1175
+ base: Object.freeze(sealedBase),
1176
+ rec: Object.freeze(sealedRec)
1135
1177
  });
1136
1178
  return recData;
1137
1179
  }
@@ -1164,7 +1206,9 @@ function makeQueryStart(theory, interiors) {
1164
1206
  },
1165
1207
  rule(build) {
1166
1208
  const built = build(makeQueryRuleScope(theory, env));
1167
- return makeQuery(theory, interiors, undefined, [built.rule]);
1209
+ return makeQuery(theory, interiors, undefined, [
1210
+ built.rule
1211
+ ]);
1168
1212
  }
1169
1213
  };
1170
1214
  Object.freeze(start);
@@ -1175,112 +1219,27 @@ function makeQueryReachStart(theory, interiors, rec) {
1175
1219
  const start = {
1176
1220
  rule(build) {
1177
1221
  const built = build(makeQueryRuleScope(theory, env));
1178
- return makeQuery(theory, interiors, rec, [built.rule]);
1222
+ return makeQuery(theory, interiors, rec, [
1223
+ built.rule
1224
+ ]);
1179
1225
  }
1180
1226
  };
1181
1227
  Object.freeze(start);
1182
1228
  return start;
1183
1229
  }
1184
1230
  function query(theory) {
1185
- return makeQueryStart(theory, []);
1186
- }
1187
- function taggedHandleId(context, closed, value) {
1188
- if (typeof value !== "string") {
1189
- throw literalShapeError(context, `a ${closed.name} handle name (string)`, value);
1190
- }
1191
- const id = closed.handles.indexOf(value);
1192
- if (id < 0) {
1193
- throw new AuthoringError({
1194
- message: `${context}: "${value}" is not a handle of ${closed.name} — the roster is ${closed.handles.join(", ")}`
1195
- });
1196
- }
1197
- return { kind: "u64", value: BigInt(id) };
1231
+ return makeQueryStart(schemaDescriptor(theory), []);
1198
1232
  }
1199
1233
  function taggedAtElementDomain(context, element, value) {
1200
- if (element === "f64") {
1201
- if (typeof value === "number") {
1202
- return { kind: "f64", value };
1203
- }
1204
- if (isFloatIntervalValue(value)) {
1205
- if (Number.isNaN(value.start) || Number.isNaN(value.end) || !(value.start < value.end)) {
1206
- throw literalShapeError(context, "a nonempty float interval with non-NaN endpoints", value);
1207
- }
1208
- return {
1209
- kind: "intervalF64",
1210
- start: Object.is(value.start, -0) ? 0 : value.start,
1211
- end: Object.is(value.end, -0) ? 0 : value.end
1212
- };
1213
- }
1214
- throw literalShapeError(context, "number (point) or { start, end } numbers (interval)", value);
1215
- }
1216
- if (typeof value === "bigint") {
1217
- if (element === "u64") {
1218
- return { kind: "u64", value };
1219
- }
1220
- return { kind: "i64", value };
1221
- }
1222
- if (isIntervalValue(value)) {
1223
- if (element === "u64") {
1224
- return { kind: "intervalU64", start: value.start, end: value.end };
1225
- }
1226
- return { kind: "intervalI64", start: value.start, end: value.end };
1227
- }
1228
- throw literalShapeError(context, "bigint (point) or { start, end } (interval)", value);
1234
+ const field = typeof value === "number" || typeof value === "bigint"
1235
+ ? { u64: u64Field, i64: i64Field, f64: f64Field }[element]
1236
+ : { kind: "interval", element, width: undefined };
1237
+ return taggedValueOf(context, field, value);
1229
1238
  }
1230
1239
  function taggedLiteral(context, field, value) {
1231
- const roster = rosterOf(field);
1232
- if (roster !== undefined) {
1233
- return taggedHandleId(context, roster, value);
1234
- }
1235
- switch (field.kind) {
1236
- case "bool": {
1237
- if (typeof value !== "boolean") {
1238
- throw literalShapeError(context, "boolean", value);
1239
- }
1240
- return { kind: "bool", value };
1241
- }
1242
- case "u64": {
1243
- if (typeof value !== "bigint") {
1244
- throw literalShapeError(context, "bigint", value);
1245
- }
1246
- return { kind: "u64", value };
1247
- }
1248
- case "i64": {
1249
- if (typeof value !== "bigint") {
1250
- throw literalShapeError(context, "bigint", value);
1251
- }
1252
- return { kind: "i64", value };
1253
- }
1254
- case "f64": {
1255
- if (typeof value !== "number") {
1256
- throw literalShapeError(context, "number", value);
1257
- }
1258
- return { kind: "f64", value };
1259
- }
1260
- case "uuid": {
1261
- if (!Uuid.isUuid(value)) {
1262
- throw literalShapeError(context, "a UUID (canonical UUID text)", value);
1263
- }
1264
- return { kind: "uuid", value };
1265
- }
1266
- case "str": {
1267
- if (typeof value !== "string") {
1268
- throw literalShapeError(context, "string", value);
1269
- }
1270
- if (!value.isWellFormed()) {
1271
- throw literalShapeError(context, "well-formed string", value);
1272
- }
1273
- return { kind: "string", value };
1274
- }
1275
- case "bytes": {
1276
- if (!(value instanceof Uint8Array)) {
1277
- throw literalShapeError(context, "Uint8Array", value);
1278
- }
1279
- return { kind: "fixedBytes", value };
1280
- }
1281
- case "interval":
1282
- return taggedAtElementDomain(context, field.element, value);
1283
- }
1240
+ return field.kind === "interval"
1241
+ ? taggedAtElementDomain(context, field.element, value)
1242
+ : taggedValueOf(context, field, value);
1284
1243
  }
1285
1244
  /**
1286
1245
  * Tags one host literal at a COMPARISON or PARAM position, where the SIBLING
@@ -1288,7 +1247,7 @@ function taggedLiteral(context, field, value) {
1288
1247
  * contributes its element domain, a scalar sibling its own type. At
1289
1248
  * `pointIn` the operand order is interval-left, point-right, so an
1290
1249
  * interval-shaped literal beside a scalar element-typed sibling is the LEGAL
1291
- * interval operand of `pointIn(t, span(...))`; under every other operator an
1250
+ * interval operand of `pointIn(t, { start, end })`; under every other operator an
1292
1251
  * interval shape against a scalar sibling stays refused.
1293
1252
  */
1294
1253
  function taggedCmpLiteral(context, sibling, value, op) {
@@ -1306,6 +1265,15 @@ function taggedCmpLiteral(context, sibling, value, op) {
1306
1265
  }
1307
1266
  return taggedLiteral(context, sibling, value);
1308
1267
  }
1268
+ /** Validate and own a literal when the query is authored, before caller mutation. */
1269
+ function ownLiteral(context, field, value, op) {
1270
+ const tagged = taggedCmpLiteral(context, field, value, op);
1271
+ if (rosterOf(field) !== undefined)
1272
+ return value;
1273
+ if ("value" in tagged)
1274
+ return tagged.value;
1275
+ return Object.freeze({ start: tagged.start, end: tagged.end });
1276
+ }
1309
1277
  function freshVarIds() {
1310
1278
  const assigned = new Map();
1311
1279
  return {
@@ -1329,7 +1297,7 @@ function paramIdOf(ctx, name) {
1329
1297
  }
1330
1298
  function lowerAtom(ctx, atom, ids) {
1331
1299
  const member = ctx.theory.relations[atom.relation.name];
1332
- if (member !== atom.relation) {
1300
+ if (!membersAgree(member, atom.relation)) {
1333
1301
  throw new AuthoringError({
1334
1302
  message: `query lowering: relation ${atom.relation.name} is not the relation value schema ${ctx.theory.name} declares`
1335
1303
  });
@@ -1563,20 +1531,21 @@ function lowerRule(ctx, rule) {
1563
1531
  }
1564
1532
  function lowerQuery(q) {
1565
1533
  const theory = q.schema;
1534
+ const data = q.data;
1566
1535
  const relationIds = new Map();
1567
1536
  Object.keys(theory.relations).forEach(function assignOrdinal(name, index) {
1568
1537
  relationIds.set(name, index);
1569
1538
  });
1570
1539
  const interiorIds = new Map();
1571
- q.data.interiors.forEach(function assignInteriorId(interior, index) {
1540
+ data.interiors.forEach(function assignInteriorId(interior, index) {
1572
1541
  interiorIds.set(interior.name, index);
1573
1542
  });
1574
- if (q.data.kind === "reach") {
1575
- interiorIds.set(q.data.rec.name, q.data.interiors.length);
1543
+ if (data.kind === "reach") {
1544
+ interiorIds.set(data.rec.name, data.interiors.length);
1576
1545
  }
1577
1546
  const paramIds = new Map();
1578
1547
  const params = new Map();
1579
- q.data.params.forEach(function assignParamId(entry, index) {
1548
+ data.params.forEach(function assignParamId(entry, index) {
1580
1549
  if (entry.anchor === undefined) {
1581
1550
  throw new AuthoringError({
1582
1551
  message: `query param ${entry.name} has no field-anchored use — bind it in an atom or compare it against a bound variable`
@@ -1586,7 +1555,7 @@ function lowerQuery(q) {
1586
1555
  params.set(entry.name, entry);
1587
1556
  });
1588
1557
  const ctx = { theory, relationIds, interiorIds, paramIds, params };
1589
- const interiors = q.data.interiors.map(function lowerInterior(interior) {
1558
+ const interiors = data.interiors.map(function lowerInterior(interior) {
1590
1559
  return {
1591
1560
  head: interior.finds.map(headTermOf),
1592
1561
  rules: interior.rules.map(function lowerInteriorRule(rule) {
@@ -1594,22 +1563,22 @@ function lowerQuery(q) {
1594
1563
  })
1595
1564
  };
1596
1565
  });
1597
- const head = q.data.finds.map(headTermOf);
1598
- const rules = q.data.rules.map(function lowerMainRule(rule) {
1566
+ const head = data.finds.map(headTermOf);
1567
+ const rules = data.rules.map(function lowerMainRule(rule) {
1599
1568
  return lowerRule(ctx, rule);
1600
1569
  });
1601
- if (q.data.kind === "cq") {
1570
+ if (data.kind === "cq") {
1602
1571
  return parseQueryIr({ kind: "cq", interiors, head, rules });
1603
1572
  }
1604
1573
  return parseQueryIr({
1605
1574
  kind: "reach",
1606
1575
  interiors,
1607
1576
  rec: {
1608
- head: q.data.rec.finds.map(headTermOf),
1609
- base: q.data.rec.base.map(function lowerBase(rule) {
1577
+ head: data.rec.finds.map(headTermOf),
1578
+ base: data.rec.base.map(function lowerBase(rule) {
1610
1579
  return lowerRule(ctx, rule);
1611
1580
  }),
1612
- rec: q.data.rec.rec.map(function lowerRecArm(rule) {
1581
+ rec: data.rec.rec.map(function lowerRecArm(rule) {
1613
1582
  return lowerRule(ctx, rule);
1614
1583
  })
1615
1584
  },
@@ -1617,5 +1586,5 @@ function lowerQuery(q) {
1617
1586
  rules
1618
1587
  });
1619
1588
  }
1620
- export { lowerQuery, query, taggedCmpLiteral };
1589
+ export { alignedHeadOf, EMPTY_RULE, lowerQuery, makeRawChain, makeRawQuery, query, taggedCmpLiteral };
1621
1590
  //# sourceMappingURL=lower.js.map