@bjornpagen/bumbledb 0.9.0 → 0.11.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 (73) hide show
  1. package/COOKBOOK.md +155 -136
  2. package/README.md +3 -7
  3. package/dist/capacity.d.ts +14 -1
  4. package/dist/capacity.d.ts.map +1 -1
  5. package/dist/capacity.js.map +1 -1
  6. package/dist/db.d.ts +77 -109
  7. package/dist/db.d.ts.map +1 -1
  8. package/dist/db.js +121 -339
  9. package/dist/db.js.map +1 -1
  10. package/dist/index.d.ts +11 -16
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +7 -10
  13. package/dist/index.js.map +1 -1
  14. package/dist/lower.d.ts.map +1 -1
  15. package/dist/lower.js +8 -1
  16. package/dist/lower.js.map +1 -1
  17. package/dist/native.d.ts +69 -50
  18. package/dist/native.d.ts.map +1 -1
  19. package/dist/native.js.map +1 -1
  20. package/dist/query/atom.d.ts +162 -122
  21. package/dist/query/atom.d.ts.map +1 -1
  22. package/dist/query/atom.js +26 -22
  23. package/dist/query/atom.js.map +1 -1
  24. package/dist/query/find.d.ts +18 -35
  25. package/dist/query/find.d.ts.map +1 -1
  26. package/dist/query/find.js +13 -32
  27. package/dist/query/find.js.map +1 -1
  28. package/dist/query/lower.d.ts +113 -122
  29. package/dist/query/lower.d.ts.map +1 -1
  30. package/dist/query/lower.js +336 -260
  31. package/dist/query/lower.js.map +1 -1
  32. package/dist/query/parse-ir.d.ts +12 -0
  33. package/dist/query/parse-ir.d.ts.map +1 -0
  34. package/dist/query/parse-ir.js +71 -0
  35. package/dist/query/parse-ir.js.map +1 -0
  36. package/dist/query/run.d.ts +2 -2
  37. package/dist/query/run.d.ts.map +1 -1
  38. package/dist/query/run.js +2 -13
  39. package/dist/query/run.js.map +1 -1
  40. package/dist/query/scope.d.ts +4 -16
  41. package/dist/query/scope.d.ts.map +1 -1
  42. package/dist/query/scope.js +1 -6
  43. package/dist/query/scope.js.map +1 -1
  44. package/dist/schema.js +2 -2
  45. package/dist/schema.js.map +1 -1
  46. package/dist/statements.d.ts +15 -9
  47. package/dist/statements.d.ts.map +1 -1
  48. package/dist/statements.js +14 -9
  49. package/dist/statements.js.map +1 -1
  50. package/package.json +2 -2
  51. package/src/capacity.ts +24 -1
  52. package/src/db.ts +182 -443
  53. package/src/index.ts +9 -23
  54. package/src/lower.ts +8 -1
  55. package/src/native.ts +69 -42
  56. package/src/query/atom.ts +255 -165
  57. package/src/query/find.ts +39 -80
  58. package/src/query/lower.ts +578 -432
  59. package/src/query/parse-ir.ts +82 -0
  60. package/src/query/run.ts +2 -14
  61. package/src/query/scope.ts +3 -21
  62. package/src/schema.ts +2 -2
  63. package/src/statements.ts +33 -17
  64. package/dist/order.d.ts +0 -87
  65. package/dist/order.d.ts.map +0 -1
  66. package/dist/order.js +0 -153
  67. package/dist/order.js.map +0 -1
  68. package/dist/query/predicate.d.ts +0 -91
  69. package/dist/query/predicate.d.ts.map +0 -1
  70. package/dist/query/predicate.js +0 -156
  71. package/dist/query/predicate.js.map +0 -1
  72. package/src/order.ts +0 -234
  73. package/src/query/predicate.ts +0 -269
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Host shape parse for the wire `QueryIr`: rec/main nonempty, aggregate
3
+ * finds split (Count has no `over`; folds require it), head/find
4
+ * alignment. The engine validator remains the one roster authority —
5
+ * this parse refuses only shape the host type can see.
6
+ */
7
+
8
+ import * as errors from "@superbuilders/errors"
9
+ import type { FindTermIr, HeadTermIr, ParsedQuery, QueryIr, RuleIr } from "#native.ts"
10
+
11
+ /** Brands a shape-checked wire query so {@link Native.dbPrepare} will accept it. */
12
+ function parseQueryIr(ir: QueryIr): ParsedQuery {
13
+ if (ir.rules.length === 0) {
14
+ throw errors.new("parseQueryIr: main rules are empty")
15
+ }
16
+ align("query", ir.head, ir.rules)
17
+ ir.interiors.forEach(function checkInterior(interior, index) {
18
+ align(`interior ${index}`, interior.head, interior.rules)
19
+ })
20
+ if (ir.rec !== null) {
21
+ if (ir.rec.base.length === 0) {
22
+ throw errors.new("parseQueryIr: rec base is empty")
23
+ }
24
+ if (ir.rec.rec.length === 0) {
25
+ throw errors.new("parseQueryIr: rec step is empty")
26
+ }
27
+ align("rec base", ir.rec.head, ir.rec.base)
28
+ align("rec step", ir.rec.head, ir.rec.rec)
29
+ }
30
+ return ir as ParsedQuery
31
+ }
32
+
33
+ /** One rule list must share the head's width and var/aggregate family. */
34
+ function align(context: string, head: readonly HeadTermIr[], rules: readonly RuleIr[]): void {
35
+ for (const [ruleIndex, rule] of rules.entries()) {
36
+ if (rule.finds.length !== head.length) {
37
+ throw errors.new(
38
+ `${context}: rule ${ruleIndex} finds width ${rule.finds.length} does not match head width ${head.length}`
39
+ )
40
+ }
41
+ rule.finds.forEach(function checkFind(find, position) {
42
+ parseFind(`${context} rule ${ruleIndex} find ${position}`, find)
43
+ const family = findFamily(find)
44
+ if (family !== head[position]?.kind) {
45
+ throw errors.new(
46
+ `${context}: rule ${ruleIndex} find ${position} is ${family}, not head ${head[position]?.kind}`
47
+ )
48
+ }
49
+ })
50
+ }
51
+ }
52
+
53
+ /** Count forbids `over`; every other aggregate requires it. */
54
+ function parseFind(context: string, find: FindTermIr): void {
55
+ if (find.kind !== "aggregate") {
56
+ return
57
+ }
58
+ if (find.op.kind === "count") {
59
+ if ("over" in find) {
60
+ throw errors.new(`${context}: Count carries no over`)
61
+ }
62
+ return
63
+ }
64
+ if (!("over" in find)) {
65
+ throw errors.new(`${context}: fold aggregate requires over`)
66
+ }
67
+ }
68
+
69
+ /** Head family of one find term: measure is a var slot; measure-folds are aggregates. */
70
+ function findFamily(find: FindTermIr): "var" | "aggregate" {
71
+ switch (find.kind) {
72
+ case "var":
73
+ case "measure":
74
+ return "var"
75
+ case "aggregate":
76
+ case "aggregateMeasure":
77
+ return "aggregate"
78
+ }
79
+ }
80
+
81
+ export type { ParsedQuery }
82
+ export { parseQueryIr }
package/src/query/run.ts CHANGED
@@ -20,18 +20,9 @@ import * as errors from "@superbuilders/errors"
20
20
  import { handleOf } from "#marshal.ts"
