@bjornpagen/bumbledb 0.19.1 → 0.20.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 +2 -0
- package/README.md +1 -0
- package/dist/closed.d.ts +9 -9
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +27 -18
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +8 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +6 -0
- package/dist/db.js.map +1 -1
- package/dist/face.d.ts +18 -23
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +54 -8
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +28 -1
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/judgment.d.ts +13 -0
- package/dist/judgment.d.ts.map +1 -0
- package/dist/judgment.js +11 -0
- package/dist/judgment.js.map +1 -0
- package/dist/law.d.ts +2 -1
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js.map +1 -1
- package/dist/marshal.d.ts +2 -2
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +168 -3
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +86 -2
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +10 -7
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +1 -1
- package/dist/query/atom.js.map +1 -1
- package/dist/query/find.d.ts +1 -2
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +3 -39
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +48 -19
- package/dist/query/lower.js.map +1 -1
- package/dist/query/scope.d.ts +43 -38
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +24 -15
- package/dist/query/scope.js.map +1 -1
- package/dist/spec.d.ts +1 -1
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +1 -1
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +2 -2
- package/dist/statements.js.map +1 -1
- package/package.json +5 -4
- package/src/closed.ts +85 -51
- package/src/db.ts +15 -0
- package/src/face.ts +18 -24
- package/src/fields.ts +85 -7
- package/src/index.ts +43 -1
- package/src/judgment.ts +25 -0
- package/src/law.ts +2 -1
- package/src/marshal.ts +3 -3
- package/src/native.ts +320 -12
- package/src/query/atom.ts +6 -19
- package/src/query/find.ts +1 -16
- package/src/query/lower.ts +51 -32
- package/src/query/scope.ts +84 -65
- package/src/spec.ts +0 -1
- package/src/statements.ts +3 -4
package/src/closed.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as errors from "@superbuilders/errors"
|
|
2
2
|
import {
|
|
3
|
+
type AnyClosedIdField,
|
|
3
4
|
type AnyField,
|
|
4
5
|
assertDeclarationOrderKey,
|
|
5
6
|
assertDeclarationRecord,
|
|
7
|
+
type ClosedHandleTuple,
|
|
6
8
|
type ClosedIdField,
|
|
7
9
|
type ClosedRoster,
|
|
8
10
|
type Infer,
|
|
@@ -39,20 +41,28 @@ type Axioms<Handles extends string, Cols extends Record<string, PayloadField>> =
|
|
|
39
41
|
readonly [H in Handles]: AxiomRow<Cols>
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
interface ClosedCore<
|
|
44
|
+
interface ClosedCore<
|
|
45
|
+
Name extends string,
|
|
46
|
+
Handles extends ClosedHandleTuple,
|
|
47
|
+
Cols extends Record<string, PayloadField>
|
|
48
|
+
> {
|
|
43
49
|
readonly name: Name
|
|
44
50
|
|
|
45
51
|
readonly id: ClosedIdField<Name, Handles>
|
|
46
52
|
readonly data: ClosedData
|
|
47
53
|
|
|
48
|
-
readonly axioms: Axioms<Handles, Cols>
|
|
54
|
+
readonly axioms: Axioms<Handles[number], Cols>
|
|
49
55
|
|
|
50
56
|
readonly columns: Cols
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
type ClosedSelectionInput<Cols extends Record<string, PayloadField>> = SelectionInput<Cols>
|
|
54
60
|
|
|
55
|
-
interface SelectedClosed<
|
|
61
|
+
interface SelectedClosed<
|
|
62
|
+
Name extends string,
|
|
63
|
+
Handles extends ClosedHandleTuple,
|
|
64
|
+
Cols extends Record<string, PayloadField>
|
|
65
|
+
> {
|
|
56
66
|
readonly relation: Closed<Name, Handles, Cols>
|
|
57
67
|
readonly selection: readonly SelectionBinding[]
|
|
58
68
|
}
|
|
@@ -62,11 +72,15 @@ interface AnySelectedClosed {
|
|
|
62
72
|
readonly selection: readonly SelectionBinding[]
|
|
63
73
|
}
|
|
64
74
|
|
|
65
|
-
interface ClosedSelectable<
|
|
75
|
+
interface ClosedSelectable<
|
|
76
|
+
Name extends string,
|
|
77
|
+
Handles extends ClosedHandleTuple,
|
|
78
|
+
Cols extends Record<string, PayloadField>
|
|
79
|
+
> {
|
|
66
80
|
where(selection: ClosedSelectionInput<Cols>): SelectedClosed<Name, Handles, Cols>
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
type Closed<Name extends string, Handles extends
|
|
83
|
+
type Closed<Name extends string, Handles extends ClosedHandleTuple, Cols extends Record<string, PayloadField>> = [
|
|
70
84
|
keyof Cols
|
|
71
85
|
] extends [never]
|
|
72
86
|
? ClosedCore<Name, Handles, Cols>
|
|
@@ -74,7 +88,7 @@ type Closed<Name extends string, Handles extends string, Cols extends Record<str
|
|
|
74
88
|
|
|
75
89
|
interface AnyClosed {
|
|
76
90
|
readonly name: string
|
|
77
|
-
readonly id:
|
|
91
|
+
readonly id: AnyClosedIdField
|
|
78
92
|
readonly data: ClosedData
|
|
79
93
|
readonly axioms: Readonly<Record<string, object>>
|
|
80
94
|
readonly columns: Readonly<Record<string, PayloadField>>
|
|
@@ -98,25 +112,34 @@ function sealedFieldOf(member: AnyRelation | AnyClosed, fieldName: string): AnyF
|
|
|
98
112
|
return declared?.field
|
|
99
113
|
}
|
|
100
114
|
|
|
101
|
-
function isHandleTuple(
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
|
|
115
|
+
function isHandleTuple(shape: unknown): shape is ClosedHandleTuple {
|
|
116
|
+
return (
|
|
117
|
+
Array.isArray(shape) &&
|
|
118
|
+
shape.length > 0 &&
|
|
119
|
+
shape.every(function stringHandle(handle) {
|
|
120
|
+
return typeof handle === "string"
|
|
121
|
+
})
|
|
122
|
+
)
|
|
105
123
|
}
|
|
106
124
|
|
|
107
125
|
/**
|
|
108
|
-
* The trusted seam of the payload tier
|
|
109
|
-
* record
|
|
110
|
-
*
|
|
111
|
-
* that checkable fact before the key list is admitted at the handle type.
|
|
126
|
+
* The trusted seam of the payload tier: the handle tuple and the axioms
|
|
127
|
+
* record are the same finite set — every tuple name is an own key, and
|
|
128
|
+
* every own key is in the tuple.
|
|
112
129
|
*/
|
|
113
130
|
function handleKeysOwn<Handles extends string>(
|
|
114
131
|
axioms: { readonly [H in Handles]: object },
|
|
115
|
-
names: readonly
|
|
116
|
-
):
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
132
|
+
names: readonly Handles[]
|
|
133
|
+
): boolean {
|
|
134
|
+
const listed = new Set<string>(names)
|
|
135
|
+
return (
|
|
136
|
+
names.every(function ownHandle(name) {
|
|
137
|
+
return Object.hasOwn(axioms, name)
|
|
138
|
+
}) &&
|
|
139
|
+
Object.keys(axioms).every(function listedHandle(name) {
|
|
140
|
+
return listed.has(name)
|
|
141
|
+
})
|
|
142
|
+
)
|
|
120
143
|
}
|
|
121
144
|
|
|
122
145
|
/**
|
|
@@ -160,40 +183,50 @@ function mintAxioms<Handles extends string, Cols extends Record<string, PayloadF
|
|
|
160
183
|
return out
|
|
161
184
|
}
|
|
162
185
|
|
|
163
|
-
function closed<const Name extends string, const Handles extends
|
|
186
|
+
function closed<const Name extends string, const Handles extends ClosedHandleTuple>(
|
|
164
187
|
name: Name,
|
|
165
188
|
handles: Handles
|
|
166
|
-
): Closed<Name, Handles
|
|
189
|
+
): Closed<Name, Handles, Record<never, never>>
|
|
167
190
|
|
|
168
|
-
function closed<const Name extends string, const
|
|
191
|
+
function closed<const Name extends string, const Handles extends ClosedHandleTuple, const Cols extends PayloadColumns>(
|
|
169
192
|
name: Name,
|
|
193
|
+
handles: Handles,
|
|
170
194
|
columns: Cols,
|
|
171
|
-
axioms: Axioms<Handles, Cols>
|
|
195
|
+
axioms: Axioms<Handles[number], Cols>
|
|
172
196
|
): Closed<Name, Handles, Cols>
|
|
173
197
|
|
|
174
|
-
function closed<
|
|
198
|
+
function closed<Name extends string, Handles extends ClosedHandleTuple, Cols extends PayloadColumns>(
|
|
175
199
|
name: Name,
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
200
|
+
handles: Handles,
|
|
201
|
+
columns?: Cols,
|
|
202
|
+
axioms?: Axioms<Handles[number], Cols>
|
|
203
|
+
): Closed<Name, Handles, Record<never, never>> | Closed<Name, Handles, Cols> {
|
|
204
|
+
if (!Array.isArray(handles)) {
|
|
205
|
+
throw errors.new(
|
|
206
|
+
`closed relation ${name}: payload columns declared without ground axioms — the payload tier is spelled closed(name, handles, columns, axioms)`
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
if (!isHandleTuple(handles)) {
|
|
210
|
+
throw errors.new(`closed relation ${name}: at least one handle is required (an empty vocabulary declares nothing)`)
|
|
211
|
+
}
|
|
212
|
+
if (columns === undefined) {
|
|
180
213
|
if (axioms !== undefined) {
|
|
181
214
|
throw errors.new(`closed relation ${name}: the bare tier declares no columns, so ground axioms are inadmissible`)
|
|
182
215
|
}
|
|
183
|
-
return closedBare(name,
|
|
216
|
+
return closedBare(name, handles)
|
|
184
217
|
}
|
|
185
218
|
if (axioms === undefined) {
|
|
186
219
|
throw errors.new(
|
|
187
|
-
`closed relation ${name}: payload columns declared without ground axioms — the payload tier is spelled closed(name, columns, axioms)
|
|
220
|
+
`closed relation ${name}: payload columns declared without ground axioms — the payload tier is spelled closed(name, handles, columns, axioms)`
|
|
188
221
|
)
|
|
189
222
|
}
|
|
190
|
-
return closedPayload(name,
|
|
223
|
+
return closedPayload(name, handles, columns, axioms)
|
|
191
224
|
}
|
|
192
225
|
|
|
193
|
-
function closedBare<Name extends string,
|
|
226
|
+
function closedBare<Name extends string, const Hs extends ClosedHandleTuple>(
|
|
194
227
|
name: Name,
|
|
195
|
-
handles:
|
|
196
|
-
): Closed<Name,
|
|
228
|
+
handles: Hs
|
|
229
|
+
): Closed<Name, Hs, Record<never, never>> {
|
|
197
230
|
const empty: Record<string, object> = {}
|
|
198
231
|
for (const handle of handles) {
|
|
199
232
|
/** A duplicated name mints one row; the roster's own duplicate refusal in {@link mintClosed} stays the judge. */
|
|
@@ -202,33 +235,37 @@ function closedBare<Name extends string, Handles extends string>(
|
|
|
202
235
|
}
|
|
203
236
|
}
|
|
204
237
|
Object.freeze(empty)
|
|
205
|
-
if (!axiomsMinted<
|
|
238
|
+
if (!axiomsMinted<Hs[number], Record<never, never>>(empty, handles, [])) {
|
|
206
239
|
throw errors.new(`closed relation ${name}: bare-tier axiom-row minting incomplete`)
|
|
207
240
|
}
|
|
208
|
-
return mintClosed
|
|
241
|
+
return mintClosed(name, handles, {}, empty)
|
|
209
242
|
}
|
|
210
243
|
|
|
211
|
-
function closedPayload<Name extends string, Handles extends
|
|
244
|
+
function closedPayload<Name extends string, Handles extends ClosedHandleTuple, Cols extends PayloadColumns>(
|
|
212
245
|
name: Name,
|
|
246
|
+
handles: Handles,
|
|
213
247
|
columns: Cols,
|
|
214
|
-
axioms: Axioms<Handles, Cols>
|
|
248
|
+
axioms: Axioms<Handles[number], Cols>
|
|
215
249
|
): Closed<Name, Handles, Cols> {
|
|
216
250
|
assertDeclarationRecord(`closed relation ${name} columns`, columns)
|
|
217
251
|
for (const columnName of Object.keys(columns)) {
|
|
218
252
|
assertDeclarationOrderKey(`closed relation ${name} column`, columnName)
|
|
219
253
|
}
|
|
220
254
|
assertDeclarationRecord(`closed relation ${name} axioms`, axioms)
|
|
221
|
-
const handles = Object.keys(axioms)
|
|
222
255
|
for (const handle of handles) {
|
|
223
256
|
assertDeclarationOrderKey(`closed relation ${name} handle`, handle)
|
|
224
257
|
}
|
|
225
258
|
if (!handleKeysOwn(axioms, handles)) {
|
|
226
259
|
throw errors.new(`closed relation ${name}: handle enumeration incomplete`)
|
|
227
260
|
}
|
|
228
|
-
return mintClosed
|
|
261
|
+
return mintClosed(name, handles, columns, axioms)
|
|
229
262
|
}
|
|
230
263
|
|
|
231
|
-
function surfaceMinted<
|
|
264
|
+
function surfaceMinted<
|
|
265
|
+
Name extends string,
|
|
266
|
+
Handles extends ClosedHandleTuple,
|
|
267
|
+
Cols extends Record<string, PayloadField>
|
|
268
|
+
>(
|
|
232
269
|
value: ClosedCore<Name, Handles, Cols>,
|
|
233
270
|
cols: readonly ClosedColumn[]
|
|
234
271
|
): value is ClosedCore<Name, Handles, Cols> & Closed<Name, Handles, Cols> {
|
|
@@ -236,16 +273,13 @@ function surfaceMinted<Name extends string, Handles extends string, Cols extends
|
|
|
236
273
|
return cols.length > 0 ? selectable : !selectable
|
|
237
274
|
}
|
|
238
275
|
|
|
239
|
-
function mintClosed<Name extends string, Handles extends
|
|
276
|
+
function mintClosed<Name extends string, Handles extends ClosedHandleTuple, Cols extends Record<string, PayloadField>>(
|
|
240
277
|
name: Name,
|
|
241
|
-
handles:
|
|
278
|
+
handles: Handles,
|
|
242
279
|
columns: Cols,
|
|
243
|
-
axioms: Axioms<Handles, Cols>
|
|
280
|
+
axioms: Axioms<Handles[number], Cols>
|
|
244
281
|
): Closed<Name, Handles, Cols> {
|
|
245
282
|
assertDeclarationOrderKey("closed relation", name)
|
|
246
|
-
if (handles.length === 0) {
|
|
247
|
-
throw errors.new(`closed relation ${name}: at least one handle is required (an empty vocabulary declares nothing)`)
|
|
248
|
-
}
|
|
249
283
|
const seen = new Set<string>()
|
|
250
284
|
for (const handle of handles) {
|
|
251
285
|
if (seen.has(handle)) {
|
|
@@ -253,7 +287,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
253
287
|
}
|
|
254
288
|
seen.add(handle)
|
|
255
289
|
}
|
|
256
|
-
const handleList
|
|
290
|
+
const handleList = Object.freeze(handles)
|
|
257
291
|
const roster: ClosedRoster<Name, Handles> = Object.freeze({ name, handles: handleList })
|
|
258
292
|
const cols: ClosedColumn[] = []
|
|
259
293
|
for (const [columnName, field] of Object.entries(columns)) {
|
|
@@ -266,7 +300,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
266
300
|
cols.push(Object.freeze({ name: columnName, field }))
|
|
267
301
|
}
|
|
268
302
|
Object.freeze(cols)
|
|
269
|
-
const rows: ClosedRow[] = handleList.map(function lowerRow(handle) {
|
|
303
|
+
const rows: ClosedRow[] = handleList.map(function lowerRow(handle: Handles[number]) {
|
|
270
304
|
const row: Readonly<Record<string, unknown>> = axioms[handle]
|
|
271
305
|
const values = cols.map(function lowerAxiomLiteral(column) {
|
|
272
306
|
return Object.freeze(literalOf(column.field, row[column.name]))
|
|
@@ -281,7 +315,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
281
315
|
})
|
|
282
316
|
const id: ClosedIdField<Name, Handles> = Object.freeze({ kind: "u64", closed: roster })
|
|
283
317
|
|
|
284
|
-
const axiomsOut = mintAxioms<Handles, Cols>(name, handleList, cols, axioms)
|
|
318
|
+
const axiomsOut = mintAxioms<Handles[number], Cols>(name, handleList, cols, axioms)
|
|
285
319
|
const columnsOut: Cols = { ...columns }
|
|
286
320
|
Object.freeze(columnsOut)
|
|
287
321
|
const holder: { value: Closed<Name, Handles, Cols> | undefined } = { value: undefined }
|
|
@@ -299,7 +333,7 @@ function mintClosed<Name extends string, Handles extends string, Cols extends Re
|
|
|
299
333
|
const core = { name, id, data, axioms: axiomsOut, columns: columnsOut }
|
|
300
334
|
const value: ClosedCore<Name, Handles, Cols> =
|
|
301
335
|
cols.length > 0 ? Object.freeze({ ...core, where }) : Object.freeze(core)
|
|
302
|
-
if (!surfaceMinted
|
|
336
|
+
if (!surfaceMinted(value, cols)) {
|
|
303
337
|
throw errors.new(`closed relation ${name}: ergonomic-surface minting incomplete`)
|
|
304
338
|
}
|
|
305
339
|
holder.value = value
|
package/src/db.ts
CHANGED
|
@@ -367,6 +367,13 @@ interface Db<Rels extends SchemaRelations> {
|
|
|
367
367
|
write<R>(fn: (tx: WriteTx<Rels>) => SyncResult<R>): WriteOutcome<Rels, SyncResult<R>>
|
|
368
368
|
|
|
369
369
|
writeFrom<R>(witness: Witness<Rels>, fn: (tx: WriteTx<Rels>) => SyncResult<R>): WriteFromOutcome<Rels, SyncResult<R>>
|
|
370
|
+
/**
|
|
371
|
+
* blake3 over the canonical catalog enumeration — the replication
|
|
372
|
+
* equality oracle: equal digests imply identical judged content
|
|
373
|
+
* regardless of page layout or allocation history. Harness-tier
|
|
374
|
+
* (bounded sequential passes over the store), off any hot path.
|
|
375
|
+
*/
|
|
376
|
+
catalogDigest(): Uint8Array
|
|
370
377
|
/**
|
|
371
378
|
* Prepares a query value built against THIS schema (identity is the
|
|
372
379
|
* membership rule): lowers it to the engine IR, pins the plan, and
|
|
@@ -1288,6 +1295,12 @@ function openDb<Rels extends SchemaRelations>(handle: DbHandle, theory: Schema<R
|
|
|
1288
1295
|
}, fn)
|
|
1289
1296
|
}
|
|
1290
1297
|
|
|
1298
|
+
function catalogDigest(): Uint8Array {
|
|
1299
|
+
return bridged("bumbledb catalog digest", function readCatalogDigest() {
|
|
1300
|
+
return native.dbCatalogDigest(handle)
|
|
1301
|
+
})
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1291
1304
|
function prepare<Row, Params extends ParamsRecord>(q: Query<Rels, Row, Params>): Prepared<Rels, Row, Params> {
|
|
1292
1305
|
if (q.schema !== theory) {
|
|
1293
1306
|
throw errors.new(
|
|
@@ -1309,6 +1322,7 @@ function openDb<Rels extends SchemaRelations>(handle: DbHandle, theory: Schema<R
|
|
|
1309
1322
|
read,
|
|
1310
1323
|
write,
|
|
1311
1324
|
writeFrom,
|
|
1325
|
+
catalogDigest,
|
|
1312
1326
|
prepare
|
|
1313
1327
|
})
|
|
1314
1328
|
}
|
|
@@ -1668,6 +1682,7 @@ export type {
|
|
|
1668
1682
|
AbandonedArm,
|
|
1669
1683
|
Admission,
|
|
1670
1684
|
CapacityViolation,
|
|
1685
|
+
CollectionWrite,
|
|
1671
1686
|
Committed,
|
|
1672
1687
|
ContainmentViolation,
|
|
1673
1688
|
DeclaredKeyFact,
|
package/src/face.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as errors from "@superbuilders/errors"
|
|
2
2
|
import type { AnyClosed, AnySelectedClosed, PayloadField } from "#closed.ts"
|
|
3
|
-
import type { AnyField } from "#fields.ts"
|
|
3
|
+
import type { AnyField, SignatureOf } from "#fields.ts"
|
|
4
|
+
import type { Same } from "#judgment.ts"
|
|
4
5
|
import type { AnyRelation, AnySelected, FieldsShape, RelationFields, SelectionBinding } from "#relation.ts"
|
|
5
6
|
import { renderLiteralSet } from "#spec.ts"
|
|
6
7
|
|
|
@@ -46,24 +47,25 @@ type FaceFields<S extends FaceSource> = S extends AnySelected
|
|
|
46
47
|
? "id" | (keyof Row & string)
|
|
47
48
|
: never
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
]
|
|
50
|
+
/**
|
|
51
|
+
* The wire shape a face projects: the field's {@link SignatureOf} with an
|
|
52
|
+
* interval's width erased. A fixed-width interval pairs with a plain one —
|
|
53
|
+
* width is a measure label, not wire structure. Bytes width IS wire
|
|
54
|
+
* structure and stays. The roster stays the full handle vector.
|
|
55
|
+
*/
|
|
56
|
+
type ProjectedSignature<F extends AnyField> = F extends { readonly kind: "interval" }
|
|
57
|
+
? readonly [F["kind"], undefined, F extends { readonly element: infer E } ? E : undefined, undefined]
|
|
58
|
+
: SignatureOf<F>
|
|
59
59
|
|
|
60
|
-
type ShapeIn<Fields extends FieldsShape, K extends string> = K extends keyof Fields
|
|
60
|
+
type ShapeIn<Fields extends FieldsShape, K extends string> = K extends keyof Fields
|
|
61
|
+
? ProjectedSignature<Fields[K]>
|
|
62
|
+
: undefined
|
|
61
63
|
|
|
62
64
|
type ProjectedShape<S extends FaceSource, K extends string> = S extends AnySelected
|
|
63
65
|
? ShapeIn<RelationFields<S["relation"]>, K>
|
|
64
66
|
: S extends AnySelectedClosed
|
|
65
67
|
? K extends "id"
|
|
66
|
-
?
|
|
68
|
+
? ProjectedSignature<S["relation"]["id"]>
|
|
67
69
|
: ShapeIn<S["relation"]["columns"], K>
|
|
68
70
|
: S extends AnyRelation
|
|
69
71
|
? ShapeIn<RelationFields<S>, K>
|
|
@@ -72,7 +74,7 @@ type ProjectedShape<S extends FaceSource, K extends string> = S extends AnySelec
|
|
|
72
74
|
readonly columns: infer Cols extends Record<string, PayloadField>
|
|
73
75
|
}
|
|
74
76
|
? K extends "id"
|
|
75
|
-
?
|
|
77
|
+
? ProjectedSignature<Id>
|
|
76
78
|
: ShapeIn<Cols, K>
|
|
77
79
|
: undefined
|
|
78
80
|
|
|
@@ -92,11 +94,7 @@ interface FaceArityMismatch<Left, Right> {
|
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
type SameArity<A extends AnyFace, B extends AnyFace> =
|
|
95
|
-
Arity<A
|
|
96
|
-
? Arity<B> extends Arity<A>
|
|
97
|
-
? unknown
|
|
98
|
-
: FaceArityMismatch<Arity<A>, Arity<B>>
|
|
99
|
-
: FaceArityMismatch<Arity<A>, Arity<B>>
|
|
97
|
+
Same<Arity<A>, Arity<B>> extends true ? unknown : FaceArityMismatch<Arity<A>, Arity<B>>
|
|
100
98
|
|
|
101
99
|
interface FaceShapeMismatch<Left, Right> {
|
|
102
100
|
readonly "face shape mismatch — positionwise kind, width, element, and closed roster must be equal on both sides": readonly [
|
|
@@ -106,11 +104,7 @@ interface FaceShapeMismatch<Left, Right> {
|
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
type SameShapes<A extends AnyFace, B extends AnyFace> =
|
|
109
|
-
FaceShapes<A
|
|
110
|
-
? FaceShapes<B> extends FaceShapes<A>
|
|
111
|
-
? unknown
|
|
112
|
-
: FaceShapeMismatch<FaceShapes<A>, FaceShapes<B>>
|
|
113
|
-
: FaceShapeMismatch<FaceShapes<A>, FaceShapes<B>>
|
|
107
|
+
Same<FaceShapes<A>, FaceShapes<B>> extends true ? unknown : FaceShapeMismatch<FaceShapes<A>, FaceShapes<B>>
|
|
114
108
|
|
|
115
109
|
function on<S extends FaceSource, const F extends FaceFields<S>>(source: S, field: F): Face<S, readonly [F]>
|
|
116
110
|
function on<S extends FaceSource, const P extends readonly [FaceFields<S>, ...FaceFields<S>[]]>(
|
package/src/fields.ts
CHANGED
|
@@ -32,11 +32,22 @@ function span(start: bigint, end: bigint): IntervalValue {
|
|
|
32
32
|
return Object.freeze({ start, end })
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Nonempty declaration-order handle vector — the ONE roster carrier. The
|
|
37
|
+
* handle union is `Handles[number]`, the ordinal of a handle is its tuple
|
|
38
|
+
* position, and the roster size is the tuple length. An empty vocabulary
|
|
39
|
+
* is unspellable.
|
|
40
|
+
*/
|
|
41
|
+
type ClosedHandleTuple = readonly [string, ...string[]]
|
|
42
|
+
|
|
43
|
+
interface ClosedRoster<Name extends string, Handles extends ClosedHandleTuple> {
|
|
36
44
|
readonly name: Name
|
|
37
|
-
readonly handles:
|
|
45
|
+
readonly handles: Handles
|
|
38
46
|
}
|
|
39
47
|
|
|
48
|
+
/** The roster top type — what an erased carrier knows about any roster. */
|
|
49
|
+
type AnyClosedRoster = ClosedRoster<string, ClosedHandleTuple>
|
|
50
|
+
|
|
40
51
|
interface BoolField {
|
|
41
52
|
readonly kind: "bool"
|
|
42
53
|
}
|
|
@@ -73,12 +84,42 @@ interface IntervalField<
|
|
|
73
84
|
readonly width: Width
|
|
74
85
|
}
|
|
75
86
|
|
|
76
|
-
interface ClosedIdField<Name extends string
|
|
87
|
+
interface ClosedIdField<Name extends string, Handles extends ClosedHandleTuple> {
|
|
77
88
|
readonly kind: "u64"
|
|
78
|
-
readonly closed: ClosedRoster<Name,
|
|
89
|
+
readonly closed: ClosedRoster<Name, Handles>
|
|
79
90
|
}
|
|
80
91
|
|
|
81
|
-
|
|
92
|
+
/** The closed-id top type — the erased carrier's view of any closed id. */
|
|
93
|
+
type AnyClosedIdField = ClosedIdField<string, ClosedHandleTuple>
|
|
94
|
+
|
|
95
|
+
type AnyField =
|
|
96
|
+
| BoolField
|
|
97
|
+
| StrField
|
|
98
|
+
| U64Field
|
|
99
|
+
| FreshU64Field
|
|
100
|
+
| I64Field
|
|
101
|
+
| BytesField
|
|
102
|
+
| IntervalField
|
|
103
|
+
| AnyClosedIdField
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The ONE structural interpreter of a field descriptor — the positional
|
|
107
|
+
* signature every equality judgment reads (the positive join wall in
|
|
108
|
+
* `#query/scope.ts` and the face pairing wall in `#face.ts`). Two fields
|
|
109
|
+
* are one shape exactly when their signatures are the same tuple: kind,
|
|
110
|
+
* width, interval element, and the roster as name plus the handle VECTOR
|
|
111
|
+
* (order and length carry meaning; a set would forget both).
|
|
112
|
+
*/
|
|
113
|
+
type SignatureOf<F extends AnyField> = readonly [
|
|
114
|
+
F["kind"],
|
|
115
|
+
F extends { readonly width: infer W } ? W : undefined,
|
|
116
|
+
F extends { readonly element: infer E } ? E : undefined,
|
|
117
|
+
F extends {
|
|
118
|
+
readonly closed: { readonly name: infer N extends string; readonly handles: infer H extends ClosedHandleTuple }
|
|
119
|
+
}
|
|
120
|
+
? readonly [N, H]
|
|
121
|
+
: undefined
|
|
122
|
+
]
|
|
82
123
|
|
|
83
124
|
type Infer<F extends AnyField> = F extends { readonly kind: "bool" }
|
|
84
125
|
? boolean
|
|
@@ -106,13 +147,44 @@ function literalShapeError(context: string, expected: string, value: unknown): E
|
|
|
106
147
|
return errors.new(`${context}: expected ${expected}, got ${typeof value}`)
|
|
107
148
|
}
|
|
108
149
|
|
|
109
|
-
function rosterOf(field: AnyField | undefined):
|
|
150
|
+
function rosterOf(field: AnyField | undefined): AnyClosedRoster | undefined {
|
|
110
151
|
if (field !== undefined && "closed" in field) {
|
|
111
152
|
return field.closed
|
|
112
153
|
}
|
|
113
154
|
return undefined
|
|
114
155
|
}
|
|
115
156
|
|
|
157
|
+
/**
|
|
158
|
+
* The runtime twin of roster equality inside {@link SignatureOf}: same
|
|
159
|
+
* vocabulary name, same handle vector (order and length). Two absent
|
|
160
|
+
* rosters agree; a roster never agrees with a bare field.
|
|
161
|
+
*/
|
|
162
|
+
function rostersAgree(a: AnyClosedRoster | undefined, b: AnyClosedRoster | undefined): boolean {
|
|
163
|
+
if (a === undefined || b === undefined) {
|
|
164
|
+
return a === b
|
|
165
|
+
}
|
|
166
|
+
return (
|
|
167
|
+
a.name === b.name &&
|
|
168
|
+
a.handles.length === b.handles.length &&
|
|
169
|
+
a.handles.every(function sameHandle(handle, index) {
|
|
170
|
+
return handle === b.handles[index]
|
|
171
|
+
})
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The runtime twin of {@link SignatureOf} equality — the ONE spelling of
|
|
177
|
+
* "these two descriptors are one shape". Kind, width, interval element,
|
|
178
|
+
* and the roster vector must all agree.
|
|
179
|
+
*/
|
|
180
|
+
function signaturesAgree(a: AnyField, b: AnyField): boolean {
|
|
181
|
+
const widthA = "width" in a ? a.width : undefined
|
|
182
|
+
const widthB = "width" in b ? b.width : undefined
|
|
183
|
+
const elementA = "element" in a ? a.element : undefined
|
|
184
|
+
const elementB = "element" in b ? b.element : undefined
|
|
185
|
+
return a.kind === b.kind && widthA === widthB && elementA === elementB && rostersAgree(rosterOf(a), rosterOf(b))
|
|
186
|
+
}
|
|
187
|
+
|
|
116
188
|
function isIntervalValue(value: unknown): value is IntervalValue {
|
|
117
189
|
return (
|
|
118
190
|
typeof value === "object" &&
|
|
@@ -124,7 +196,7 @@ function isIntervalValue(value: unknown): value is IntervalValue {
|
|
|
124
196
|
)
|
|
125
197
|
}
|
|
126
198
|
|
|
127
|
-
function handleLiteral(closed:
|
|
199
|
+
function handleLiteral(closed: AnyClosedRoster, value: unknown): LiteralSpec {
|
|
128
200
|
if (typeof value !== "string") {
|
|
129
201
|
throw literalShapeError("selection literal", `a ${closed.name} handle name (string)`, value)
|
|
130
202
|
}
|
|
@@ -245,9 +317,12 @@ function literalOf(field: AnyField, value: unknown): LiteralSpec {
|
|
|
245
317
|
}
|
|
246
318
|
|
|
247
319
|
export type {
|
|
320
|
+
AnyClosedIdField,
|
|
321
|
+
AnyClosedRoster,
|
|
248
322
|
AnyField,
|
|
249
323
|
BoolField,
|
|
250
324
|
BytesField,
|
|
325
|
+
ClosedHandleTuple,
|
|
251
326
|
ClosedIdField,
|
|
252
327
|
ClosedRoster,
|
|
253
328
|
FreshU64Field,
|
|
@@ -255,6 +330,7 @@ export type {
|
|
|
255
330
|
Infer,
|
|
256
331
|
IntervalField,
|
|
257
332
|
IntervalValue,
|
|
333
|
+
SignatureOf,
|
|
258
334
|
StrField,
|
|
259
335
|
U64Field
|
|
260
336
|
}
|
|
@@ -269,6 +345,8 @@ export {
|
|
|
269
345
|
literalOf,
|
|
270
346
|
literalShapeError,
|
|
271
347
|
rosterOf,
|
|
348
|
+
rostersAgree,
|
|
349
|
+
signaturesAgree,
|
|
272
350
|
span,
|
|
273
351
|
str,
|
|
274
352
|
u64
|
package/src/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ export type {
|
|
|
47
47
|
AbandonedArm,
|
|
48
48
|
Admission,
|
|
49
49
|
CapacityViolation,
|
|
50
|
+
CollectionWrite,
|
|
50
51
|
Committed,
|
|
51
52
|
ContainmentViolation,
|
|
52
53
|
DeclaredKeyFact,
|
|
@@ -100,9 +101,12 @@ export type {
|
|
|
100
101
|
} from "#face.ts"
|
|
101
102
|
export { on } from "#face.ts"
|
|
102
103
|
export type {
|
|
104
|
+
AnyClosedIdField,
|
|
105
|
+
AnyClosedRoster,
|
|
103
106
|
AnyField,
|
|
104
107
|
BoolField,
|
|
105
108
|
BytesField,
|
|
109
|
+
ClosedHandleTuple,
|
|
106
110
|
ClosedIdField,
|
|
107
111
|
ClosedRoster,
|
|
108
112
|
FreshU64Field,
|
|
@@ -110,15 +114,38 @@ export type {
|
|
|
110
114
|
Infer,
|
|
111
115
|
IntervalField,
|
|
112
116
|
IntervalValue,
|
|
117
|
+
SignatureOf,
|
|
113
118
|
StrField,
|
|
114
119
|
U64Field
|
|
115
120
|
} from "#fields.ts"
|
|
116
121
|
export { bool, bytes, i64, interval, span, str, u64 } from "#fields.ts"
|
|
122
|
+
export type { Same, SameLen } from "#judgment.ts"
|
|
117
123
|
export type { ClassesOf, ClassWall, LawfulStatements, RelationClasses, SchemaClasses } from "#law.ts"
|
|
118
124
|
export { lower } from "#lower.ts"
|
|
119
125
|
export type { KeyFact } from "#marshal.ts"
|
|
126
|
+
export { factOf, rowOf } from "#marshal.ts"
|
|
120
127
|
export type {
|
|
121
128
|
FactValue,
|
|
129
|
+
LogBatch,
|
|
130
|
+
LogBatchDecodeKind,
|
|
131
|
+
LogBatchEncodeKind,
|
|
132
|
+
LogBatchHeader,
|
|
133
|
+
LogBraidComponent,
|
|
134
|
+
LogBraids,
|
|
135
|
+
LogChain,
|
|
136
|
+
LogChainEntry,
|
|
137
|
+
LogCheckpointDoc,
|
|
138
|
+
LogCheckpointHead,
|
|
139
|
+
LogCheckpointKind,
|
|
140
|
+
LogCodecHandle,
|
|
141
|
+
LogManifestDoc,
|
|
142
|
+
LogManifestKind,
|
|
143
|
+
LogOpIn,
|
|
144
|
+
LogOpKind,
|
|
145
|
+
LogOpOut,
|
|
146
|
+
LogPendingBatch,
|
|
147
|
+
LogResult,
|
|
148
|
+
LogSidecarKind,
|
|
122
149
|
ParsedQuery,
|
|
123
150
|
QueryIr,
|
|
124
151
|
SealedDescriptor,
|
|
@@ -128,7 +155,22 @@ export type {
|
|
|
128
155
|
SealedWeight,
|
|
129
156
|
StatementKindTag
|
|
130
157
|
} from "#native.ts"
|
|
131
|
-
export {
|
|
158
|
+
export {
|
|
159
|
+
internalBlake3,
|
|
160
|
+
internalDescriptor,
|
|
161
|
+
internalLogBraidsOf,
|
|
162
|
+
internalLogCodec,
|
|
163
|
+
internalLogDecodeBatch,
|
|
164
|
+
internalLogEncodeBatch,
|
|
165
|
+
internalLogParseCheckpoint,
|
|
166
|
+
internalLogParseCkptScratch,
|
|
167
|
+
internalLogParseManifest,
|
|
168
|
+
internalLogParseSidecar,
|
|
169
|
+
internalLogRenderCheckpoint,
|
|
170
|
+
internalLogRenderCkptScratch,
|
|
171
|
+
internalLogRenderManifest,
|
|
172
|
+
internalLogRenderSidecar
|
|
173
|
+
} from "#native.ts"
|
|
132
174
|
|
|
133
175
|
export type {
|
|
134
176
|
AnyCond,
|
package/src/judgment.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type-level judgment kernel. Two primitives, no imports, no runtime.
|
|
3
|
+
*
|
|
4
|
+
* {@link Same} is definitional equality by mutual extension — the ONE
|
|
5
|
+
* spelling of `A = B` at the type tier. {@link SameLen} is Peano equality
|
|
6
|
+
* on tuple lengths — zero equals zero, successor recurses on successor,
|
|
7
|
+
* everything else is refused. An open array carries no Nat (its length is
|
|
8
|
+
* `number`), so it proves nothing.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
type Same<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false
|
|
12
|
+
|
|
13
|
+
type SameLen<A extends readonly unknown[], B extends readonly unknown[]> = number extends A["length"]
|
|
14
|
+
? false
|
|
15
|
+
: number extends B["length"]
|
|
16
|
+
? false
|
|
17
|
+
: A extends readonly [unknown, ...infer ARest]
|
|
18
|
+
? B extends readonly [unknown, ...infer BRest]
|
|
19
|
+
? SameLen<ARest, BRest>
|
|
20
|
+
: false
|
|
21
|
+
: B extends readonly [unknown, ...unknown[]]
|
|
22
|
+
? false
|
|
23
|
+
: true
|
|
24
|
+
|
|
25
|
+
export type { Same, SameLen }
|