@bjornpagen/bumbledb 0.6.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.
- package/COOKBOOK.md +150 -9
- package/README.md +18 -5
- package/dist/capacity.d.ts +310 -0
- package/dist/capacity.d.ts.map +1 -0
- package/dist/capacity.js +138 -0
- package/dist/capacity.js.map +1 -0
- package/dist/closed.d.ts +7 -5
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +4 -1
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +115 -76
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +178 -122
- package/dist/db.js.map +1 -1
- package/dist/exhume.d.ts +22 -10
- package/dist/exhume.d.ts.map +1 -1
- package/dist/exhume.js +42 -9
- package/dist/exhume.js.map +1 -1
- package/dist/face.d.ts +11 -7
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +38 -16
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +33 -8
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +3 -2
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +1 -1
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts +9 -9
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +20 -14
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts +17 -7
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +32 -10
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +66 -12
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +72 -7
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +12 -9
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts +8 -0
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +80 -13
- package/dist/query/lower.js.map +1 -1
- package/dist/query/run.d.ts +5 -5
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +7 -12
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +15 -5
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +3 -1
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +12 -2
- package/dist/schema.js.map +1 -1
- package/dist/spec.d.ts +95 -32
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js +39 -7
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +62 -25
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +105 -22
- package/dist/statements.js.map +1 -1
- package/package.json +3 -3
- package/src/capacity.ts +454 -0
- package/src/closed.ts +13 -7
- package/src/db.ts +302 -184
- package/src/exhume.ts +48 -11
- package/src/face.ts +14 -6
- package/src/fields.ts +51 -15
- package/src/index.ts +20 -9
- package/src/law.ts +3 -2
- package/src/lower.ts +20 -14
- package/src/marshal.ts +38 -13
- package/src/native.ts +65 -11
- package/src/query/atom.ts +119 -15
- package/src/query/lower.ts +117 -15
- package/src/query/run.ts +7 -12
- package/src/query/scope.ts +15 -6
- package/src/relation.ts +3 -1
- package/src/schema.ts +14 -2
- package/src/spec.ts +112 -34
- package/src/statements.ts +188 -38
- package/dist/count.d.ts +0 -102
- package/dist/count.d.ts.map +0 -1
- package/dist/count.js +0 -115
- package/dist/count.js.map +0 -1
- package/src/count.ts +0 -211
package/dist/statements.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statements.js","sourceRoot":"","sources":["../src/statements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,MAAM,MAAM,uBAAuB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"statements.js","sourceRoot":"","sources":["../src/statements.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bjornpagen/bumbledb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Type-theoretic TypeScript SDK for the bumbledb embedded relational engine",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@superbuilders/errors": "^4.0.2"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@bjornpagen/bumbledb-darwin-arm64": "0.
|
|
44
|
+
"@bjornpagen/bumbledb-darwin-arm64": "0.8.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@biomejs/biome": "^2.0.0-beta.5",
|
|
@@ -59,6 +59,6 @@
|
|
|
59
59
|
"build": "node scripts/build.ts",
|
|
60
60
|
"typecheck": "tsc --noEmit",
|
|
61
61
|
"lint": "biome check .",
|
|
62
|
-
"test": "pnpm run build && node --test test/**/*.test.ts"
|
|
62
|
+
"test": "pnpm run build && node --test 'test/**/*.test.ts'"
|
|
63
63
|
}
|
|
64
64
|
}
|
package/src/capacity.ts
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capacity-law mints — the window, weight, and dependent-bound vocabulary
|
|
3
|
+
* the one `capacity()` statement constructor consumes
|
|
4
|
+
* (`docs/architecture/70-api.md` § the canonical-utterance law, restated
|
|
5
|
+
* around the aggregate form). `within()` is the ONE window spelling —
|
|
6
|
+
* `within(n)` exact (`within(0n)` IS the exclusion's one spelling),
|
|
7
|
+
* `within(lo, hi)` range (`within(0n, hi)` the canonical ceiling),
|
|
8
|
+
* `within(lo, "*")` floor — `weigh()` names the measure on the SOURCE row
|
|
9
|
+
* (`weigh("watts")` a u64 field, `weigh(duration("booked"))` an interval's
|
|
10
|
+
* measure), and `ref()`/`duration()` read a dependent bound from the
|
|
11
|
+
* TARGET row (hi slot only — ruled 2026-07-24, C6). The ban table is
|
|
12
|
+
* enforced REPRESENTATIONALLY in two tiers, split per-aggregate where
|
|
13
|
+
* weight-sensitive (design § 6: a ban is canonical-utterance policing when
|
|
14
|
+
* it is weight-independent, semantic deduplication when it is not):
|
|
15
|
+
*
|
|
16
|
+
* - **The type tier**: a banned spelling written as a LITERAL does not
|
|
17
|
+
* compile — every negative bound, `within(n, n)`, `within(0n, 0n)`, and
|
|
18
|
+
* `within(0n, "*")` are type errors naming the canonical form. The
|
|
19
|
+
* weight-SENSITIVE row rides the `capacity()` overloads themselves:
|
|
20
|
+
* `within(1n, "*")` is banned on the unit overload only (`{1..*}` on the
|
|
21
|
+
* count instance is the bare containment respelled —
|
|
22
|
+
* `window_floor_containment`), and LEGAL on the weighted one ("positive
|
|
23
|
+
* total" is not an existence claim over rows).
|
|
24
|
+
* - **The construction tier**: a bound the type level cannot judge — a
|
|
25
|
+
* COMPUTED `bigint`, or an inverted `within(lo, hi)` order — is judged at
|
|
26
|
+
* construction with the same canonical-naming errors; and past both
|
|
27
|
+
* tiers the engine's own spec validation remains the law for a hostile
|
|
28
|
+
* FFI caller (the standing two-tier ban enforcement).
|
|
29
|
+
*
|
|
30
|
+
* The weight vocabulary is closed at the row (ruled 2026-07-24, ruling 6):
|
|
31
|
+
* a path weight (`weigh("model.watts")`) is a typed refusal at BOTH tiers
|
|
32
|
+
* whose diagnostic names the pinned-column idiom — the two-column
|
|
33
|
+
* containment IS the join, stated as a law. Bounds are `bigint` (u64
|
|
34
|
+
* crosses as bigint always, PRD-04's law); the witnessed measure comes
|
|
35
|
+
* back as `bigint` too (u128-wide engine accumulator, C3).
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import * as errors from "@superbuilders/errors"
|
|
39
|
+
import type { AnyFace, FaceFields, FaceSource, ProjectedShape } from "#face.ts"
|
|
40
|
+
import type { CapacityBoundSpec, CapacityWindowSpec, WeightSpec } from "#spec.ts"
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The admission brand — a module-private symbol, deliberately unexported
|
|
44
|
+
* (the standing statement-mint pattern): `CapacityWindowSpec` and
|
|
45
|
+
* `WeightSpec` are public wire types, so without this brand every banned
|
|
46
|
+
* spelling in the ban table would be writable as a plain object literal.
|
|
47
|
+
* The symbol makes `within()` and `weigh()` the ONLY producers of the
|
|
48
|
+
* values `capacity()` accepts, which is what "the ban table is unwritable"
|
|
49
|
+
* means.
|
|
50
|
+
*/
|
|
51
|
+
const admitted: unique symbol = Symbol("bumbledb.capacity.admitted")
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* An admitted capacity window — opaque and inert: a fact about the theory,
|
|
55
|
+
* not a builder. Only `within()` produces one; the spec is carried at its
|
|
56
|
+
* EXACT type so the weight-sensitive `{1..*}` ban and the dependent-bound
|
|
57
|
+
* target wall are judged at the `capacity()` call.
|
|
58
|
+
*/
|
|
59
|
+
interface CapacityWindow<S extends CapacityWindowSpec = CapacityWindowSpec> {
|
|
60
|
+
readonly window: S
|
|
61
|
+
readonly [admitted]: true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* An admitted measure — `weigh()`'s product, the `[w]` bracket of the
|
|
66
|
+
* operator. The spec is carried at its exact type so the u64/interval
|
|
67
|
+
* source wall ({@link WeightOnSource}) reads the weighed field's name off
|
|
68
|
+
* the value.
|
|
69
|
+
*/
|
|
70
|
+
interface CapacityWeight<S extends WeightSpec = WeightSpec> {
|
|
71
|
+
readonly weight: S
|
|
72
|
+
readonly [admitted]: true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A dependent bound naming a u64 field of the TARGET row — `ref()`'s
|
|
77
|
+
* product, legal in `within()`'s hi slot only (C6: a dependent floor has
|
|
78
|
+
* no use case; inversion with idents is unrepresentable). Carries no
|
|
79
|
+
* value: bounds resolve per target row at judge time.
|
|
80
|
+
*/
|
|
81
|
+
interface FieldRef<F extends string = string> {
|
|
82
|
+
readonly kind: "field"
|
|
83
|
+
readonly field: F
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A dependent interval-measure bound (`Duration(field)` of the TARGET
|
|
88
|
+
* row), or — handed to `weigh()` — the interval-measure weight of the
|
|
89
|
+
* SOURCE row. One mint, both slots: the interval enters through the
|
|
90
|
+
* measure argument, never the group key.
|
|
91
|
+
*/
|
|
92
|
+
interface DurationRef<F extends string = string> {
|
|
93
|
+
readonly kind: "durationField"
|
|
94
|
+
readonly field: F
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Narrows any value to an admitted capacity window through the module-private brand. */
|
|
98
|
+
function isCapacityWindow(value: unknown): value is CapacityWindow {
|
|
99
|
+
return typeof value === "object" && value !== null && admitted in value && "window" in value
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Narrows any value to an admitted capacity weight through the module-private brand. */
|
|
103
|
+
function isCapacityWeight(value: unknown): value is CapacityWeight {
|
|
104
|
+
return typeof value === "object" && value !== null && admitted in value && "weight" in value
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The legible banned-spelling verdict: intersected into a mint's parameter
|
|
109
|
+
* when the LITERAL argument spells a banned window, naming the canonical
|
|
110
|
+
* form — the compile-time face of the ban table.
|
|
111
|
+
*/
|
|
112
|
+
interface BannedWindow<Canonical extends string> {
|
|
113
|
+
readonly "banned window spelling — the canonical-utterance law names the one legal form": Canonical
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The path-weight refusal (ruling 6 — a boundary, not a deferral): the
|
|
118
|
+
* verdict names the pinned-column idiom, the same diagnostic the macro
|
|
119
|
+
* expansion and the spec resolver carry.
|
|
120
|
+
*/
|
|
121
|
+
interface RefusedPath<Idiom extends string> {
|
|
122
|
+
readonly "path spelling refused — the vocabulary is closed at the row": Idiom
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** `true` exactly when the literal bigint `N` is negative (out of the u64 bound domain). */
|
|
126
|
+
type IsNegative<N extends bigint> = `${N}` extends `-${string}` ? true : false
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The dotted-name ban, both mints: a `a.b` spelling is a typed refusal
|
|
130
|
+
* whose verdict names the composition idiom — pin the column with a
|
|
131
|
+
* two-column containment (`Device(model, watts) <= Model(id, watts)`) and
|
|
132
|
+
* name the local field.
|
|
133
|
+
*/
|
|
134
|
+
type PathBan<F extends string> = string extends F
|
|
135
|
+
? unknown
|
|
136
|
+
: F extends `${string}.${string}`
|
|
137
|
+
? RefusedPath<"pin the column — a two-column containment (Source(ref, f) <= Catalog(id, f)) proves the local copy, then name the local field">
|
|
138
|
+
: unknown
|
|
139
|
+
|
|
140
|
+
/** The ban verdict on a single bound: negatives are out of the u64 domain. */
|
|
141
|
+
type NegativeBan<N extends bigint> = bigint extends N
|
|
142
|
+
? unknown
|
|
143
|
+
: IsNegative<N> extends true
|
|
144
|
+
? BannedWindow<"capacity bounds are u64 — a negative bound is out of domain">
|
|
145
|
+
: unknown
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The ban verdict on `within(lo, "*")`: `{0..*}` is vacuous —
|
|
149
|
+
* weight-independent (sums are ≥ 0). `{1..*}` is NOT judged here: the ban
|
|
150
|
+
* is weight-sensitive (Count-instance only) and rides the `capacity()`
|
|
151
|
+
* unit overload ({@link UnitWindowBan}).
|
|
152
|
+
*/
|
|
153
|
+
type FloorBan<N extends bigint> = bigint extends N
|
|
154
|
+
? unknown
|
|
155
|
+
: IsNegative<N> extends true
|
|
156
|
+
? BannedWindow<"capacity bounds are u64 — a negative bound is out of domain">
|
|
157
|
+
: N extends 0n
|
|
158
|
+
? BannedWindow<"`{0..*}` is vacuous — it provably says nothing; delete the statement">
|
|
159
|
+
: unknown
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The ban verdict on `within(lo, hi)` with both literals known: `{n..n}`
|
|
163
|
+
* is the exact measure respelled (`within(n)`, or `within(0n)` at 0) —
|
|
164
|
+
* weight-independent canonical policing. Bound ORDER (`{hi..lo}` inverted)
|
|
165
|
+
* is not type-expressible — bigint literals have no type-level comparison
|
|
166
|
+
* — so inversion stays a construction error.
|
|
167
|
+
*/
|
|
168
|
+
type RangeBan<Lo extends bigint, Hi extends bigint> = bigint extends Lo
|
|
169
|
+
? unknown
|
|
170
|
+
: bigint extends Hi
|
|
171
|
+
? unknown
|
|
172
|
+
: IsNegative<Lo> extends true
|
|
173
|
+
? BannedWindow<"capacity bounds are u64 — a negative bound is out of domain">
|
|
174
|
+
: IsNegative<Hi> extends true
|
|
175
|
+
? BannedWindow<"capacity bounds are u64 — a negative bound is out of domain">
|
|
176
|
+
: Lo extends Hi
|
|
177
|
+
? Hi extends Lo
|
|
178
|
+
? Lo extends 0n
|
|
179
|
+
? BannedWindow<"`{0..0}` — the point window is written `{0}`: use within(0n)">
|
|
180
|
+
: BannedWindow<"`{n..n}` — an exact measure is written `{n}`: use within(n)">
|
|
181
|
+
: unknown
|
|
182
|
+
: unknown
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The weight-SENSITIVE ban row, judged at the `capacity()` call where the
|
|
186
|
+
* aggregate instance is known (design § 6): on the UNIT overload a
|
|
187
|
+
* `{1..*}` floor says only what the bare containment says
|
|
188
|
+
* (`window_floor_containment`) and is banned naming `contained`; on the
|
|
189
|
+
* weighted overload the same window is LEGAL — "positive total" admits
|
|
190
|
+
* zero-weight rows and is a different, weaker law.
|
|
191
|
+
*/
|
|
192
|
+
type UnitWindowBan<W extends CapacityWindow> = W["window"] extends {
|
|
193
|
+
readonly kind: "floor"
|
|
194
|
+
readonly lo: { readonly kind: "lit"; readonly value: 1n }
|
|
195
|
+
}
|
|
196
|
+
? BannedWindow<"`{1..*}` on the unit instance says only what the bare containment says — write contained(source, target)">
|
|
197
|
+
: unknown
|
|
198
|
+
|
|
199
|
+
/** The projected kind of one field of a face's source, read off the schema type. */
|
|
200
|
+
type KindAt<S extends FaceSource, K extends string> =
|
|
201
|
+
ProjectedShape<S, K> extends readonly [infer Kind, ...unknown[]] ? Kind : undefined
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* The legible off-roster verdict for a dependent bound: bound names
|
|
205
|
+
* resolve against the TARGET's full field roster (C1 — the written
|
|
206
|
+
* projection tuple stays the pure grouping key), and the verdict names
|
|
207
|
+
* that roster.
|
|
208
|
+
*/
|
|
209
|
+
interface BoundOffTargetRoster<K, Roster> {
|
|
210
|
+
readonly "dependent bound must name a field of the TARGET's own row — bound names resolve against the target's full roster": readonly [
|
|
211
|
+
K,
|
|
212
|
+
Roster
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** The legible kind-mismatch verdict for a dependent bound: `ref()` needs u64, `duration()` an interval. */
|
|
217
|
+
interface BoundKindMismatch<K, Want> {
|
|
218
|
+
readonly "dependent bound kind mismatch — ref() reads a u64 field, duration() an interval field, of the TARGET row": readonly [
|
|
219
|
+
K,
|
|
220
|
+
Want
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* One dependent-bound slot judged against the target face's roster and
|
|
226
|
+
* kinds. A WIDE field name (the untyped-caller path — literal identity
|
|
227
|
+
* already lost) passes the type tier and is judged at construction.
|
|
228
|
+
*/
|
|
229
|
+
type BoundOnTarget<K extends string, Want extends "u64" | "interval", B extends AnyFace> = string extends K
|
|
230
|
+
? unknown
|
|
231
|
+
: K extends FaceFields<B["source"]>
|
|
232
|
+
? KindAt<B["source"], K> extends Want
|
|
233
|
+
? unknown
|
|
234
|
+
: BoundKindMismatch<K, Want>
|
|
235
|
+
: BoundOffTargetRoster<K, FaceFields<B["source"]>>
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* The dependent-bound target wall (type tier): for a `ref(K)` bound in the
|
|
239
|
+
* window's hi slot, `K` must name a u64 field of the TARGET face's own
|
|
240
|
+
* row; for a `duration(K)` bound, an interval field. Literal-bound windows
|
|
241
|
+
* pass untouched. The runtime twin for untyped callers lives at the
|
|
242
|
+
* `capacity()` construction (`statements.ts`).
|
|
243
|
+
*/
|
|
244
|
+
type BoundsOnTarget<W extends CapacityWindow, B extends AnyFace> = W["window"] extends {
|
|
245
|
+
readonly hi: FieldRef<infer K>
|
|
246
|
+
}
|
|
247
|
+
? BoundOnTarget<K, "u64", B>
|
|
248
|
+
: W["window"] extends { readonly hi: DurationRef<infer K> }
|
|
249
|
+
? BoundOnTarget<K, "interval", B>
|
|
250
|
+
: unknown
|
|
251
|
+
|
|
252
|
+
/** The legible off-roster verdict for a weight: the vocabulary is closed at the SOURCE row. */
|
|
253
|
+
interface WeightOffSourceRoster<K, Roster> {
|
|
254
|
+
readonly "weight must name a field of the SOURCE's own row — the weight vocabulary is closed at the row": readonly [
|
|
255
|
+
K,
|
|
256
|
+
Roster
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* The legible kind-mismatch verdict for a weight: a signed weight would
|
|
262
|
+
* break the polarity scheduler (an insert could lower a sum), so the
|
|
263
|
+
* illegal weight is unrepresentable, not checked.
|
|
264
|
+
*/
|
|
265
|
+
interface WeightKindMismatch<K, Want> {
|
|
266
|
+
readonly "weight kind mismatch — weigh(field) reads a u64 field, weigh(duration(field)) an interval field, of the SOURCE row": readonly [
|
|
267
|
+
K,
|
|
268
|
+
Want
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* The weight source wall (type tier): `weigh(K)`'s field must be a
|
|
274
|
+
* u64-encoded position of the SOURCE face's own row (signed encodings are
|
|
275
|
+
* the typed polarity refusal), `weigh(duration(K))`'s an interval
|
|
276
|
+
* position. Checked at the `capacity()` call where the source face is
|
|
277
|
+
* inferred — the proven constrain-after-inference pattern.
|
|
278
|
+
*/
|
|
279
|
+
type WeightOnSource<M extends CapacityWeight, A extends AnyFace> = M["weight"] extends {
|
|
280
|
+
readonly kind: "field"
|
|
281
|
+
readonly field: infer K extends string
|
|
282
|
+
}
|
|
283
|
+
? string extends K
|
|
284
|
+
? unknown
|
|
285
|
+
: K extends FaceFields<A["source"]>
|
|
286
|
+
? KindAt<A["source"], K> extends "u64"
|
|
287
|
+
? unknown
|
|
288
|
+
: WeightKindMismatch<K, "u64">
|
|
289
|
+
: WeightOffSourceRoster<K, FaceFields<A["source"]>>
|
|
290
|
+
: M["weight"] extends { readonly kind: "durationField"; readonly field: infer K extends string }
|
|
291
|
+
? string extends K
|
|
292
|
+
? unknown
|
|
293
|
+
: K extends FaceFields<A["source"]>
|
|
294
|
+
? KindAt<A["source"], K> extends "interval"
|
|
295
|
+
? unknown
|
|
296
|
+
: WeightKindMismatch<K, "interval">
|
|
297
|
+
: WeightOffSourceRoster<K, FaceFields<A["source"]>>
|
|
298
|
+
: unknown
|
|
299
|
+
|
|
300
|
+
/** The unit weight — a case, not an absence (C4): the count instance's one wire spelling. */
|
|
301
|
+
const unitWeight: WeightSpec = Object.freeze({ kind: "unit" })
|
|
302
|
+
|
|
303
|
+
/** The construction-tier twin of {@link PathBan}: a dotted name refuses naming the idiom. */
|
|
304
|
+
function assertRowLocal(field: string, role: string): string {
|
|
305
|
+
if (field.includes(".")) {
|
|
306
|
+
throw errors.new(
|
|
307
|
+
`${role} \`${field}\` walks a reference — the vocabulary is closed at the row (ruling 6): pin the column with a two-column containment (Source(ref, f) <= Catalog(id, f)) and name the local field`
|
|
308
|
+
)
|
|
309
|
+
}
|
|
310
|
+
return field
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/** Stamps one admitted window spec as a frozen branded value. */
|
|
314
|
+
function admitWindow<S extends CapacityWindowSpec>(window: S): CapacityWindow<S> {
|
|
315
|
+
const value: CapacityWindow<S> = { window, [admitted]: true }
|
|
316
|
+
return Object.freeze(value)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** One literal bound. */
|
|
320
|
+
function lit(value: bigint): CapacityBoundSpec {
|
|
321
|
+
return Object.freeze({ kind: "lit", value })
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* `{n}` — THE exact-measure spelling; `within(0n)` IS the exclusion's one
|
|
326
|
+
* spelling on the unit instance, and the weaker "total is zero" law on a
|
|
327
|
+
* weighted one (zero-weight rows may exist — design § 6, stated loudly).
|
|
328
|
+
*/
|
|
329
|
+
function within<const N extends bigint>(
|
|
330
|
+
n: N & NegativeBan<N>
|
|
331
|
+
): CapacityWindow<{ readonly kind: "exact"; readonly n: { readonly kind: "lit"; readonly value: N } }>
|
|
332
|
+
/**
|
|
333
|
+
* `{lo..*}` — a floor with no ceiling. `within(0n, "*")` is vacuous
|
|
334
|
+
* (unwritable as a literal); `within(1n, "*")` constructs — the `{1..*}`
|
|
335
|
+
* ban is weight-sensitive and judged at the `capacity()` call (unit
|
|
336
|
+
* instance only).
|
|
337
|
+
*/
|
|
338
|
+
function within<const Lo extends bigint>(
|
|
339
|
+
lo: Lo & FloorBan<Lo>,
|
|
340
|
+
hi: "*"
|
|
341
|
+
): CapacityWindow<{ readonly kind: "floor"; readonly lo: { readonly kind: "lit"; readonly value: Lo } }>
|
|
342
|
+
/**
|
|
343
|
+
* `{lo..field}` / `{lo..Duration(field)}` — the dependent ceiling, read
|
|
344
|
+
* from the TARGET row per group (C6: hi slot only). The ref carries no
|
|
345
|
+
* value, so no inversion judgment exists at construction — a per-row
|
|
346
|
+
* inverted window is the judge's typed refusal.
|
|
347
|
+
*/
|
|
348
|
+
function within<const Lo extends bigint, const R extends FieldRef | DurationRef>(
|
|
349
|
+
lo: Lo & NegativeBan<Lo>,
|
|
350
|
+
hi: R
|
|
351
|
+
): CapacityWindow<{
|
|
352
|
+
readonly kind: "range"
|
|
353
|
+
readonly lo: { readonly kind: "lit"; readonly value: Lo }
|
|
354
|
+
readonly hi: R
|
|
355
|
+
}>
|
|
356
|
+
/**
|
|
357
|
+
* `{lo..hi}` — both bounds explicit, lo < hi; `within(0n, hi)` is the
|
|
358
|
+
* canonical ceiling. `lo === hi` is the exact measure respelled
|
|
359
|
+
* (unwritable as literals — {@link RangeBan} names `within(n)`), rejected
|
|
360
|
+
* at construction when computed; an inverted window is unsatisfiable and
|
|
361
|
+
* rejected at construction (bigint literals carry no type-level order).
|
|
362
|
+
*/
|
|
363
|
+
function within<const Lo extends bigint, const Hi extends bigint>(
|
|
364
|
+
lo: Lo,
|
|
365
|
+
hi: Hi & RangeBan<Lo, Hi>
|
|
366
|
+
): CapacityWindow<{
|
|
367
|
+
readonly kind: "range"
|
|
368
|
+
readonly lo: { readonly kind: "lit"; readonly value: Lo }
|
|
369
|
+
readonly hi: { readonly kind: "lit"; readonly value: Hi }
|
|
370
|
+
}>
|
|
371
|
+
function within(lo: bigint, hi?: bigint | "*" | FieldRef | DurationRef): CapacityWindow {
|
|
372
|
+
if (lo < 0n) {
|
|
373
|
+
throw errors.new(`capacity bounds are u64: within(${lo}${hi === undefined ? "" : ", …"}) is out of domain`)
|
|
374
|
+
}
|
|
375
|
+
if (hi === undefined) {
|
|
376
|
+
return admitWindow({ kind: "exact", n: lit(lo) })
|
|
377
|
+
}
|
|
378
|
+
if (hi === "*") {
|
|
379
|
+
if (lo === 0n) {
|
|
380
|
+
throw errors.new("the `{0..*}` window is vacuous — it provably says nothing; delete the statement")
|
|
381
|
+
}
|
|
382
|
+
return admitWindow({ kind: "floor", lo: lit(lo) })
|
|
383
|
+
}
|
|
384
|
+
if (typeof hi === "bigint") {
|
|
385
|
+
if (hi < 0n) {
|
|
386
|
+
throw errors.new(`capacity bounds are u64: within(${lo}, ${hi}) is out of domain`)
|
|
387
|
+
}
|
|
388
|
+
if (hi < lo) {
|
|
389
|
+
throw errors.new(
|
|
390
|
+
`the window \`{${lo}..${hi}}\` is inverted — no measure satisfies it; bounds are \`{lo..hi}\` with lo < hi (an exact measure is \`{n}\`: within(n))`
|
|
391
|
+
)
|
|
392
|
+
}
|
|
393
|
+
if (lo === hi) {
|
|
394
|
+
if (lo === 0n) {
|
|
395
|
+
throw errors.new("`{0..0}` — the point window is written `{0}`: use within(0n)")
|
|
396
|
+
}
|
|
397
|
+
throw errors.new(`\`{${lo}..${lo}}\` — an exact measure is written \`{${lo}}\`: use within(${lo}n)`)
|
|
398
|
+
}
|
|
399
|
+
return admitWindow({ kind: "range", lo: lit(lo), hi: lit(hi) })
|
|
400
|
+
}
|
|
401
|
+
const field = assertRowLocal(hi.field, "dependent bound")
|
|
402
|
+
if (hi.kind === "durationField") {
|
|
403
|
+
return admitWindow({ kind: "range", lo: lit(lo), hi: Object.freeze({ kind: "durationField", field }) })
|
|
404
|
+
}
|
|
405
|
+
return admitWindow({ kind: "range", lo: lit(lo), hi: Object.freeze({ kind: "field", field }) })
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Stamps one admitted weight spec as a frozen branded value. */
|
|
409
|
+
function admitWeight<S extends WeightSpec>(weight: S): CapacityWeight<S> {
|
|
410
|
+
const value: CapacityWeight<S> = { weight, [admitted]: true }
|
|
411
|
+
return Object.freeze(value)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* `[field]` — the measure: a u64-encoded field of the SOURCE row summed
|
|
416
|
+
* per target group. A dotted path is the typed refusal naming the
|
|
417
|
+
* pinned-column idiom (ruling 6); `weigh(duration(field))` is the
|
|
418
|
+
* interval-measure weight — calendar capacity as one statement.
|
|
419
|
+
*/
|
|
420
|
+
function weigh<const F extends string>(
|
|
421
|
+
field: F & PathBan<F>
|
|
422
|
+
): CapacityWeight<{ readonly kind: "field"; readonly field: F }>
|
|
423
|
+
function weigh<const F extends string>(
|
|
424
|
+
measure: DurationRef<F>
|
|
425
|
+
): CapacityWeight<{ readonly kind: "durationField"; readonly field: F }>
|
|
426
|
+
function weigh(measure: string | DurationRef): CapacityWeight {
|
|
427
|
+
if (typeof measure === "string") {
|
|
428
|
+
return admitWeight({ kind: "field", field: assertRowLocal(measure, "weight") })
|
|
429
|
+
}
|
|
430
|
+
return admitWeight({ kind: "durationField", field: assertRowLocal(measure.field, "weight") })
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* A dependent bound by name — `within(0n, ref("supply"))` reads each
|
|
435
|
+
* group's ceiling from the TARGET row's u64 field (bound names resolve
|
|
436
|
+
* against the target's FULL roster, C1 — the projection tuple stays the
|
|
437
|
+
* pure grouping key). Carries no value.
|
|
438
|
+
*/
|
|
439
|
+
function ref<const F extends string>(field: F & PathBan<F>): FieldRef<F> {
|
|
440
|
+
return Object.freeze({ kind: "field", field: assertRowLocal(field, "dependent bound") }) as FieldRef<F>
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* `Duration(field)` — the interval-measure spelling, one mint for both
|
|
445
|
+
* slots: handed to `weigh()` it is the SOURCE row's interval measure;
|
|
446
|
+
* in `within()`'s hi slot it is the TARGET row's interval-measure bound
|
|
447
|
+
* (Duration weights pair with Duration-capable bounds — C18).
|
|
448
|
+
*/
|
|
449
|
+
function duration<const F extends string>(field: F & PathBan<F>): DurationRef<F> {
|
|
450
|
+
return Object.freeze({ kind: "durationField", field: assertRowLocal(field, "Duration measure") }) as DurationRef<F>
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export type { BoundsOnTarget, CapacityWeight, CapacityWindow, DurationRef, FieldRef, UnitWindowBan, WeightOnSource }
|
|
454
|
+
export { duration, isCapacityWeight, isCapacityWindow, ref, unitWeight, weigh, within }
|
package/src/closed.ts
CHANGED
|
@@ -34,6 +34,7 @@ import * as errors from "@superbuilders/errors"
|
|
|
34
34
|
import {
|
|
35
35
|
type AnyField,
|
|
36
36
|
assertDeclarationOrderKey,
|
|
37
|
+
assertDeclarationRecord,
|
|
37
38
|
type ClosedIdField,
|
|
38
39
|
type ClosedRoster,
|
|
39
40
|
type Infer,
|
|
@@ -109,12 +110,14 @@ interface ClosedCore<Name extends string, Handles extends string, Cols extends R
|
|
|
109
110
|
* The closed reference descriptor: `kind: Kind.id` in another relation's
|
|
110
111
|
* field block is the reference through which handle literals become
|
|
111
112
|
* legal in that relation's selections. Pure structure plus the PRECISE
|
|
112
|
-
* roster (`ClosedIdField<Handles>` — the handle union is the
|
|
113
|
-
* value type under `Infer
|
|
114
|
-
*
|
|
115
|
-
*
|
|
113
|
+
* roster (`ClosedIdField<Name, Handles>` — the handle union is the
|
|
114
|
+
* field's value type under `Infer`, and the name literal keeps two
|
|
115
|
+
* same-shaped vocabularies distinct at the type tier, matching the
|
|
116
|
+
* runtime's roster-identity judgment); the referencing field's domain is
|
|
117
|
+
* law-born: `schema()` computes it from the declared containment
|
|
118
|
+
* (`"Kind.id"`, the generator class).
|
|
116
119
|
*/
|
|
117
|
-
readonly id: ClosedIdField<Handles>
|
|
120
|
+
readonly id: ClosedIdField<Name, Handles>
|
|
118
121
|
readonly data: ClosedData
|
|
119
122
|
/** Payload readback: handle to its declared column values, bare and structural. */
|
|
120
123
|
readonly axioms: Axioms<Handles, Cols>
|
|
@@ -384,9 +387,11 @@ function closedPayload<Name extends string, Handles extends string, Cols extends
|
|
|
384
387
|
columns: Cols,
|
|
385
388
|
axioms: Axioms<Handles, Cols>
|
|
386
389
|
): Closed<Name, Handles, Cols> {
|
|
390
|
+
assertDeclarationRecord(`closed relation ${name} columns`, columns)
|
|
387
391
|
for (const columnName of Object.keys(columns)) {
|
|
388
392
|
assertDeclarationOrderKey(`closed relation ${name} column`, columnName)
|
|
389
393
|
}
|
|
394
|
+
assertDeclarationRecord(`closed relation ${name} axioms`, axioms)
|
|
390
395
|
const handles = Object.keys(axioms)
|
|
391
396
|
for (const handle of handles) {
|
|
392
397
|
assertDeclarationOrderKey(`closed relation ${name} handle`, handle)
|
|
@@ -426,6 +431,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
426
431
|
columns: Cols,
|
|
427
432
|
axioms: Axioms<Handles, Cols>
|
|
428
433
|
): Closed<Name, Handles, Cols> {
|
|
434
|
+
assertDeclarationOrderKey("closed relation", name)
|
|
429
435
|
if (handles.length === 0) {
|
|
430
436
|
throw errors.new(`closed relation ${name}: at least one handle is required (an empty vocabulary declares nothing)`)
|
|
431
437
|
}
|
|
@@ -437,7 +443,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
437
443
|
seen.add(handle)
|
|
438
444
|
}
|
|
439
445
|
const handleList: readonly Handles[] = Object.freeze([...handles])
|
|
440
|
-
const roster: ClosedRoster<Handles> = Object.freeze({ name, handles: handleList })
|
|
446
|
+
const roster: ClosedRoster<Name, Handles> = Object.freeze({ name, handles: handleList })
|
|
441
447
|
const cols: ClosedColumn[] = []
|
|
442
448
|
for (const [columnName, field] of Object.entries(columns)) {
|
|
443
449
|
assertDeclarationOrderKey(`closed relation ${name} column`, columnName)
|
|
@@ -462,7 +468,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
462
468
|
columns: cols,
|
|
463
469
|
rows: Object.freeze(rows)
|
|
464
470
|
})
|
|
465
|
-
const id: ClosedIdField<Handles> = Object.freeze({ kind: "u64", closed: roster })
|
|
471
|
+
const id: ClosedIdField<Name, Handles> = Object.freeze({ kind: "u64", closed: roster })
|
|
466
472
|
/**
|
|
467
473
|
* Handle names are arbitrary identifiers, so axiom rows are minted with
|
|
468
474
|
* OWN-property definition (inside {@link mintAxioms}), never assignment:
|