21
21
  import type { FactValue, QueryParam, TaggedValue } from "#native.ts"
22
22
  import type { FindColumn } from "#query/atom.ts"
23
- import { ALLEN_ALL_BITS } from "#query/atom.ts"
24
23
  import { taggedCmpLiteral } from "#query/lower.ts"
25
24
  import type { ParamEntry } from "#query/scope.ts"
26
25
 
27
- /** Tags one supplied mask-param value. */
28
- function wireMask(name: string, value: unknown): TaggedValue {
29
- if (typeof value !== "number" || !Number.isInteger(value) || value < 0 || value > ALLEN_ALL_BITS) {
30
- throw errors.new(`param ${name}: an Allen-mask param binds a 13-bit mask number built from the ALLEN constants`)
31
- }
32
- return { kind: "allenMask", mask: value }
33
- }
34
-
35
26
  /** Tags one supplied value-param cell by its anchoring use. */
36
27
  function wireValue(entry: ParamEntry, context: string, value: unknown): TaggedValue {
37
28
  if (entry.anchor === undefined) {
@@ -48,7 +39,7 @@ function wireValue(entry: ParamEntry, context: string, value: unknown): TaggedVa
48
39
  * is a typed error naming the param; values tag by the anchoring use's
49
40
  * structural type; a set param takes a readonly array (the empty set is
50
41
  * legal and matches nothing — the engine's rule). A MEMBERSHIP-ARRAY
51
- * entry (`membership` present — a literal set folded into the program) is
42
+ * entry (`membership` present — a literal set folded into the query) is
52
43
  * a program constant the registry already resolved through the one
53
44
  * roster-verification point at BUILD time: it crosses as its prebuilt
54
45
  * frozen `{ kind: "set", values }` by reference — the host's params object
@@ -63,9 +54,6 @@ function wireParams(entries: readonly ParamEntry[], supplied: Readonly<Record<st
63
54
  if (value === undefined) {
64
55
  throw errors.new(`execute params object is missing param ${entry.name}`)
65
56
  }
66
- if (entry.shape === "mask") {
67
- return wireMask(entry.name, value)
68
- }
69
57
  if (entry.shape === "set") {
70
58
  if (!Array.isArray(value)) {
71
59
  throw errors.new(`param ${entry.name}: a set param binds a readonly array of values`)
@@ -98,7 +86,7 @@ function isAnswerRow<Row>(
98
86
  }
99
87
 
100
88
  /**
101
- * Decodes positional answer rows (column order = the program's head order
89
+ * Decodes positional answer rows (column order = the query's head order
102
90
  * = the select's written order) to named, frozen row objects of bare
103
91
  * structural values. A closed column lifts its row id back to the handle
104
92
  * NAME through the marshal's bijection — an out-of-roster id is the same
@@ -119,17 +119,6 @@ interface SetParam<Name extends string = string> {
119
119
  readonly name: Name
120
120
  }
121
121
 
122
- /**
123
- * An Allen-mask parameter (the IR's `MaskTerm::Param`) — the temporal
124
- * relation as a bind-time argument: one prepared query answers any of the
125
- * mask questions per execution. Bound to a 13-bit mask number built from
126
- * the `ALLEN` constants.
127
- */
128
- interface MaskParam<Name extends string = string> {
129
- readonly [term]: "maskParam"
130
- readonly name: Name
131
- }
132
-
133
122
  /**
134
123
  * The measure of an interval-typed variable (`ir::Term::Measure`):
135
124
  * `|[s, e)| = e − s`, u64 — legal as one side of an order comparison, as a
@@ -143,7 +132,7 @@ interface Duration<V extends AnyVar = AnyVar> {
143
132
  }
144
133
 
145
134
  /** Any scope term value. */
146
- type AnyTerm = Var | Param | SetParam | MaskParam | Duration
135
+ type AnyTerm = Var | Param | SetParam | Duration
147
136
 
148
137
  /** Narrows an unknown position value to a scope term (vs a host literal). */
149
138
  function isTerm(value: unknown): value is AnyTerm {
@@ -213,12 +202,6 @@ function makeSetParam<const Name extends string>(name: Name): SetParam<Name> {
213
202
  return Object.freeze(value)
214
203
  }
215
204
 
216
- /** Builds one Allen-mask-parameter term. */
217
- function makeMaskParam<const Name extends string>(name: Name): MaskParam<Name> {
218
- const value: MaskParam<Name> = { [term]: "maskParam", name }
219
- return Object.freeze(value)
220
- }
221
-
222
205
  /** Builds one measure term over an interval-typed variable reference. */
223
206
  function makeDuration<const V extends AnyVar>(over: V): Duration<V> {
224
207
  const value: Duration<V> = { [term]: "duration", over }
@@ -391,7 +374,7 @@ type InferredOf<T> = T extends { readonly [inferred]?: infer S } ? Exclude<S, un
391
374
  */
392
375
  interface ParamEntry {
393
376
  readonly name: string
394
- readonly shape: "value" | "set" | "mask"
377
+ readonly shape: "value" | "set"
395
378
  readonly anchor: AnyField | "measure" | undefined
396
379
  readonly op: "binding" | "eq" | "ne" | "lt" | "le" | "gt" | "ge" | "pointIn" | "allen"
397
380
  readonly membership: QueryParam | undefined
@@ -405,7 +388,6 @@ export type {
405
388
  Flatten,
406
389
  InferredOf,
407
390
  JoinOk,
408
- MaskParam,
409
391
  MatchFields,
410
392
  MatchOwner,
411
393
  MintClassOf,
@@ -420,4 +402,4 @@ export type {
420
402
  Var,
421
403
  VarsOf
422
404
  }
423
- export { fieldJoins, inferred, isTerm, makeDuration, makeMaskParam, makeParam, makeSetParam, renderFieldKind, term, v }
405
+ export { fieldJoins, inferred, isTerm, makeDuration, makeParam, makeSetParam, renderFieldKind, term, v }
package/src/schema.ts CHANGED
@@ -138,11 +138,11 @@ function verifyHandles(name: string, statement: Statement, rendered: string): vo
138
138
  function closedTargetOf(statements: readonly Statement[], owner: string, field: string): string | undefined {
139
139
  for (const statement of statements) {
140
140
  const data = statement.data
141
- if (data.kind !== "containment") {
141
+ if (data.kind !== "containment" && data.kind !== "mirrors") {
142
142
  continue
143
143
  }
144
144
  const pairs: Array<readonly [FaceData, FaceData]> = [[data.source, data.target]]
145
- if (data.bidirectional) {
145
+ if (data.kind === "mirrors") {
146
146
  pairs.push([data.target, data.source])
147
147
  }
148
148
  for (const [source, target] of pairs) {
package/src/statements.ts CHANGED
@@ -41,6 +41,7 @@ import {
41
41
  type CapacityWindow,
42
42
  isCapacityWeight,
43
43
  isCapacityWindow,
44
+ type UnitDimensionBan,
44
45
  type UnitWindowBan,
45
46
  unitWeight,
46
47
  type WeightOnSource
@@ -69,7 +70,12 @@ interface ContainmentData<Src extends FaceData = FaceData, Tgt extends FaceData
69
70
  readonly kind: "containment"
70
71
  readonly source: Src
71
72
  readonly target: Tgt
72
- readonly bidirectional: boolean
73
+ }
74
+
75
+ interface MirrorsData<Src extends FaceData = FaceData, Tgt extends FaceData = FaceData> {
76
+ readonly kind: "mirrors"
77
+ readonly source: Src
78
+ readonly target: Tgt
73
79
  }
74
80
 
75
81
  /**
@@ -87,7 +93,7 @@ interface CapacityData<Tgt extends FaceData = FaceData, Src extends FaceData = F
87
93
  }
88
94
 
89
95
  /** One statement's runtime description, tagged by form. */
90
- type StatementData = KeyData<AnyRelation, readonly string[]> | ContainmentData | CapacityData
96
+ type StatementData = KeyData<AnyRelation, readonly string[]> | ContainmentData | MirrorsData | CapacityData
91
97
 
92
98
  /**
93
99
  * The admission brand — a module-private symbol, deliberately unexported
@@ -127,7 +133,7 @@ function isStatement(value: unknown): value is Statement {
127
133
  * {@link Statement}.
128
134
  */
129
135
  interface ContainedStatement<Src extends FaceData, Tgt extends FaceData> extends Statement {
130
- readonly data: ContainmentData<Src, Tgt>
136
+ readonly data: ContainmentData<Src, Tgt> | MirrorsData<Src, Tgt>
131
137
  }
132
138
 
133
139
  /** A capacity statement as a TYPED value — the {@link ContainedStatement} of the capacity form. */
@@ -246,8 +252,7 @@ function contained<A extends AnyFace, B extends AnyFace>(
246
252
  const data: ContainmentData<A["data"], B["data"]> = Object.freeze({
247
253
  kind: "containment",
248
254
  source: source.data,
249
- target: target.data,
250
- bidirectional: false
255
+ target: target.data
251
256
  })
252
257
  const statement = Object.freeze({ data, [admitted]: true as const })
253
258
  assertArityAgreement(data.source, data.target, statement)
@@ -268,11 +273,10 @@ function mirrors<A extends AnyFace, B extends AnyFace>(
268
273
  source: A,
269
274
  target: B & SameArity<A, B> & SameShapes<A, B>
270
275
  ): ContainedStatement<A["data"], B["data"]> {
271
- const data: ContainmentData<A["data"], B["data"]> = Object.freeze({
272
- kind: "containment",
276
+ const data: MirrorsData<A["data"], B["data"]> = Object.freeze({
277
+ kind: "mirrors",
273
278
  source: source.data,
274
- target: target.data,
275
- bidirectional: true
279
+ target: target.data
276
280
  })
277
281
  const statement = Object.freeze({ data, [admitted]: true as const })
278
282
  assertArityAgreement(data.source, data.target, statement)
@@ -357,13 +361,15 @@ function assertBoundsOnTarget(window: CapacityWindowSpec, target: FaceData, stat
357
361
  * on(Device, "pool"))` bounds each pool's summed draw by the pool's own
358
362
  * row. The two faces pair by arity AND structural shape
359
363
  * ({@link SameShapes}), exactly as containment — the grouping join reads
360
- * the same positionwise field pairing. The weight-sensitive `{1..*}` ban
361
- * rides the UNIT overload only ({@link UnitWindowBan} — on a weighted
362
- * statement "positive total" is a different, weaker law than containment).
364
+ * the same positionwise field pairing. The weight-sensitive bans ride the
365
+ * UNIT overload only: `{1..*}` ({@link UnitWindowBan} — on a weighted
366
+ * statement "positive total" is a different, weaker law than containment)
367
+ * and the `duration()` bound ({@link UnitDimensionBan} — a count of facts
368
+ * bounded by a span of time mixes dimensions, C18).
363
369
  */
364
370
  function capacity<B extends AnyFace, W extends CapacityWindow, A extends AnyFace>(
365
371
  target: B,
366
- window: W & UnitWindowBan<W> & BoundsOnTarget<W, B>,
372
+ window: W & UnitWindowBan<W> & UnitDimensionBan<W> & BoundsOnTarget<W, B>,
367
373
  source: A & SameArity<B, A> & SameShapes<B, A>
368
374
  ): CapacityStatement<B["data"], A["data"]>
369
375
  function capacity<B extends AnyFace, M extends CapacityWeight, W extends CapacityWindow, A extends AnyFace>(
@@ -401,6 +407,15 @@ function capacity(
401
407
  "`{1..*}` on the unit instance says only what the bare containment says — drop the annotation and write the containment: contained(source, target)"
402
408
  )
403
409
  }
410
+ // The C18 dimension gate, unit instance (the engine's
411
+ // CapacityDimensionMixing twin — ruled 2026-07-24): a count of facts
412
+ // bounded by a span of time mixes dimensions. Judged here for untyped
413
+ // callers; the engine's validate_capacity stays the final authority.
414
+ if (weight.kind === "unit" && window.kind === "range" && window.hi.kind === "durationField") {
415
+ throw errors.new(
416
+ `a unit (count) window against the duration() bound on ${window.hi.field} mixes dimensions (C18) — weigh the source with weigh(duration(field)), or bound by a u64 field or literal`
417
+ )
418
+ }
404
419
  const data: CapacityData = Object.freeze({
405
420
  kind: "capacity",
406
421
  target: target.data,
@@ -433,10 +448,10 @@ function renderStatement(statement: Statement): string {
433
448
  switch (data.kind) {
434
449
  case "key":
435
450
  return `${data.owner.name}(${data.projection.join(", ")}) -> ${data.owner.name}`
436
- case "containment": {
437
- const operator = data.bidirectional ? "==" : "<="
438
- return `${renderFace(data.source)} ${operator} ${renderFace(data.target)}`
439
- }
451
+ case "containment":
452
+ return `${renderFace(data.source)} <= ${renderFace(data.target)}`
453
+ case "mirrors":
454
+ return `${renderFace(data.source)} == ${renderFace(data.target)}`
440
455
  case "capacity":
441
456
  return `${renderFace(data.target)} <=${renderWeight(data.weight)}${renderCapacityWindow(data.window)} ${renderFace(data.source)}`
442
457
  }
@@ -449,6 +464,7 @@ export type {
449
464
  ContainmentData,
450
465
  KeyData,
451
466
  KeyStatement,
467
+ MirrorsData,
452
468
  Statement,
453
469
  StatementData
454
470
  }
package/dist/order.d.ts DELETED
@@ -1,87 +0,0 @@
1
- /**
2
- * Host-side answer ordering — the census-fired convenience
3
- * (`docs/architecture/70-api.md` § the freeze ledger). Answers are SETS and
4
- * the ENGINE NEVER ORDERS; the language owns the sort (`rows.sort(...)`)
5
- * and the limit (`.slice(0, n)`) — the drizzle law. What JS lacks is a
6
- * number-returning comparator over the SDK's bigint-bearing cells, so the
7
- * SDK ships exactly that: sort keys are DATA — a bare column name is
8
- * ascending (the punning spelling; no `asc` wrapper exists — one spelling
9
- * per meaning) and `desc(name)` is the one descending spelling — folded by
10
- * `by(...)` into one row-typed comparator. Cross-type cells cannot arise
11
- * within one column (one column, one domain), and the cell order is TOTAL
12
- * anyway (the type-rank wall), so the comparator never throws.
13
- *
14
- * ZERO keys is the identity key (ruled 2026-07-25): `by()` / `desc()` are
15
- * the same two spellings over BARE scalar arrays (`bigint[]` of ids, map
16
- * keys) — with no column to name, the value itself is the key, there is
17
- * nothing to fold, and the comparator IS the result. One ordering
18
- * vocabulary, no sibling names. The identity arms are typed to EXACTLY the
19
- * engine-orderable roster ({@link EngineOrderable}) because a bare scalar
20
- * carries no decoded-row provenance — the type wall must carry the
21
- * orderability law itself, where the row arm's cells arrive under their
22
- * columns' law-typed proof.
23
- */
24
- import type { FactValue } from "#native.ts";
25
- /** One DESCENDING sort key, plain data — built by {@link desc}. */
26
- interface Desc<K extends string> {
27
- readonly key: K;
28
- readonly desc: true;
29
- }
30
- /** One sort key: a bare column name (ascending — the punning spelling) or `desc(name)`. */
31
- type SortKey<K extends string> = K | Desc<K>;
32
- /**
33
- * The engine-orderable scalar roster in the SDK's representation — `bigint`
34
- * (U64/I64) and `boolean` (false < true — the strict 0/1 encoding IS the
35
- * order), EXACTLY as `docs/architecture/10-data-model.md` § "Orderability,
36
- * complete" admits it (ruled 2026-07-23, R3/R4), and nothing more:
37
- * `string` is deliberately absent (intern ids are meaningless to order — a
38
- * typed refusal, not a gap) and `number` is not an engine scalar at all.
39
- * The identity comparators `by()`/`desc()` constrain on this alias, so
40
- * sorting a `string[]` or `number[]` through them is a COMPILE error naming
41
- * this roster. ONE OWNER for scalar ordering semantics: both identity arms
42
- * route through the same cell order the row arm uses, whose bigint and
43
- * boolean arms mirror the engine's U64/I64/Bool order exactly — a host
44
- * sort over these values can never disagree with an engine order judgment
45
- * (`Lt`-family, `Min`/`Max`) over the same column.
46
- */
47
- type EngineOrderable = bigint | boolean;
48
- /**
49
- * The descending spelling — ONE name, both arities of one ordering
50
- * vocabulary. `desc(name)` marks one sort key DESCENDING: plain data for
51
- * {@link by} to fold (a bare name is already ascending). `desc()` — zero
52
- * keys, the identity key (ruled 2026-07-25) — is the descending comparator
53
- * over engine-orderable scalars themselves: a bare `bigint[]` or
54
- * `boolean[]` has no column to name, so the value IS the key, there is
55
- * nothing to fold, and the comparator is the result directly. The identity
56
- * arm covers EXACTLY the {@link EngineOrderable} roster — `string` and
57
- * `number` refuse at compile time, citing the orderability law
58
- * (`10-data-model.md` § "Orderability, complete").
59
- */
60
- declare function desc(): <T extends EngineOrderable>(left: T, right: T) => number;
61
- declare function desc<const K extends string>(key: K): Desc<K>;
62
- /**
63
- * Folds sort keys into ONE comparator typed against the row —
64
- * `Row extends Readonly<Record<K, FactValue>>` — so a key the row lacks, or
65
- * a column typed `number` (outside the cell domain), is a COMPILE error at
66
- * the `.sort` call site: the laws typed the columns, and the row type
67
- * carries that proof here (parse-don't-validate). The generic RETURN is the
68
- * load-bearing trick: `rows.sort(by("rank"))` instantiates `Row` from the
69
- * array's own element type and checks the key set right there.
70
- *
71
- * ZERO keys is the identity key (ruled 2026-07-25): `by()` is the
72
- * ascending comparator over engine-orderable scalars themselves —
73
- * `ids.sort(by())` — for the bare arrays (`bigint[]`, map keys) the
74
- * row-typed arm cannot reach because they have no column to name. One
75
- * vocabulary, both arities. The identity arm is typed to EXACTLY the
76
- * {@link EngineOrderable} roster: with no law-typed column standing proof
77
- * over the values, the type wall carries the orderability law itself —
78
- * `string` ordering is deliberately refused and `number` is not an engine
79
- * scalar (`10-data-model.md` § "Orderability, complete"), so both refuse
80
- * at compile time and a host sort can never disagree with an engine order
81
- * judgment.
82
- */
83
- declare function by(): <T extends EngineOrderable>(left: T, right: T) => number;
84
- declare function by<const K extends string>(first: SortKey<K>, ...rest: ReadonlyArray<SortKey<K>>): <Row extends Readonly<Record<K, FactValue>>>(left: Row, right: Row) => number;
85
- export type { Desc, EngineOrderable, SortKey };
86
- export { by, desc };
87
- //# sourceMappingURL=order.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"order.d.ts","sourceRoot":"","sources":["../src/order.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,mEAAmE;AACnE,UAAU,IAAI,CAAC,CAAC,SAAS,MAAM;IAC9B,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAA;IACf,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CACnB;AAED,2FAA2F;AAC3F,KAAK,OAAO,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;AAE5C;;;;;;;;;;;;;;GAcG;AACH,KAAK,eAAe,GAAG,MAAM,GAAG,OAAO,CAAA;AA6GvC;;;;;;;;;;;GAWG;AACH,iBAAS,IAAI,IAAI,CAAC,CAAC,SAAS,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,MAAM,CAAA;AACzE,iBAAS,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;AAStD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iBAAS,EAAE,IAAI,CAAC,CAAC,SAAS,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,MAAM,CAAA;AACvE,iBAAS,EAAE,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EACjC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EACjB,GAAG,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAChC,CAAC,GAAG,SAAS,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,MAAM,CAAA;AA0BhF,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,CAAA;AAC9C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA"}
package/dist/order.js DELETED
@@ -1,153 +0,0 @@
1
- /**
2
- * Host-side answer ordering — the census-fired convenience
3
- * (`docs/architecture/70-api.md` § the freeze ledger). Answers are SETS and
4
- * the ENGINE NEVER ORDERS; the language owns the sort (`rows.sort(...)`)
5
- * and the limit (`.slice(0, n)`) — the drizzle law. What JS lacks is a
6
- * number-returning comparator over the SDK's bigint-bearing cells, so the
7
- * SDK ships exactly that: sort keys are DATA — a bare column name is
8
- * ascending (the punning spelling; no `asc` wrapper exists — one spelling
9
- * per meaning) and `desc(name)` is the one descending spelling — folded by
10
- * `by(...)` into one row-typed comparator. Cross-type cells cannot arise
11
- * within one column (one column, one domain), and the cell order is TOTAL
12
- * anyway (the type-rank wall), so the comparator never throws.
13
- *
14
- * ZERO keys is the identity key (ruled 2026-07-25): `by()` / `desc()` are
15
- * the same two spellings over BARE scalar arrays (`bigint[]` of ids, map
16
- * keys) — with no column to name, the value itself is the key, there is
17
- * nothing to fold, and the comparator IS the result. One ordering
18
- * vocabulary, no sibling names. The identity arms are typed to EXACTLY the
19
- * engine-orderable roster ({@link EngineOrderable}) because a bare scalar
20
- * carries no decoded-row provenance — the type wall must carry the
21
- * orderability law itself, where the row arm's cells arrive under their
22
- * columns' law-typed proof.
23
- */
24
- /**
25
- * The type-rank wall: boolean 0, bigint 1, string 2, bytes 3, interval 4.
26
- * One column carries one domain, so a mixed pair never arises from decoded
27
- * answer rows — the wall exists to keep the cell order TOTAL (never a
28
- * throw), not to be reached.
29
- */
30
- function cellRank(value) {
31
- if (typeof value === "boolean") {
32
- return 0;
33
- }
34
- if (typeof value === "bigint") {
35
- return 1;
36
- }
37
- if (typeof value === "string") {
38
- return 2;
39
- }
40
- if (value instanceof Uint8Array) {
41
- return 3;
42
- }
43
- return 4;
44
- }
45
- /**
46
- * One cell against one cell. Same-type arms: boolean orders false < true;
47
- * bigint by `<`/`>`; string by the host language's own `<`/`>` (flavor,
48
- * recorded); bytes bytewise over the shared prefix, then by length;
49
- * intervals by start, then end. A mixed pair falls through to the
50
- * type-rank wall.
51
- */
52
- function cellCmp(left, right) {
53
- if (typeof left === "boolean" && typeof right === "boolean") {
54
- if (left === right) {
55
- return 0;
56
- }
57
- if (left) {
58
- return 1;
59
- }
60
- return -1;
61
- }
62
- if (typeof left === "bigint" && typeof right === "bigint") {
63
- if (left < right) {
64
- return -1;
65
- }
66
- if (left > right) {
67
- return 1;
68
- }
69
- return 0;
70
- }
71
- if (typeof left === "string" && typeof right === "string") {
72
- if (left < right) {
73
- return -1;
74
- }
75
- if (left > right) {
76
- return 1;
77
- }
78
- return 0;
79
- }
80
- if (left instanceof Uint8Array && right instanceof Uint8Array) {
81
- const shared = Math.min(left.length, right.length);
82
- for (let index = 0; index < shared; index += 1) {
83
- const leftByte = left[index];
84
- const rightByte = right[index];
85
- // `index < shared` keeps both reads in bounds; the `undefined`
86
- // arms are the checker's indexed-access tax, never taken.
87
- if (leftByte !== undefined && rightByte !== undefined && leftByte !== rightByte) {
88
- return leftByte - rightByte;
89
- }
90
- }
91
- return left.length - right.length;
92
- }
93
- if (typeof left === "object" &&
94
- !(left instanceof Uint8Array) &&
95
- typeof right === "object" &&
96
- !(right instanceof Uint8Array)) {
97
- if (left.start < right.start) {
98
- return -1;
99
- }
100
- if (left.start > right.start) {
101
- return 1;
102
- }
103
- if (left.end < right.end) {
104
- return -1;
105
- }
106
- if (left.end > right.end) {
107
- return 1;
108
- }
109
- return 0;
110
- }
111
- return cellRank(left) - cellRank(right);
112
- }
113
- /**
114
- * The ascending identity comparator `by()` returns — one value, minted
115
- * once (`by() === by()`), {@link cellCmp} narrowed to the engine-orderable
116
- * roster (the one owner of the cell order).
117
- */
118
- function identityAscending(left, right) {
119
- return cellCmp(left, right);
120
- }
121
- /** The descending identity comparator `desc()` returns — the same owner, sides flipped. */
122
- function identityDescending(left, right) {
123
- return cellCmp(right, left);
124
- }
125
- function desc(key) {
126
- if (key === undefined) {
127
- return identityDescending;
128
- }
129
- const marker = { key, desc: true };
130
- return Object.freeze(marker);
131
- }
132
- function by(...keys) {
133
- if (keys.length === 0) {
134
- return identityAscending;
135
- }
136
- const entries = keys.map(function normalizeKey(sortKey) {
137
- if (typeof sortKey === "string") {
138
- return { key: sortKey, factor: 1 };
139
- }
140
- return { key: sortKey.key, factor: -1 };
141
- });
142
- return function compare(left, right) {
143
- for (const entry of entries) {
144
- const order = cellCmp(left[entry.key], right[entry.key]) * entry.factor;
145
- if (order !== 0) {
146
- return order;
147
- }
148
- }
149
- return 0;
150
- };
151
- }
152
- export { by, desc };
153
- //# sourceMappingURL=order.js.map
package/dist/order.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"order.js","sourceRoot":"","sources":["../src/order.ts"],"names":[],"mappings":"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"}