@bjornpagen/bumbledb 0.19.0 → 0.19.2
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/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 +2 -1
- package/dist/index.d.ts.map +1 -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/query/atom.d.ts +10 -6
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +4 -4
- package/dist/query/lower.js.map +1 -1
- package/dist/query/scope.d.ts +38 -31
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +17 -13
- package/dist/query/scope.js.map +1 -1
- package/dist/statements.js +2 -2
- package/dist/statements.js.map +1 -1
- package/package.json +3 -3
- package/src/closed.ts +85 -51
- package/src/face.ts +18 -24
- package/src/fields.ts +85 -7
- package/src/index.ts +5 -0
- package/src/judgment.ts +25 -0
- package/src/law.ts +2 -1
- package/src/marshal.ts +3 -3
- package/src/query/atom.ts +6 -5
- package/src/query/lower.ts +17 -7
- package/src/query/scope.ts +79 -47
- package/src/statements.ts +3 -3
package/src/query/lower.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as errors from "@superbuilders/errors"
|
|
2
2
|
import { sealedFieldsOf } from "#closed.ts"
|
|
3
|
-
import type {
|
|
3
|
+
import type { AnyClosedRoster, AnyField } from "#fields.ts"
|
|
4
4
|
import { assertDeclarationOrderKey, isIntervalValue, literalShapeError, rosterOf } from "#fields.ts"
|
|
5
5
|
import type { ClassRecordOf, SchemaClasses } from "#law.ts"
|
|
6
6
|
import type {
|
|
@@ -58,7 +58,16 @@ import type {
|
|
|
58
58
|
ShapeOf,
|
|
59
59
|
VarsOf
|
|
60
60
|
} from "#query/scope.ts"
|
|
61
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
fieldAntiJoins,
|
|
63
|
+
fieldJoins,
|
|
64
|
+
inferred,
|
|
65
|
+
isTerm,
|
|
66
|
+
makeParam,
|
|
67
|
+
makeSetParam,
|
|
68
|
+
renderFieldKind,
|
|
69
|
+
term
|
|
70
|
+
} from "#query/scope.ts"
|
|
62
71
|
import type { AnySchema, Schema, SchemaRelations } from "#schema.ts"
|
|
63
72
|
|
|
64
73
|
type QueryRelation<Rels extends SchemaRelations> = Extract<Rels[keyof Rels], MatchOwner>
|
|
@@ -469,7 +478,8 @@ function resolveBindings(
|
|
|
469
478
|
context: ChainContext,
|
|
470
479
|
label: string,
|
|
471
480
|
relation: MatchOwner,
|
|
472
|
-
bindings: Readonly<Record<string, unknown
|
|
481
|
+
bindings: Readonly<Record<string, unknown>>,
|
|
482
|
+
joins: (a: ClassedField, b: ClassedField) => boolean = fieldJoins
|
|
473
483
|
): ResolvedBindings {
|
|
474
484
|
const entries: BindingEntry[] = []
|
|
475
485
|
const vars: AnyVar[] = []
|
|
@@ -494,7 +504,7 @@ function resolveBindings(
|
|
|
494
504
|
const ref = value
|
|
495
505
|
const mint = mintSlotOf(context, ref)
|
|
496
506
|
const positionSlot: ClassedField = { field: declared.field, class: fieldClass }
|
|
497
|
-
if (!
|
|
507
|
+
if (!joins(mint, positionSlot)) {
|
|
498
508
|
throw errors.new(
|
|
499
509
|
`${label}: the variable ${ref.label} joins domain-unequal fields — minted at ${renderFieldKind(mint)}, reused at ${renderFieldKind(positionSlot)} (a var joins only class-equal slots; bare pairs only with bare)`
|
|
500
510
|
)
|
|
@@ -648,7 +658,7 @@ function advanceWhere(context: ChainContext, state: RuleBuildState, cond: AnyCon
|
|
|
648
658
|
return value !== undefined
|
|
649
659
|
})
|
|
650
660
|
)
|
|
651
|
-
const resolved = resolveBindings(context, `negated relation ${relation.name}`, relation, bindings)
|
|
661
|
+
const resolved = resolveBindings(context, `negated relation ${relation.name}`, relation, bindings, fieldAntiJoins)
|
|
652
662
|
return Object.freeze({
|
|
653
663
|
items: Object.freeze([...state.items, Object.freeze({ kind: "negated" as const, atom: resolved.atom })]),
|
|
654
664
|
bound: state.bound,
|
|
@@ -1161,7 +1171,7 @@ function makeRecRuleScope<Rels extends SchemaRelations, Classes extends SchemaCl
|
|
|
1161
1171
|
return raw
|
|
1162
1172
|
}
|
|
1163
1173
|
|
|
1164
|
-
function renderClosedSlice(closed:
|
|
1174
|
+
function renderClosedSlice(closed: AnyClosedRoster | undefined): string {
|
|
1165
1175
|
return closed === undefined ? "a bare value" : `a ${closed.name} reference`
|
|
1166
1176
|
}
|
|
1167
1177
|
|
|
@@ -1177,7 +1187,7 @@ function headSignature(column: FindColumn): string {
|
|
|
1177
1187
|
return `${column.name}:${agg.op}`
|
|
1178
1188
|
}
|
|
1179
1189
|
|
|
1180
|
-
function renderParamAnchor(roster:
|
|
1190
|
+
function renderParamAnchor(roster: AnyClosedRoster | undefined): string {
|
|
1181
1191
|
return roster === undefined ? "a non-closed position" : `a ${roster.name} reference`
|
|
1182
1192
|
}
|
|
1183
1193
|
|
package/src/query/scope.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as errors from "@superbuilders/errors"
|
|
2
2
|
import type { AnyClosed } from "#closed.ts"
|
|
3
3
|
import { sealedFieldsOf } from "#closed.ts"
|
|
4
|
-
import type { AnyField, Infer } from "#fields.ts"
|
|
5
|
-
import { rosterOf } from "#fields.ts"
|
|
4
|
+
import type { AnyField, Infer, SignatureOf } from "#fields.ts"
|
|
5
|
+
import { rosterOf, signaturesAgree } from "#fields.ts"
|
|
6
|
+
import type { Same, SameLen } from "#judgment.ts"
|
|
6
7
|
import type { ClassLookup, ClassRecordOf, SchemaClasses } from "#law.ts"
|
|
7
8
|
import type { QueryParam } from "#native.ts"
|
|
8
9
|
import type { AnyRelation, RelationFields } from "#relation.ts"
|
|
@@ -19,7 +20,7 @@ type MatchFields<R extends MatchOwner> = R extends AnyClosed
|
|
|
19
20
|
? RelationFields<R>
|
|
20
21
|
: never
|
|
21
22
|
|
|
22
|
-
interface Var<F extends AnyField
|
|
23
|
+
interface Var<F extends AnyField, RN extends string, K extends string> {
|
|
23
24
|
readonly [term]: "var"
|
|
24
25
|
readonly owner: MatchOwner & { readonly name: RN }
|
|
25
26
|
readonly column: K
|
|
@@ -27,19 +28,19 @@ interface Var<F extends AnyField = AnyField, RN extends string = string, K exten
|
|
|
27
28
|
readonly label: string
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
type AnyVar = Var
|
|
31
|
+
type AnyVar = Var<AnyField, string, string>
|
|
31
32
|
|
|
32
|
-
interface Param<Name extends string
|
|
33
|
+
interface Param<Name extends string> {
|
|
33
34
|
readonly [term]: "param"
|
|
34
35
|
readonly name: Name
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
interface SetParam<Name extends string
|
|
38
|
+
interface SetParam<Name extends string> {
|
|
38
39
|
readonly [term]: "setParam"
|
|
39
40
|
readonly name: Name
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
type AnyTerm =
|
|
43
|
+
type AnyTerm = AnyVar | Param<string> | SetParam<string>
|
|
43
44
|
|
|
44
45
|
function isTerm(value: unknown): value is AnyTerm {
|
|
45
46
|
return typeof value === "object" && value !== null && term in value
|
|
@@ -147,48 +148,78 @@ type UnionToIntersection<U> = (U extends unknown ? (member: U) => void : never)
|
|
|
147
148
|
|
|
148
149
|
type ShapeOf<U> = [U] extends [never] ? Record<never, never> : Flatten<UnionToIntersection<U>>
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
WidthOf<A["field"]>,
|
|
164
|
-
ElementOf<A["field"]>,
|
|
165
|
-
RosterOf<A["field"]>
|
|
166
|
-
] extends [B["field"]["kind"], B["class"], WidthOf<B["field"]>, ElementOf<B["field"]>, RosterOf<B["field"]>]
|
|
167
|
-
? [B["field"]["kind"], B["class"], WidthOf<B["field"]>, ElementOf<B["field"]>, RosterOf<B["field"]>] extends [
|
|
168
|
-
A["field"]["kind"],
|
|
169
|
-
A["class"],
|
|
170
|
-
WidthOf<A["field"]>,
|
|
171
|
-
ElementOf<A["field"]>,
|
|
172
|
-
RosterOf<A["field"]>
|
|
173
|
-
]
|
|
174
|
-
? true
|
|
175
|
-
: false
|
|
151
|
+
/**
|
|
152
|
+
* A slot's identity for the positive-join judgment: the field's structural
|
|
153
|
+
* signature ({@link SignatureOf} — the ONE interpreter, shared with the
|
|
154
|
+
* face pairing wall) plus the slot's law class.
|
|
155
|
+
*/
|
|
156
|
+
type SlotSignature<S extends ClassedField> = readonly [SignatureOf<S["field"]>, S["class"]]
|
|
157
|
+
|
|
158
|
+
type JoinOk<A extends ClassedField, B extends ClassedField> = Same<SlotSignature<A>, SlotSignature<B>>
|
|
159
|
+
|
|
160
|
+
type U64Wire<F extends AnyField> = F extends { readonly kind: "u64" }
|
|
161
|
+
? F extends { readonly closed: unknown }
|
|
162
|
+
? false
|
|
163
|
+
: true
|
|
176
164
|
: false
|
|
177
165
|
|
|
166
|
+
type ClosedHandles<F extends AnyField> = F extends {
|
|
167
|
+
readonly closed: { readonly handles: infer H extends readonly string[] }
|
|
168
|
+
}
|
|
169
|
+
? H
|
|
170
|
+
: never
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Two closed ids anti-join when their handle vectors carry the same Peano
|
|
174
|
+
* length ({@link SameLen}: zero equals zero, successor recurses on
|
|
175
|
+
* successor). A bare field has no vector and proves nothing.
|
|
176
|
+
*/
|
|
177
|
+
type ClosedIdOk<A extends AnyField, B extends AnyField> = [ClosedHandles<A>] extends [never]
|
|
178
|
+
? false
|
|
179
|
+
: [ClosedHandles<B>] extends [never]
|
|
180
|
+
? false
|
|
181
|
+
: SameLen<ClosedHandles<A>, ClosedHandles<B>>
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Anti-join class safety: class-equal slots, plus same-identity u64
|
|
185
|
+
* (fresh mint, foreign-key copy, or bare u64) when one side is bare,
|
|
186
|
+
* plus two closed-id fields whose handle tuples have the same length.
|
|
187
|
+
* Two distinct generators stay refused.
|
|
188
|
+
*/
|
|
189
|
+
type AntiJoinOk<A extends ClassedField, B extends ClassedField> =
|
|
190
|
+
JoinOk<A, B> extends true
|
|
191
|
+
? true
|
|
192
|
+
: ClosedIdOk<A["field"], B["field"]> extends true
|
|
193
|
+
? true
|
|
194
|
+
: U64Wire<A["field"]> extends true
|
|
195
|
+
? U64Wire<B["field"]> extends true
|
|
196
|
+
? [A["class"]] extends [undefined]
|
|
197
|
+
? true
|
|
198
|
+
: [B["class"]] extends [undefined]
|
|
199
|
+
? true
|
|
200
|
+
: false
|
|
201
|
+
: false
|
|
202
|
+
: false
|
|
203
|
+
|
|
178
204
|
function fieldJoins(a: ClassedField, b: ClassedField): boolean {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
205
|
+
return a.class === b.class && signaturesAgree(a.field, b.field)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function u64Wire(field: AnyField): boolean {
|
|
209
|
+
return field.kind === "u64" && rosterOf(field) === undefined
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function closedIdAntiJoins(a: AnyField, b: AnyField): boolean {
|
|
213
|
+
const rosterA = rosterOf(a)
|
|
214
|
+
const rosterB = rosterOf(b)
|
|
215
|
+
return rosterA !== undefined && rosterB !== undefined && rosterA.handles.length === rosterB.handles.length
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function fieldAntiJoins(a: ClassedField, b: ClassedField): boolean {
|
|
219
|
+
if (fieldJoins(a, b) || closedIdAntiJoins(a.field, b.field)) {
|
|
220
|
+
return true
|
|
221
|
+
}
|
|
222
|
+
return u64Wire(a.field) && u64Wire(b.field) && (a.class === undefined || b.class === undefined)
|
|
192
223
|
}
|
|
193
224
|
|
|
194
225
|
function renderFieldKind(slot: ClassedField): string {
|
|
@@ -220,6 +251,7 @@ interface ParamEntry {
|
|
|
220
251
|
}
|
|
221
252
|
|
|
222
253
|
export type {
|
|
254
|
+
AntiJoinOk,
|
|
223
255
|
AnyTerm,
|
|
224
256
|
AnyVar,
|
|
225
257
|
ClassedField,
|
|
@@ -241,4 +273,4 @@ export type {
|
|
|
241
273
|
Var,
|
|
242
274
|
VarsOf
|
|
243
275
|
}
|
|
244
|
-
export { fieldJoins, inferred, isTerm, makeParam, makeSetParam, renderFieldKind, term, v }
|
|
276
|
+
export { fieldAntiJoins, fieldJoins, inferred, isTerm, makeParam, makeSetParam, renderFieldKind, term, v }
|
package/src/statements.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
} from "#capacity.ts"
|
|
13
13
|
import { isClosedMember, sealedFieldOf } from "#closed.ts"
|
|
14
14
|
import { type AnyFace, type FaceData, renderFace, type SameArity, type SameShapes } from "#face.ts"
|
|
15
|
-
import { type
|
|
15
|
+
import { type AnyClosedRoster, rosterOf, rostersAgree } from "#fields.ts"
|
|
16
16
|
import type { AnyRelation, RelationFields } from "#relation.ts"
|
|
17
17
|
import { type CapacityWindowSpec, renderCapacityWindow, renderWeight, type WeightSpec } from "#spec.ts"
|
|
18
18
|
|
|
@@ -67,7 +67,7 @@ interface KeyStatement<R extends AnyRelation, Projection extends readonly string
|
|
|
67
67
|
readonly data: KeyData<R, Projection>
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function renderRosterSide(roster:
|
|
70
|
+
function renderRosterSide(roster: AnyClosedRoster | undefined): string {
|
|
71
71
|
return roster === undefined ? "a bare column" : `a ${roster.name} reference`
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -96,7 +96,7 @@ function assertRosterAgreement(source: FaceData, target: FaceData, statement: St
|
|
|
96
96
|
}
|
|
97
97
|
const sourceRoster = rosterOf(sealedFieldOf(source.owner, fieldName))
|
|
98
98
|
const targetRoster = rosterOf(sealedFieldOf(target.owner, targetField))
|
|
99
|
-
if (sourceRoster
|
|
99
|
+
if (!rostersAgree(sourceRoster, targetRoster)) {
|
|
100
100
|
throw errors.new(
|
|
101
101
|
`${source.owner.name}.${fieldName} is ${renderRosterSide(sourceRoster)} but ${target.owner.name}.${targetField} is ${renderRosterSide(targetRoster)} — closedness rides the descriptor: a closed reference is spelled with the vocabulary's own id descriptor (one meaning, one spelling), so faces pair closed-with-closed through one roster or bare-with-bare, never across — ${renderStatement(statement)}`
|
|
102
102
|
)
|