@bjornpagen/bumbledb 1.3.1 → 2.0.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 +153 -77
- package/README.md +107 -41
- package/dist/alternatives.d.ts +5 -6
- package/dist/alternatives.d.ts.map +1 -1
- package/dist/alternatives.js +5 -6
- package/dist/alternatives.js.map +1 -1
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +85 -0
- package/dist/bin.js.map +1 -0
- package/dist/capacity.d.ts +14 -17
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +7 -7
- package/dist/capacity.js.map +1 -1
- package/dist/changes.d.ts +32 -40
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +86 -104
- package/dist/changes.js.map +1 -1
- package/dist/closed.d.ts +2 -2
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +5 -5
- package/dist/closed.js.map +1 -1
- package/dist/codec.d.ts +13 -27
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +20 -21
- package/dist/codec.js.map +1 -1
- package/dist/compile.d.ts +26 -50
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +75 -64
- package/dist/compile.js.map +1 -1
- package/dist/database/database.d.ts +98 -0
- package/dist/database/database.d.ts.map +1 -0
- package/dist/database/database.js +249 -0
- package/dist/database/database.js.map +1 -0
- package/dist/database/driver.d.ts +40 -0
- package/dist/database/driver.d.ts.map +1 -0
- package/dist/database/driver.js +68 -0
- package/dist/database/driver.js.map +1 -0
- package/dist/database/fs.d.ts +12 -0
- package/dist/database/fs.d.ts.map +1 -0
- package/dist/database/fs.js +120 -0
- package/dist/database/fs.js.map +1 -0
- package/dist/database/generate.d.ts +26 -0
- package/dist/database/generate.d.ts.map +1 -0
- package/dist/database/generate.js +102 -0
- package/dist/database/generate.js.map +1 -0
- package/dist/database/hosted.d.ts +32 -0
- package/dist/database/hosted.d.ts.map +1 -0
- package/dist/database/hosted.js +44 -0
- package/dist/database/hosted.js.map +1 -0
- package/dist/database/io.d.ts +94 -0
- package/dist/database/io.d.ts.map +1 -0
- package/dist/database/io.js +35 -0
- package/dist/database/io.js.map +1 -0
- package/dist/database/mem.d.ts +26 -0
- package/dist/database/mem.d.ts.map +1 -0
- package/dist/database/mem.js +67 -0
- package/dist/database/mem.js.map +1 -0
- package/dist/database/migration.d.ts +55 -0
- package/dist/database/migration.d.ts.map +1 -0
- package/dist/database/migration.js +46 -0
- package/dist/database/migration.js.map +1 -0
- package/dist/database/s3.d.ts +36 -0
- package/dist/database/s3.d.ts.map +1 -0
- package/dist/database/s3.js +141 -0
- package/dist/database/s3.js.map +1 -0
- package/dist/db.d.ts +44 -128
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +163 -287
- package/dist/db.js.map +1 -1
- package/dist/engine.d.ts +7 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +2 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.d.ts +152 -46
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +107 -19
- package/dist/errors.js.map +1 -1
- package/dist/face.d.ts +5 -5
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +6 -6
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +4 -5
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +3 -3
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +60 -57
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -28
- package/dist/index.js.map +1 -1
- package/dist/judgment.d.ts +1 -1
- package/dist/judgment.js +1 -1
- package/dist/law.d.ts +16 -68
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +3 -3
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts +3 -3
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +35 -39
- package/dist/lower.js.map +1 -1
- package/dist/native/addon.d.ts +23 -0
- package/dist/native/addon.d.ts.map +1 -0
- package/dist/native/addon.js +15 -0
- package/dist/native/addon.js.map +1 -0
- package/dist/native/binding.d.ts +996 -0
- package/dist/native/json.d.ts +14 -0
- package/dist/native/json.d.ts.map +1 -0
- package/dist/native/json.js +73 -0
- package/dist/native/json.js.map +1 -0
- package/dist/native/load.d.ts +9 -0
- package/dist/native/load.d.ts.map +1 -0
- package/dist/native/load.js +30 -0
- package/dist/native/load.js.map +1 -0
- package/dist/native/op.d.ts +29 -0
- package/dist/native/op.d.ts.map +1 -0
- package/dist/native/op.js +50 -0
- package/dist/native/op.js.map +1 -0
- package/dist/query/atom.d.ts +13 -14
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +2 -2
- package/dist/query/atom.js.map +1 -1
- package/dist/query/compute.d.ts +4 -4
- package/dist/query/compute.d.ts.map +1 -1
- package/dist/query/compute.js +4 -4
- package/dist/query/compute.js.map +1 -1
- package/dist/query/find.d.ts +8 -8
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +1 -1
- package/dist/query/lower.d.ts +22 -17
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +230 -343
- 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 +32 -15
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +20 -28
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +7 -7
- package/dist/query/scope.js.map +1 -1
- package/dist/query/segments.d.ts +2 -2
- package/dist/query/segments.d.ts.map +1 -1
- package/dist/query/segments.js +3 -3
- package/dist/query/segments.js.map +1 -1
- package/dist/relation.d.ts +1 -1
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +4 -4
- package/dist/relation.js.map +1 -1
- package/dist/result.d.ts +15 -22
- package/dist/result.d.ts.map +1 -1
- package/dist/result.js +30 -39
- package/dist/result.js.map +1 -1
- package/dist/rows.d.ts +9 -33
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +8 -12
- package/dist/rows.js.map +1 -1
- package/dist/runtime.d.ts +17 -20
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +41 -205
- package/dist/runtime.js.map +1 -1
- package/dist/scalar.d.ts +4 -4
- package/dist/scalar.d.ts.map +1 -1
- package/dist/scalar.js +24 -8
- package/dist/scalar.js.map +1 -1
- package/dist/schema.d.ts +7 -18
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +18 -228
- package/dist/schema.js.map +1 -1
- package/dist/selection.d.ts +4 -4
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +5 -5
- package/dist/selection.js.map +1 -1
- package/dist/shape.d.ts +5 -5
- package/dist/shape.d.ts.map +1 -1
- package/dist/spec.d.ts +7 -79
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +3 -3
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +10 -10
- package/dist/statements.js.map +1 -1
- package/dist/uuid.d.ts +1 -1
- package/dist/uuid.d.ts.map +1 -1
- package/dist/uuid.js +1 -1
- package/dist/uuid.js.map +1 -1
- package/dist/values.d.ts +2 -2
- package/dist/values.d.ts.map +1 -1
- package/dist/values.js +2 -2
- package/dist/values.js.map +1 -1
- package/package.json +18 -18
- package/src/alternatives.ts +7 -8
- package/src/bin.ts +82 -0
- package/src/capacity.ts +20 -23
- package/src/changes.ts +134 -191
- package/src/closed.ts +5 -5
- package/src/codec.ts +35 -49
- package/src/compile.ts +91 -113
- package/src/database/database.ts +413 -0
- package/src/database/driver.ts +134 -0
- package/src/database/fs.ts +119 -0
- package/src/database/generate.ts +116 -0
- package/src/database/hosted.ts +102 -0
- package/src/database/io.ts +134 -0
- package/src/database/mem.ts +113 -0
- package/src/database/migration.ts +107 -0
- package/src/database/s3.ts +231 -0
- package/src/db.ts +290 -547
- package/src/engine.ts +14 -0
- package/src/errors.ts +118 -39
- package/src/face.ts +9 -9
- package/src/fields.ts +6 -7
- package/src/index.ts +92 -105
- package/src/judgment.ts +1 -1
- package/src/law.ts +18 -70
- package/src/lower.ts +61 -72
- package/src/native/addon.ts +54 -0
- package/src/native/binding.d.ts +996 -0
- package/src/native/json.ts +100 -0
- package/src/native/load.ts +31 -0
- package/src/native/op.ts +73 -0
- package/src/query/atom.ts +15 -16
- package/src/query/compute.ts +7 -7
- package/src/query/find.ts +8 -8
- package/src/query/lower.ts +270 -392
- package/src/query/run.ts +42 -21
- package/src/query/scope.ts +29 -37
- package/src/query/segments.ts +4 -4
- package/src/relation.ts +4 -4
- package/src/result.ts +53 -80
- package/src/rows.ts +18 -46
- package/src/runtime.ts +50 -277
- package/src/scalar.ts +32 -12
- package/src/schema.ts +23 -284
- package/src/selection.ts +6 -6
- package/src/shape.ts +5 -5
- package/src/spec.ts +7 -85
- package/src/statements.ts +11 -11
- package/src/uuid.ts +1 -1
- package/src/values.ts +4 -4
- package/dist/close.d.ts +0 -24
- package/dist/close.d.ts.map +0 -1
- package/dist/close.js +0 -34
- package/dist/close.js.map +0 -1
- package/dist/db-native.d.ts +0 -189
- package/dist/db-native.d.ts.map +0 -1
- package/dist/db-native.js +0 -13
- package/dist/db-native.js.map +0 -1
- package/dist/internal/log.d.ts +0 -26
- package/dist/internal/log.d.ts.map +0 -1
- package/dist/internal/log.js +0 -12
- package/dist/internal/log.js.map +0 -1
- package/dist/native.d.ts +0 -562
- package/dist/native.d.ts.map +0 -1
- package/dist/native.js +0 -123
- package/dist/native.js.map +0 -1
- package/dist/query/description.d.ts +0 -41
- package/dist/query/description.d.ts.map +0 -1
- package/dist/query/description.js +0 -311
- package/dist/query/description.js.map +0 -1
- package/dist/query/parse-ir.d.ts +0 -10
- package/dist/query/parse-ir.d.ts.map +0 -1
- package/dist/query/parse-ir.js +0 -280
- package/dist/query/parse-ir.js.map +0 -1
- package/dist/runtime-codes.d.ts +0 -2
- package/dist/runtime-codes.d.ts.map +0 -1
- package/dist/runtime-codes.js +0 -19
- package/dist/runtime-codes.js.map +0 -1
- package/dist/runtime-errors.d.ts +0 -138
- package/dist/runtime-errors.d.ts.map +0 -1
- package/dist/runtime-errors.js +0 -111
- package/dist/runtime-errors.js.map +0 -1
- package/dist/runtime-native.d.ts +0 -136
- package/dist/runtime-native.d.ts.map +0 -1
- package/dist/runtime-native.js +0 -5
- package/dist/runtime-native.js.map +0 -1
- package/dist/schema-file.d.ts +0 -7
- package/dist/schema-file.d.ts.map +0 -1
- package/dist/schema-file.js +0 -24
- package/dist/schema-file.js.map +0 -1
- package/pack-provenance.json +0 -7
- package/src/close.ts +0 -53
- package/src/db-native.ts +0 -235
- package/src/internal/log.ts +0 -46
- package/src/native.ts +0 -736
- package/src/query/description.ts +0 -424
- package/src/query/parse-ir.ts +0 -293
- package/src/runtime-codes.ts +0 -18
- package/src/runtime-errors.ts +0 -122
- package/src/runtime-native.ts +0 -181
- package/src/schema-file.ts +0 -38
package/dist/query/lower.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { membersAgree, sealedFieldsOf } from "
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
1
|
+
import { membersAgree, sealedFieldsOf } from "../closed.js";
|
|
2
|
+
import { compiledOf } from "../compile.js";
|
|
3
|
+
import { AuthoringError, internalError } from "../errors.js";
|
|
4
|
+
import { assertDeclarationOrderKey, f64 as f64Field, i64 as i64Field, isFloatIntervalValue, isIntervalValue, literalShapeError, rosterOf, rostersAgree, u64 as u64Field } from "../fields.js";
|
|
5
|
+
import { snapshotData } from "../immutable.js";
|
|
6
|
+
import { addon } from "../native/addon.js";
|
|
7
|
+
import { valueIn } from "../native/json.js";
|
|
8
|
+
import { scalarWire } from "../scalar.js";
|
|
9
|
+
import { schemaDescriptor, schemasAgree } from "../schema.js";
|
|
10
|
+
import { arrayValue, recordValue, taggedValueOf } from "../values.js";
|
|
11
|
+
import { allen, and, eq, ge, gt, le, lt, ne, not, or, pointIn } from "./atom.js";
|
|
12
|
+
import { computeFieldOf, isComputeExpr, MAX_COMPUTE_DEPTH } from "./compute.js";
|
|
13
|
+
import { count, max, mean, min, pack, sum } from "./find.js";
|
|
14
|
+
import { fieldAntiJoins, fieldJoins, headFieldJoins, importFacadeOf, importFacadeOfOwner, inferred, isImportedSource, isTerm, labelImport, makeParam, makeSetParam, renderFieldKind, term } from "./scope.js";
|
|
15
|
+
import { difference, intersection, isSegments, segmentField } from "./segments.js";
|
|
14
16
|
const termOps = Object.freeze({
|
|
15
17
|
param: makeParam,
|
|
16
18
|
inSet: makeSetParam,
|
|
@@ -384,45 +386,6 @@ function findColumnOf(name, entry) {
|
|
|
384
386
|
message: `find ${name}: not a find entry — find takes variables, aggregates or Compute expressions`
|
|
385
387
|
});
|
|
386
388
|
}
|
|
387
|
-
/**
|
|
388
|
-
* The orderable ban's pointed refusal
|
|
389
|
-
* § orderability): a closed reference is equality-and-membership only.
|
|
390
|
-
*/
|
|
391
|
-
function closedOrderError(context, position, vocabulary) {
|
|
392
|
-
return new AuthoringError({
|
|
393
|
-
message: `${context}: ${position} is a ${vocabulary} reference — declaration order is an accident, not semantics: vocabularies do not order (equality, membership, and counting remain)`
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
function isOrderOp(op) {
|
|
397
|
-
return op === "lt" || op === "le" || op === "gt" || op === "ge" || op === "pointIn";
|
|
398
|
-
}
|
|
399
|
-
function assertBound(where, bound, ref) {
|
|
400
|
-
if (!bound.has(ref)) {
|
|
401
|
-
throw new AuthoringError({
|
|
402
|
-
message: `${where}: the variable ${ref.label} is not bound by a relation atom of the rule`
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
function assertInterval(where, ref) {
|
|
407
|
-
if (ref.field.kind !== "interval") {
|
|
408
|
-
throw new AuthoringError({
|
|
409
|
-
message: `${where}: ${ref.label} is not interval-typed — the measure is defined over interval-typed variables only`
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
function assertNotClosed(where, position, ref) {
|
|
414
|
-
const roster = rosterOf(ref.field);
|
|
415
|
-
if (roster !== undefined) {
|
|
416
|
-
throw closedOrderError(where, `${position} ${ref.label}`, roster.name);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
function assertNumeric(where, position, ref) {
|
|
420
|
-
if (ref.field.kind !== "u64" && ref.field.kind !== "i64" && ref.field.kind !== "f64") {
|
|
421
|
-
throw new AuthoringError({
|
|
422
|
-
message: `${where}: ${position} ${ref.label} is ${ref.field.kind}, not numeric — a fold reads u64/i64/f64 only`
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
389
|
/**
|
|
427
390
|
* The head column's slot: a projected variable keeps its mint slot; an
|
|
428
391
|
* aggregate output is a NEW derived scalar — its descriptor follows the
|
|
@@ -457,76 +420,24 @@ function findColumnSlotOf(context, column) {
|
|
|
457
420
|
};
|
|
458
421
|
}
|
|
459
422
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
assertBound(where, bound, entry.right);
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
if (entry.kind === "var") {
|
|
469
|
-
assertBound(where, bound, entry.over);
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
if (entry.kind === "compute") {
|
|
473
|
-
// Kind agreement, closed-reference and depth walls hold at
|
|
474
|
-
// construction (#query/compute.ts); boundness is a RULE property,
|
|
475
|
-
// judged here like every other term position.
|
|
476
|
-
for (const ref of computeVarsOf(entry.expr)) {
|
|
477
|
-
assertBound(where, bound, ref);
|
|
478
|
-
}
|
|
423
|
+
/** An equality between two variables joins them, so their slots must join under the class law. */
|
|
424
|
+
function validateCond(context, cond) {
|
|
425
|
+
if (cond.kind !== "cmp") {
|
|
426
|
+
for (const child of cond.children)
|
|
427
|
+
validateCond(context, child);
|
|
479
428
|
return;
|
|
480
429
|
}
|
|
481
|
-
|
|
482
|
-
switch (agg.op) {
|
|
483
|
-
case "count":
|
|
484
|
-
return;
|
|
485
|
-
case "fold": {
|
|
486
|
-
assertBound(where, bound, agg.over);
|
|
487
|
-
assertNotClosed(where, `the ${agg.fold} input`, agg.over);
|
|
488
|
-
assertNumeric(where, `the ${agg.fold} input`, agg.over);
|
|
489
|
-
if (agg.fold === "mean" && agg.over.field.kind !== "f64") {
|
|
490
|
-
throw new AuthoringError({ message: `${where}: mean requires an f64 input; cast integers explicitly` });
|
|
491
|
-
}
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
case "pack":
|
|
495
|
-
assertBound(where, bound, agg.over);
|
|
496
|
-
assertInterval(where, agg.over);
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
function validateCond(context, bound, cond) {
|
|
501
|
-
const label = contextLabel(context);
|
|
502
|
-
if (cond.kind === "cmp") {
|
|
503
|
-
for (const side of [cond.lhs, cond.rhs]) {
|
|
504
|
-
if (side.kind === "var") {
|
|
505
|
-
assertBound(label, bound, side.ref);
|
|
506
|
-
const roster = rosterOf(side.ref.field);
|
|
507
|
-
if (isOrderOp(cond.op.kind) && roster !== undefined) {
|
|
508
|
-
throw closedOrderError(label, `the ${cond.op.kind} side ${side.ref.label}`, roster.name);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
if ((cond.op.kind === "eq" || cond.op.kind === "ne") && cond.lhs.kind === "var" && cond.rhs.kind === "var") {
|
|
513
|
-
assertBound(label, bound, cond.lhs.ref);
|
|
514
|
-
assertBound(label, bound, cond.rhs.ref);
|
|
515
|
-
const lhs = mintSlotOf(context, cond.lhs.ref);
|
|
516
|
-
const rhs = mintSlotOf(context, cond.rhs.ref);
|
|
517
|
-
if (!fieldJoins(lhs, rhs)) {
|
|
518
|
-
throw new AuthoringError({
|
|
519
|
-
message: `${label}: ${cond.op.kind}(${cond.lhs.ref.label}, ${cond.rhs.ref.label}) unifies domain-unequal fields — ${cond.lhs.ref.label} bound at ${renderFieldKind(lhs)}, ${cond.rhs.ref.label} at ${renderFieldKind(rhs)} (a var joins only class-equal slots; bare pairs only with bare)`
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
}
|
|
430
|
+
if ((cond.op.kind !== "eq" && cond.op.kind !== "ne") || cond.lhs.kind !== "var" || cond.rhs.kind !== "var")
|
|
523
431
|
return;
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
432
|
+
const lhs = mintSlotOf(context, cond.lhs.ref);
|
|
433
|
+
const rhs = mintSlotOf(context, cond.rhs.ref);
|
|
434
|
+
if (!fieldJoins(lhs, rhs)) {
|
|
435
|
+
throw new AuthoringError({
|
|
436
|
+
message: `${contextLabel(context)}: ${cond.op.kind}(${cond.lhs.ref.label}, ${cond.rhs.ref.label}) unifies domain-unequal fields — ${cond.lhs.ref.label} bound at ${renderFieldKind(lhs)}, ${cond.rhs.ref.label} at ${renderFieldKind(rhs)} (a var joins only class-equal slots; bare pairs only with bare)`
|
|
437
|
+
});
|
|
527
438
|
}
|
|
528
439
|
}
|
|
529
|
-
function validateInterior(context,
|
|
440
|
+
function validateInterior(context, item, columns) {
|
|
530
441
|
const label = contextLabel(context);
|
|
531
442
|
const headColumns = item.target.finds.length > 0 ? item.target.finds : columns;
|
|
532
443
|
const headNames = headColumns.map(function nameOf(column) {
|
|
@@ -550,11 +461,6 @@ function validateInterior(context, bound, item, columns) {
|
|
|
550
461
|
}
|
|
551
462
|
}
|
|
552
463
|
for (const binding of item.bindings) {
|
|
553
|
-
if (item.kind === "negatedInterior" && !bound.has(binding.ref)) {
|
|
554
|
-
throw new AuthoringError({
|
|
555
|
-
message: `${label}: negated interior ${item.target.name} names the variable ${binding.ref.label}, but no positive atom of the rule binds it — a negated atom binds nothing, only rejects (the safety rule)`
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
464
|
const headColumn = headColumns.find(function byName(column) {
|
|
559
465
|
return column.name === binding.key;
|
|
560
466
|
});
|
|
@@ -571,39 +477,16 @@ function validateInterior(context, bound, item, columns) {
|
|
|
571
477
|
}
|
|
572
478
|
function completeRule(context, state, rawColumns) {
|
|
573
479
|
const label = contextLabel(context);
|
|
574
|
-
if (rawColumns.length === 0) {
|
|
575
|
-
throw new AuthoringError({ message: `${label}: a find needs at least one entry` });
|
|
576
|
-
}
|
|
577
|
-
const aggregates = rawColumns.flatMap((column) => (column.entry.kind === "aggregate" ? [column.entry.agg] : []));
|
|
578
|
-
const packs = aggregates.filter((agg) => agg.op === "pack").length;
|
|
579
|
-
if (packs > 1)
|
|
580
|
-
throw new AuthoringError({ message: "a query stage can pack one interval column" });
|
|
581
|
-
if (packs !== 0 && aggregates.length !== packs)
|
|
582
|
-
throw new AuthoringError({ message: "pack intervals and compute numeric aggregates in separate query stages" });
|
|
583
|
-
if (rawColumns.some((c) => c.entry.kind === "segments") && aggregates.length !== 0)
|
|
584
|
-
throw new AuthoringError({ message: "aggregate generated segments in a following query stage" });
|
|
585
480
|
const columns = rawColumns.map(function enrichColumn(column) {
|
|
586
481
|
assertDeclarationOrderKey(`${label} find column`, column.name);
|
|
587
|
-
validateColumn(context, state.bound, column);
|
|
588
482
|
const slot = findColumnSlotOf(context, column);
|
|
589
483
|
return Object.freeze({ name: column.name, entry: column.entry, slot, closed: rosterOf(slot?.field) });
|
|
590
484
|
});
|
|
591
485
|
for (const item of state.items) {
|
|
592
|
-
if (item.kind === "
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
message: `${label}: negated ${item.atom.relation.name} atom binds the variable ${binding.term.ref.label} at position ${binding.field}, but no positive atom of the rule binds it — a negated atom binds nothing, only rejects (the safety rule)`
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
if (item.kind === "interior" || item.kind === "negatedInterior") {
|
|
602
|
-
validateInterior(context, state.bound, item, columns);
|
|
603
|
-
}
|
|
604
|
-
if (item.kind === "cond") {
|
|
605
|
-
validateCond(context, state.bound, item.cond);
|
|
606
|
-
}
|
|
486
|
+
if (item.kind === "interior" || item.kind === "negatedInterior")
|
|
487
|
+
validateInterior(context, item, columns);
|
|
488
|
+
if (item.kind === "cond")
|
|
489
|
+
validateCond(context, item.cond);
|
|
607
490
|
}
|
|
608
491
|
return Object.freeze({ items: state.items, finds: Object.freeze(columns), paramUses: state.paramUses });
|
|
609
492
|
}
|
|
@@ -693,7 +576,7 @@ function importEntryOf(context, imported) {
|
|
|
693
576
|
const data = imported.data;
|
|
694
577
|
if (data.kind === "reach") {
|
|
695
578
|
throw new AuthoringError({
|
|
696
|
-
message: `${contextLabel(context)}: a recursive query is not importable as a relation expression
|
|
579
|
+
message: `${contextLabel(context)}: a recursive query is not importable as a relation expression — declare the recursion on the consuming query`
|
|
697
580
|
});
|
|
698
581
|
}
|
|
699
582
|
const userParams = data.params.filter(function userSupplied(entry) {
|
|
@@ -808,8 +691,7 @@ function findColumns(context, entries) {
|
|
|
808
691
|
const columns = [];
|
|
809
692
|
queryRecord("query find", entries);
|
|
810
693
|
// Nonrecursive derived stages (interiors) may emit aggregate/computed
|
|
811
|
-
// outputs
|
|
812
|
-
// recursive feedback cycle stays projection-only — no aggregate,
|
|
694
|
+
// outputs; ONLY the recursive feedback cycle stays projection-only — no aggregate,
|
|
813
695
|
// arithmetic-created value or negation flows through it.
|
|
814
696
|
const recName = context.kind === "rec-base" || context.kind === "rec-arm" ? context.self.name : undefined;
|
|
815
697
|
for (const [name, entry] of Object.entries(entries)) {
|
|
@@ -874,14 +756,14 @@ function isTypedScope(scope) {
|
|
|
874
756
|
function makeQueryRuleScope(theory, env) {
|
|
875
757
|
const raw = makeRawScope({ kind: "query", classes: theory.classes, theory, ...env });
|
|
876
758
|
if (!isTypedScope(raw)) {
|
|
877
|
-
throw
|
|
759
|
+
throw internalError("query rule builder construction incomplete");
|
|
878
760
|
}
|
|
879
761
|
return raw;
|
|
880
762
|
}
|
|
881
763
|
function makeInteriorRuleScope(theory, env, self) {
|
|
882
764
|
const raw = makeRawScope({ kind: "interior", self, classes: theory.classes, theory, ...env });
|
|
883
765
|
if (!isTypedScope(raw)) {
|
|
884
|
-
throw
|
|
766
|
+
throw internalError("interior rule builder construction incomplete");
|
|
885
767
|
}
|
|
886
768
|
return raw;
|
|
887
769
|
}
|
|
@@ -902,7 +784,7 @@ function makeRecRuleScope(theory, env, self, kind) {
|
|
|
902
784
|
...env
|
|
903
785
|
});
|
|
904
786
|
if (!isTypedScope(raw)) {
|
|
905
|
-
throw
|
|
787
|
+
throw internalError("rec rule builder construction incomplete");
|
|
906
788
|
}
|
|
907
789
|
return raw;
|
|
908
790
|
}
|
|
@@ -910,22 +792,19 @@ function renderClosedSlice(closed) {
|
|
|
910
792
|
return closed === undefined ? "a bare value" : `a ${closed.name} reference`;
|
|
911
793
|
}
|
|
912
794
|
function headOperation(column) {
|
|
913
|
-
|
|
795
|
+
if (column.entry.kind !== "aggregate")
|
|
796
|
+
return undefined;
|
|
797
|
+
const agg = column.entry.agg;
|
|
798
|
+
return agg.op === "fold" ? agg.fold : agg.op;
|
|
914
799
|
}
|
|
915
800
|
function renderParamAnchor(roster) {
|
|
916
801
|
return roster === undefined ? "a non-closed position" : `a ${roster.name} reference`;
|
|
917
802
|
}
|
|
918
803
|
/**
|
|
919
|
-
* Folds every rule's param uses
|
|
920
|
-
*
|
|
921
|
-
*
|
|
922
|
-
*
|
|
923
|
-
* closedness. The orderable ban needs no registry arm: an order use always
|
|
924
|
-
* anchors its SIBLING's domain (the no-variable-side spelling is refused
|
|
925
|
-
* at the comparison constructor), so a closed-anchored param under an
|
|
926
|
-
* order op dies at the one-domain wall here — and an order use whose
|
|
927
|
-
* sibling is itself closed-bound dies at the comparison's own var-side
|
|
928
|
-
* wall first.
|
|
804
|
+
* Folds every rule's param uses, in lowering order, into the query's registry: the first use mints
|
|
805
|
+
* the dense `ParamId`, the first field-anchored use types it, and one name keeps one shape and one
|
|
806
|
+
* closedness. An order use always anchors its sibling's domain, so a closed-anchored param under an
|
|
807
|
+
* order op fails the one-domain check here.
|
|
929
808
|
*/
|
|
930
809
|
function paramRegistryOf(interiors, rec, rules) {
|
|
931
810
|
const order = [];
|
|
@@ -1089,6 +968,49 @@ function afterMainError(what) {
|
|
|
1089
968
|
message: `query: ${what} after a main rule is unwritable — declaration order is interiors, then rec, then main`
|
|
1090
969
|
});
|
|
1091
970
|
}
|
|
971
|
+
/** Names the parts of `data` an engine query diagnostic cites. */
|
|
972
|
+
function explainQuery(data, labels, diagnostic) {
|
|
973
|
+
const tables = [...data.interiors, ...(data.kind === "reach" ? [data.rec] : [])];
|
|
974
|
+
const table = diagnostic.interior === undefined ? undefined : tables[diagnostic.interior];
|
|
975
|
+
const ruleLabels = diagnostic.rule === undefined
|
|
976
|
+
? undefined
|
|
977
|
+
: (diagnostic.interior === undefined ? labels.main : labels.interiors[diagnostic.interior])?.[diagnostic.rule];
|
|
978
|
+
const finds = table?.finds ?? data.finds;
|
|
979
|
+
const cited = [
|
|
980
|
+
table === undefined ? undefined : `in ${table.name}`,
|
|
981
|
+
diagnostic.rule === undefined ? undefined : `rule ${diagnostic.rule}`,
|
|
982
|
+
diagnostic.find === undefined ? undefined : `find ${finds[diagnostic.find]?.name ?? diagnostic.find}`,
|
|
983
|
+
diagnostic.atom === undefined ? undefined : `atom ${diagnostic.atom}`,
|
|
984
|
+
diagnostic.var === undefined ? undefined : `variable ${ruleLabels?.[diagnostic.var] ?? diagnostic.var}`,
|
|
985
|
+
diagnostic.param === undefined ? undefined : `param ${data.params[diagnostic.param]?.name ?? diagnostic.param}`,
|
|
986
|
+
diagnostic.comparison === undefined ? undefined : `comparison ${diagnostic.comparison}`
|
|
987
|
+
].filter((part) => part !== undefined);
|
|
988
|
+
return cited.length === 0 ? diagnostic.message : `${diagnostic.message} (${cited.join(", ")})`;
|
|
989
|
+
}
|
|
990
|
+
/** Validates a complete query with the engine and returns its compiled handle. */
|
|
991
|
+
function validateQueryData(theory, data) {
|
|
992
|
+
const lowered = lowerQueryLabelled({ schema: theory, data });
|
|
993
|
+
const validated = addon.validateQuery(compiledOf(schemaDescriptor(theory)).handle, JSON.stringify(lowered.query));
|
|
994
|
+
switch (validated._tag) {
|
|
995
|
+
case "Valid":
|
|
996
|
+
return validated.query;
|
|
997
|
+
case "Invalid":
|
|
998
|
+
throw new AuthoringError({
|
|
999
|
+
message: `query: ${explainQuery(data, lowered.labels, validated.diagnostic)}`,
|
|
1000
|
+
diagnostic: { code: "InvalidQuery", context: validated.diagnostic.code, expected: validated.diagnostic.message }
|
|
1001
|
+
});
|
|
1002
|
+
case "Malformed":
|
|
1003
|
+
throw internalError(`validateQuery: ${validated.path}: ${validated.message}`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
const validatedQueries = new WeakMap();
|
|
1007
|
+
/** The engine's validated form of a query value `query()` built. */
|
|
1008
|
+
function queryHandleOf(query) {
|
|
1009
|
+
const handle = validatedQueries.get(query);
|
|
1010
|
+
if (handle === undefined)
|
|
1011
|
+
throw internalError("queryHandleOf: the query was not built by query()");
|
|
1012
|
+
return handle;
|
|
1013
|
+
}
|
|
1092
1014
|
function makeRawQuery(inputTheory, inputInteriors, inputRec, inputRules) {
|
|
1093
1015
|
const { theory, interiors, rec, rules } = snapshotQueryData({
|
|
1094
1016
|
theory: inputTheory,
|
|
@@ -1122,6 +1044,7 @@ function makeRawQuery(inputTheory, inputInteriors, inputRec, inputRules) {
|
|
|
1122
1044
|
finds: mergedFinds,
|
|
1123
1045
|
params
|
|
1124
1046
|
});
|
|
1047
|
+
const handle = validateQueryData(theory, data);
|
|
1125
1048
|
const value = {
|
|
1126
1049
|
get schema() {
|
|
1127
1050
|
return snapshotData(theory);
|
|
@@ -1147,6 +1070,7 @@ function makeRawQuery(inputTheory, inputInteriors, inputRec, inputRules) {
|
|
|
1147
1070
|
}
|
|
1148
1071
|
};
|
|
1149
1072
|
Object.freeze(value);
|
|
1073
|
+
validatedQueries.set(value, handle);
|
|
1150
1074
|
return value;
|
|
1151
1075
|
}
|
|
1152
1076
|
function makeQuery(theory, interiors, rec, rules) {
|
|
@@ -1317,6 +1241,9 @@ function freshVarIds() {
|
|
|
1317
1241
|
const id = assigned.size;
|
|
1318
1242
|
assigned.set(ref, id);
|
|
1319
1243
|
return id;
|
|
1244
|
+
},
|
|
1245
|
+
labels() {
|
|
1246
|
+
return [...assigned.keys()].map((ref) => ref.label);
|
|
1320
1247
|
}
|
|
1321
1248
|
};
|
|
1322
1249
|
}
|
|
@@ -1328,238 +1255,203 @@ function paramIdOf(ctx, name) {
|
|
|
1328
1255
|
return id;
|
|
1329
1256
|
}
|
|
1330
1257
|
function lowerAtom(ctx, atom, ids) {
|
|
1331
|
-
const
|
|
1332
|
-
if (!membersAgree(
|
|
1258
|
+
const relationId = ctx.relationIds.get(atom.relation.name);
|
|
1259
|
+
if (!membersAgree(ctx.theory.relations[atom.relation.name], atom.relation) || relationId === undefined) {
|
|
1333
1260
|
throw new AuthoringError({
|
|
1334
|
-
message: `query
|
|
1261
|
+
message: `query: relation ${atom.relation.name} is not the relation value schema ${ctx.theory.name} declares`
|
|
1335
1262
|
});
|
|
1336
1263
|
}
|
|
1337
|
-
const relationId = ctx.relationIds.get(atom.relation.name);
|
|
1338
|
-
if (relationId === undefined) {
|
|
1339
|
-
throw new AuthoringError({ message: `query lowering: relation ${atom.relation.name} has no ordinal` });
|
|
1340
|
-
}
|
|
1341
1264
|
const ordered = sealedFieldsOf(atom.relation);
|
|
1342
|
-
const bindings = atom.bindings.map(
|
|
1343
|
-
const
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
throw new AuthoringError({
|
|
1348
|
-
message: `query lowering: relation ${atom.relation.name} has no field ${binding.field}`
|
|
1349
|
-
});
|
|
1350
|
-
}
|
|
1351
|
-
return [ordinal, lowerBindingTerm(ctx, `${atom.relation.name}.${binding.field}`, binding, ids)];
|
|
1265
|
+
const bindings = atom.bindings.map((binding) => {
|
|
1266
|
+
const field = ordered.findIndex((candidate) => candidate.name === binding.field);
|
|
1267
|
+
if (field < 0)
|
|
1268
|
+
throw new AuthoringError({ message: `query: relation ${atom.relation.name} has no field ${binding.field}` });
|
|
1269
|
+
return { field, term: lowerBindingTerm(ctx, `${atom.relation.name}.${binding.field}`, binding, ids) };
|
|
1352
1270
|
});
|
|
1353
|
-
return { source: { kind: "
|
|
1271
|
+
return { source: { kind: "Edb", relation: relationId }, bindings };
|
|
1354
1272
|
}
|
|
1355
1273
|
function lowerBindingTerm(ctx, context, binding, ids) {
|
|
1356
1274
|
const bound = binding.term;
|
|
1357
1275
|
switch (bound.kind) {
|
|
1358
1276
|
case "var":
|
|
1359
|
-
return { kind: "
|
|
1277
|
+
return { kind: "Var", var: ids.of(bound.ref) };
|
|
1360
1278
|
case "param":
|
|
1361
|
-
return { kind: "
|
|
1279
|
+
return { kind: "Param", param: paramIdOf(ctx, bound.name) };
|
|
1362
1280
|
case "setParam":
|
|
1363
|
-
return { kind: "paramSet", param: paramIdOf(ctx, bound.name) };
|
|
1364
1281
|
case "literalSet":
|
|
1365
|
-
return { kind: "
|
|
1282
|
+
return { kind: "ParamSet", param: paramIdOf(ctx, bound.name) };
|
|
1366
1283
|
case "literal":
|
|
1367
|
-
return { kind: "
|
|
1284
|
+
return { kind: "Literal", value: valueIn(taggedLiteral(context, binding.data, bound.value)) };
|
|
1368
1285
|
}
|
|
1369
1286
|
}
|
|
1370
|
-
/**
|
|
1371
|
-
* Lowers one interior atom: named bindings placed by HEAD order, `FieldId(i)` =
|
|
1372
|
-
* head position i. Every head column of the table must be bound (a missing key
|
|
1373
|
-
* is refused pointed); the var-id assignment order is head order, so the
|
|
1374
|
-
* first-use numbering matches the name-keyed edition exactly.
|
|
1375
|
-
*/
|
|
1287
|
+
/** An interior atom binds every head column of the table, by head position. */
|
|
1376
1288
|
function lowerInteriorAtom(ctx, target, bindings, ids) {
|
|
1377
1289
|
const interior = ctx.interiorIds.get(target.name);
|
|
1378
1290
|
if (interior === undefined) {
|
|
1379
|
-
throw new AuthoringError({ message: `query
|
|
1380
|
-
}
|
|
1381
|
-
if (target.finds.length === 0) {
|
|
1382
|
-
throw new AuthoringError({ message: `query lowering: derived table ${target.name} has no head` });
|
|
1291
|
+
throw new AuthoringError({ message: `query: derived table ${target.name} was not declared on this query` });
|
|
1383
1292
|
}
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1293
|
+
return {
|
|
1294
|
+
source: { kind: "Interior", interior },
|
|
1295
|
+
bindings: target.finds.map((column, field) => {
|
|
1296
|
+
const binding = bindings.find((candidate) => candidate.key === column.name);
|
|
1297
|
+
if (binding === undefined) {
|
|
1298
|
+
throw new AuthoringError({ message: `query: interior ${target.name} omits head column ${column.name}` });
|
|
1299
|
+
}
|
|
1300
|
+
return { field, term: { kind: "Var", var: ids.of(binding.ref) } };
|
|
1301
|
+
})
|
|
1302
|
+
};
|
|
1394
1303
|
}
|
|
1395
1304
|
function lowerCmpTerm(ctx, side, sibling, ids, op) {
|
|
1396
1305
|
switch (side.kind) {
|
|
1397
1306
|
case "var":
|
|
1398
|
-
return { kind: "
|
|
1307
|
+
return { kind: "Var", var: ids.of(side.ref) };
|
|
1399
1308
|
case "param":
|
|
1400
|
-
return { kind: "
|
|
1309
|
+
return { kind: "Param", param: paramIdOf(ctx, side.name) };
|
|
1401
1310
|
case "setParam":
|
|
1402
|
-
return { kind: "
|
|
1311
|
+
return { kind: "ParamSet", param: paramIdOf(ctx, side.name) };
|
|
1403
1312
|
case "literal": {
|
|
1404
1313
|
const anchor = cmpAnchorOf(ctx, sibling);
|
|
1405
1314
|
if (anchor === undefined) {
|
|
1406
1315
|
throw new AuthoringError({
|
|
1407
|
-
message: "query
|
|
1316
|
+
message: "query: a comparison literal needs a bound-variable or anchored-param sibling to type it"
|
|
1408
1317
|
});
|
|
1409
1318
|
}
|
|
1410
|
-
return { kind: "
|
|
1319
|
+
return { kind: "Literal", value: valueIn(taggedCmpLiteral("comparison literal", anchor, side.value, op)) };
|
|
1411
1320
|
}
|
|
1412
1321
|
}
|
|
1413
1322
|
}
|
|
1414
1323
|
function cmpAnchorOf(ctx, sibling) {
|
|
1415
|
-
if (sibling.kind === "var")
|
|
1324
|
+
if (sibling.kind === "var")
|
|
1416
1325
|
return sibling.ref.field;
|
|
1417
|
-
|
|
1418
|
-
if (sibling.kind === "param" || sibling.kind === "setParam") {
|
|
1326
|
+
if (sibling.kind === "param" || sibling.kind === "setParam")
|
|
1419
1327
|
return ctx.params.get(sibling.name)?.anchor;
|
|
1420
|
-
}
|
|
1421
1328
|
return undefined;
|
|
1422
1329
|
}
|
|
1423
|
-
|
|
1424
|
-
|
|
1330
|
+
const CMP = { eq: "Eq", ne: "Ne", lt: "Lt", le: "Le", gt: "Gt", ge: "Ge", pointIn: "PointIn" };
|
|
1331
|
+
function lowerCondition(ctx, cond, ids) {
|
|
1332
|
+
if (cond.kind !== "cmp") {
|
|
1425
1333
|
return {
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
rhs: lowerCmpTerm(ctx, cmp.rhs, cmp.lhs, ids, "allen")
|
|
1334
|
+
kind: cond.op === "and" ? "And" : "Or",
|
|
1335
|
+
children: cond.children.map((child) => lowerCondition(ctx, child, ids))
|
|
1429
1336
|
};
|
|
1430
1337
|
}
|
|
1338
|
+
const kind = cond.op.kind;
|
|
1431
1339
|
return {
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
}
|
|
1437
|
-
function lowerCondition(ctx, cond, ids) {
|
|
1438
|
-
if (cond.kind === "cmp") {
|
|
1439
|
-
return { kind: "leaf", cmp: lowerComparison(ctx, cond, ids) };
|
|
1440
|
-
}
|
|
1441
|
-
return {
|
|
1442
|
-
kind: cond.op,
|
|
1443
|
-
children: cond.children.map(function lowerChild(child) {
|
|
1444
|
-
return lowerCondition(ctx, child, ids);
|
|
1445
|
-
})
|
|
1340
|
+
kind: "Leaf",
|
|
1341
|
+
op: cond.op.kind === "allen" ? { kind: "Allen", mask: cond.op.mask } : { kind: CMP[cond.op.kind] },
|
|
1342
|
+
lhs: lowerCmpTerm(ctx, cond.lhs, cond.rhs, ids, kind),
|
|
1343
|
+
rhs: lowerCmpTerm(ctx, cond.rhs, cond.lhs, ids, kind)
|
|
1446
1344
|
};
|
|
1447
1345
|
}
|
|
1448
|
-
|
|
1449
|
-
* Lowers one computed scalar node to the C05 wire (`#native.ts`'s
|
|
1450
|
-
* `ScalarExprIr`): the shared grammar arms pass through 1:1. Cached
|
|
1451
|
-
* construction depth is the bound; this walk emits wire only and does
|
|
1452
|
-
* not re-judge kinds (L14/native compile owns binding).
|
|
1453
|
-
*/
|
|
1454
|
-
function lowerComputeNode(node, ids) {
|
|
1455
|
-
if (node.depth > MAX_COMPUTE_DEPTH) {
|
|
1456
|
-
throw new AuthoringError({
|
|
1457
|
-
message: `query lowering: a compute expression is deeper than ${MAX_COMPUTE_DEPTH} nodes (the engine's scalar depth bound)`
|
|
1458
|
-
});
|
|
1459
|
-
}
|
|
1460
|
-
return lowerComputeGrammar(node, ids);
|
|
1461
|
-
}
|
|
1462
|
-
function lowerComputeGrammar(node, ids) {
|
|
1463
|
-
return scalarWire(node, (leaf) => {
|
|
1464
|
-
return ids.of(leaf.ref);
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1346
|
+
const FOLD = { sum: "Sum", mean: "Mean", min: "Min", max: "Max" };
|
|
1467
1347
|
function lowerFind(entry, ids) {
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1348
|
+
switch (entry.kind) {
|
|
1349
|
+
case "segments":
|
|
1350
|
+
return {
|
|
1351
|
+
kind: "Segments",
|
|
1352
|
+
op: entry.op === "intersection" ? "Intersection" : "Difference",
|
|
1353
|
+
left: ids.of(entry.left),
|
|
1354
|
+
right: ids.of(entry.right)
|
|
1355
|
+
};
|
|
1356
|
+
case "var":
|
|
1357
|
+
return { kind: "Var", var: ids.of(entry.over) };
|
|
1358
|
+
case "compute":
|
|
1359
|
+
if (entry.expr.depth > MAX_COMPUTE_DEPTH) {
|
|
1360
|
+
throw new AuthoringError({
|
|
1361
|
+
message: `query: a compute expression is deeper than ${MAX_COMPUTE_DEPTH} nodes`
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1364
|
+
return { kind: "Compute", expr: scalarWire(entry.expr, (leaf) => ids.of(leaf.ref)) };
|
|
1475
1365
|
}
|
|
1476
1366
|
const agg = entry.agg;
|
|
1477
1367
|
switch (agg.op) {
|
|
1478
1368
|
case "count":
|
|
1479
|
-
return { kind: "
|
|
1369
|
+
return { kind: "Count" };
|
|
1480
1370
|
case "fold":
|
|
1481
|
-
return { kind: "
|
|
1371
|
+
return { kind: "Aggregate", op: FOLD[agg.fold], over: ids.of(agg.over) };
|
|
1482
1372
|
case "pack":
|
|
1483
|
-
return { kind: "
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
function headOpOf(agg) {
|
|
1487
|
-
switch (agg.op) {
|
|
1488
|
-
case "count":
|
|
1489
|
-
return "count";
|
|
1490
|
-
case "fold":
|
|
1491
|
-
return agg.fold;
|
|
1492
|
-
case "pack":
|
|
1493
|
-
return "pack";
|
|
1373
|
+
return { kind: "Pack", over: ids.of(agg.over) };
|
|
1494
1374
|
}
|
|
1495
1375
|
}
|
|
1496
1376
|
function headTermOf(column) {
|
|
1497
1377
|
const entry = column.entry;
|
|
1498
|
-
if (entry.kind === "segments")
|
|
1499
|
-
return { kind: "
|
|
1500
|
-
if (entry.kind === "var")
|
|
1501
|
-
return { kind: "
|
|
1502
|
-
|
|
1503
|
-
if (
|
|
1504
|
-
return { kind: "
|
|
1505
|
-
|
|
1506
|
-
|
|
1378
|
+
if (entry.kind === "segments" || entry.kind === "compute")
|
|
1379
|
+
return { kind: "Compute" };
|
|
1380
|
+
if (entry.kind === "var")
|
|
1381
|
+
return { kind: "Var" };
|
|
1382
|
+
const agg = entry.agg;
|
|
1383
|
+
if (agg.op === "count")
|
|
1384
|
+
return { kind: "Aggregate", op: "Count" };
|
|
1385
|
+
if (agg.op === "pack")
|
|
1386
|
+
return { kind: "Aggregate", op: "Pack" };
|
|
1387
|
+
return { kind: "Aggregate", op: FOLD[agg.fold] };
|
|
1507
1388
|
}
|
|
1508
|
-
function lowerRule(ctx, rule) {
|
|
1389
|
+
function lowerRule(ctx, rule, labels) {
|
|
1509
1390
|
const ids = freshVarIds();
|
|
1510
1391
|
const atoms = [];
|
|
1511
1392
|
const negated = [];
|
|
1512
1393
|
const conditions = [];
|
|
1513
1394
|
for (const item of rule.items) {
|
|
1514
1395
|
switch (item.kind) {
|
|
1515
|
-
case "atom":
|
|
1396
|
+
case "atom":
|
|
1516
1397
|
atoms.push(lowerAtom(ctx, item.atom, ids));
|
|
1517
1398
|
break;
|
|
1518
|
-
|
|
1519
|
-
case "negated": {
|
|
1399
|
+
case "negated":
|
|
1520
1400
|
negated.push(lowerAtom(ctx, item.atom, ids));
|
|
1521
1401
|
break;
|
|
1522
|
-
|
|
1523
|
-
case "interior": {
|
|
1402
|
+
case "interior":
|
|
1524
1403
|
atoms.push(lowerInteriorAtom(ctx, item.target, item.bindings, ids));
|
|
1525
1404
|
break;
|
|
1526
|
-
|
|
1527
|
-
case "negatedInterior": {
|
|
1405
|
+
case "negatedInterior":
|
|
1528
1406
|
negated.push(lowerInteriorAtom(ctx, item.target, item.bindings, ids));
|
|
1529
1407
|
break;
|
|
1530
|
-
|
|
1531
|
-
case "cond": {
|
|
1408
|
+
case "cond":
|
|
1532
1409
|
conditions.push(lowerCondition(ctx, item.cond, ids));
|
|
1533
1410
|
break;
|
|
1534
|
-
}
|
|
1535
1411
|
}
|
|
1536
1412
|
}
|
|
1413
|
+
const finds = rule.finds.map((column) => lowerFind(column.entry, ids));
|
|
1414
|
+
labels?.push(ids.labels());
|
|
1415
|
+
return { finds, atoms, negated, conditions };
|
|
1416
|
+
}
|
|
1417
|
+
/** A recursive rule projects variables only and negates nothing. */
|
|
1418
|
+
function recFinds(label, rule) {
|
|
1419
|
+
if (rule.negated.length > 0)
|
|
1420
|
+
throw new AuthoringError({ message: `query ${label}: a recursive rule cannot negate` });
|
|
1421
|
+
return rule.finds.map((find) => {
|
|
1422
|
+
if (find.kind !== "Var")
|
|
1423
|
+
throw new AuthoringError({ message: `query ${label}: a recursive rule finds variables only` });
|
|
1424
|
+
return find.var;
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
/** A recursive step reads its own previous output through exactly one self-atom. */
|
|
1428
|
+
function recStep(label, rule, self) {
|
|
1429
|
+
const selfAtoms = rule.atoms.filter((atom) => atom.source.kind === "Interior" && atom.source.interior === self);
|
|
1430
|
+
const [selfAtom] = selfAtoms;
|
|
1431
|
+
if (selfAtom === undefined || selfAtoms.length > 1) {
|
|
1432
|
+
throw new AuthoringError({ message: `query ${label}: a recursive step reads the recursion exactly once` });
|
|
1433
|
+
}
|
|
1537
1434
|
return {
|
|
1538
|
-
finds:
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
negated,
|
|
1543
|
-
conditions
|
|
1435
|
+
finds: recFinds(label, rule),
|
|
1436
|
+
selfBindings: selfAtom.bindings,
|
|
1437
|
+
atoms: rule.atoms.filter((atom) => atom !== selfAtom),
|
|
1438
|
+
conditions: rule.conditions
|
|
1544
1439
|
};
|
|
1545
1440
|
}
|
|
1441
|
+
/** Lowers a query to the addon's `QueryIn`. The engine validates it; lowering judges nothing. */
|
|
1546
1442
|
function lowerQuery(q) {
|
|
1443
|
+
return lowerQueryLabelled(q).query;
|
|
1444
|
+
}
|
|
1445
|
+
function lowerQueryLabelled(q) {
|
|
1547
1446
|
const theory = q.schema;
|
|
1548
1447
|
const data = q.data;
|
|
1549
|
-
const relationIds = new Map();
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
});
|
|
1553
|
-
const interiorIds = new Map();
|
|
1554
|
-
data.interiors.forEach(function assignInteriorId(interior, index) {
|
|
1555
|
-
interiorIds.set(interior.name, index);
|
|
1556
|
-
});
|
|
1557
|
-
if (data.kind === "reach") {
|
|
1448
|
+
const relationIds = new Map(Object.keys(theory.relations).map((name, index) => [name, index]));
|
|
1449
|
+
const interiorIds = new Map(data.interiors.map((interior, index) => [interior.name, index]));
|
|
1450
|
+
if (data.kind === "reach")
|
|
1558
1451
|
interiorIds.set(data.rec.name, data.interiors.length);
|
|
1559
|
-
}
|
|
1560
1452
|
const paramIds = new Map();
|
|
1561
1453
|
const params = new Map();
|
|
1562
|
-
data.params.forEach(
|
|
1454
|
+
data.params.forEach((entry, index) => {
|
|
1563
1455
|
if (entry.anchor === undefined) {
|
|
1564
1456
|
throw new AuthoringError({
|
|
1565
1457
|
message: `query param ${entry.name} has no field-anchored use — bind it in an atom or compare it against a bound variable`
|
|
@@ -1569,36 +1461,31 @@ function lowerQuery(q) {
|
|
|
1569
1461
|
params.set(entry.name, entry);
|
|
1570
1462
|
});
|
|
1571
1463
|
const ctx = { theory, relationIds, interiorIds, paramIds, params };
|
|
1572
|
-
const
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
rules: interior.rules.map(
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
}
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
}),
|
|
1595
|
-
rec: data.rec.rec.map(function lowerRecArm(rule) {
|
|
1596
|
-
return lowerRule(ctx, rule);
|
|
1597
|
-
})
|
|
1464
|
+
const labels = { main: [], interiors: data.interiors.map(() => []) };
|
|
1465
|
+
const query = {
|
|
1466
|
+
interiors: data.interiors.map((interior, index) => ({
|
|
1467
|
+
rules: interior.rules.map((rule) => lowerRule(ctx, rule, labels.interiors[index]))
|
|
1468
|
+
})),
|
|
1469
|
+
head: data.finds.map(headTermOf),
|
|
1470
|
+
rules: data.rules.map((rule) => lowerRule(ctx, rule, labels.main))
|
|
1471
|
+
};
|
|
1472
|
+
if (data.kind === "cq")
|
|
1473
|
+
return { query, labels };
|
|
1474
|
+
const label = `recursion ${data.rec.name}`;
|
|
1475
|
+
const self = data.interiors.length;
|
|
1476
|
+
return {
|
|
1477
|
+
query: {
|
|
1478
|
+
...query,
|
|
1479
|
+
rec: {
|
|
1480
|
+
base: data.rec.base.map((rule) => {
|
|
1481
|
+
const lowered = lowerRule(ctx, rule);
|
|
1482
|
+
return { finds: recFinds(label, lowered), atoms: lowered.atoms, conditions: lowered.conditions };
|
|
1483
|
+
}),
|
|
1484
|
+
rec: data.rec.rec.map((rule) => recStep(label, lowerRule(ctx, rule), self))
|
|
1485
|
+
}
|
|
1598
1486
|
},
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
});
|
|
1487
|
+
labels
|
|
1488
|
+
};
|
|
1602
1489
|
}
|
|
1603
|
-
export { alignedHeadOf, EMPTY_RULE, lowerQuery, makeRawChain, makeRawQuery, query, taggedCmpLiteral };
|
|
1490
|
+
export { alignedHeadOf, EMPTY_RULE, lowerQuery, makeRawChain, makeRawQuery, query, queryHandleOf, taggedCmpLiteral };
|
|
1604
1491
|
//# sourceMappingURL=lower.js.map
|