@bjornpagen/bumbledb 0.20.2 → 1.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 +283 -1611
- package/README.md +156 -118
- package/dist/capacity.d.ts +16 -12
- package/dist/capacity.d.ts.map +1 -1
- package/dist/capacity.js +16 -48
- package/dist/capacity.js.map +1 -1
- package/dist/changes.d.ts +54 -0
- package/dist/changes.d.ts.map +1 -0
- package/dist/changes.js +245 -0
- package/dist/changes.js.map +1 -0
- package/dist/close.d.ts +24 -0
- package/dist/close.d.ts.map +1 -0
- package/dist/close.js +34 -0
- package/dist/close.js.map +1 -0
- package/dist/closed.d.ts +1 -3
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +24 -12
- package/dist/closed.js.map +1 -1
- package/dist/codec.d.ts +56 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +289 -0
- package/dist/codec.js.map +1 -0
- package/dist/compile.d.ts +68 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +75 -0
- package/dist/compile.js.map +1 -0
- package/dist/db-native.d.ts +170 -0
- package/dist/db-native.d.ts.map +1 -0
- package/dist/db-native.js +5 -0
- package/dist/db-native.js.map +1 -0
- package/dist/db.d.ts +101 -233
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +232 -1084
- package/dist/db.js.map +1 -1
- package/dist/errors.d.ts +57 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +2 -2
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +65 -24
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +94 -24
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +37 -32
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -21
- package/dist/index.js.map +1 -1
- package/dist/internal/log.d.ts +24 -0
- package/dist/internal/log.d.ts.map +1 -0
- package/dist/internal/log.js +10 -0
- package/dist/internal/log.js.map +1 -0
- package/dist/law.d.ts +8 -13
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +6 -59
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts +0 -13
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +9 -17
- package/dist/lower.js.map +1 -1
- package/dist/migration.d.ts +33 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/migration.js +48 -0
- package/dist/migration.js.map +1 -0
- package/dist/native.d.ts +256 -301
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +65 -108
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +24 -13
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +7 -3
- package/dist/query/atom.js.map +1 -1
- package/dist/query/compute.d.ts +68 -0
- package/dist/query/compute.d.ts.map +1 -0
- package/dist/query/compute.js +141 -0
- package/dist/query/compute.js.map +1 -0
- package/dist/query/find.d.ts +15 -8
- package/dist/query/find.d.ts.map +1 -1
- package/dist/query/find.js +6 -2
- package/dist/query/find.js.map +1 -1
- package/dist/query/lower.d.ts +23 -2
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +433 -80
- package/dist/query/lower.js.map +1 -1
- package/dist/query/parse-ir.d.ts.map +1 -1
- package/dist/query/parse-ir.js +17 -8
- package/dist/query/parse-ir.js.map +1 -1
- package/dist/query/run.d.ts +12 -2
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +26 -9
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +47 -3
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +83 -19
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +3 -8
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +16 -10
- package/dist/relation.js.map +1 -1
- package/dist/result.d.ts +47 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +50 -0
- package/dist/result.js.map +1 -0
- package/dist/rows.d.ts +69 -0
- package/dist/rows.d.ts.map +1 -0
- package/dist/rows.js +328 -0
- package/dist/rows.js.map +1 -0
- package/dist/runtime-codes.d.ts +2 -0
- package/dist/runtime-codes.d.ts.map +1 -0
- package/dist/runtime-codes.js +19 -0
- package/dist/runtime-codes.js.map +1 -0
- package/dist/runtime-errors.d.ts +106 -0
- package/dist/runtime-errors.d.ts.map +1 -0
- package/dist/runtime-errors.js +62 -0
- package/dist/runtime-errors.js.map +1 -0
- package/dist/runtime-native.d.ts +171 -0
- package/dist/runtime-native.d.ts.map +1 -0
- package/dist/runtime-native.js +5 -0
- package/dist/runtime-native.js.map +1 -0
- package/dist/runtime.d.ts +73 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +293 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scalar.d.ts +165 -0
- package/dist/scalar.d.ts.map +1 -0
- package/dist/scalar.js +344 -0
- package/dist/scalar.js.map +1 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +34 -37
- package/dist/schema.js.map +1 -1
- package/dist/shape.d.ts +28 -0
- package/dist/shape.d.ts.map +1 -0
- package/dist/shape.js +2 -0
- package/dist/shape.js.map +1 -0
- package/dist/spec.d.ts +27 -3
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js +22 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +16 -3
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +54 -28
- package/dist/statements.js.map +1 -1
- package/dist/uuid.d.ts +23 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +54 -0
- package/dist/uuid.js.map +1 -0
- package/pack-provenance.json +7 -0
- package/package.json +12 -16
- package/src/capacity.ts +34 -54
- package/src/changes.ts +361 -0
- package/src/close.ts +53 -0
- package/src/closed.ts +25 -19
- package/src/codec.ts +379 -0
- package/src/compile.ts +149 -0
- package/src/db-native.ts +247 -0
- package/src/db.ts +461 -1632
- package/src/errors.ts +50 -0
- package/src/face.ts +2 -2
- package/src/fields.ts +182 -55
- package/src/index.ts +62 -126
- package/src/internal/log.ts +51 -0
- package/src/law.ts +13 -28
- package/src/lower.ts +9 -4
- package/src/migration.ts +69 -0
- package/src/native.ts +326 -487
- package/src/query/atom.ts +61 -25
- package/src/query/compute.ts +237 -0
- package/src/query/find.ts +31 -12
- package/src/query/lower.ts +531 -143
- package/src/query/parse-ir.ts +18 -13
- package/src/query/run.ts +32 -16
- package/src/query/scope.ts +140 -8
- package/src/relation.ts +17 -21
- package/src/result.ts +130 -0
- package/src/rows.ts +404 -0
- package/src/runtime-codes.ts +18 -0
- package/src/runtime-errors.ts +69 -0
- package/src/runtime-native.ts +242 -0
- package/src/runtime.ts +440 -0
- package/src/scalar.ts +560 -0
- package/src/schema.ts +35 -37
- package/src/shape.ts +31 -0
- package/src/spec.ts +33 -3
- package/src/statements.ts +75 -68
- package/src/uuid.ts +69 -0
- package/dist/marshal.d.ts +0 -44
- package/dist/marshal.d.ts.map +0 -1
- package/dist/marshal.js +0 -165
- package/dist/marshal.js.map +0 -1
- package/src/marshal.ts +0 -200
package/src/errors.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Data } from "effect"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure authoring refusals and SDK-invariant defects. These are the ONLY
|
|
5
|
+
* non-`DbError` throw families in the core package: chapter 35 permits
|
|
6
|
+
* programmer-facing AST misuse to throw synchronously (no I/O ever), and a
|
|
7
|
+
* contradiction between SDK and native state is a defect, not a domain
|
|
8
|
+
* outcome. Every operational failure of effectful work is the single
|
|
9
|
+
* `DbError` tagged-reason class in `#runtime-errors.ts` — the old
|
|
10
|
+
* per-surface `Err*` wrapper family is deleted (duplicate error wrappers
|
|
11
|
+
* are banned by C02/C10).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** A pure schema, query, parameter, or value-authoring refusal. */
|
|
15
|
+
export class AuthoringError extends Data.TaggedError("AuthoringError")<{
|
|
16
|
+
readonly message: string
|
|
17
|
+
}> {}
|
|
18
|
+
|
|
19
|
+
/** A contradiction in an SDK/native result, not an application refusal. */
|
|
20
|
+
export class SdkInvariantError extends Data.TaggedError("SdkInvariantError")<{
|
|
21
|
+
readonly message: string
|
|
22
|
+
}> {}
|
|
23
|
+
|
|
24
|
+
export class NativeLoadError extends Data.TaggedError("NativeLoadError")<{
|
|
25
|
+
readonly package: string
|
|
26
|
+
readonly operation: "resolve" | "load"
|
|
27
|
+
readonly message: string
|
|
28
|
+
readonly cause: unknown
|
|
29
|
+
}> {}
|
|
30
|
+
|
|
31
|
+
/** A native bridge call's contextual failure; the exact thrown value is retained. */
|
|
32
|
+
export class NativeOperationError extends Data.TaggedError("NativeOperationError")<{
|
|
33
|
+
readonly operation: string
|
|
34
|
+
readonly cause: unknown
|
|
35
|
+
}> {
|
|
36
|
+
override get message(): string {
|
|
37
|
+
const cause = this.cause
|
|
38
|
+
const detail =
|
|
39
|
+
typeof cause === "object" && cause !== null && "message" in cause && typeof cause.message === "string"
|
|
40
|
+
? cause.message
|
|
41
|
+
: String(cause)
|
|
42
|
+
return `${this.operation}: ${detail}`
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class NativeReportedError extends Data.TaggedError("NativeReportedError")<{
|
|
47
|
+
readonly kind: string
|
|
48
|
+
readonly message: string
|
|
49
|
+
readonly cause: unknown
|
|
50
|
+
}> {}
|
package/src/face.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as errors from "@superbuilders/errors"
|
|
2
1
|
import type { AnyClosed, AnySelectedClosed, PayloadField } from "#closed.ts"
|
|
2
|
+
import { AuthoringError } from "#errors.ts"
|
|
3
3
|
import type { AnyField, SignatureOf } from "#fields.ts"
|
|
4
4
|
import type { Same } from "#judgment.ts"
|
|
5
5
|
import type { AnyRelation, AnySelected, FieldsShape, RelationFields, SelectionBinding } from "#relation.ts"
|
|
@@ -121,7 +121,7 @@ function on<S extends FaceSource>(source: S, fields: string | readonly string[])
|
|
|
121
121
|
})
|
|
122
122
|
const value = Object.freeze({ source, projection, data })
|
|
123
123
|
if (!faceMinted<S, readonly string[]>(value, source, projection)) {
|
|
124
|
-
throw
|
|
124
|
+
throw new AuthoringError({ message: `face over ${parts.owner.name}: face construction incomplete` })
|
|
125
125
|
}
|
|
126
126
|
return value
|
|
127
127
|
}
|
package/src/fields.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import * as errors from "@superbuilders/errors"
|
|
2
1
|
import { regex } from "arkregex"
|
|
2
|
+
import { Result } from "effect"
|
|
3
|
+
import { AuthoringError } from "#errors.ts"
|
|
4
|
+
import { DbError } from "#runtime-errors.ts"
|
|
3
5
|
import type { LiteralSpec } from "#spec.ts"
|
|
6
|
+
import { Uuid } from "#uuid.ts"
|
|
4
7
|
|
|
5
8
|
const INTEGER_INDEX_NAME = regex("^(?:0|[1-9][0-9]*)$")
|
|
6
9
|
|
|
7
10
|
/**
|
|
8
|
-
* A half-open interval `[start, end)` as a plain value object —
|
|
9
|
-
* interval value type, whatever the field's element type
|
|
10
|
-
* The ray is representable (`end` = the element type's
|
|
11
|
-
* and signedness are NOT modeled on the value — they are
|
|
12
|
-
* labels the engine judges at the typed write boundary.
|
|
13
|
-
* derive no order
|
|
14
|
-
* so no comparators exist on the value type.
|
|
11
|
+
* A half-open integer interval `[start, end)` as a plain value object —
|
|
12
|
+
* the ONE discrete interval value type, whatever the field's element type
|
|
13
|
+
* or width label. The ray is representable (`end` = the element type's
|
|
14
|
+
* MAX_END); widths and signedness are NOT modeled on the value — they are
|
|
15
|
+
* descriptor-type labels the engine judges at the typed write boundary.
|
|
16
|
+
* Interval fields derive no order, so no comparators exist on the value.
|
|
15
17
|
*/
|
|
16
18
|
interface IntervalValue {
|
|
17
19
|
readonly start: bigint
|
|
@@ -19,17 +21,55 @@ interface IntervalValue {
|
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* A half-open dense float interval `[start, end)` as a plain value object
|
|
25
|
+
* (chapter 11): two canonical binary64 bounds on the dense numeric line.
|
|
26
|
+
* NaN is never an endpoint, signed zero is normalized at the checked
|
|
27
|
+
* constructor and again by the native boundary, and strict `start < end`
|
|
28
|
+
* makes empty spans unrepresentable through {@link span}. Infinite bounds
|
|
29
|
+
* denote a missing bound, not a member point.
|
|
27
30
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
interface FloatIntervalValue {
|
|
32
|
+
readonly start: number
|
|
33
|
+
readonly end: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Constructs a checked interval literal — the `start..end` spelling.
|
|
38
|
+
* Half-open and nonempty by construction. This is one of chapter 35's
|
|
39
|
+
* "checked small interval constructors": genuinely fallible pure parsing
|
|
40
|
+
* returns `Result` (use `Effect.fromResult(span(...))` inside a generator),
|
|
41
|
+
* never hidden I/O and never a thrown domain outcome.
|
|
42
|
+
*
|
|
43
|
+
* Two element domains, selected by argument type: `span(0n, 60n)` is a
|
|
44
|
+
* discrete integer interval; `span(0.5, 1.5)` is a dense float interval
|
|
45
|
+
* with canonical endpoints (NaN refused, `-0` normalized to `+0`,
|
|
46
|
+
* `-Infinity` legal only as the lower bound and `+Infinity` only as the
|
|
47
|
+
* upper bound — both enforced by strict numeric `start < end`).
|
|
48
|
+
*/
|
|
49
|
+
function span(start: bigint, end: bigint): Result.Result<IntervalValue, DbError>
|
|
50
|
+
function span(start: number, end: number): Result.Result<FloatIntervalValue, DbError>
|
|
51
|
+
function span(
|
|
52
|
+
start: bigint | number,
|
|
53
|
+
end: bigint | number
|
|
54
|
+
): Result.Result<IntervalValue, DbError> | Result.Result<FloatIntervalValue, DbError> {
|
|
55
|
+
if (typeof start === "bigint" && typeof end === "bigint") {
|
|
56
|
+
if (start >= end) {
|
|
57
|
+
return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
|
|
58
|
+
}
|
|
59
|
+
return Result.succeed(Object.freeze({ start, end }))
|
|
60
|
+
}
|
|
61
|
+
if (typeof start === "number" && typeof end === "number") {
|
|
62
|
+
if (Number.isNaN(start) || Number.isNaN(end)) {
|
|
63
|
+
return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
|
|
64
|
+
}
|
|
65
|
+
const lo = Object.is(start, -0) ? 0 : start
|
|
66
|
+
const hi = Object.is(end, -0) ? 0 : end
|
|
67
|
+
if (!(lo < hi)) {
|
|
68
|
+
return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
|
|
69
|
+
}
|
|
70
|
+
return Result.succeed(Object.freeze({ start: lo, end: hi }))
|
|
31
71
|
}
|
|
32
|
-
return
|
|
72
|
+
return Result.fail(new DbError({ operation: "span", reason: { _tag: "InvalidArgument" } }))
|
|
33
73
|
}
|
|
34
74
|
|
|
35
75
|
/**
|
|
@@ -56,27 +96,37 @@ interface StrField {
|
|
|
56
96
|
readonly kind: "str"
|
|
57
97
|
}
|
|
58
98
|
|
|
59
|
-
interface FreshU64Field {
|
|
60
|
-
readonly kind: "u64"
|
|
61
|
-
readonly fresh: true
|
|
62
|
-
}
|
|
63
|
-
|
|
64
99
|
interface U64Field {
|
|
65
100
|
readonly kind: "u64"
|
|
66
|
-
readonly fresh: FreshU64Field
|
|
67
101
|
}
|
|
68
102
|
|
|
69
103
|
interface I64Field {
|
|
70
104
|
readonly kind: "i64"
|
|
71
105
|
}
|
|
72
106
|
|
|
107
|
+
interface F64Field {
|
|
108
|
+
readonly kind: "f64"
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The application-owned 128-bit identity scalar (chapter 30/34): sixteen
|
|
113
|
+
* exact bytes, spelled as the canonical hyphenated UUID {@link Uuid}
|
|
114
|
+
* host value. There is no `fresh` mark anywhere: the database issues no
|
|
115
|
+
* identity, and key laws are declared statements.
|
|
116
|
+
*/
|
|
117
|
+
interface UuidField {
|
|
118
|
+
readonly kind: "uuid"
|
|
119
|
+
}
|
|
120
|
+
|
|
73
121
|
interface BytesField<Width extends number = number> {
|
|
74
122
|
readonly kind: "bytes"
|
|
75
123
|
readonly width: Width
|
|
76
124
|
}
|
|
77
125
|
|
|
126
|
+
type IntervalElementKind = "u64" | "i64" | "f64"
|
|
127
|
+
|
|
78
128
|
interface IntervalField<
|
|
79
|
-
Element extends
|
|
129
|
+
Element extends IntervalElementKind = IntervalElementKind,
|
|
80
130
|
Width extends bigint | undefined = bigint | undefined
|
|
81
131
|
> {
|
|
82
132
|
readonly kind: "interval"
|
|
@@ -96,8 +146,9 @@ type AnyField =
|
|
|
96
146
|
| BoolField
|
|
97
147
|
| StrField
|
|
98
148
|
| U64Field
|
|
99
|
-
| FreshU64Field
|
|
100
149
|
| I64Field
|
|
150
|
+
| F64Field
|
|
151
|
+
| UuidField
|
|
101
152
|
| BytesField
|
|
102
153
|
| IntervalField
|
|
103
154
|
| AnyClosedIdField
|
|
@@ -131,20 +182,26 @@ type Infer<F extends AnyField> = F extends { readonly kind: "bool" }
|
|
|
131
182
|
? bigint
|
|
132
183
|
: F extends { readonly kind: "i64" }
|
|
133
184
|
? bigint
|
|
134
|
-
: F extends { readonly kind: "
|
|
135
|
-
?
|
|
136
|
-
: F extends { readonly kind: "
|
|
137
|
-
?
|
|
138
|
-
:
|
|
185
|
+
: F extends { readonly kind: "f64" }
|
|
186
|
+
? number
|
|
187
|
+
: F extends { readonly kind: "uuid" }
|
|
188
|
+
? Uuid
|
|
189
|
+
: F extends { readonly kind: "bytes" }
|
|
190
|
+
? Uint8Array
|
|
191
|
+
: F extends { readonly kind: "interval"; readonly element: "f64" }
|
|
192
|
+
? FloatIntervalValue
|
|
193
|
+
: F extends { readonly kind: "interval" }
|
|
194
|
+
? IntervalValue
|
|
195
|
+
: never
|
|
139
196
|
|
|
140
197
|
/**
|
|
141
198
|
* The typed shape refusal shared by every literal machine — the selection
|
|
142
|
-
* lowering here, the row
|
|
199
|
+
* lowering here, the row codec (`rows.ts`), and the query-literal
|
|
143
200
|
* tagger (`query/lower.ts`) all throw through this ONE voice; reached only
|
|
144
201
|
* through ill-typed input (the well-typed surfaces make it unrepresentable).
|
|
145
202
|
*/
|
|
146
203
|
function literalShapeError(context: string, expected: string, value: unknown): Error {
|
|
147
|
-
return
|
|
204
|
+
return new AuthoringError({ message: `${context}: expected ${expected}, got ${typeof value}` })
|
|
148
205
|
}
|
|
149
206
|
|
|
150
207
|
function rosterOf(field: AnyField | undefined): AnyClosedRoster | undefined {
|
|
@@ -196,17 +253,48 @@ function isIntervalValue(value: unknown): value is IntervalValue {
|
|
|
196
253
|
)
|
|
197
254
|
}
|
|
198
255
|
|
|
256
|
+
function isFloatIntervalValue(value: unknown): value is FloatIntervalValue {
|
|
257
|
+
return (
|
|
258
|
+
typeof value === "object" &&
|
|
259
|
+
value !== null &&
|
|
260
|
+
"start" in value &&
|
|
261
|
+
"end" in value &&
|
|
262
|
+
typeof value.start === "number" &&
|
|
263
|
+
typeof value.end === "number"
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
|
|
199
267
|
function handleLiteral(closed: AnyClosedRoster, value: unknown): LiteralSpec {
|
|
200
268
|
if (typeof value !== "string") {
|
|
201
269
|
throw literalShapeError("selection literal", `a ${closed.name} handle name (string)`, value)
|
|
202
270
|
}
|
|
203
271
|
if (!closed.handles.includes(value)) {
|
|
204
|
-
throw
|
|
272
|
+
throw new AuthoringError({
|
|
273
|
+
message: `"${value}" is not a handle of ${closed.name} — the roster is ${closed.handles.join(", ")}`
|
|
274
|
+
})
|
|
205
275
|
}
|
|
206
276
|
return { kind: "handle", handle: value }
|
|
207
277
|
}
|
|
208
278
|
|
|
209
|
-
function intervalLiteral(element:
|
|
279
|
+
function intervalLiteral(element: IntervalElementKind, value: unknown): LiteralSpec {
|
|
280
|
+
if (element === "f64") {
|
|
281
|
+
if (!isFloatIntervalValue(value)) {
|
|
282
|
+
throw literalShapeError("selection literal", "float interval ({ start, end } numbers)", value)
|
|
283
|
+
}
|
|
284
|
+
if (Number.isNaN(value.start) || Number.isNaN(value.end) || !(value.start < value.end)) {
|
|
285
|
+
throw new AuthoringError({
|
|
286
|
+
message: "selection literal: a float interval is half-open and nonempty with non-NaN canonical endpoints"
|
|
287
|
+
})
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
kind: "value",
|
|
291
|
+
value: {
|
|
292
|
+
kind: "intervalF64",
|
|
293
|
+
start: Object.is(value.start, -0) ? 0 : value.start,
|
|
294
|
+
end: Object.is(value.end, -0) ? 0 : value.end
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
210
298
|
if (!isIntervalValue(value)) {
|
|
211
299
|
throw literalShapeError("selection literal", "interval ({ start, end } bigints)", value)
|
|
212
300
|
}
|
|
@@ -218,55 +306,76 @@ function intervalLiteral(element: "u64" | "i64", value: unknown): LiteralSpec {
|
|
|
218
306
|
|
|
219
307
|
function assertDeclarationOrderKey(where: string, name: string): void {
|
|
220
308
|
if (INTEGER_INDEX_NAME.test(name)) {
|
|
221
|
-
throw
|
|
222
|
-
`${where}: name ${name} is an integer index — JavaScript object keys re-order integer indices, breaking the declaration-order law; use a non-numeric name`
|
|
223
|
-
)
|
|
309
|
+
throw new AuthoringError({
|
|
310
|
+
message: `${where}: name ${name} is an integer index — JavaScript object keys re-order integer indices, breaking the declaration-order law; use a non-numeric name`
|
|
311
|
+
})
|
|
224
312
|
}
|
|
225
313
|
if (name.includes(".")) {
|
|
226
|
-
throw
|
|
227
|
-
`${where}: name ${name} contains a dot — the law classes key on the \`relation.field\` coordinate, so a dotted name would alias unrelated slots (macro parity: Rust identifiers cannot contain dots); use a dot-free name`
|
|
228
|
-
)
|
|
314
|
+
throw new AuthoringError({
|
|
315
|
+
message: `${where}: name ${name} contains a dot — the law classes key on the \`relation.field\` coordinate, so a dotted name would alias unrelated slots (macro parity: Rust identifiers cannot contain dots); use a dot-free name`
|
|
316
|
+
})
|
|
229
317
|
}
|
|
230
318
|
}
|
|
231
319
|
|
|
232
320
|
function assertDeclarationRecord(where: string, record: object): void {
|
|
233
321
|
const proto = Object.getPrototypeOf(record)
|
|
234
322
|
if (proto !== Object.prototype && proto !== null) {
|
|
235
|
-
throw
|
|
236
|
-
`${where}: the declaration record's prototype was replaced — a plain \`__proto__: {...}\` entry is the prototype setter, so its key silently vanishes from the declaration; spell it computed (["__proto__"]: {...}) to declare it as data`
|
|
237
|
-
)
|
|
323
|
+
throw new AuthoringError({
|
|
324
|
+
message: `${where}: the declaration record's prototype was replaced — a plain \`__proto__: {...}\` entry is the prototype setter, so its key silently vanishes from the declaration; spell it computed (["__proto__"]: {...}) to declare it as data`
|
|
325
|
+
})
|
|
238
326
|
}
|
|
239
327
|
}
|
|
240
328
|
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
const u64: U64Field = Object.freeze({ kind: "u64", fresh: freshU64 })
|
|
329
|
+
const u64: U64Field = Object.freeze({ kind: "u64" })
|
|
244
330
|
|
|
245
331
|
const i64: I64Field = Object.freeze({ kind: "i64" })
|
|
246
332
|
|
|
333
|
+
/** Binary64. The native value boundary canonicalizes NaN and signed zero. */
|
|
334
|
+
const f64: F64Field = Object.freeze({ kind: "f64" })
|
|
335
|
+
|
|
336
|
+
/** The application-owned 128-bit identity scalar; no fresh mark exists. */
|
|
337
|
+
const uuid: UuidField = Object.freeze({ kind: "uuid" })
|
|
338
|
+
|
|
247
339
|
const bool: BoolField = Object.freeze({ kind: "bool" })
|
|
248
340
|
|
|
249
341
|
const str: StrField = Object.freeze({ kind: "str" })
|
|
250
342
|
|
|
251
343
|
function bytes<const Width extends number>(width: Width): BytesField<Width> {
|
|
252
344
|
if (!Number.isInteger(width) || width < 1 || width > 64) {
|
|
253
|
-
throw
|
|
345
|
+
throw new AuthoringError({
|
|
346
|
+
message: `bytes width must be an integer in 1..=64 (got ${width}) — the range is pinned at declaration`
|
|
347
|
+
})
|
|
254
348
|
}
|
|
255
349
|
return Object.freeze({ kind: "bytes", width })
|
|
256
350
|
}
|
|
257
351
|
|
|
258
|
-
function interval<Element extends U64Field | I64Field
|
|
352
|
+
function interval<Element extends U64Field | I64Field | F64Field>(
|
|
353
|
+
element: Element
|
|
354
|
+
): IntervalField<Element["kind"], undefined>
|
|
259
355
|
function interval<Element extends U64Field | I64Field, const Width extends bigint>(
|
|
260
356
|
element: Element,
|
|
261
357
|
width: Width
|
|
262
358
|
): IntervalField<Element["kind"], Width>
|
|
263
|
-
function interval(
|
|
359
|
+
function interval(
|
|
360
|
+
element: U64Field | I64Field | F64Field,
|
|
361
|
+
width?: bigint
|
|
362
|
+
): IntervalField<IntervalElementKind, bigint | undefined> {
|
|
264
363
|
const elementKind = element.kind
|
|
265
|
-
if (elementKind !== "u64" && elementKind !== "i64") {
|
|
266
|
-
throw
|
|
364
|
+
if (elementKind !== "u64" && elementKind !== "i64" && elementKind !== "f64") {
|
|
365
|
+
throw new AuthoringError({
|
|
366
|
+
message: `interval element must be the u64, i64 or f64 field constructor (got ${elementKind})`
|
|
367
|
+
})
|
|
368
|
+
}
|
|
369
|
+
if (width !== undefined && elementKind === "f64") {
|
|
370
|
+
throw new AuthoringError({
|
|
371
|
+
message:
|
|
372
|
+
"interval(f64) takes no width — a fixed-width float interval is unrepresentable (rounded start + width is not an exact fixed length on the dense line); applications supply two checked bounds"
|
|
373
|
+
})
|
|
267
374
|
}
|
|
268
375
|
if (width !== undefined && width < 1n) {
|
|
269
|
-
throw
|
|
376
|
+
throw new AuthoringError({
|
|
377
|
+
message: `interval width must be >= 1 (got ${width}) — w >= 1 is pinned at declaration`
|
|
378
|
+
})
|
|
270
379
|
}
|
|
271
380
|
return Object.freeze({ kind: "interval", element: elementKind, width })
|
|
272
381
|
}
|
|
@@ -305,6 +414,18 @@ function literalOf(field: AnyField, value: unknown): LiteralSpec {
|
|
|
305
414
|
}
|
|
306
415
|
return { kind: "value", value: { kind: "string", value } }
|
|
307
416
|
}
|
|
417
|
+
case "f64": {
|
|
418
|
+
if (typeof value !== "number") {
|
|
419
|
+
throw literalShapeError("selection literal", "number", value)
|
|
420
|
+
}
|
|
421
|
+
return { kind: "value", value: { kind: "f64", value } }
|
|
422
|
+
}
|
|
423
|
+
case "uuid": {
|
|
424
|
+
if (!Uuid.isUuid(value)) {
|
|
425
|
+
throw literalShapeError("selection literal", "a UUID (canonical UUID text)", value)
|
|
426
|
+
}
|
|
427
|
+
return { kind: "value", value: { kind: "uuid", value } }
|
|
428
|
+
}
|
|
308
429
|
case "bytes": {
|
|
309
430
|
if (!(value instanceof Uint8Array)) {
|
|
310
431
|
throw literalShapeError("selection literal", "Uint8Array", value)
|
|
@@ -325,22 +446,27 @@ export type {
|
|
|
325
446
|
ClosedHandleTuple,
|
|
326
447
|
ClosedIdField,
|
|
327
448
|
ClosedRoster,
|
|
328
|
-
|
|
449
|
+
F64Field,
|
|
450
|
+
FloatIntervalValue,
|
|
329
451
|
I64Field,
|
|
330
452
|
Infer,
|
|
453
|
+
IntervalElementKind,
|
|
331
454
|
IntervalField,
|
|
332
455
|
IntervalValue,
|
|
333
456
|
SignatureOf,
|
|
334
457
|
StrField,
|
|
335
|
-
U64Field
|
|
458
|
+
U64Field,
|
|
459
|
+
UuidField
|
|
336
460
|
}
|
|
337
461
|
export {
|
|
338
462
|
assertDeclarationOrderKey,
|
|
339
463
|
assertDeclarationRecord,
|
|
340
464
|
bool,
|
|
341
465
|
bytes,
|
|
466
|
+
f64,
|
|
342
467
|
i64,
|
|
343
468
|
interval,
|
|
469
|
+
isFloatIntervalValue,
|
|
344
470
|
isIntervalValue,
|
|
345
471
|
literalOf,
|
|
346
472
|
literalShapeError,
|
|
@@ -349,5 +475,6 @@ export {
|
|
|
349
475
|
signaturesAgree,
|
|
350
476
|
span,
|
|
351
477
|
str,
|
|
352
|
-
u64
|
|
478
|
+
u64,
|
|
479
|
+
uuid
|
|
353
480
|
}
|