@bjornpagen/bumbledb 0.1.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/LICENSE +12 -0
- package/README.md +84 -0
- package/dist/brand.d.ts +59 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +47 -0
- package/dist/brand.js.map +1 -0
- package/dist/closed.d.ts +97 -0
- package/dist/closed.d.ts.map +1 -0
- package/dist/closed.js +107 -0
- package/dist/closed.js.map +1 -0
- package/dist/count.d.ts +55 -0
- package/dist/count.d.ts.map +1 -0
- package/dist/count.js +92 -0
- package/dist/count.js.map +1 -0
- package/dist/db.d.ts +341 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +1016 -0
- package/dist/db.js.map +1 -0
- package/dist/exhume.d.ts +130 -0
- package/dist/exhume.d.ts.map +1 -0
- package/dist/exhume.js +145 -0
- package/dist/exhume.js.map +1 -0
- package/dist/face.d.ts +91 -0
- package/dist/face.d.ts.map +1 -0
- package/dist/face.js +69 -0
- package/dist/face.js.map +1 -0
- package/dist/fields.d.ts +187 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +204 -0
- package/dist/fields.js.map +1 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/lower.d.ts +34 -0
- package/dist/lower.d.ts.map +1 -0
- package/dist/lower.js +105 -0
- package/dist/lower.js.map +1 -0
- package/dist/marshal.d.ts +79 -0
- package/dist/marshal.d.ts.map +1 -0
- package/dist/marshal.js +167 -0
- package/dist/marshal.js.map +1 -0
- package/dist/native.d.ts +532 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +64 -0
- package/dist/native.js.map +1 -0
- package/dist/query/atom.d.ts +285 -0
- package/dist/query/atom.d.ts.map +1 -0
- package/dist/query/atom.js +281 -0
- package/dist/query/atom.js.map +1 -0
- package/dist/query/lower.d.ts +145 -0
- package/dist/query/lower.d.ts.map +1 -0
- package/dist/query/lower.js +604 -0
- package/dist/query/lower.js.map +1 -0
- package/dist/query/predicate.d.ts +101 -0
- package/dist/query/predicate.d.ts.map +1 -0
- package/dist/query/predicate.js +85 -0
- package/dist/query/predicate.js.map +1 -0
- package/dist/query/run.d.ts +30 -0
- package/dist/query/run.d.ts.map +1 -0
- package/dist/query/run.js +94 -0
- package/dist/query/run.js.map +1 -0
- package/dist/query/scope.d.ts +168 -0
- package/dist/query/scope.d.ts.map +1 -0
- package/dist/query/scope.js +134 -0
- package/dist/query/scope.js.map +1 -0
- package/dist/query/select.d.ts +106 -0
- package/dist/query/select.d.ts.map +1 -0
- package/dist/query/select.js +69 -0
- package/dist/query/select.js.map +1 -0
- package/dist/relation.d.ts +120 -0
- package/dist/relation.d.ts.map +1 -0
- package/dist/relation.js +108 -0
- package/dist/relation.js.map +1 -0
- package/dist/schema.d.ts +50 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +235 -0
- package/dist/schema.js.map +1 -0
- package/dist/spec.d.ts +218 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/spec.js +154 -0
- package/dist/spec.js.map +1 -0
- package/dist/statements.d.ts +91 -0
- package/dist/statements.d.ts.map +1 -0
- package/dist/statements.js +101 -0
- package/dist/statements.js.map +1 -0
- package/package.json +66 -0
- package/src/brand.ts +82 -0
- package/src/closed.ts +228 -0
- package/src/count.ts +117 -0
- package/src/db.ts +1519 -0
- package/src/exhume.ts +243 -0
- package/src/face.ts +161 -0
- package/src/fields.ts +385 -0
- package/src/index.ts +185 -0
- package/src/lower.ts +118 -0
- package/src/marshal.ts +220 -0
- package/src/native.ts +576 -0
- package/src/query/atom.ts +556 -0
- package/src/query/lower.ts +855 -0
- package/src/query/predicate.ts +195 -0
- package/src/query/run.ts +106 -0
- package/src/query/scope.ts +301 -0
- package/src/query/select.ts +140 -0
- package/src/relation.ts +252 -0
- package/src/schema.ts +297 -0
- package/src/spec.ts +325 -0
- package/src/statements.ts +148 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency statements as typed values (`docs/architecture/30-dependencies.md`
|
|
3
|
+
* owns the semantics; `docs/architecture/70-api.md` the surface): the FD key
|
|
4
|
+
* form, conditional containment, the bidirectional `==` abbreviation, and
|
|
5
|
+
* the cardinality window. A statement value is opaque and inert — no
|
|
6
|
+
* methods, no fluent continuation: a fact about the theory, not a builder.
|
|
7
|
+
*/
|
|
8
|
+
import { phantom } from "#brand.ts";
|
|
9
|
+
import type { Count } from "#count.ts";
|
|
10
|
+
import { type AnyFace, type FaceData, type SameArity } from "#face.ts";
|
|
11
|
+
import type { AnyRelation, RelationFields } from "#relation.ts";
|
|
12
|
+
import { type WindowSpec } from "#spec.ts";
|
|
13
|
+
/** One statement's runtime description, tagged by form. */
|
|
14
|
+
type StatementData = {
|
|
15
|
+
readonly kind: "key";
|
|
16
|
+
readonly owner: AnyRelation;
|
|
17
|
+
readonly projection: readonly string[];
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "containment";
|
|
20
|
+
readonly source: FaceData;
|
|
21
|
+
readonly target: FaceData;
|
|
22
|
+
readonly bidirectional: boolean;
|
|
23
|
+
} | {
|
|
24
|
+
readonly kind: "window";
|
|
25
|
+
readonly target: FaceData;
|
|
26
|
+
readonly window: WindowSpec;
|
|
27
|
+
readonly source: FaceData;
|
|
28
|
+
};
|
|
29
|
+
/** An opaque statement value — what `schema()` assembles into a theory. */
|
|
30
|
+
interface Statement {
|
|
31
|
+
readonly data: StatementData;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A `key()` statement as a TYPED value: the statement plus a phantom
|
|
35
|
+
* carrying its owner and projection tuple — what the key-statement-selected
|
|
36
|
+
* `get(relation, keyStatement, key)` overload types its key object by
|
|
37
|
+
* (`docs/architecture/70-api.md` § the freeze, the multi-key typed get).
|
|
38
|
+
* Structurally still a plain {@link Statement}; the phantom is never present
|
|
39
|
+
* at runtime.
|
|
40
|
+
*/
|
|
41
|
+
interface KeyStatement<R extends AnyRelation, Projection extends readonly string[]> extends Statement {
|
|
42
|
+
readonly [phantom]?: {
|
|
43
|
+
readonly owner: R;
|
|
44
|
+
readonly projection: Projection;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* `R(X) -> R` — the FD key form, composite keys as tuples. No selection
|
|
49
|
+
* parameter exists (the FD-with-selection shape is unrepresentable, as in
|
|
50
|
+
* the grammar), and only ordinary relations are accepted: a closed
|
|
51
|
+
* relation's key `R(id) -> R` is materialized by the engine, so an
|
|
52
|
+
* explicit one would only ever be a duplicate. The projection tuple is
|
|
53
|
+
* carried in the returned value's type ({@link KeyStatement}), so keyed
|
|
54
|
+
* point reads through THIS statement are typed field-for-field.
|
|
55
|
+
*/
|
|
56
|
+
declare function key<R extends AnyRelation, const Projection extends readonly [keyof RelationFields<R> & string, ...(keyof RelationFields<R> & string)[]]>(relation: R, fields: Projection): KeyStatement<R, Projection>;
|
|
57
|
+
/**
|
|
58
|
+
* `A(X|φ) <= B(Y|ψ)` — conditional inclusion, source left. The target
|
|
59
|
+
* side must resolve a declared key of B — DELIBERATELY judged by the
|
|
60
|
+
* engine at `Db.create`/`Db.open` (`SchemaError`), never re-checked here.
|
|
61
|
+
* Arity mismatch between the two faces is a type error ({@link SameArity}).
|
|
62
|
+
*/
|
|
63
|
+
declare function contained<A extends AnyFace, B extends AnyFace>(source: A, target: B & SameArity<A, B>): Statement;
|
|
64
|
+
/**
|
|
65
|
+
* `A(X|φ) == B(Y|ψ)` — the bidirectional abbreviation, one utterance. It
|
|
66
|
+
* lowers to the two adjacent containments in the `A <= B` first order
|
|
67
|
+
* (macro parity) and renders as `==` once, in the written orientation.
|
|
68
|
+
*/
|
|
69
|
+
declare function mirrors<A extends AnyFace, B extends AnyFace>(source: A, target: B & SameArity<A, B>): Statement;
|
|
70
|
+
/**
|
|
71
|
+
* `B(Y|ψ) <={window} A(X|φ)` — the cardinality window. READ CAREFULLY: the
|
|
72
|
+
* LEFT face is the window's TARGET, the per-group parent (B-family,
|
|
73
|
+
* target-left — macro parity), and the RIGHT face is the counted source.
|
|
74
|
+
* `window(on(Holder, "id"), atMost(3n), on(Account, "holder"))` says: each
|
|
75
|
+
* Holder id groups at most three Account rows by holder.
|
|
76
|
+
*/
|
|
77
|
+
declare function window<B extends AnyFace, A extends AnyFace>(target: B, count: Count, source: A & SameArity<B, A>): Statement;
|
|
78
|
+
/**
|
|
79
|
+
* Renders one statement in the CANONICAL macro spelling
|
|
80
|
+
* (`docs/architecture/70-api.md`; the engine's `schema/render.rs` emits the
|
|
81
|
+
* same shapes for violations) — `Account(id) -> Account`,
|
|
82
|
+
* `Account(holder) <= Holder(id)`,
|
|
83
|
+
* `Account(id | kind == Savings) == SavingsTerms(account)`,
|
|
84
|
+
* `Holder(id) <={0..3} Account(holder)` — so TS-side errors and
|
|
85
|
+
* engine-side diagnostics read identically. A renderer, never a parser:
|
|
86
|
+
* strings are output-only.
|
|
87
|
+
*/
|
|
88
|
+
declare function renderStatement(statement: Statement): string;
|
|
89
|
+
export type { KeyStatement, Statement, StatementData };
|
|
90
|
+
export { contained, key, mirrors, renderStatement, window };
|
|
91
|
+
//# sourceMappingURL=statements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../src/statements.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency statements as typed values (`docs/architecture/30-dependencies.md`
|
|
3
|
+
* owns the semantics; `docs/architecture/70-api.md` the surface): the FD key
|
|
4
|
+
* form, conditional containment, the bidirectional `==` abbreviation, and
|
|
5
|
+
* the cardinality window. A statement value is opaque and inert — no
|
|
6
|
+
* methods, no fluent continuation: a fact about the theory, not a builder.
|
|
7
|
+
*/
|
|
8
|
+
import * as errors from "@superbuilders/errors";
|
|
9
|
+
import { phantom } from "#brand.ts";
|
|
10
|
+
import { renderFace } from "#face.ts";
|
|
11
|
+
import { renderWindow } from "#spec.ts";
|
|
12
|
+
/**
|
|
13
|
+
* `R(X) -> R` — the FD key form, composite keys as tuples. No selection
|
|
14
|
+
* parameter exists (the FD-with-selection shape is unrepresentable, as in
|
|
15
|
+
* the grammar), and only ordinary relations are accepted: a closed
|
|
16
|
+
* relation's key `R(id) -> R` is materialized by the engine, so an
|
|
17
|
+
* explicit one would only ever be a duplicate. The projection tuple is
|
|
18
|
+
* carried in the returned value's type ({@link KeyStatement}), so keyed
|
|
19
|
+
* point reads through THIS statement are typed field-for-field.
|
|
20
|
+
*/
|
|
21
|
+
function key(relation, fields) {
|
|
22
|
+
if (!("fields" in relation.data)) {
|
|
23
|
+
throw errors.new(`key(${relation.name}, ...): closedness already materializes ${relation.name}(id) -> ${relation.name} — an explicit key on a closed relation is rejected as a duplicate`);
|
|
24
|
+
}
|
|
25
|
+
const data = Object.freeze({
|
|
26
|
+
kind: "key",
|
|
27
|
+
owner: relation,
|
|
28
|
+
projection: Object.freeze([...fields])
|
|
29
|
+
});
|
|
30
|
+
return Object.freeze({ data });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* `A(X|φ) <= B(Y|ψ)` — conditional inclusion, source left. The target
|
|
34
|
+
* side must resolve a declared key of B — DELIBERATELY judged by the
|
|
35
|
+
* engine at `Db.create`/`Db.open` (`SchemaError`), never re-checked here.
|
|
36
|
+
* Arity mismatch between the two faces is a type error ({@link SameArity}).
|
|
37
|
+
*/
|
|
38
|
+
function contained(source, target) {
|
|
39
|
+
const data = Object.freeze({
|
|
40
|
+
kind: "containment",
|
|
41
|
+
source: source.data,
|
|
42
|
+
target: target.data,
|
|
43
|
+
bidirectional: false
|
|
44
|
+
});
|
|
45
|
+
return Object.freeze({ data });
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* `A(X|φ) == B(Y|ψ)` — the bidirectional abbreviation, one utterance. It
|
|
49
|
+
* lowers to the two adjacent containments in the `A <= B` first order
|
|
50
|
+
* (macro parity) and renders as `==` once, in the written orientation.
|
|
51
|
+
*/
|
|
52
|
+
function mirrors(source, target) {
|
|
53
|
+
const data = Object.freeze({
|
|
54
|
+
kind: "containment",
|
|
55
|
+
source: source.data,
|
|
56
|
+
target: target.data,
|
|
57
|
+
bidirectional: true
|
|
58
|
+
});
|
|
59
|
+
return Object.freeze({ data });
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* `B(Y|ψ) <={window} A(X|φ)` — the cardinality window. READ CAREFULLY: the
|
|
63
|
+
* LEFT face is the window's TARGET, the per-group parent (B-family,
|
|
64
|
+
* target-left — macro parity), and the RIGHT face is the counted source.
|
|
65
|
+
* `window(on(Holder, "id"), atMost(3n), on(Account, "holder"))` says: each
|
|
66
|
+
* Holder id groups at most three Account rows by holder.
|
|
67
|
+
*/
|
|
68
|
+
function window(target, count, source) {
|
|
69
|
+
const data = Object.freeze({
|
|
70
|
+
kind: "window",
|
|
71
|
+
target: target.data,
|
|
72
|
+
window: count.window,
|
|
73
|
+
source: source.data
|
|
74
|
+
});
|
|
75
|
+
return Object.freeze({ data });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Renders one statement in the CANONICAL macro spelling
|
|
79
|
+
* (`docs/architecture/70-api.md`; the engine's `schema/render.rs` emits the
|
|
80
|
+
* same shapes for violations) — `Account(id) -> Account`,
|
|
81
|
+
* `Account(holder) <= Holder(id)`,
|
|
82
|
+
* `Account(id | kind == Savings) == SavingsTerms(account)`,
|
|
83
|
+
* `Holder(id) <={0..3} Account(holder)` — so TS-side errors and
|
|
84
|
+
* engine-side diagnostics read identically. A renderer, never a parser:
|
|
85
|
+
* strings are output-only.
|
|
86
|
+
*/
|
|
87
|
+
function renderStatement(statement) {
|
|
88
|
+
const data = statement.data;
|
|
89
|
+
switch (data.kind) {
|
|
90
|
+
case "key":
|
|
91
|
+
return `${data.owner.name}(${data.projection.join(", ")}) -> ${data.owner.name}`;
|
|
92
|
+
case "containment": {
|
|
93
|
+
const operator = data.bidirectional ? "==" : "<=";
|
|
94
|
+
return `${renderFace(data.source)} ${operator} ${renderFace(data.target)}`;
|
|
95
|
+
}
|
|
96
|
+
case "window":
|
|
97
|
+
return `${renderFace(data.target)} <=${renderWindow(data.window)} ${renderFace(data.source)}`;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export { contained, key, mirrors, renderStatement, window };
|
|
101
|
+
//# sourceMappingURL=statements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"statements.js","sourceRoot":"","sources":["../src/statements.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bjornpagen/bumbledb",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Type-theoretic TypeScript SDK for the bumbledb embedded relational engine",
|
|
5
|
+
"module": "dist/index.js",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"imports": {
|
|
16
|
+
"#test/*.ts": "./test/*.ts",
|
|
17
|
+
"#*.ts": {
|
|
18
|
+
"types": "./src/*.ts",
|
|
19
|
+
"default": "./dist/*.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"database",
|
|
28
|
+
"relational",
|
|
29
|
+
"datalog",
|
|
30
|
+
"embedded",
|
|
31
|
+
"type-safe",
|
|
32
|
+
"typescript"
|
|
33
|
+
],
|
|
34
|
+
"author": "Bjorn Pagen",
|
|
35
|
+
"license": "0BSD",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/bjornpagen/bumbledb.git",
|
|
39
|
+
"directory": "ts"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://github.com/bjornpagen/bumbledb#readme",
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@superbuilders/errors": "^4.0.2"
|
|
44
|
+
},
|
|
45
|
+
"optionalDependencies": {
|
|
46
|
+
"@bjornpagen/bumbledb-darwin-arm64": "0.1.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@biomejs/biome": "^2.0.0-beta.5",
|
|
50
|
+
"@types/node": "^26.1.0",
|
|
51
|
+
"typescript": "^7.0.2"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=24"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"private": false,
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "node scripts/build.ts",
|
|
62
|
+
"typecheck": "tsc --noEmit",
|
|
63
|
+
"lint": "biome check .",
|
|
64
|
+
"test": "pnpm run build && node --test test/**/*.test.ts"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/brand.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nominal branding — the TS analog of the Rust macro's host newtypes
|
|
3
|
+
* (`docs/architecture/10-data-model.md`, the nominal-safety layer). A brand
|
|
4
|
+
* is a phantom: it exists only in the type, tsc polices the wall exactly as
|
|
5
|
+
* rustc polices newtype domains, and nothing is allocated or wrapped at
|
|
6
|
+
* runtime.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as errors from "@superbuilders/errors"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The brand-minting guard behind {@link span} — the one nominal step, as a
|
|
13
|
+
* type guard carrying the interval's REAL invariant (`start < end`, the
|
|
14
|
+
* same check Rust's `Interval::new` runs): a value that passes IS a legal
|
|
15
|
+
* interval of any brand, exactly as a Rust newtype wraps a checked
|
|
16
|
+
* `Interval<T>` at construction.
|
|
17
|
+
*/
|
|
18
|
+
function isNonemptyInterval<Name extends string>(value: IntervalValue): value is Interval<Name> {
|
|
19
|
+
return value.start < value.end
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The brand key. A real runtime symbol (so modules can import it without a
|
|
24
|
+
* `declare`-only lie), but no branded value ever carries the property — the
|
|
25
|
+
* brand is purely a typing device.
|
|
26
|
+
*/
|
|
27
|
+
const brand: unique symbol = Symbol("bumbledb.brand")
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The phantom-value key used by field values, field references, and faces
|
|
31
|
+
* to carry their value type without any runtime representation.
|
|
32
|
+
*/
|
|
33
|
+
const phantom: unique symbol = Symbol("bumbledb.phantom")
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A branded scalar: `T` walled off under the literal name `Name`. A
|
|
37
|
+
* `Brand<bigint, "HolderId">` is not assignable where a
|
|
38
|
+
* `Brand<bigint, "AccountId">` is expected — the Rust newtype wall,
|
|
39
|
+
* verbatim. Scalars brand as `bigint` (u64/i64), `Uint8Array` (bytes), and
|
|
40
|
+
* whole interval objects (`Interval<Name>`); `bool` and `str` take no
|
|
41
|
+
* newtype, exactly as the macro's `as` grammar refuses them.
|
|
42
|
+
*/
|
|
43
|
+
type Brand<T, Name extends string> = T & { readonly [brand]: Name }
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A half-open interval `[start, end)` as a plain value object. The ray is
|
|
47
|
+
* representable (`end` = the element domain's MAX_END); widths and
|
|
48
|
+
* signedness are NOT modeled here — the engine judges widths at the typed
|
|
49
|
+
* write boundary, the brand blocks cross-field assignment, and nothing
|
|
50
|
+
* else is TS's business. Interval newtypes derive no order (the Rust
|
|
51
|
+
* refusal, `docs/architecture/10-data-model.md`), so no comparators exist.
|
|
52
|
+
*/
|
|
53
|
+
interface IntervalValue {
|
|
54
|
+
readonly start: bigint
|
|
55
|
+
readonly end: bigint
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* A branded interval: the whole `{ start, end }` object walled under
|
|
60
|
+
* `Name` — the `interval<i64> as ActiveDuring` analog.
|
|
61
|
+
*/
|
|
62
|
+
type Interval<Name extends string> = Brand<IntervalValue, Name>
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Constructs an interval literal — the `start..end` spelling. Half-open
|
|
66
|
+
* and nonempty by construction: `start >= end` is a typed construction
|
|
67
|
+
* error (parse, don't validate — the same invariant Rust's
|
|
68
|
+
* `Interval::new` enforces at the host boundary). The default `never`
|
|
69
|
+
* brand makes a fresh literal assignable to any interval field or brand,
|
|
70
|
+
* the wrap-at-construction idiom; pass the brand explicitly
|
|
71
|
+
* (`span<"ActiveDuring">(0n, 10n)`) to pin it.
|
|
72
|
+
*/
|
|
73
|
+
function span<Name extends string = never>(start: bigint, end: bigint): Interval<Name> {
|
|
74
|
+
const value: IntervalValue = Object.freeze({ start, end })
|
|
75
|
+
if (!isNonemptyInterval<Name>(value)) {
|
|
76
|
+
throw errors.new(`interval is half-open and nonempty: start must be < end (got ${start}..${end})`)
|
|
77
|
+
}
|
|
78
|
+
return value
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type { Brand, Interval, IntervalValue }
|
|
82
|
+
export { brand, phantom, span }
|
package/src/closed.ts
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Closed relations (`docs/architecture/10-data-model.md` § closed
|
|
3
|
+
* relations): a vocabulary whose extension is declared in the schema — two
|
|
4
|
+
* tiers, one function. The emission per closed relation mirrors the macro's
|
|
5
|
+
* (host-enum analog): handle CONSTANTS on the value (`Kind.Checking`, ids =
|
|
6
|
+
* declaration order), the `fromId` weld, an `id` field constructor
|
|
7
|
+
* pre-branded with the handle newtype for other relations' field blocks
|
|
8
|
+
* (`kind: Kind.id`), and payload readback (`Kind.axioms`). No fact type and
|
|
9
|
+
* no insert surface exist — closed relations are unwritable by
|
|
10
|
+
* construction: the value simply lacks the writable relation shape.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import * as errors from "@superbuilders/errors"
|
|
14
|
+
import type { Brand } from "#brand.ts"
|
|
15
|
+
import {
|
|
16
|
+
type AnyField,
|
|
17
|
+
assertDeclarationOrderKey,
|
|
18
|
+
type ClosedIdField,
|
|
19
|
+
type ClosedRoster,
|
|
20
|
+
type FieldData,
|
|
21
|
+
type FieldValue,
|
|
22
|
+
fieldData,
|
|
23
|
+
literalOf
|
|
24
|
+
} from "#fields.ts"
|
|
25
|
+
import type { LiteralSpec } from "#spec.ts"
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The value-surface property names a handle may not shadow — the macro's
|
|
29
|
+
* name-collision diagnostic, here over the closed value's own properties
|
|
30
|
+
* (`relation`/`selection` are reserved so a closed value can never be
|
|
31
|
+
* mistaken for a selected relation by `on()`'s discriminant).
|
|
32
|
+
*/
|
|
33
|
+
const reservedHandleNames: readonly string[] = Object.freeze([
|
|
34
|
+
"name",
|
|
35
|
+
"id",
|
|
36
|
+
"data",
|
|
37
|
+
"axioms",
|
|
38
|
+
"fromId",
|
|
39
|
+
"relation",
|
|
40
|
+
"selection"
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Reads one handle's axiom row, refusing absence loudly: the payload tier's
|
|
45
|
+
* overload types the record exhaustively, so a missing row is ill-typed
|
|
46
|
+
* input, and the bare tier never reaches here (it declares no columns).
|
|
47
|
+
*/
|
|
48
|
+
function axiomRow(
|
|
49
|
+
name: string,
|
|
50
|
+
axioms: Readonly<Record<string, Readonly<Record<string, unknown>>>> | undefined,
|
|
51
|
+
handle: string
|
|
52
|
+
): Readonly<Record<string, unknown>> {
|
|
53
|
+
if (axioms === undefined) {
|
|
54
|
+
throw errors.new(`closed relation ${name}: payload columns declared without ground axioms`)
|
|
55
|
+
}
|
|
56
|
+
const row = axioms[handle]
|
|
57
|
+
if (row === undefined) {
|
|
58
|
+
throw errors.new(`closed relation ${name}: no ground axiom for handle ${handle}`)
|
|
59
|
+
}
|
|
60
|
+
return row
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A payload column of a closed relation: any field constructor except a
|
|
65
|
+
* fresh-marked one (a vocabulary's rows are ground axioms, never minted).
|
|
66
|
+
*/
|
|
67
|
+
type PayloadField = AnyField & { readonly data: FieldData<false> }
|
|
68
|
+
|
|
69
|
+
/** One declared payload column: name plus its field description. */
|
|
70
|
+
interface ClosedColumn {
|
|
71
|
+
readonly name: string
|
|
72
|
+
readonly field: FieldData
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* One ground axiom, already lowered: the handle plus one wire literal per
|
|
77
|
+
* declared column in column-declaration order (row id = index). Lowered
|
|
78
|
+
* EAGERLY at construction so axiom literals ride the same selection-literal
|
|
79
|
+
* machine as `where()` bindings, with the same errors (the macro's rule).
|
|
80
|
+
*/
|
|
81
|
+
interface ClosedRow {
|
|
82
|
+
readonly handle: string
|
|
83
|
+
readonly values: readonly LiteralSpec[]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A closed relation's runtime description. */
|
|
87
|
+
interface ClosedData {
|
|
88
|
+
readonly name: string
|
|
89
|
+
readonly handles: readonly string[]
|
|
90
|
+
readonly columns: readonly ClosedColumn[]
|
|
91
|
+
readonly rows: readonly ClosedRow[]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** One axiom row as the host writes and reads it: column name to host value. */
|
|
95
|
+
type AxiomRow<Cols> = { readonly [C in keyof Cols]: FieldValue<Cols[C]> }
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The whole axiom record: every handle exactly once, every column exactly
|
|
99
|
+
* once per row — a missing or extra axiom, column, or handle is a TYPE
|
|
100
|
+
* error (mapped over the handle tuple).
|
|
101
|
+
*/
|
|
102
|
+
type Axioms<Handles extends readonly string[], Cols> = {
|
|
103
|
+
readonly [H in Handles[number]]: AxiomRow<Cols>
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The named surface of a closed relation value, minus the handle constants
|
|
108
|
+
* (which {@link Closed} intersects in).
|
|
109
|
+
*/
|
|
110
|
+
interface ClosedCore<Name extends string, Handles extends readonly string[], Cols> {
|
|
111
|
+
readonly name: Name
|
|
112
|
+
/**
|
|
113
|
+
* The pre-branded u64 field constructor: `kind: Kind.id` in another
|
|
114
|
+
* relation's field block is the reference through which bare handles
|
|
115
|
+
* become legal in that relation's selections.
|
|
116
|
+
*/
|
|
117
|
+
readonly id: ClosedIdField<Name>
|
|
118
|
+
readonly data: ClosedData
|
|
119
|
+
/** Payload readback: handle to its declared column values. */
|
|
120
|
+
readonly axioms: Axioms<Handles, Cols>
|
|
121
|
+
/** The weld: declaration-order id back to its handle, or undefined beyond the roster. */
|
|
122
|
+
fromId(id: Brand<bigint, Name>): Handles[number] | undefined
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A closed relation value: the core surface plus one branded constant per
|
|
127
|
+
* handle (`Kind.Checking: Brand<bigint, "Kind">`, ids = declaration order).
|
|
128
|
+
*/
|
|
129
|
+
type Closed<Name extends string, Handles extends readonly string[], Cols> = ClosedCore<Name, Handles, Cols> & {
|
|
130
|
+
readonly [H in Handles[number]]: Brand<bigint, Name>
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Any closed relation value, whatever its roster and columns. */
|
|
134
|
+
interface AnyClosed {
|
|
135
|
+
readonly name: string
|
|
136
|
+
readonly id: ClosedIdField<string>
|
|
137
|
+
readonly data: ClosedData
|
|
138
|
+
readonly axioms: Readonly<Record<string, object>>
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Bare tier: `closed("Kind", ["Checking", "Savings"])` — handles only. */
|
|
142
|
+
function closed<const Name extends string, const Handles extends readonly [string, ...string[]]>(
|
|
143
|
+
name: Name,
|
|
144
|
+
handles: Handles
|
|
145
|
+
): Closed<Name, Handles, Record<never, never>>
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Payload tier: declared columns plus ground axioms, every handle with
|
|
149
|
+
* every column exactly once (type-enforced by {@link Axioms}).
|
|
150
|
+
*/
|
|
151
|
+
function closed<
|
|
152
|
+
const Name extends string,
|
|
153
|
+
const Handles extends readonly [string, ...string[]],
|
|
154
|
+
const Cols extends Record<string, PayloadField>
|
|
155
|
+
>(name: Name, handles: Handles, columns: Cols, axioms: Axioms<Handles, Cols>): Closed<Name, Handles, Cols>
|
|
156
|
+
|
|
157
|
+
function closed(
|
|
158
|
+
name: string,
|
|
159
|
+
handles: readonly [string, ...string[]],
|
|
160
|
+
columns?: Record<string, PayloadField>,
|
|
161
|
+
axioms?: Readonly<Record<string, Readonly<Record<string, unknown>>>>
|
|
162
|
+
): unknown {
|
|
163
|
+
const seen = new Set<string>()
|
|
164
|
+
for (const handle of handles) {
|
|
165
|
+
if (seen.has(handle)) {
|
|
166
|
+
throw errors.new(`closed relation ${name}: duplicate handle ${handle}`)
|
|
167
|
+
}
|
|
168
|
+
seen.add(handle)
|
|
169
|
+
if (reservedHandleNames.includes(handle)) {
|
|
170
|
+
throw errors.new(
|
|
171
|
+
`closed relation ${name}: handle ${handle} collides with the closed value's own surface (${reservedHandleNames.join(", ")})`
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const roster: ClosedRoster = Object.freeze({ name, handles: Object.freeze([...handles]) })
|
|
176
|
+
const cols: ClosedColumn[] = []
|
|
177
|
+
if (columns !== undefined) {
|
|
178
|
+
for (const [columnName, field] of Object.entries(columns)) {
|
|
179
|
+
assertDeclarationOrderKey(`closed relation ${name} column`, columnName)
|
|
180
|
+
cols.push(Object.freeze({ name: columnName, field: field.data }))
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const rows: ClosedRow[] = handles.map(function lowerRow(handle) {
|
|
184
|
+
const values = cols.map(function lowerAxiomLiteral(column) {
|
|
185
|
+
const row = axiomRow(name, axioms, handle)
|
|
186
|
+
return Object.freeze(literalOf(column.field, row[column.name]))
|
|
187
|
+
})
|
|
188
|
+
return Object.freeze({ handle, values: Object.freeze(values) })
|
|
189
|
+
})
|
|
190
|
+
const data: ClosedData = Object.freeze({
|
|
191
|
+
name,
|
|
192
|
+
handles: roster.handles,
|
|
193
|
+
columns: Object.freeze(cols),
|
|
194
|
+
rows: Object.freeze(rows)
|
|
195
|
+
})
|
|
196
|
+
const id: ClosedIdField<string> = Object.freeze({
|
|
197
|
+
data: fieldData({ kind: "u64" }, name, false, roster)
|
|
198
|
+
})
|
|
199
|
+
/**
|
|
200
|
+
* Handle names are arbitrary identifiers, so rows and constants are
|
|
201
|
+
* minted with OWN-property definition, never assignment: a handle named
|
|
202
|
+
* "__proto__" would otherwise ride the Object.prototype accessor —
|
|
203
|
+
* silently swapping the record's prototype instead of creating the row,
|
|
204
|
+
* and no-oping the constant (a primitive through the setter) — minting a
|
|
205
|
+
* value whose type claims Brand<bigint, Name> but reads back an object.
|
|
206
|
+
*/
|
|
207
|
+
const axiomsOut: Record<string, object> = {}
|
|
208
|
+
for (const handle of handles) {
|
|
209
|
+
const row = axioms === undefined ? Object.freeze({}) : Object.freeze({ ...axiomRow(name, axioms, handle) })
|
|
210
|
+
Object.defineProperty(axiomsOut, handle, { value: row, enumerable: true })
|
|
211
|
+
}
|
|
212
|
+
const value: Record<string, unknown> = {
|
|
213
|
+
name,
|
|
214
|
+
id,
|
|
215
|
+
data,
|
|
216
|
+
axioms: Object.freeze(axiomsOut),
|
|
217
|
+
fromId(idValue: bigint): string | undefined {
|
|
218
|
+
return roster.handles[Number(idValue)]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
handles.forEach(function mintHandleConstant(handle, index) {
|
|
222
|
+
Object.defineProperty(value, handle, { value: BigInt(index), enumerable: true })
|
|
223
|
+
})
|
|
224
|
+
return Object.freeze(value)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export type { AnyClosed, AxiomRow, Axioms, Closed, ClosedColumn, ClosedCore, ClosedData, ClosedRow, PayloadField }
|
|
228
|
+
export { closed }
|