@bjornpagen/bumbledb 0.19.2 → 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/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/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.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 +2 -3
- 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 +11 -2
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +16 -2
- 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.map +1 -1
- package/package.json +5 -4
- package/src/db.ts +15 -0
- package/src/index.ts +38 -1
- package/src/native.ts +320 -12
- package/src/query/atom.ts +2 -15
- package/src/query/find.ts +1 -16
- package/src/query/lower.ts +48 -29
- package/src/query/scope.ts +29 -5
- package/src/spec.ts +0 -1
- package/src/statements.ts +0 -1
package/src/query/lower.ts
CHANGED
|
@@ -61,6 +61,7 @@ import type {
|
|
|
61
61
|
import {
|
|
62
62
|
fieldAntiJoins,
|
|
63
63
|
fieldJoins,
|
|
64
|
+
headFieldJoins,
|
|
64
65
|
inferred,
|
|
65
66
|
isTerm,
|
|
66
67
|
makeParam,
|
|
@@ -85,9 +86,6 @@ interface RuleValue<Row, P extends ParamsRecord, Head extends HeadShape = undefi
|
|
|
85
86
|
|
|
86
87
|
type AnyRuleValue = RuleValue<unknown, ParamsRecord, HeadShape>
|
|
87
88
|
|
|
88
|
-
type HeadOf<T> =
|
|
89
|
-
InferredOf<T> extends { readonly head: infer H extends Readonly<Record<string, ClassedField>> } ? H : undefined
|
|
90
|
-
|
|
91
89
|
type InteriorBindingOk<V> = V extends AnyVar ? true : false
|
|
92
90
|
|
|
93
91
|
type CheckInteriorBindings<B> = {
|
|
@@ -1307,7 +1305,15 @@ interface RawQuery {
|
|
|
1307
1305
|
reach(name: string, arms: never): never
|
|
1308
1306
|
}
|
|
1309
1307
|
|
|
1310
|
-
|
|
1308
|
+
/**
|
|
1309
|
+
* Verifies every rule derives the same head and returns the MERGED head:
|
|
1310
|
+
* the meet of the rules' column slots. A head column joins class-equal
|
|
1311
|
+
* slots, and — the anti-join law's head twin — same-identity u64 wire
|
|
1312
|
+
* with at least one side bare; when the bare arm admits the pair, the
|
|
1313
|
+
* merged column's class claim demotes to bare, so a consumer joining
|
|
1314
|
+
* the head cannot inherit provenance a rule never proved.
|
|
1315
|
+
*/
|
|
1316
|
+
function alignedHeadOf(label: string, rules: readonly RuleData[]): readonly FindColumn[] {
|
|
1311
1317
|
const first = rules[0]
|
|
1312
1318
|
if (first === undefined) {
|
|
1313
1319
|
throw errors.new(`${label} needs at least one rule`)
|
|
@@ -1330,13 +1336,33 @@ function assertAlignedHeads(label: string, rules: readonly RuleData[]): void {
|
|
|
1330
1336
|
if (lead === undefined) {
|
|
1331
1337
|
return
|
|
1332
1338
|
}
|
|
1333
|
-
if (lead.slot !== undefined && column.slot !== undefined && !
|
|
1339
|
+
if (lead.slot !== undefined && column.slot !== undefined && !headFieldJoins(lead.slot, column.slot)) {
|
|
1334
1340
|
throw errors.new(
|
|
1335
|
-
`every rule of ${label} derives the same head — the head column ${lead.name} is bound at ${renderFieldKind(lead.slot)} in rule 0 but at ${renderFieldKind(column.slot)} in rule ${index} (a head column joins
|
|
1341
|
+
`every rule of ${label} derives the same head — the head column ${lead.name} is bound at ${renderFieldKind(lead.slot)} in rule 0 but at ${renderFieldKind(column.slot)} in rule ${index} (a head column joins class-equal slots; same-wire u64 admits a bare side, and the merged head is bare)`
|
|
1336
1342
|
)
|
|
1337
1343
|
}
|
|
1338
1344
|
})
|
|
1339
1345
|
})
|
|
1346
|
+
const merged = first.finds.map(function meetColumn(lead, position) {
|
|
1347
|
+
const slot = lead.slot
|
|
1348
|
+
if (slot === undefined || slot.class === undefined) {
|
|
1349
|
+
return lead
|
|
1350
|
+
}
|
|
1351
|
+
const demoted = rules.some(function bareElsewhere(rule) {
|
|
1352
|
+
const column = rule.finds[position]
|
|
1353
|
+
return column !== undefined && column.slot !== undefined && column.slot.class !== slot.class
|
|
1354
|
+
})
|
|
1355
|
+
if (!demoted) {
|
|
1356
|
+
return lead
|
|
1357
|
+
}
|
|
1358
|
+
return Object.freeze({
|
|
1359
|
+
name: lead.name,
|
|
1360
|
+
entry: lead.entry,
|
|
1361
|
+
closed: lead.closed,
|
|
1362
|
+
slot: Object.freeze({ field: slot.field, class: undefined })
|
|
1363
|
+
})
|
|
1364
|
+
})
|
|
1365
|
+
return Object.freeze(merged)
|
|
1340
1366
|
}
|
|
1341
1367
|
|
|
1342
1368
|
function afterMainError(what: string): Error {
|
|
@@ -1351,7 +1377,7 @@ function makeRawQuery(
|
|
|
1351
1377
|
rec: RecData | undefined,
|
|
1352
1378
|
rules: readonly RuleData[]
|
|
1353
1379
|
): RawQuery {
|
|
1354
|
-
|
|
1380
|
+
const mergedFinds = alignedHeadOf("a query", rules)
|
|
1355
1381
|
const first = rules[0]
|
|
1356
1382
|
if (first === undefined) {
|
|
1357
1383
|
throw errors.new("a query needs at least one rule")
|
|
@@ -1366,7 +1392,7 @@ function makeRawQuery(
|
|
|
1366
1392
|
kind: "cq" as const,
|
|
1367
1393
|
interiors: frozenInteriors,
|
|
1368
1394
|
rules: frozenRules,
|
|
1369
|
-
finds:
|
|
1395
|
+
finds: mergedFinds,
|
|
1370
1396
|
params
|
|
1371
1397
|
})
|
|
1372
1398
|
: Object.freeze({
|
|
@@ -1374,7 +1400,7 @@ function makeRawQuery(
|
|
|
1374
1400
|
interiors: frozenInteriors,
|
|
1375
1401
|
rec,
|
|
1376
1402
|
rules: frozenRules,
|
|
1377
|
-
finds:
|
|
1403
|
+
finds: mergedFinds,
|
|
1378
1404
|
params
|
|
1379
1405
|
})
|
|
1380
1406
|
const value: RawQuery = {
|
|
@@ -1416,12 +1442,8 @@ function collectInterior<Rels extends SchemaRelations, Classes extends SchemaCla
|
|
|
1416
1442
|
const rules = builds.map(function buildRule(buildOne) {
|
|
1417
1443
|
return buildOne(makeInteriorRuleScope<Rels, Classes>(theory, env, name)).rule
|
|
1418
1444
|
})
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
if (first === undefined) {
|
|
1422
|
-
throw errors.new(`query: interior ${name} needs at least one rule`)
|
|
1423
|
-
}
|
|
1424
|
-
return Object.freeze({ name, finds: first.finds, rules: Object.freeze(rules) })
|
|
1445
|
+
const mergedFinds = alignedHeadOf(`interior ${name}`, rules)
|
|
1446
|
+
return Object.freeze({ name, finds: mergedFinds, rules: Object.freeze(rules) })
|
|
1425
1447
|
}
|
|
1426
1448
|
|
|
1427
1449
|
function collectRec<Rels extends SchemaRelations, Classes extends SchemaClasses>(
|
|
@@ -1442,22 +1464,27 @@ function collectRec<Rels extends SchemaRelations, Classes extends SchemaClasses>
|
|
|
1442
1464
|
const base = baseBuilds.map(function buildBase(buildOne) {
|
|
1443
1465
|
return buildOne(makeRecRuleScope<Rels, Classes>(theory, baseEnv, handle, "rec-base")).rule
|
|
1444
1466
|
})
|
|
1445
|
-
|
|
1467
|
+
const baseFinds = alignedHeadOf(`rec ${name}`, base)
|
|
1446
1468
|
const first = base[0]
|
|
1447
1469
|
if (first === undefined) {
|
|
1448
1470
|
throw errors.new(`query: rec ${name} has no base arms`)
|
|
1449
1471
|
}
|
|
1450
|
-
const firstFind =
|
|
1472
|
+
const firstFind = baseFinds[0]
|
|
1451
1473
|
if (firstFind === undefined) {
|
|
1452
1474
|
throw errors.new(`query: rec ${name} has no head`)
|
|
1453
1475
|
}
|
|
1454
|
-
const finds: RecHead["finds"] = [firstFind, ...
|
|
1476
|
+
const finds: RecHead["finds"] = [firstFind, ...baseFinds.slice(1)]
|
|
1455
1477
|
const head: RecHead = Object.freeze({ name, finds })
|
|
1456
1478
|
const recEnv: DerivedEnv = { interiors, rec: head }
|
|
1457
1479
|
const rec = recBuilds.map(function buildRec(buildOne) {
|
|
1458
1480
|
return buildOne(makeRecRuleScope<Rels, Classes>(theory, recEnv, head, "rec-arm")).rule
|
|
1459
1481
|
})
|
|
1460
|
-
|
|
1482
|
+
const mergedAll = alignedHeadOf(`rec ${name}`, [...base, ...rec])
|
|
1483
|
+
const mergedFirst = mergedAll[0]
|
|
1484
|
+
if (mergedFirst === undefined) {
|
|
1485
|
+
throw errors.new(`query: rec ${name} has no head`)
|
|
1486
|
+
}
|
|
1487
|
+
const sealedFinds: RecHead["finds"] = [mergedFirst, ...mergedAll.slice(1)]
|
|
1461
1488
|
const firstRec = rec[0]
|
|
1462
1489
|
if (firstRec === undefined) {
|
|
1463
1490
|
throw errors.new(`query: rec ${name} has no rec arms`)
|
|
@@ -1466,7 +1493,7 @@ function collectRec<Rels extends SchemaRelations, Classes extends SchemaClasses>
|
|
|
1466
1493
|
const sealedRec: RecData["rec"] = [firstRec, ...rec.slice(1)]
|
|
1467
1494
|
const recData: RecData = Object.freeze({
|
|
1468
1495
|
name,
|
|
1469
|
-
finds,
|
|
1496
|
+
finds: sealedFinds,
|
|
1470
1497
|
base: sealedBase,
|
|
1471
1498
|
rec: sealedRec
|
|
1472
1499
|
})
|
|
@@ -1949,11 +1976,6 @@ function lowerQuery(q: AnyQuery): ParsedQuery {
|
|
|
1949
1976
|
export type {
|
|
1950
1977
|
AnyQuery,
|
|
1951
1978
|
AnyRuleValue,
|
|
1952
|
-
HeadOf,
|
|
1953
|
-
HeadShape,
|
|
1954
|
-
InteriorRuleChain,
|
|
1955
|
-
InteriorRuleScope,
|
|
1956
|
-
ParamsOf,
|
|
1957
1979
|
Query,
|
|
1958
1980
|
QueryData,
|
|
1959
1981
|
QueryParams,
|
|
@@ -1963,12 +1985,9 @@ export type {
|
|
|
1963
1985
|
QueryRuleChain,
|
|
1964
1986
|
QueryRuleScope,
|
|
1965
1987
|
QueryStart,
|
|
1966
|
-
RawChain,
|
|
1967
|
-
RawScope,
|
|
1968
1988
|
RecRuleChain,
|
|
1969
1989
|
RecRuleScope,
|
|
1970
|
-
RowOf,
|
|
1971
1990
|
RuleValue,
|
|
1972
1991
|
TermOps
|
|
1973
1992
|
}
|
|
1974
|
-
export { lowerQuery,
|
|
1993
|
+
export { lowerQuery, query, taggedCmpLiteral }
|
package/src/query/scope.ts
CHANGED
|
@@ -215,11 +215,27 @@ function closedIdAntiJoins(a: AnyField, b: AnyField): boolean {
|
|
|
215
215
|
return rosterA !== undefined && rosterB !== undefined && rosterA.handles.length === rosterB.handles.length
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
function u64BareWirePair(a: ClassedField, b: ClassedField): boolean {
|
|
219
|
+
return u64Wire(a.field) && u64Wire(b.field) && (a.class === undefined || b.class === undefined)
|
|
220
|
+
}
|
|
221
|
+
|
|
218
222
|
function fieldAntiJoins(a: ClassedField, b: ClassedField): boolean {
|
|
219
223
|
if (fieldJoins(a, b) || closedIdAntiJoins(a.field, b.field)) {
|
|
220
224
|
return true
|
|
221
225
|
}
|
|
222
|
-
return
|
|
226
|
+
return u64BareWirePair(a, b)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Union-head class safety, the anti-join law's head twin: class-equal
|
|
231
|
+
* slots, plus same-identity u64 wire when one side is bare. A head cell
|
|
232
|
+
* is a value that flows to the caller either way — the class is
|
|
233
|
+
* provenance, not wire shape — and the merged head carries the meet:
|
|
234
|
+
* a bare rule demotes the column's class claim to bare, so downstream
|
|
235
|
+
* joins cannot inherit provenance a rule never proved.
|
|
236
|
+
*/
|
|
237
|
+
function headFieldJoins(a: ClassedField, b: ClassedField): boolean {
|
|
238
|
+
return fieldJoins(a, b) || u64BareWirePair(a, b)
|
|
223
239
|
}
|
|
224
240
|
|
|
225
241
|
function renderFieldKind(slot: ClassedField): string {
|
|
@@ -252,7 +268,6 @@ interface ParamEntry {
|
|
|
252
268
|
|
|
253
269
|
export type {
|
|
254
270
|
AntiJoinOk,
|
|
255
|
-
AnyTerm,
|
|
256
271
|
AnyVar,
|
|
257
272
|
ClassedField,
|
|
258
273
|
ExactVars,
|
|
@@ -261,7 +276,6 @@ export type {
|
|
|
261
276
|
JoinOk,
|
|
262
277
|
MatchFields,
|
|
263
278
|
MatchOwner,
|
|
264
|
-
MintClassOf,
|
|
265
279
|
MintSlotOf,
|
|
266
280
|
Param,
|
|
267
281
|
ParamEntry,
|
|
@@ -269,8 +283,18 @@ export type {
|
|
|
269
283
|
ParamValueAt,
|
|
270
284
|
SetParam,
|
|
271
285
|
ShapeOf,
|
|
272
|
-
UnionToIntersection,
|
|
273
286
|
Var,
|
|
274
287
|
VarsOf
|
|
275
288
|
}
|
|
276
|
-
export {
|
|
289
|
+
export {
|
|
290
|
+
fieldAntiJoins,
|
|
291
|
+
fieldJoins,
|
|
292
|
+
headFieldJoins,
|
|
293
|
+
inferred,
|
|
294
|
+
isTerm,
|
|
295
|
+
makeParam,
|
|
296
|
+
makeSetParam,
|
|
297
|
+
renderFieldKind,
|
|
298
|
+
term,
|
|
299
|
+
v
|
|
300
|
+
}
|
package/src/spec.ts
CHANGED