@schemic/surrealdb 0.1.0-alpha.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 +21 -0
- package/README.md +103 -0
- package/lib/index.d.ts +1231 -0
- package/lib/index.js +5019 -0
- package/lib/index.js.map +1 -0
- package/package.json +68 -0
- package/src/cli/engine.ts +189 -0
- package/src/cli/introspect.ts +275 -0
- package/src/cli/lower.ts +370 -0
- package/src/cli/pull.ts +1049 -0
- package/src/cli/scaffold.ts +167 -0
- package/src/cli/struct.ts +0 -0
- package/src/cli/structure.ts +696 -0
- package/src/cli/surreal-connect.ts +112 -0
- package/src/cli/surreal-diff.ts +321 -0
- package/src/cli/surreal-filter.ts +67 -0
- package/src/config.ts +94 -0
- package/src/connection.ts +51 -0
- package/src/ddl.ts +931 -0
- package/src/driver/surql-type.ts +191 -0
- package/src/driver/surreal.ts +364 -0
- package/src/index.ts +99 -0
- package/src/kinds/explode.ts +201 -0
- package/src/kinds/portable.ts +116 -0
- package/src/kinds/registry.ts +177 -0
- package/src/pure.ts +2671 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,1231 @@
|
|
|
1
|
+
import { Driver } from '@schemic/core';
|
|
2
|
+
import { BoundQuery, Table, RecordIdValue, RecordId, Bound, RecordIdRange, Uuid, DateTime, Duration, Decimal, FileRef, Geometry, Surreal } from 'surrealdb';
|
|
3
|
+
export { BoundQuery } from 'surrealdb';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { ConnectionConfigBase, ConnectionEntry, ResolveContext } from '@schemic/core/driver';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The "pure" approach: a field is a stock Zod schema + SurrealQL DDL metadata.
|
|
9
|
+
* The JS<->DB mapping rides on Zod's two native channels via codecs:
|
|
10
|
+
* - encoded side (`z.input`) = DB wire type
|
|
11
|
+
* - decoded side (`z.output`) = app type
|
|
12
|
+
* `z.decode` reads from the DB, `z.encode` writes to it.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Maps a Surreal-native schema (datetime codec, recordId) to its SurrealQL type.
|
|
16
|
+
* Kept on the schema — not the field — so it composes through array()/optional()/nesting.
|
|
17
|
+
*/
|
|
18
|
+
declare const surrealTypeRegistry: WeakMap<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, string>;
|
|
19
|
+
/**
|
|
20
|
+
* Maps an object schema built via `s.object` to its original SField shape, so
|
|
21
|
+
* nested fields keep their DDL metadata ($default/$assert/...) during generation.
|
|
22
|
+
*/
|
|
23
|
+
declare const objectFieldsRegistry: WeakMap<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, Record<string, AnyField>>;
|
|
24
|
+
/**
|
|
25
|
+
* Per-table/field row-level permissions. A `PermOp` is one access operation; `Perm` is
|
|
26
|
+
* the rule for one op — `true` (FULL) / `false` (NONE) / a `BoundQuery` (a `WHERE` expr) /
|
|
27
|
+
* `` `same as X` `` to reuse another op's resolved rule. A `TablePermissions` is a blanket
|
|
28
|
+
* rule, a shared `WHERE`, or per-op rules. Fields have NO `delete` op (verified against
|
|
29
|
+
* the DB), so they use `FieldPerm` / `FieldPermissions`.
|
|
30
|
+
*/
|
|
31
|
+
type PermOp = "select" | "create" | "update" | "delete";
|
|
32
|
+
type Perm = boolean | BoundQuery | `same as ${PermOp}`;
|
|
33
|
+
type TablePermissions = boolean | BoundQuery | Partial<Record<PermOp, Perm>>;
|
|
34
|
+
type FieldPerm = boolean | BoundQuery | "same as select" | "same as create" | "same as update";
|
|
35
|
+
type FieldPermissions = boolean | BoundQuery | Partial<Record<"select" | "create" | "update", FieldPerm>>;
|
|
36
|
+
/** SurrealQL DDL metadata — the `$`-prefixed field options. */
|
|
37
|
+
interface SurrealMeta {
|
|
38
|
+
default?: BoundQuery;
|
|
39
|
+
defaultAlways?: boolean;
|
|
40
|
+
value?: BoundQuery;
|
|
41
|
+
/** `COMPUTED <expr>` — a derived, read-only column (computed on read; never written). */
|
|
42
|
+
computed?: BoundQuery;
|
|
43
|
+
/**
|
|
44
|
+
* `ASSERT` fragments that AND-combine into one clause. Computed checks (format
|
|
45
|
+
* builders, `$`-constraints, `.$assert()`-derived) are plain strings; a custom
|
|
46
|
+
* `.$assert(surql\`…\`)` is a `BoundQuery` (inlined during DDL generation).
|
|
47
|
+
*/
|
|
48
|
+
asserts?: (string | BoundQuery)[];
|
|
49
|
+
readonly?: boolean;
|
|
50
|
+
comment?: string;
|
|
51
|
+
/** Field-level `PERMISSIONS` (no `delete` op). Omitted ops default to FULL in
|
|
52
|
+
* SurrealDB — the table is the gate; set an op `false` to lock it. See `.$permissions()`. */
|
|
53
|
+
permissions?: FieldPermissions;
|
|
54
|
+
/** DB-managed, client-hidden: still emits DEFINE FIELD (+ PERMISSIONS NONE) but is
|
|
55
|
+
* excluded from the public app/create/update surface. See `.$internal()` / `.system`. */
|
|
56
|
+
internal?: boolean;
|
|
57
|
+
/** Single-field index: `.index()` (normal) / `.unique()` (uniqueness). Emits a `DEFINE
|
|
58
|
+
* INDEX <table>_<field>_idx ON TABLE <table> FIELDS <field> [UNIQUE]`. */
|
|
59
|
+
index?: {
|
|
60
|
+
unique?: boolean;
|
|
61
|
+
};
|
|
62
|
+
/** `REFERENCE [ON DELETE …]` on a record-link field. See `.reference()`. */
|
|
63
|
+
reference?: true | {
|
|
64
|
+
onDelete?: "reject" | "cascade" | "ignore" | "unset" | BoundQuery;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reverse of {@link formatAssert}: recover a format name from a baked `string::is_<fmt>($value)`
|
|
69
|
+
* assert. Used by `pull` to restore `s.<format>()` instead of `s.string().$assert(...)`. Returns
|
|
70
|
+
* undefined for any other assert — including one that combines a format with extra text — so only an
|
|
71
|
+
* exact, single-format assert reverses (a user's own assert is never swallowed).
|
|
72
|
+
*/
|
|
73
|
+
declare function formatForAssert(assert: string): string | undefined;
|
|
74
|
+
/** The schema one wrapper down — what `unwrap()` returns. */
|
|
75
|
+
type InnerOf<S extends z.ZodType> = S extends z.ZodOptional<infer I extends z.ZodType> ? I : S extends z.ZodNullable<infer I extends z.ZodType> ? I : S extends z.ZodDefault<infer I extends z.ZodType> ? I : S extends z.ZodPrefault<infer I extends z.ZodType> ? I : S extends z.ZodCatch<infer I extends z.ZodType> ? I : S extends z.ZodReadonly<infer I extends z.ZodType> ? I : S extends z.ZodArray<infer I extends z.ZodType> ? I : S;
|
|
76
|
+
/**
|
|
77
|
+
* A Zod schema paired with SurrealQL DDL metadata. `Flags` tracks input traits
|
|
78
|
+
* used by `Create<>`/`Update<>`: `"create"` (DB-filled -> optional on create) and
|
|
79
|
+
* `"readonly"` (excluded from updates). It only appears in method return types, so
|
|
80
|
+
* `SField` is covariant in it.
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* The PORTABLE, dialect-agnostic field base (extraction phase B — see docs/AUTHORING-SPLIT.md).
|
|
84
|
+
* Holds the Zod schema, an opaque per-dialect `native` metadata slot, the field-level codecs, and
|
|
85
|
+
* the App-land Zod wrappers (which carry `native` forward via the `rebuild` hook so a chain keeps
|
|
86
|
+
* its concrete dialect type). It references NOTHING SurrealDB-specific. Each dialect subclasses it
|
|
87
|
+
* (see {@link SField} for SurrealDB) to add native authoring (`$`-methods) and re-type the wrappers.
|
|
88
|
+
*/
|
|
89
|
+
declare abstract class SFieldBase<S extends z.ZodType = z.ZodType, Flags extends string = never, N = unknown> {
|
|
90
|
+
readonly schema: S;
|
|
91
|
+
readonly native: N;
|
|
92
|
+
constructor(schema: S, native: N);
|
|
93
|
+
/** Rebuild a sibling field of the SAME dialect with a new schema/flags. Each dialect overrides it. */
|
|
94
|
+
protected abstract rebuild<S2 extends z.ZodType, F2 extends string>(schema: S2, native: N): SFieldBase<S2, F2, N>;
|
|
95
|
+
/** A fresh, empty native-metadata bag (for wrappers like `or`/`and` that reset it). */
|
|
96
|
+
protected abstract blank(): N;
|
|
97
|
+
/** Decode a DB value to its app type (wire -> app). */
|
|
98
|
+
decode(value: unknown): z.output<S>;
|
|
99
|
+
/** Encode an app value to its DB wire type (app -> wire). */
|
|
100
|
+
encode(value: z.output<S>): z.input<S>;
|
|
101
|
+
decodeAsync(value: unknown): Promise<z.output<S>>;
|
|
102
|
+
encodeAsync(value: z.output<S>): Promise<z.input<S>>;
|
|
103
|
+
safeDecode(value: unknown): z.ZodSafeParseResult<z.core.output<S>>;
|
|
104
|
+
safeEncode(value: z.output<S>): z.ZodSafeParseResult<z.core.input<S>>;
|
|
105
|
+
safeDecodeAsync(value: unknown): Promise<z.ZodSafeParseResult<z.core.output<S>>>;
|
|
106
|
+
safeEncodeAsync(value: z.output<S>): Promise<z.ZodSafeParseResult<z.core.input<S>>>;
|
|
107
|
+
/** @deprecated `parse` decodes a value (wire -> app). Use {@link SField.decode | decode}. */
|
|
108
|
+
parse(value: unknown): z.output<S>;
|
|
109
|
+
/** @deprecated Use {@link SField.safeDecode | safeDecode}. */
|
|
110
|
+
safeParse(value: unknown): z.ZodSafeParseResult<z.core.output<S>>;
|
|
111
|
+
/** @deprecated Use {@link SField.decodeAsync | decodeAsync}. */
|
|
112
|
+
parseAsync(value: unknown): Promise<z.output<S>>;
|
|
113
|
+
/** @deprecated Use {@link SField.safeDecodeAsync | safeDecodeAsync}. */
|
|
114
|
+
safeParseAsync(value: unknown): Promise<z.ZodSafeParseResult<z.core.output<S>>>;
|
|
115
|
+
optional(): SFieldBase<z.ZodOptional<S>, Flags, N>;
|
|
116
|
+
nullable(): SFieldBase<z.ZodNullable<S>, Flags, N>;
|
|
117
|
+
default(value: z.input<S>): SFieldBase<z.ZodDefault<S>, Flags, N>;
|
|
118
|
+
/** Zod prefault: fill an absent value with `value`, then validate it (unlike `.default`). */
|
|
119
|
+
prefault(value: z.input<S>): SFieldBase<z.ZodPrefault<S>, Flags, N>;
|
|
120
|
+
/** Zod catch: fall back to `value` when parsing fails. */
|
|
121
|
+
catch(value: z.output<S>): SFieldBase<z.ZodCatch<S>, Flags, N>;
|
|
122
|
+
array(): SFieldBase<z.ZodArray<S>, Flags, N>;
|
|
123
|
+
nullish(): SFieldBase<z.ZodOptional<z.ZodNullable<S>>, Flags, N>;
|
|
124
|
+
/** Zod union — `a.or(b)` accepts either; SurrealQL `<a> | <b>`. Mirrors Zod's `.or()`. */
|
|
125
|
+
or<F extends AnyField | z.ZodType>(other: F): SFieldBase<z.ZodUnion<[S, SchemaOf<F>]>, never, N>;
|
|
126
|
+
/** Zod intersection — `a.and(b)`; merges object fields in DDL. Mirrors Zod's `.and()`. */
|
|
127
|
+
and<F extends AnyField | z.ZodType>(other: F): SFieldBase<z.ZodIntersection<S, SchemaOf<F>>, never, N>;
|
|
128
|
+
refine(check: (arg: z.output<S>) => unknown, params?: string | z.core.$ZodCustomParams): this;
|
|
129
|
+
superRefine(refinement: (arg: z.output<S>, ctx: z.core.$RefinementCtx<z.output<S>>) => void): this;
|
|
130
|
+
check(...checks: (z.core.CheckFn<z.output<S>> | z.core.$ZodCheck<z.output<S>>)[]): this;
|
|
131
|
+
overwrite(fn: (x: z.output<S>) => z.output<S>): this;
|
|
132
|
+
brand<B extends PropertyKey = PropertyKey>(value?: B): this;
|
|
133
|
+
/** Zod's app-side metadata (JSON-schema/docs) — distinct from `$comment()` (SurrealDB COMMENT). */
|
|
134
|
+
describe(description: string): this;
|
|
135
|
+
meta(data: z.core.GlobalMeta): this;
|
|
136
|
+
/** Zod's app-side readonly (TS-immutable output) — distinct from `$readonly()` (SurrealDB READONLY). */
|
|
137
|
+
readonly(): SFieldBase<z.ZodReadonly<S>, Flags, N>;
|
|
138
|
+
/** Zod transform — changes the decoded `App<>` value; the stored (wire) type is unchanged. */
|
|
139
|
+
transform<NewOut>(fn: (arg: z.output<S>, ctx: z.core.$RefinementCtx<z.output<S>>) => NewOut): SFieldBase<z.ZodPipe<S, z.ZodTransform<Awaited<NewOut>, z.output<S>>>, Flags, N>;
|
|
140
|
+
/** Zod pipe — feed this field's output into `target`; the stored (wire) type stays `this`. */
|
|
141
|
+
pipe<T extends z.core.$ZodType<unknown, z.output<S>>>(target: T): SFieldBase<z.ZodPipe<S, T>, Flags, N>;
|
|
142
|
+
/** Peel one wrapper (optional/nullable/default/prefault/catch/readonly/array) off the field. */
|
|
143
|
+
unwrap(): SFieldBase<InnerOf<S>, Flags, N>;
|
|
144
|
+
/** Object-only: allow arbitrary extra keys — `FLEXIBLE` in DDL. Mirrors Zod's `.loose()`. */
|
|
145
|
+
loose(): this;
|
|
146
|
+
/** Object-only: reject unknown keys — non-`FLEXIBLE` (the default). Mirrors Zod's `.strict()`. */
|
|
147
|
+
strict(): this;
|
|
148
|
+
/** Alias for {@link loose} — a `FLEXIBLE` object accepting arbitrary keys. */
|
|
149
|
+
flexible(): this;
|
|
150
|
+
private objectMode;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The SurrealDB field — the dialect extension of {@link SFieldBase}. Adds SurrealDB-native authoring
|
|
154
|
+
* (the `$`-methods over `SurrealMeta`: DEFAULT/VALUE/ASSERT/PERMISSIONS/REFERENCE/…) and re-types the
|
|
155
|
+
* inherited portable Zod wrappers so a chain stays a `SField`. `s.*` produces these. In the package
|
|
156
|
+
* split this class moves to `@schemic/surrealdb` (see docs/AUTHORING-SPLIT.md).
|
|
157
|
+
*/
|
|
158
|
+
declare class SField<S extends z.ZodType = z.ZodType, Flags extends string = never> extends SFieldBase<S, Flags, SurrealMeta> {
|
|
159
|
+
constructor(schema: S, surreal?: SurrealMeta);
|
|
160
|
+
/** The SurrealDB-native field metadata (DEFAULT/VALUE/ASSERT/PERMISSIONS/…). */
|
|
161
|
+
get surreal(): SurrealMeta;
|
|
162
|
+
protected rebuild<S2 extends z.ZodType, F2 extends string>(schema: S2, native: SurrealMeta): SField<S2, F2>;
|
|
163
|
+
protected blank(): SurrealMeta;
|
|
164
|
+
optional(): SField<z.ZodOptional<S>, Flags>;
|
|
165
|
+
nullable(): SField<z.ZodNullable<S>, Flags>;
|
|
166
|
+
default(value: z.input<S>): SField<z.ZodDefault<S>, Flags>;
|
|
167
|
+
prefault(value: z.input<S>): SField<z.ZodPrefault<S>, Flags>;
|
|
168
|
+
catch(value: z.output<S>): SField<z.ZodCatch<S>, Flags>;
|
|
169
|
+
array(): SField<z.ZodArray<S>, Flags>;
|
|
170
|
+
nullish(): SField<z.ZodOptional<z.ZodNullable<S>>, Flags>;
|
|
171
|
+
or<F extends AnyField | z.ZodType>(other: F): SField<z.ZodUnion<[S, SchemaOf<F>]>>;
|
|
172
|
+
and<F extends AnyField | z.ZodType>(other: F): SField<z.ZodIntersection<S, SchemaOf<F>>>;
|
|
173
|
+
readonly(): SField<z.ZodReadonly<S>, Flags>;
|
|
174
|
+
transform<NewOut>(fn: (arg: z.output<S>, ctx: z.core.$RefinementCtx<z.output<S>>) => NewOut): SField<z.ZodPipe<S, z.ZodTransform<Awaited<NewOut>, z.output<S>>>, Flags>;
|
|
175
|
+
pipe<T extends z.core.$ZodType<unknown, z.output<S>>>(target: T): SField<z.ZodPipe<S, T>, Flags>;
|
|
176
|
+
unwrap(): SField<InnerOf<S>, Flags>;
|
|
177
|
+
$default(value: z.output<S> | BoundQuery): SField<S, Flags | "create">;
|
|
178
|
+
$defaultAlways(value: z.output<S> | BoundQuery): SField<S, Flags | "create">;
|
|
179
|
+
/**
|
|
180
|
+
* Set a DB-side `VALUE` clause. Whether the field is create-OPTIONAL depends on
|
|
181
|
+
* whether the expression consumes the client input (`$value`), which can't be
|
|
182
|
+
* inferred — so it's explicit via the `optional` option:
|
|
183
|
+
* - `time::now()` ignores input -> `{ optional: true }` (create-optional)
|
|
184
|
+
* - `string::lowercase($value)` requires input -> default (create-required)
|
|
185
|
+
* Optionality is purely type-level (the option drives the `"create"` flag that
|
|
186
|
+
* `Create<>`/`encode()` read); it does not touch the app type or DB nullability.
|
|
187
|
+
* There is no separate update option — every field is already optional in `Update<>`.
|
|
188
|
+
*/
|
|
189
|
+
$value<O extends boolean = false>(expr: BoundQuery, opts?: {
|
|
190
|
+
optional?: O;
|
|
191
|
+
}): SField<S, O extends true ? Flags | "create" : Flags>;
|
|
192
|
+
/**
|
|
193
|
+
* `COMPUTED <expr>` — a derived, read-only column computed from other fields. Never written, so
|
|
194
|
+
* it's create-OPTIONAL: `s.string().$computed(surql\`string::concat(first, " ", last)\`)`.
|
|
195
|
+
*/
|
|
196
|
+
$computed(expr: BoundQuery): SField<S, Flags | "create">;
|
|
197
|
+
/**
|
|
198
|
+
* Add an `ASSERT` fragment (fragments AND-combine into one clause):
|
|
199
|
+
* - `.$assert(surql\`…\`)` pushes a custom expression (inlined during DDL generation).
|
|
200
|
+
* - `.$assert()` (no args) derives fragments from the field's existing Zod checks
|
|
201
|
+
* (formats, string length/regex, number bounds) — best-effort; unknowns are skipped.
|
|
202
|
+
*/
|
|
203
|
+
$assert(expr?: BoundQuery): SField<S, Flags>;
|
|
204
|
+
/** Min length (string) / minimum value (number). */
|
|
205
|
+
$min(n: number): SField<S, Flags>;
|
|
206
|
+
/** Max length (string) / maximum value (number). */
|
|
207
|
+
$max(n: number): SField<S, Flags>;
|
|
208
|
+
/** Exact length (string). */
|
|
209
|
+
$length(n: number): SField<S, Flags>;
|
|
210
|
+
/** Pattern match (string). */
|
|
211
|
+
$regex(re: RegExp): SField<S, Flags>;
|
|
212
|
+
/** Greater than (number). */
|
|
213
|
+
$gt(n: number): SField<S, Flags>;
|
|
214
|
+
/** Greater than or equal (number). */
|
|
215
|
+
$gte(n: number): SField<S, Flags>;
|
|
216
|
+
/** Less than (number). */
|
|
217
|
+
$lt(n: number): SField<S, Flags>;
|
|
218
|
+
/** Less than or equal (number). */
|
|
219
|
+
$lte(n: number): SField<S, Flags>;
|
|
220
|
+
/** The underlying Zod schema's `def.type` ("string" / "number" / …). */
|
|
221
|
+
private get schemaType();
|
|
222
|
+
/** Append ASSERT fragments, returning a new field (same type param + flags). */
|
|
223
|
+
private pushAsserts;
|
|
224
|
+
/** Apply a concrete-subtype Zod check (`min`/`max`/`length`/`regex`/`gt`/…) and push its
|
|
225
|
+
* matching DB fragment, returning a new field carrying the refined schema. */
|
|
226
|
+
private constrain;
|
|
227
|
+
/** Set field-level `PERMISSIONS` (no `delete` op). Omitted ops default to FULL. */
|
|
228
|
+
$permissions(spec: FieldPermissions): SField<S, Flags>;
|
|
229
|
+
$readonly(readonly?: boolean): SField<S, Flags | "readonly">;
|
|
230
|
+
$comment(comment: string): SField<S, Flags>;
|
|
231
|
+
/** Index this field — `DEFINE INDEX <table>_<field>_idx ON TABLE <table> FIELDS <field>`. */
|
|
232
|
+
index(): SField<S, Flags>;
|
|
233
|
+
/** Index this field with a uniqueness constraint (`… FIELDS <field> UNIQUE`). */
|
|
234
|
+
unique(): SField<S, Flags>;
|
|
235
|
+
/**
|
|
236
|
+
* Mark a record-link field as a `REFERENCE` so the DB tracks back-links. `onDelete` sets the
|
|
237
|
+
* `ON DELETE` action — `"reject" | "cascade" | "ignore" | "unset"`, or a `surql` expression
|
|
238
|
+
* (emitted as `ON DELETE THEN …`). Omit it for a bare `REFERENCE`.
|
|
239
|
+
*/
|
|
240
|
+
reference(opts?: {
|
|
241
|
+
onDelete?: "reject" | "cascade" | "ignore" | "unset" | BoundQuery;
|
|
242
|
+
}): SField<S, Flags>;
|
|
243
|
+
/**
|
|
244
|
+
* Teach @schemic/core how to store this value in SurrealDB: give the **wire type** as an `s.*`
|
|
245
|
+
* field (its SurrealQL DDL type and Zod schema are derived from it) plus a codec
|
|
246
|
+
* (`encode`: app -> wire, `decode`: wire -> app). This turns an otherwise-unmappable field
|
|
247
|
+
* (e.g. `s.custom`/`s.instanceof`) into a real table field and clears the no-mapping brand;
|
|
248
|
+
* `s.input<>` then reports the wire type. Omit the codec for an identity mapping (the app
|
|
249
|
+
* value is stored as-is). `$`-prefixed to avoid clashing with Zod.
|
|
250
|
+
*/
|
|
251
|
+
$surreal<WF extends AnyField | z.ZodType, A = z.output<S>>(wire: WF, codec?: {
|
|
252
|
+
encode: (app: A) => z.output<SchemaOf<WF>>;
|
|
253
|
+
decode: (wire: z.output<SchemaOf<WF>>) => A;
|
|
254
|
+
}): SField<z.ZodCodec<SchemaOf<WF>, S>, Exclude<Flags, NoDdl>>;
|
|
255
|
+
/**
|
|
256
|
+
* Mark the field DB-managed and client-hidden. It still emits its `DEFINE FIELD`
|
|
257
|
+
* (so SCHEMAFULL writes from a record-access SIGNUP block succeed) plus
|
|
258
|
+
* `PERMISSIONS NONE`, but is excluded from the public app/create/update surface.
|
|
259
|
+
* Reach internal fields via the `.system` view (server/system code).
|
|
260
|
+
*/
|
|
261
|
+
$internal(): SField<S, Flags | "internal">;
|
|
262
|
+
}
|
|
263
|
+
/** A flag-agnostic SField, for internal storage where flags don't matter. */
|
|
264
|
+
type AnyField = SField<z.ZodType, string>;
|
|
265
|
+
type GeometryKind = "point" | "line" | "polygon" | "multipoint" | "multiline" | "multipolygon" | "collection";
|
|
266
|
+
/** A `record<…>` field: table restriction (+ optional id-value type) and construction helpers. */
|
|
267
|
+
declare class RecordIdField<T extends string, V extends RecordIdValue = RecordIdValue> extends SField<z.ZodType<RecordId<T, V>, RecordId<T, V>>> {
|
|
268
|
+
readonly tables: T[];
|
|
269
|
+
readonly valueType?: z.ZodType<V> | undefined;
|
|
270
|
+
constructor(tables: T[], valueType?: z.ZodType<V> | undefined, surreal?: SurrealMeta, schemaOverride?: z.ZodType<RecordId<T, V>, RecordId<T, V>>);
|
|
271
|
+
protected rebuild<S2 extends z.ZodType, F2 extends string>(schema: S2, native: SurrealMeta): SField<S2, F2>;
|
|
272
|
+
/** Restrict the id value's type — reflected as `RecordId<T, V>` and validated at runtime. */
|
|
273
|
+
type<V2 extends RecordIdValue>(schema: z.ZodType<V2>): RecordIdField<T, V2>;
|
|
274
|
+
/** Build a RecordId. Single-table: `for(id)`; multi-table: `for(table, id)`. */
|
|
275
|
+
for(idOrTable: V | T, id?: V): RecordId<T, V>;
|
|
276
|
+
/** A record-id range for queries (default: inclusive start .. exclusive end). */
|
|
277
|
+
range(from?: V | Bound<V>, to?: V | Bound<V>): RecordIdRange<T, V>;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Internal `Flags` brand for a field with no SurrealQL mapping. It rides the `Flags` channel,
|
|
281
|
+
* so it survives every wrapper (`.optional()`/`.array()`/…); `defineTable`/`defineRelation`
|
|
282
|
+
* reject a branded field at compile time, and `.$surreal(...)` clears it. (Runtime `inferField`
|
|
283
|
+
* is the backstop for nested/dynamic shapes.)
|
|
284
|
+
*/
|
|
285
|
+
type NoDdl = "~no-ddl";
|
|
286
|
+
type ZodsOf<T extends readonly (AnyField | z.ZodType)[]> = {
|
|
287
|
+
-readonly [K in keyof T]: SchemaOf<T[K]>;
|
|
288
|
+
};
|
|
289
|
+
type Shape = Record<string, AnyField | z.ZodType>;
|
|
290
|
+
type SchemaOf<F> = F extends SField<infer S, infer _> ? S : F extends z.ZodType ? F : never;
|
|
291
|
+
type FlagsOf<F> = F extends SField<z.ZodType, infer Fl> ? Fl : never;
|
|
292
|
+
/**
|
|
293
|
+
* Whether a field carries the `"internal"` flag (set by `.$internal()`). The
|
|
294
|
+
* `string extends FlagsOf<F>` guard short-circuits the broad `Shape` case (where
|
|
295
|
+
* flags widen to `string`, and `"internal" extends string` would wrongly be true),
|
|
296
|
+
* so `ZShape<Shape>` keeps every key for shape-agnostic refs like `TableDef<string, Shape>`.
|
|
297
|
+
*/
|
|
298
|
+
type IsInternal<F> = string extends FlagsOf<F> ? false : "internal" extends FlagsOf<F> ? true : false;
|
|
299
|
+
/** The public zshape — internal fields are excluded (see `ZShapeAll` for the system view). */
|
|
300
|
+
type ZShape<S extends Shape> = {
|
|
301
|
+
[K in keyof S as IsInternal<S[K]> extends true ? never : K]: SchemaOf<S[K]>;
|
|
302
|
+
};
|
|
303
|
+
/** Every field's zshape, including internal ones — backs the `.system` view. */
|
|
304
|
+
type ZShapeAll<S extends Shape> = {
|
|
305
|
+
[K in keyof S]: SchemaOf<S[K]>;
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* The schema type returned by `s.object`: a plain `z.ZodObject` carrying its original
|
|
309
|
+
* `Shape` via a type-only `~szShape` brand. The brand is optional, so the runtime cast
|
|
310
|
+
* (`z.object(...) as SZObject<S>`) is sound and the brand is invisible to `z.input`/
|
|
311
|
+
* `z.output`/`App`/`Wire` — nested fields stay REQUIRED on the decoded side. It exists
|
|
312
|
+
* solely so `ShapeOf`/`CreateValue` can recover the nested shape for the create surface.
|
|
313
|
+
*/
|
|
314
|
+
type SZObject<S extends Shape> = z.ZodObject<ZShape<S>> & {
|
|
315
|
+
readonly "~szShape"?: S;
|
|
316
|
+
};
|
|
317
|
+
type ToField<F> = F extends SField<infer Sc, infer Fl> ? SField<Sc, Fl> : SField<SchemaOf<F>>;
|
|
318
|
+
type Fields<S extends Shape> = {
|
|
319
|
+
[K in keyof S]: ToField<S[K]>;
|
|
320
|
+
};
|
|
321
|
+
type Unwrap<F> = F extends SField<z.ZodOptional<infer Inner extends z.ZodType>, infer Fl> ? SField<Inner, Fl> : F;
|
|
322
|
+
type PartialShape<S extends Shape> = {
|
|
323
|
+
[K in keyof S]: SField<z.ZodOptional<SchemaOf<S[K]>>, FlagsOf<S[K]>>;
|
|
324
|
+
};
|
|
325
|
+
type RequiredShape<S extends Shape> = {
|
|
326
|
+
[K in keyof S]: Unwrap<Fields<S>[K]>;
|
|
327
|
+
};
|
|
328
|
+
interface TableConfig {
|
|
329
|
+
schemafull: boolean;
|
|
330
|
+
/** Table `TYPE`: `normal` (default) or `any` (holds both records and graph edges). */
|
|
331
|
+
type?: "normal" | "any";
|
|
332
|
+
drop?: boolean;
|
|
333
|
+
comment?: string;
|
|
334
|
+
/** Table-level `PERMISSIONS`. Omitted ops default to NONE in SurrealDB. See `.permissions()`. */
|
|
335
|
+
permissions?: TablePermissions;
|
|
336
|
+
relation?: {
|
|
337
|
+
from: string[];
|
|
338
|
+
to: string[];
|
|
339
|
+
enforced?: boolean;
|
|
340
|
+
};
|
|
341
|
+
/** Composite (multi-field) indexes. See `.index(name, fields, opts)`. */
|
|
342
|
+
indexes?: TableIndex[];
|
|
343
|
+
/** Row-change events. See `.event(name, { when?, then })`. */
|
|
344
|
+
events?: TableEvent[];
|
|
345
|
+
/** `CHANGEFEED <dur> [INCLUDE ORIGINAL]`. See `.changefeed(dur, opts?)`. */
|
|
346
|
+
changefeed?: {
|
|
347
|
+
expiry: string;
|
|
348
|
+
includeOriginal?: boolean;
|
|
349
|
+
};
|
|
350
|
+
/**
|
|
351
|
+
* A pre-computed (materialized) VIEW — `AS <SELECT …>`. When set, the table is computed from the
|
|
352
|
+
* query (forced `TYPE ANY SCHEMALESS`, no authored fields). See {@link defineView}.
|
|
353
|
+
*/
|
|
354
|
+
view?: Expr;
|
|
355
|
+
}
|
|
356
|
+
/** A table index definition (single- or multi-field, or a row-count index). */
|
|
357
|
+
interface TableIndex {
|
|
358
|
+
name: string;
|
|
359
|
+
fields: string[];
|
|
360
|
+
unique?: boolean;
|
|
361
|
+
/** A materialized row-count index (`DEFINE INDEX … COUNT`, no fields). */
|
|
362
|
+
count?: boolean;
|
|
363
|
+
/** `COMMENT <string>` on the index. */
|
|
364
|
+
comment?: string;
|
|
365
|
+
/**
|
|
366
|
+
* A special index spec appended after `FIELDS` — a vector (`HNSW …`/`DISKANN …`) or full-text
|
|
367
|
+
* (`FULLTEXT ANALYZER …`) index. Built from the `.index()` opts; minimal form (SurrealDB
|
|
368
|
+
* materializes the rest), so it round-trips against the introspected, canonicalized spec.
|
|
369
|
+
*/
|
|
370
|
+
spec?: string;
|
|
371
|
+
}
|
|
372
|
+
/** Options for a HNSW vector index (`.index(name, [field], { hnsw: {…} })`). */
|
|
373
|
+
interface HnswOptions {
|
|
374
|
+
dimension: number;
|
|
375
|
+
dist?: "euclidean" | "cosine" | "manhattan" | "minkowski" | "hamming";
|
|
376
|
+
type?: "f64" | "f32" | "i64" | "i32" | "i16";
|
|
377
|
+
efc?: number;
|
|
378
|
+
m?: number;
|
|
379
|
+
}
|
|
380
|
+
/** Options for a DISKANN vector index (`.index(name, [field], { diskann: {…} })`). */
|
|
381
|
+
interface DiskannOptions {
|
|
382
|
+
dimension: number;
|
|
383
|
+
dist?: "euclidean" | "cosine" | "manhattan";
|
|
384
|
+
type?: "f64" | "f32" | "i64" | "i32" | "i16";
|
|
385
|
+
degree?: number;
|
|
386
|
+
l_build?: number;
|
|
387
|
+
alpha?: number;
|
|
388
|
+
}
|
|
389
|
+
/** Options for a FULL-TEXT search index (`.index(name, [field], { fulltext: {…} })`). Needs a
|
|
390
|
+
* `defineAnalyzer` of the same name. `bm25: [k1, b]` tunes scoring; `true` uses the defaults. */
|
|
391
|
+
interface FulltextOptions {
|
|
392
|
+
analyzer: string;
|
|
393
|
+
bm25?: boolean | [number, number];
|
|
394
|
+
highlights?: boolean;
|
|
395
|
+
}
|
|
396
|
+
/** A SurrealQL expression: a `surql\`…\`` bound query (bindings inlined) or a raw string. */
|
|
397
|
+
type Expr = BoundQuery | string;
|
|
398
|
+
/**
|
|
399
|
+
* A table event: `DEFINE EVENT <name> ON TABLE <table> [WHEN <when>] THEN <then>`. The event
|
|
400
|
+
* body sees `$before`/`$after`/`$event`/`$value`. `then` may be one expression or several
|
|
401
|
+
* (run in order). Author expressions with `surql\`…\`` (bindings inline) or a raw string.
|
|
402
|
+
*/
|
|
403
|
+
interface TableEvent {
|
|
404
|
+
name: string;
|
|
405
|
+
when?: Expr;
|
|
406
|
+
then: Expr | Expr[];
|
|
407
|
+
}
|
|
408
|
+
type Prettify<T> = {
|
|
409
|
+
[K in keyof T]: T[K];
|
|
410
|
+
} & {};
|
|
411
|
+
type AppOf<F> = z.output<SchemaOf<F>>;
|
|
412
|
+
type InputOptional<F> = undefined extends z.input<SchemaOf<F>> ? true : false;
|
|
413
|
+
/**
|
|
414
|
+
* Recover the nested `Shape` of an `s.object` schema (`never` if the schema isn't one).
|
|
415
|
+
* Identity-preserving wrappers (optional/default/readonly/nullable) are peeled first, then
|
|
416
|
+
* the `~szShape` brand is read. The inner `NS extends Shape ? NS : never` drops the
|
|
417
|
+
* `| undefined` that inferring from an optional property can introduce, so the result is the
|
|
418
|
+
* clean shape — or `never` for any non-object schema.
|
|
419
|
+
*/
|
|
420
|
+
type ShapeOf<Sc> = Sc extends z.ZodOptional<infer I> ? ShapeOf<I> : Sc extends z.ZodDefault<infer I> ? ShapeOf<I> : Sc extends z.ZodReadonly<infer I> ? ShapeOf<I> : Sc extends z.ZodNullable<infer I> ? ShapeOf<I> : Sc extends {
|
|
421
|
+
"~szShape"?: infer NS;
|
|
422
|
+
} ? NS extends Shape ? NS : never : never;
|
|
423
|
+
/**
|
|
424
|
+
* The element `Shape` of an `s.object(...).array()` field (`never` otherwise). Peels the
|
|
425
|
+
* same identity-preserving wrappers off the array, then reads the element's `~szShape`.
|
|
426
|
+
*/
|
|
427
|
+
type ArrayShapeOf<Sc> = Sc extends z.ZodOptional<infer I> ? ArrayShapeOf<I> : Sc extends z.ZodDefault<infer I> ? ArrayShapeOf<I> : Sc extends z.ZodReadonly<infer I> ? ArrayShapeOf<I> : Sc extends z.ZodNullable<infer I> ? ArrayShapeOf<I> : Sc extends z.ZodArray<infer E> ? ShapeOf<E> : never;
|
|
428
|
+
/**
|
|
429
|
+
* The create-input VALUE type for a field. A nested `s.object` recurses into its own
|
|
430
|
+
* `CreateShape` (so nested `$default`/`"create"` fields become optional too); an array of
|
|
431
|
+
* `s.object` becomes that nested create-shape's array; everything else is the plain app
|
|
432
|
+
* type (`AppOf`). `[X] extends [never]` guards each branch because `never extends Shape` is
|
|
433
|
+
* vacuously true and would otherwise wrongly match the object branch for scalar fields.
|
|
434
|
+
*/
|
|
435
|
+
type CreateValue<F, Sc = SchemaOf<F>> = [ShapeOf<Sc>] extends [never] ? [ArrayShapeOf<Sc>] extends [never] ? AppOf<F> : ArrayShapeOf<Sc> extends infer ENS extends Shape ? CreateShape<ENS>[] : AppOf<F> : ShapeOf<Sc> extends infer NS extends Shape ? CreateShape<NS> : AppOf<F>;
|
|
436
|
+
type CreateOptional<S extends Shape, K extends keyof S> = K extends "id" ? true : "create" extends FlagsOf<S[K]> ? true : InputOptional<S[K]>;
|
|
437
|
+
type CreateShape<S extends Shape> = Prettify<{
|
|
438
|
+
[K in keyof S as IsInternal<S[K]> extends true ? never : CreateOptional<S, K> extends true ? never : K]: CreateValue<S[K]>;
|
|
439
|
+
} & {
|
|
440
|
+
[K in keyof S as IsInternal<S[K]> extends true ? never : CreateOptional<S, K> extends true ? K : never]?: CreateValue<S[K]>;
|
|
441
|
+
}>;
|
|
442
|
+
type CreateShapeAll<S extends Shape> = Prettify<{
|
|
443
|
+
[K in keyof S as CreateOptional<S, K> extends true ? never : K]: CreateValue<S[K]>;
|
|
444
|
+
} & {
|
|
445
|
+
[K in keyof S as CreateOptional<S, K> extends true ? K : never]?: CreateValue<S[K]>;
|
|
446
|
+
}>;
|
|
447
|
+
type UpdateExcluded<S extends Shape, K extends keyof S> = K extends "id" ? true : "readonly" extends FlagsOf<S[K]> ? true : false;
|
|
448
|
+
/**
|
|
449
|
+
* The update-input VALUE type for a field — a DEEP partial, since `MERGE` recursively
|
|
450
|
+
* deep-merges nested objects (so any subset of nested keys is a valid patch). A nested
|
|
451
|
+
* `s.object` recurses into its own `UpdateShape` (every nested field optional); an array
|
|
452
|
+
* of `s.object` becomes that update-shape's array; everything else is the plain app type
|
|
453
|
+
* (`AppOf`). The `[X] extends [never]` guards mirror `CreateValue` (so scalar fields don't
|
|
454
|
+
* wrongly match the object branch via `never extends Shape`).
|
|
455
|
+
*/
|
|
456
|
+
type UpdateValue<F, Sc = SchemaOf<F>> = [ShapeOf<Sc>] extends [never] ? [ArrayShapeOf<Sc>] extends [never] ? AppOf<F> : ArrayShapeOf<Sc> extends infer ENS extends Shape ? UpdateShape<ENS>[] : AppOf<F> : ShapeOf<Sc> extends infer NS extends Shape ? UpdateShape<NS> : AppOf<F>;
|
|
457
|
+
type UpdateShape<S extends Shape> = Prettify<{
|
|
458
|
+
[K in keyof S as IsInternal<S[K]> extends true ? never : UpdateExcluded<S, K> extends true ? never : K]?: UpdateValue<S[K]>;
|
|
459
|
+
}>;
|
|
460
|
+
type UpdateShapeAll<S extends Shape> = Prettify<{
|
|
461
|
+
[K in keyof S as UpdateExcluded<S, K> extends true ? never : K]?: UpdateValue<S[K]>;
|
|
462
|
+
}>;
|
|
463
|
+
/** A Zod-style non-throwing result: `{ success: true; data }` | `{ success: false; error }`
|
|
464
|
+
* (mirrors `z.safeEncode`/`z.safeDecode`). */
|
|
465
|
+
type SafeResult<T> = z.ZodSafeParseResult<T>;
|
|
466
|
+
/** The wire payload `encode`/`safeEncode` build: the provided keys' wire (`z.input`) types. Only
|
|
467
|
+
* the supplied keys are present at runtime, hence `Partial`. */
|
|
468
|
+
type MakeWire<S extends Shape> = Partial<z.input<z.ZodObject<ZShape<S>>>>;
|
|
469
|
+
/** Same, over ALL fields — the `.system` view includes `$internal()` ones. */
|
|
470
|
+
type MakeWireAll<S extends Shape> = Partial<z.input<z.ZodObject<ZShapeAll<S>>>>;
|
|
471
|
+
/** A table (or relation) definition: shape + DDL config, with chainable builders. */
|
|
472
|
+
declare class TableDef<Name extends string, S extends Shape> {
|
|
473
|
+
readonly name: Name;
|
|
474
|
+
readonly fields: Fields<S>;
|
|
475
|
+
readonly config: TableConfig;
|
|
476
|
+
/** Zod object over the inner schemas — drives validation, encode/decode, types. */
|
|
477
|
+
readonly object: z.ZodObject<ZShape<S>>;
|
|
478
|
+
constructor(name: Name, fields: Fields<S>, config?: TableConfig);
|
|
479
|
+
get kind(): "table" | "relation";
|
|
480
|
+
/**
|
|
481
|
+
* A SurrealDB `Table` instance for this table — for direct SDK calls that take a table reference,
|
|
482
|
+
* e.g. `db.select(User.table)`. (For a record id, chain `User.record().for(id)`.)
|
|
483
|
+
*/
|
|
484
|
+
get table(): Table<Name>;
|
|
485
|
+
/** DB wire row -> app object. */
|
|
486
|
+
decode(row: unknown): z.output<z.ZodObject<ZShape<S>>>;
|
|
487
|
+
/** DB wire row -> app object (async — for async refinements). */
|
|
488
|
+
decodeAsync(row: unknown): Promise<z.output<z.ZodObject<ZShape<S>>>>;
|
|
489
|
+
safeDecode(row: unknown): z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShape<S>, {}>>;
|
|
490
|
+
safeDecodeAsync(row: unknown): Promise<z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShape<S>, {}>>>;
|
|
491
|
+
/** @deprecated `parse` decodes a DB row (wire -> app). Use {@link TableDef.decode | decode}. */
|
|
492
|
+
parse(row: unknown): z.output<z.ZodObject<ZShape<S>>>;
|
|
493
|
+
/** @deprecated Use {@link TableDef.safeDecode | safeDecode} (or {@link TableDef.safeEncode | safeEncode} to validate an app object). */
|
|
494
|
+
safeParse(row: unknown): z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShape<S>, {}>>;
|
|
495
|
+
/** @deprecated Use {@link TableDef.decodeAsync | decodeAsync}. */
|
|
496
|
+
parseAsync(row: unknown): Promise<z.output<z.ZodObject<ZShape<S>>>>;
|
|
497
|
+
/** @deprecated Use {@link TableDef.safeDecodeAsync | safeDecodeAsync}. */
|
|
498
|
+
safeParseAsync(row: unknown): Promise<z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShape<S>, {}>>>;
|
|
499
|
+
/**
|
|
500
|
+
* Build a wire payload for `CREATE` (DB-filled fields optional). Validates+encodes each
|
|
501
|
+
* provided field — so this VALIDATES and THROWS the aggregated `z.ZodError` on invalid
|
|
502
|
+
* input. Use `safeEncode` for the non-throwing form.
|
|
503
|
+
*/
|
|
504
|
+
encode(input: CreateShape<S>): MakeWire<S>;
|
|
505
|
+
/**
|
|
506
|
+
* Build a wire payload for `UPDATE`/`MERGE` (a partial patch; excludes id/readonly).
|
|
507
|
+
* VALIDATES and THROWS on invalid input; use `safeEncodePartial` for the non-throwing form.
|
|
508
|
+
*/
|
|
509
|
+
encodePartial(input: UpdateShape<S>): MakeWire<S>;
|
|
510
|
+
/**
|
|
511
|
+
* Non-throwing `encode`: validates+encodes the provided keys and returns a Zod-style
|
|
512
|
+
* `{ success: true; data }` | `{ success: false; error }`. All field errors are
|
|
513
|
+
* aggregated (with correct paths) into a single `z.ZodError`.
|
|
514
|
+
*/
|
|
515
|
+
safeEncode(input: CreateShape<S>): SafeResult<MakeWire<S>>;
|
|
516
|
+
/** Non-throwing `encodePartial` (see `safeEncode`). */
|
|
517
|
+
safeEncodePartial(input: UpdateShape<S>): SafeResult<MakeWire<S>>;
|
|
518
|
+
/** Async `encode` (awaits async refinements per leaf); throws the aggregated error. */
|
|
519
|
+
encodeAsync(input: CreateShape<S>): Promise<MakeWire<S>>;
|
|
520
|
+
/** Async `encodePartial`; throws the aggregated error. */
|
|
521
|
+
encodePartialAsync(input: UpdateShape<S>): Promise<MakeWire<S>>;
|
|
522
|
+
/** Non-throwing async `encode` (see `safeEncode`). */
|
|
523
|
+
safeEncodeAsync(input: CreateShape<S>): Promise<SafeResult<MakeWire<S>>>;
|
|
524
|
+
/** Non-throwing async `encodePartial`. */
|
|
525
|
+
safeEncodePartialAsync(input: UpdateShape<S>): Promise<SafeResult<MakeWire<S>>>;
|
|
526
|
+
/**
|
|
527
|
+
* The server/system view: the same table over ALL fields, including `$internal()`
|
|
528
|
+
* ones the public surface hides. Use it in trusted server code that must read or
|
|
529
|
+
* write internal fields (e.g. a `passhash`).
|
|
530
|
+
*/
|
|
531
|
+
get system(): SystemView<Name, S>;
|
|
532
|
+
private withConfig;
|
|
533
|
+
schemafull(): TableDef<Name, S>;
|
|
534
|
+
schemaless(): TableDef<Name, S>;
|
|
535
|
+
/** `TYPE ANY` — the table may hold both normal records and graph edges. */
|
|
536
|
+
typeAny(): TableDef<Name, S>;
|
|
537
|
+
drop(drop?: boolean): TableDef<Name, S>;
|
|
538
|
+
comment(comment: string): TableDef<Name, S>;
|
|
539
|
+
/** Set table-level `PERMISSIONS` (folded into the single `DEFINE TABLE` head). */
|
|
540
|
+
permissions(spec: TablePermissions): TableDef<Name, S>;
|
|
541
|
+
/** `CHANGEFEED <dur> [INCLUDE ORIGINAL]` — track row changes for `SHOW CHANGES`. */
|
|
542
|
+
changefeed(expiry: string, opts?: {
|
|
543
|
+
includeOriginal?: boolean;
|
|
544
|
+
}): TableDef<Name, S>;
|
|
545
|
+
/**
|
|
546
|
+
* Add a composite index: `DEFINE INDEX <name> ON TABLE <table> FIELDS <fields> [UNIQUE]`, or a
|
|
547
|
+
* materialized row-count index with `{ count: true }` (no fields → `DEFINE INDEX <name> … COUNT`).
|
|
548
|
+
*/
|
|
549
|
+
index(name: string, fields: (keyof S & string)[], opts?: {
|
|
550
|
+
unique?: boolean;
|
|
551
|
+
count?: boolean;
|
|
552
|
+
comment?: string;
|
|
553
|
+
/** A HNSW vector index over the field. */
|
|
554
|
+
hnsw?: HnswOptions;
|
|
555
|
+
/** A DISKANN vector index over the field. */
|
|
556
|
+
diskann?: DiskannOptions;
|
|
557
|
+
/** A full-text search index — needs a `defineAnalyzer` of `analyzer`'s name. */
|
|
558
|
+
fulltext?: FulltextOptions;
|
|
559
|
+
}): TableDef<Name, S>;
|
|
560
|
+
/**
|
|
561
|
+
* Add a row-change event: `DEFINE EVENT <name> ON TABLE <table> [WHEN <when>] THEN <then>`.
|
|
562
|
+
* The body sees `$before`/`$after`/`$event`/`$value`; author with `surql\`…\`` or a raw string.
|
|
563
|
+
*/
|
|
564
|
+
event(name: string, spec: {
|
|
565
|
+
when?: Expr;
|
|
566
|
+
then: Expr | Expr[];
|
|
567
|
+
}): TableDef<Name, S>;
|
|
568
|
+
extend<E extends Shape>(ext: E): TableDef<Name, Omit<S, keyof E> & E>;
|
|
569
|
+
pick<K extends keyof S>(...keys: K[]): TableDef<Name, Pick<S, K>>;
|
|
570
|
+
omit<K extends keyof S>(...keys: K[]): TableDef<Name, Omit<S, K>>;
|
|
571
|
+
partial(): TableDef<Name, PartialShape<S>>;
|
|
572
|
+
required(): TableDef<Name, RequiredShape<S>>;
|
|
573
|
+
/** Derive a `record<name>` link to this table (carrying its id value type). */
|
|
574
|
+
record(): S extends {
|
|
575
|
+
id: RecordIdField<Name, infer V>;
|
|
576
|
+
} ? RecordIdField<Name, V> : RecordIdField<Name>;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* The server/system view of a table (`TableDef.system`): the same data methods typed
|
|
580
|
+
* over ALL fields, including `$internal()` ones the public `TableDef` hides. Its
|
|
581
|
+
* `.object` validates/encodes/decodes the full shape, and `encode`/`encodePartial` accept
|
|
582
|
+
* internal fields. Exposed for trusted server code; never hand it to a browser client.
|
|
583
|
+
*/
|
|
584
|
+
declare class SystemView<Name extends string, S extends Shape> {
|
|
585
|
+
readonly fields: Record<string, AnyField>;
|
|
586
|
+
/** Zod object over ALL fields (internal included). */
|
|
587
|
+
readonly object: z.ZodObject<ZShapeAll<S>>;
|
|
588
|
+
constructor(fields: Record<string, AnyField>);
|
|
589
|
+
/** DB wire row -> app object (internal fields kept). */
|
|
590
|
+
decode(row: unknown): z.output<z.ZodObject<ZShapeAll<S>>>;
|
|
591
|
+
/** DB wire row -> app object (async; internal fields kept). */
|
|
592
|
+
decodeAsync(row: unknown): Promise<z.output<z.ZodObject<ZShapeAll<S>>>>;
|
|
593
|
+
safeDecode(row: unknown): z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShapeAll<S>, {}>>;
|
|
594
|
+
safeDecodeAsync(row: unknown): Promise<z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShapeAll<S>, {}>>>;
|
|
595
|
+
/** @deprecated `parse` decodes a DB row (wire -> app). Use {@link SystemView.decode | decode}. */
|
|
596
|
+
parse(row: unknown): z.output<z.ZodObject<ZShapeAll<S>>>;
|
|
597
|
+
/** @deprecated Use {@link SystemView.safeDecode | safeDecode}. */
|
|
598
|
+
safeParse(row: unknown): z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShapeAll<S>, {}>>;
|
|
599
|
+
/** @deprecated Use {@link SystemView.decodeAsync | decodeAsync}. */
|
|
600
|
+
parseAsync(row: unknown): Promise<z.output<z.ZodObject<ZShapeAll<S>>>>;
|
|
601
|
+
/** @deprecated Use {@link SystemView.safeDecodeAsync | safeDecodeAsync}. */
|
|
602
|
+
safeParseAsync(row: unknown): Promise<z.ZodSafeParseResult<z.core.$InferObjectOutput<ZShapeAll<S>, {}>>>;
|
|
603
|
+
/**
|
|
604
|
+
* Build a `CREATE` payload allowed to set internal fields. VALIDATES and THROWS the
|
|
605
|
+
* aggregated `z.ZodError` on invalid input; use `safeEncode` for the non-throwing form.
|
|
606
|
+
*/
|
|
607
|
+
encode(input: CreateShapeAll<S>): MakeWireAll<S>;
|
|
608
|
+
/**
|
|
609
|
+
* Build an `UPDATE`/`MERGE` payload allowed to set internal fields. VALIDATES and THROWS
|
|
610
|
+
* on invalid input; use `safeEncodePartial` for the non-throwing form.
|
|
611
|
+
*/
|
|
612
|
+
encodePartial(input: UpdateShapeAll<S>): MakeWireAll<S>;
|
|
613
|
+
/** Non-throwing `encode` over ALL fields (see `TableDef.safeEncode`). */
|
|
614
|
+
safeEncode(input: CreateShapeAll<S>): SafeResult<MakeWireAll<S>>;
|
|
615
|
+
/** Non-throwing `encodePartial` over ALL fields. */
|
|
616
|
+
safeEncodePartial(input: UpdateShapeAll<S>): SafeResult<MakeWireAll<S>>;
|
|
617
|
+
/** Async `encode` over ALL fields; throws the aggregated error. */
|
|
618
|
+
encodeAsync(input: CreateShapeAll<S>): Promise<MakeWireAll<S>>;
|
|
619
|
+
/** Async `encodePartial` over ALL fields; throws the aggregated error. */
|
|
620
|
+
encodePartialAsync(input: UpdateShapeAll<S>): Promise<MakeWireAll<S>>;
|
|
621
|
+
/** Non-throwing async `encode` over ALL fields. */
|
|
622
|
+
safeEncodeAsync(input: CreateShapeAll<S>): Promise<SafeResult<MakeWireAll<S>>>;
|
|
623
|
+
/** Non-throwing async `encodePartial` over ALL fields. */
|
|
624
|
+
safeEncodePartialAsync(input: UpdateShapeAll<S>): Promise<SafeResult<MakeWireAll<S>>>;
|
|
625
|
+
}
|
|
626
|
+
type IdValue<Id> = Id extends RecordIdField<string, infer V> ? V : Id extends SField<infer Sc, infer _> ? z.output<Sc> extends RecordIdValue ? z.output<Sc> : RecordIdValue : Id extends z.ZodType ? z.output<Id> extends RecordIdValue ? z.output<Id> : RecordIdValue : RecordIdValue;
|
|
627
|
+
type WithSmartId<Name extends string, S extends Shape> = Omit<S, "id"> & {
|
|
628
|
+
id: RecordIdField<Name, "id" extends keyof S ? IdValue<S["id"]> : RecordIdValue>;
|
|
629
|
+
};
|
|
630
|
+
/**
|
|
631
|
+
* Define a normal table (schemafull by default). The shape may be a plain object, or a callback
|
|
632
|
+
* `(self) => ({...})` that receives a `record<thisTable>` field — use it for self-referential
|
|
633
|
+
* links: `manager: self.optional()`. Type-safe with no repeated table name: `self`'s type comes
|
|
634
|
+
* from the `name` arg, not from `typeof <theConst>`, so it sidesteps the self-in-its-own-
|
|
635
|
+
* initializer cycle (TS 7022) that would otherwise widen the whole table to `any`.
|
|
636
|
+
*/
|
|
637
|
+
/**
|
|
638
|
+
* Reject a shape field carrying the `NoDdl` brand (no SurrealQL mapping) at compile time: the
|
|
639
|
+
* offending key resolves to an error string, so the shape literal won't type-check. Give such a
|
|
640
|
+
* field `.$surreal(type, codec)` to make it storable, or drop it.
|
|
641
|
+
*/
|
|
642
|
+
type RejectNoDdl<S extends Shape> = {
|
|
643
|
+
[K in keyof S]: string extends FlagsOf<S[K]> ? S[K] : NoDdl extends FlagsOf<S[K]> ? "no SurrealQL mapping for this field — give it `.$surreal(type, codec)` or remove it" : S[K];
|
|
644
|
+
};
|
|
645
|
+
type IdOutput<Id> = Id extends RecordIdField<string, infer V> ? V : Id extends SField<infer Sc, infer _> ? z.output<Sc> : Id extends z.ZodType ? z.output<Id> : never;
|
|
646
|
+
/** Compile-time guard: an explicit `id` field must have a valid `RecordIdValue` value type — a
|
|
647
|
+
* `s.symbol()`/`s.boolean()` id (not a valid id value) is rejected rather than silently widened. */
|
|
648
|
+
type RejectBadId<S extends Shape> = "id" extends keyof S ? [IdOutput<S["id"]>] extends [RecordIdValue] ? unknown : {
|
|
649
|
+
id: "the `id` field's value must be a valid RecordId value type (string | number | bigint | uuid | array | object) — e.g. s.string(), s.int(), s.uuid()";
|
|
650
|
+
} : unknown;
|
|
651
|
+
declare function defineTable<Name extends string, S extends Shape>(name: Name, shape: (S & RejectNoDdl<S> & RejectBadId<S>) | ((self: RecordIdField<Name>) => S)): TableDef<Name, WithSmartId<Name, S>>;
|
|
652
|
+
type AnyTable = TableDef<string, any>;
|
|
653
|
+
type TableRef = AnyTable | readonly AnyTable[];
|
|
654
|
+
type NamesOf<T> = T extends TableDef<infer N extends string, infer _> ? N : T extends readonly (infer E)[] ? E extends TableDef<infer N extends string, infer _> ? N : never : never;
|
|
655
|
+
/** A relation's full shape: the edge fields plus the `in`/`out` record endpoints. */
|
|
656
|
+
type RelationShape<Name extends string, S extends Shape, In extends string, Out extends string> = Omit<WithSmartId<Name, S>, "in" | "out"> & {
|
|
657
|
+
in: RecordIdField<In>;
|
|
658
|
+
out: RecordIdField<Out>;
|
|
659
|
+
};
|
|
660
|
+
/**
|
|
661
|
+
* A graph relation (edge table). It's a usable `TableDef` immediately — endpoints are OPTIONAL
|
|
662
|
+
* (`TYPE RELATION` with no `FROM`/`TO` restricts nothing) — and `.from(X)` / `.to(Y)` narrow the
|
|
663
|
+
* `in` / `out` record types. Both return a new `RelationDef` (immutable), chainable in any order.
|
|
664
|
+
*/
|
|
665
|
+
declare class RelationDef<Name extends string, S extends Shape, In extends string = string, Out extends string = string> extends TableDef<Name, RelationShape<Name, S, In, Out>> {
|
|
666
|
+
private readonly edge;
|
|
667
|
+
private readonly fromNames;
|
|
668
|
+
private readonly toNames;
|
|
669
|
+
private readonly isEnforced;
|
|
670
|
+
constructor(name: Name, edge: S, fromNames?: string[], toNames?: string[], isEnforced?: boolean);
|
|
671
|
+
/** Restrict the source endpoint(s) (`in`). */
|
|
672
|
+
from<F extends TableRef>(ref: F): RelationDef<Name, S, NamesOf<F>, Out>;
|
|
673
|
+
/** Restrict the target endpoint(s) (`out`). */
|
|
674
|
+
to<T extends TableRef>(ref: T): RelationDef<Name, S, In, NamesOf<T>>;
|
|
675
|
+
/** Require both endpoints to exist on RELATE (`TYPE RELATION … ENFORCED`). */
|
|
676
|
+
enforced(): RelationDef<Name, S, In, Out>;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Define a graph relation (edge table). Endpoints are optional — the result is a usable table
|
|
680
|
+
* right away; chain `.from(X).to(Y)` to restrict the `in`/`out` records.
|
|
681
|
+
*/
|
|
682
|
+
declare function defineRelation<Name extends string, S extends Shape = {}>(name: Name, fields?: S & RejectNoDdl<S>): RelationDef<Name, S>;
|
|
683
|
+
/**
|
|
684
|
+
* Define a pre-computed (materialized) VIEW table — `DEFINE TABLE <name> TYPE ANY SCHEMALESS AS
|
|
685
|
+
* <query>`. Its rows are computed from the SELECT (SurrealDB keeps them in sync as the source tables
|
|
686
|
+
* change), so a view has NO authored fields/id. Chain `.permissions()` / `.comment()` / `.changefeed()`
|
|
687
|
+
* as on any table:
|
|
688
|
+
*
|
|
689
|
+
* ```ts
|
|
690
|
+
* export const Adults = defineView("adults", surql`SELECT name, age FROM person WHERE age >= 18`);
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
693
|
+
declare function defineView<Name extends string>(name: Name, query: Expr): TableDef<Name, {}>;
|
|
694
|
+
/**
|
|
695
|
+
* A standalone `DEFINE EVENT`, declared apart from its table (vs the inline `TableDef.event(…)`).
|
|
696
|
+
* Export one per event when you want each event as its own named symbol. It compiles to the same
|
|
697
|
+
* statement as the inline form — `pull` regenerates events inline, so the two are interchangeable.
|
|
698
|
+
*/
|
|
699
|
+
declare class EventDef {
|
|
700
|
+
/** Owning table name. */
|
|
701
|
+
readonly table: string;
|
|
702
|
+
readonly name: string;
|
|
703
|
+
readonly when: Expr | undefined;
|
|
704
|
+
readonly then: Expr | Expr[];
|
|
705
|
+
readonly kind: "event";
|
|
706
|
+
constructor(
|
|
707
|
+
/** Owning table name. */
|
|
708
|
+
table: string, name: string, when: Expr | undefined, then: Expr | Expr[]);
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Declare a row-change event on `table` as a standalone, exportable object:
|
|
712
|
+
* `export const reverify = defineEvent(User, "reverify", { when, then })`. Pass the `TableDef`
|
|
713
|
+
* (preferred — no name repetition) or a table name string. See {@link TableDef.event} for the
|
|
714
|
+
* inline, chainable form.
|
|
715
|
+
*/
|
|
716
|
+
declare function defineEvent(table: TableDef<string, Shape> | string, name: string, spec: {
|
|
717
|
+
when?: Expr;
|
|
718
|
+
then: Expr | Expr[];
|
|
719
|
+
}): EventDef;
|
|
720
|
+
interface FunctionConfig {
|
|
721
|
+
/** Return type (an s schema, inferred to a SurrealQL type — like a field). */
|
|
722
|
+
returns?: AnyField;
|
|
723
|
+
/** Function body: a `surql\`…\`` block (or raw string). Required to emit. */
|
|
724
|
+
body?: Expr;
|
|
725
|
+
/** `PERMISSIONS FULL` (true) / `NONE` (false) / a `surql` condition. */
|
|
726
|
+
permissions?: boolean | Expr;
|
|
727
|
+
comment?: string;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* A custom function — `DEFINE FUNCTION fn::<name>(<args>) [-> <returns>] { <body> }`. Built with a
|
|
731
|
+
* chainable, immutable API (like {@link TableDef}): `defineFunction(name, args).returns(…).body(…)`.
|
|
732
|
+
* Args and the return type are s schemas (inferred to SurrealQL types, same as table fields).
|
|
733
|
+
*/
|
|
734
|
+
declare class FunctionDef {
|
|
735
|
+
readonly name: string;
|
|
736
|
+
/** Ordered named args, each an s schema. */
|
|
737
|
+
readonly args: Record<string, AnyField>;
|
|
738
|
+
readonly config: FunctionConfig;
|
|
739
|
+
readonly kind: "function";
|
|
740
|
+
constructor(name: string,
|
|
741
|
+
/** Ordered named args, each an s schema. */
|
|
742
|
+
args: Record<string, AnyField>, config?: FunctionConfig);
|
|
743
|
+
private withConfig;
|
|
744
|
+
/** Declare the return type (an s schema). */
|
|
745
|
+
returns(type: AnyField): FunctionDef;
|
|
746
|
+
/** The function body — a `surql\`…\`` block (braces optional) or a raw string. */
|
|
747
|
+
body(body: Expr): FunctionDef;
|
|
748
|
+
/** `PERMISSIONS`: `FULL` (true, the default), `NONE` (false), or a `surql` condition. */
|
|
749
|
+
permissions(p: boolean | Expr): FunctionDef;
|
|
750
|
+
comment(comment: string): FunctionDef;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* Declare a custom function as a standalone, exportable object:
|
|
754
|
+
* `export const greet = defineFunction("greet", { name: s.string() }).returns(s.string()).body(surql\`…\`)`.
|
|
755
|
+
* Emitted as `DEFINE FUNCTION fn::greet(...)`. Args are s schemas (inferred to SurrealQL types).
|
|
756
|
+
*/
|
|
757
|
+
declare function defineFunction(name: string, args?: Shape): FunctionDef;
|
|
758
|
+
/** The access type + its type-specific config. `RECORD` (default) / `JWT` / `BEARER`. */
|
|
759
|
+
type AccessKind = {
|
|
760
|
+
type: "record";
|
|
761
|
+
} | {
|
|
762
|
+
type: "jwt";
|
|
763
|
+
alg?: string;
|
|
764
|
+
key?: string;
|
|
765
|
+
url?: string;
|
|
766
|
+
} | {
|
|
767
|
+
type: "bearer";
|
|
768
|
+
subject: "record" | "user";
|
|
769
|
+
};
|
|
770
|
+
/** Token/session/grant lifetimes, e.g. `{ token: "1h", session: "12h", grant: "30d" }`. */
|
|
771
|
+
interface AccessDuration {
|
|
772
|
+
grant?: string;
|
|
773
|
+
token?: string;
|
|
774
|
+
session?: string;
|
|
775
|
+
}
|
|
776
|
+
interface AccessConfig {
|
|
777
|
+
/** `ON DATABASE` (default) or `ON NAMESPACE`. */
|
|
778
|
+
on: "database" | "namespace";
|
|
779
|
+
kind: AccessKind;
|
|
780
|
+
/** RECORD-only: SIGNUP/SIGNIN/AUTHENTICATE blocks. */
|
|
781
|
+
signup?: Expr;
|
|
782
|
+
signin?: Expr;
|
|
783
|
+
authenticate?: Expr;
|
|
784
|
+
duration?: AccessDuration;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* An access definition — `DEFINE ACCESS <name> ON DATABASE TYPE …`. Chainable like {@link TableDef}.
|
|
788
|
+
* Pick a type with `.record()` (default; SIGNUP/SIGNIN), `.jwt({ alg, key } | { url })` (validate
|
|
789
|
+
* external tokens), or `.bearer({ for })` (API-key grants). The RECORD bodies are `surql\`…\`` blocks
|
|
790
|
+
* (braces optional). NOTE: SurrealDB redacts signing keys in introspection, so `pull` can't recover
|
|
791
|
+
* them — see the CLI (`--access` is opt-in for that reason).
|
|
792
|
+
*/
|
|
793
|
+
declare class AccessDef {
|
|
794
|
+
readonly name: string;
|
|
795
|
+
readonly config: AccessConfig;
|
|
796
|
+
readonly kind: "access";
|
|
797
|
+
constructor(name: string, config?: AccessConfig);
|
|
798
|
+
private withConfig;
|
|
799
|
+
/** `TYPE RECORD` (the default) — end users sign up / sign in directly. */
|
|
800
|
+
record(): AccessDef;
|
|
801
|
+
/** `TYPE JWT` — validate tokens from an external issuer: `{ alg, key }` (symmetric/PEM) or `{ url }` (JWKS). */
|
|
802
|
+
jwt(opts: {
|
|
803
|
+
alg?: string;
|
|
804
|
+
key?: string;
|
|
805
|
+
url?: string;
|
|
806
|
+
}): AccessDef;
|
|
807
|
+
/** `TYPE BEARER FOR USER|RECORD` — bearer-token / API-key grants. */
|
|
808
|
+
bearer(opts: {
|
|
809
|
+
for: "record" | "user";
|
|
810
|
+
}): AccessDef;
|
|
811
|
+
onNamespace(): AccessDef;
|
|
812
|
+
onDatabase(): AccessDef;
|
|
813
|
+
/** `SIGNUP { … }` (RECORD) — a `surql\`…\`` block (braces optional) run on sign-up. */
|
|
814
|
+
signup(body: Expr): AccessDef;
|
|
815
|
+
/** `SIGNIN { … }` (RECORD) — a `surql\`…\`` block run on sign-in. */
|
|
816
|
+
signin(body: Expr): AccessDef;
|
|
817
|
+
/** `AUTHENTICATE { … }` — a `surql\`…\`` block run on each authenticated request. */
|
|
818
|
+
authenticate(body: Expr): AccessDef;
|
|
819
|
+
/** Token/session/grant lifetimes (`DURATION FOR TOKEN …, FOR SESSION …, FOR GRANT …`). */
|
|
820
|
+
duration(d: AccessDuration): AccessDef;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Declare an access definition: `export const account = defineAccess("account").record()
|
|
824
|
+
* .signup(surql\`…\`).signin(surql\`…\`).duration({ token: "1h", session: "12h" })`. See {@link AccessDef}
|
|
825
|
+
* for `.jwt(…)` / `.bearer(…)`.
|
|
826
|
+
*/
|
|
827
|
+
declare function defineAccess(name: string): AccessDef;
|
|
828
|
+
/** A text-search `DEFINE ANALYZER`'s config: an ordered tokenizer + filter pipeline. */
|
|
829
|
+
interface AnalyzerConfig {
|
|
830
|
+
/** `TOKENIZERS …` — e.g. `["blank", "class", "camel", "punct"]` (at least one). */
|
|
831
|
+
tokenizers: string[];
|
|
832
|
+
/** `FILTERS …` — e.g. `["lowercase", "ascii", "snowball(english)", "ngram(1,3)"]`. */
|
|
833
|
+
filters?: string[];
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* A text-search analyzer (`DEFINE ANALYZER`), referenced by a `FULLTEXT` index. Declared standalone:
|
|
837
|
+
* `export const english = defineAnalyzer("english", { tokenizers: ["blank"], filters: ["lowercase", "snowball(english)"] })`.
|
|
838
|
+
*/
|
|
839
|
+
declare class AnalyzerDef {
|
|
840
|
+
readonly name: string;
|
|
841
|
+
readonly config: AnalyzerConfig;
|
|
842
|
+
readonly kind: "analyzer";
|
|
843
|
+
constructor(name: string, config: AnalyzerConfig);
|
|
844
|
+
}
|
|
845
|
+
/** Declare a text-search analyzer. See {@link AnalyzerConfig}; reference it from a `fulltext` index. */
|
|
846
|
+
declare function defineAnalyzer(name: string, config: AnalyzerConfig): AnalyzerDef;
|
|
847
|
+
/** A schema object declared apart from a table (collected by the CLI loader and emitted on its own). */
|
|
848
|
+
type StandaloneDef = EventDef | FunctionDef | AccessDef | AnalyzerDef;
|
|
849
|
+
/**
|
|
850
|
+
* The underlying Zod schema of any s value: a field (`SField`), a table/relation def
|
|
851
|
+
* (anything carrying an `.object`), or a raw Zod type.
|
|
852
|
+
*/
|
|
853
|
+
type ZodOf<T> = T extends {
|
|
854
|
+
object: infer O;
|
|
855
|
+
} ? O extends z.ZodType ? O : never : SchemaOf<T>;
|
|
856
|
+
/** The app-facing type (what your code reads). Same as `s.output` / Zod's `infer`. */
|
|
857
|
+
type App<T> = z.output<ZodOf<T>>;
|
|
858
|
+
/** The DB wire type (what crosses the wire). Same as `s.input`. */
|
|
859
|
+
type Wire<T> = z.input<ZodOf<T>>;
|
|
860
|
+
/** Field constructors — the authoring surface. */
|
|
861
|
+
declare const s: {
|
|
862
|
+
string: () => SField<z.ZodString, never>;
|
|
863
|
+
number: () => SField<z.ZodNumber, never>;
|
|
864
|
+
boolean: () => SField<z.ZodBoolean, never>;
|
|
865
|
+
email: () => SField<z.ZodEmail, never>;
|
|
866
|
+
url: (params?: Parameters<typeof z.url>[0]) => SField<z.ZodURL, never>;
|
|
867
|
+
/** Surreal native `uuid`: a `string` app-side, stored as a `Uuid` (no ASSERT — native type). */
|
|
868
|
+
uuid: () => SField<z.ZodCodec<z.ZodCustom<Uuid, Uuid>, z.ZodUUID>, never>;
|
|
869
|
+
guid: (params?: Parameters<typeof z.guid>[0]) => SField<z.ZodGUID, never>;
|
|
870
|
+
nanoid: (params?: Parameters<typeof z.nanoid>[0]) => SField<z.ZodNanoID, never>;
|
|
871
|
+
cuid: (params?: Parameters<typeof z.cuid>[0]) => SField<z.ZodCUID, never>;
|
|
872
|
+
cuid2: (params?: Parameters<typeof z.cuid2>[0]) => SField<z.ZodCUID2, never>;
|
|
873
|
+
ulid: (params?: Parameters<typeof z.ulid>[0]) => SField<z.ZodULID, never>;
|
|
874
|
+
xid: (params?: Parameters<typeof z.xid>[0]) => SField<z.ZodXID, never>;
|
|
875
|
+
ksuid: (params?: Parameters<typeof z.ksuid>[0]) => SField<z.ZodKSUID, never>;
|
|
876
|
+
ipv4: (params?: Parameters<typeof z.ipv4>[0]) => SField<z.ZodIPv4, never>;
|
|
877
|
+
ipv6: (params?: Parameters<typeof z.ipv6>[0]) => SField<z.ZodIPv6, never>;
|
|
878
|
+
cidrv4: (params?: Parameters<typeof z.cidrv4>[0]) => SField<z.ZodCIDRv4, never>;
|
|
879
|
+
cidrv6: (params?: Parameters<typeof z.cidrv6>[0]) => SField<z.ZodCIDRv6, never>;
|
|
880
|
+
base64: (params?: Parameters<typeof z.base64>[0]) => SField<z.ZodBase64, never>;
|
|
881
|
+
base64url: (params?: Parameters<typeof z.base64url>[0]) => SField<z.ZodBase64URL, never>;
|
|
882
|
+
e164: (params?: Parameters<typeof z.e164>[0]) => SField<z.ZodE164, never>;
|
|
883
|
+
jwt: (params?: Parameters<typeof z.jwt>[0]) => SField<z.ZodJWT, never>;
|
|
884
|
+
emoji: (params?: Parameters<typeof z.emoji>[0]) => SField<z.ZodEmoji, never>;
|
|
885
|
+
alpha: () => SField<z.ZodString, never>;
|
|
886
|
+
alphanum: () => SField<z.ZodString, never>;
|
|
887
|
+
ascii: () => SField<z.ZodString, never>;
|
|
888
|
+
numeric: () => SField<z.ZodString, never>;
|
|
889
|
+
semver: () => SField<z.ZodString, never>;
|
|
890
|
+
hexadecimal: () => SField<z.ZodString, never>;
|
|
891
|
+
latitude: () => SField<z.ZodString, never>;
|
|
892
|
+
longitude: () => SField<z.ZodString, never>;
|
|
893
|
+
ip: () => SField<z.ZodString, never>;
|
|
894
|
+
domain: () => SField<z.ZodString, never>;
|
|
895
|
+
int: (params?: Parameters<typeof z.int>[0]) => SField<z.ZodInt, never>;
|
|
896
|
+
float: (params?: Parameters<typeof z.float64>[0]) => SField<z.ZodFloat64, never>;
|
|
897
|
+
int32: (params?: Parameters<typeof z.int32>[0]) => SField<z.ZodInt32, never>;
|
|
898
|
+
uint32: (params?: Parameters<typeof z.uint32>[0]) => SField<z.ZodUInt32, never>;
|
|
899
|
+
bigint: (params?: Parameters<typeof z.bigint>[0]) => SField<z.ZodBigInt, never>;
|
|
900
|
+
datetime: () => SField<z.ZodCodec<z.ZodCustom<DateTime, DateTime>, z.ZodDate>, never>;
|
|
901
|
+
/** Alias of `datetime` (Surreal stores a `datetime`; there is no plain date). */
|
|
902
|
+
date: () => SField<z.ZodCodec<z.ZodCustom<DateTime, DateTime>, z.ZodDate>, never>;
|
|
903
|
+
/** Surreal `duration` (a `Duration` instance). */
|
|
904
|
+
duration: () => SField<z.ZodType<Duration, Duration, z.core.$ZodTypeInternals<Duration, Duration>>, never>;
|
|
905
|
+
/** Surreal `decimal` (a `Decimal` instance — arbitrary precision). */
|
|
906
|
+
decimal: () => SField<z.ZodType<Decimal, Decimal, z.core.$ZodTypeInternals<Decimal, Decimal>>, never>;
|
|
907
|
+
/** Surreal `bytes` (a `Uint8Array`). */
|
|
908
|
+
bytes: () => SField<z.ZodCodec<z.ZodUnion<readonly [z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<ArrayBuffer, ArrayBuffer>]>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>, never>;
|
|
909
|
+
/** Surreal `file` (a `FileRef`). */
|
|
910
|
+
file: () => SField<z.ZodType<FileRef, FileRef, z.core.$ZodTypeInternals<FileRef, FileRef>>, never>;
|
|
911
|
+
/** Surreal `geometry` (a `Geometry`), optionally narrowed to a kind. */
|
|
912
|
+
geometry: (kind?: GeometryKind) => SField<z.ZodType<Geometry, Geometry, z.core.$ZodTypeInternals<Geometry, Geometry>>, never>;
|
|
913
|
+
/**
|
|
914
|
+
* A `record<…>` link. Pass a table name, the imported `TableDef`/`RelationDef`, or an array for a
|
|
915
|
+
* multi-table union — `s.recordId(User)`, `s.recordId([User, Service])` — so a table's name is
|
|
916
|
+
* only ever written in its own definition. (For a single-table link `User.record()` is preferred:
|
|
917
|
+
* it also carries the id value type; `User.record().or(Post.record())` composes a union.)
|
|
918
|
+
*
|
|
919
|
+
* Called with NO argument — `s.recordId()` — it emits a bare `record` (a link to ANY table), since a
|
|
920
|
+
* record id's table is optional in SurrealDB.
|
|
921
|
+
*/
|
|
922
|
+
recordId: <T extends string | AnyTable = string>(table?: T | readonly T[]) => RecordIdField<T extends string ? T : NamesOf<T>>;
|
|
923
|
+
/**
|
|
924
|
+
* A nested object whose fields keep their surreal metadata + native types. The returned
|
|
925
|
+
* schema TYPE carries the original shape `S` via the `~szShape` brand (type-only — runtime
|
|
926
|
+
* is unchanged) so `CreateValue`/`ShapeOf` can recover the nested fields' create-flags
|
|
927
|
+
* (e.g. a nested `$default`) and make them create-optional. The brand survives every
|
|
928
|
+
* `$`-method and Zod wrapper (`.optional()`/`.array()`/`.$default()`), which all reuse
|
|
929
|
+
* `this.schema`.
|
|
930
|
+
*/
|
|
931
|
+
object: <S extends Shape>(shape: S) => SField<SZObject<S>>;
|
|
932
|
+
/** An array of `element`. `opts.max` -> sized `array<T, N>` (N is the MAX length). */
|
|
933
|
+
array: <F extends AnyField | z.ZodType>(element: F, opts?: {
|
|
934
|
+
max?: number;
|
|
935
|
+
}) => SField<z.ZodArray<SchemaOf<F>>>;
|
|
936
|
+
/** A literal value type. */
|
|
937
|
+
literal: <const T extends string | number | boolean | bigint>(value: T) => SField<z.ZodLiteral<T>, never>;
|
|
938
|
+
/** A string enum. */
|
|
939
|
+
enum: <const T extends readonly [string, ...string[]]>(values: T) => SField<z.ZodEnum<{ [k_1 in T[number]]: k_1; } extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never>, never>;
|
|
940
|
+
/** A union of fields/schemas. */
|
|
941
|
+
union: <const T extends readonly [AnyField | z.ZodType, ...(AnyField | z.ZodType)[]]>(options: T) => SField<z.ZodUnion<ZodsOf<T>>>;
|
|
942
|
+
/** A fixed-length tuple of fields/schemas. */
|
|
943
|
+
tuple: <const T extends readonly [AnyField | z.ZodType, ...(AnyField | z.ZodType)[]]>(items: T) => SField<z.ZodTuple<ZodsOf<T>>>;
|
|
944
|
+
/** An open-keyed record `record<key, value>` -> SurrealQL `object` with a `.*` value field. */
|
|
945
|
+
record: <K extends z.core.$ZodRecordKey, V extends AnyField | z.ZodType>(key: K, value: V) => SField<z.ZodRecord<K, SchemaOf<V>>>;
|
|
946
|
+
/** A `Map<key, value>` -> SurrealQL `object` with a `.*` value field. */
|
|
947
|
+
map: <K extends AnyField | z.ZodType, V extends AnyField | z.ZodType>(key: K, value: V) => SField<z.ZodMap<SchemaOf<K>, SchemaOf<V>>>;
|
|
948
|
+
/** A `Set<element>` -> SurrealQL `set<element>`. `opts.max` -> sized `set<T, N>` (MAX). */
|
|
949
|
+
set: <V extends AnyField | z.ZodType>(element: V, opts?: {
|
|
950
|
+
max?: number;
|
|
951
|
+
}) => SField<z.ZodSet<SchemaOf<V>>>;
|
|
952
|
+
/** The intersection of two schemas (object fields are merged in DDL). */
|
|
953
|
+
intersection: <A extends AnyField | z.ZodType, B extends AnyField | z.ZodType>(a: A, b: B) => SField<z.ZodIntersection<SchemaOf<A>, SchemaOf<B>>>;
|
|
954
|
+
/** A lazily-resolved schema/field (for recursive types). */
|
|
955
|
+
lazy: <V extends AnyField | z.ZodType>(getter: () => V) => SField<z.ZodLazy<SchemaOf<V>>>;
|
|
956
|
+
/** A native TS enum — string or numeric (numeric reverse-mappings are filtered out). */
|
|
957
|
+
nativeEnum: <const T extends Record<string, string | number>>(entries: T) => SField<z.ZodEnum<T>, never>;
|
|
958
|
+
/** A discriminated union of object schemas/fields -> DDL `object`. */
|
|
959
|
+
discriminatedUnion: <Disc extends string, const T extends readonly [AnyField | z.ZodType, ...(AnyField | z.ZodType)[]]>(discriminator: Disc, options: T) => SField<z.ZodDiscriminatedUnion<ZodsOf<T>, Disc>>;
|
|
960
|
+
/** Wrap a field/schema as optional (constructor form of `.optional()`). */
|
|
961
|
+
optional: <F extends AnyField | z.ZodType>(field: F) => SField<z.ZodOptional<SchemaOf<F>>, FlagsOf<F>>;
|
|
962
|
+
/** Wrap a field/schema as nullable (constructor form of `.nullable()`). */
|
|
963
|
+
nullable: <F extends AnyField | z.ZodType>(field: F) => SField<z.ZodNullable<SchemaOf<F>>, FlagsOf<F>>;
|
|
964
|
+
/** Optional **and** nullable — Zod's `nullish`. */
|
|
965
|
+
nullish: <F extends AnyField | z.ZodType>(field: F) => SField<z.ZodNullable<z.ZodOptional<SchemaOf<F>>>, FlagsOf<F>>;
|
|
966
|
+
/**
|
|
967
|
+
* Zod-style coercion. Each maps to the **same** SurrealQL type as its non-coerced builder —
|
|
968
|
+
* coercion only loosens the app/input side; the DB/wire type is unchanged.
|
|
969
|
+
*/
|
|
970
|
+
coerce: {
|
|
971
|
+
string: () => SField<z.ZodCoercedString<unknown>, never>;
|
|
972
|
+
number: () => SField<z.ZodCoercedNumber<unknown>, never>;
|
|
973
|
+
boolean: () => SField<z.ZodCoercedBoolean<unknown>, never>;
|
|
974
|
+
bigint: () => SField<z.ZodCoercedBigInt<unknown>, never>;
|
|
975
|
+
date: () => SField<z.ZodCodec<z.ZodCustom<DateTime, DateTime>, z.ZodCoercedDate<unknown>>, never>;
|
|
976
|
+
};
|
|
977
|
+
any: () => SField<z.ZodAny, never>;
|
|
978
|
+
unknown: () => SField<z.ZodUnknown, never>;
|
|
979
|
+
null: () => SField<z.ZodNull, never>;
|
|
980
|
+
symbol: () => SField<z.ZodSymbol, "~no-ddl">;
|
|
981
|
+
undefined: () => SField<z.ZodUndefined, "~no-ddl">;
|
|
982
|
+
void: () => SField<z.ZodVoid, "~no-ddl">;
|
|
983
|
+
never: () => SField<z.ZodNever, "~no-ddl">;
|
|
984
|
+
nan: () => SField<z.ZodNaN, "~no-ddl">;
|
|
985
|
+
custom: <T>(check?: (val: unknown) => boolean) => SField<z.ZodCustom<T, T>, "~no-ddl">;
|
|
986
|
+
instanceof: <T extends Parameters<typeof z.instanceof>[0]>(cls: T) => SField<z.ZodCustom<InstanceType<T>, InstanceType<T>>, "~no-ddl">;
|
|
987
|
+
promise: <F extends AnyField | z.ZodType>(schema: F) => SField<z.ZodPromise<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>, "~no-ddl">;
|
|
988
|
+
/** Zod's function factory (not a schema/field — present for drop-in `z.*` parity). */
|
|
989
|
+
function: (params?: {
|
|
990
|
+
input: z.core.$ZodFunctionArgs;
|
|
991
|
+
output: z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|
|
992
|
+
} | undefined) => z.ZodFunction<z.core.$ZodFunctionArgs, z.core.$ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
993
|
+
};
|
|
994
|
+
/**
|
|
995
|
+
* Zod-style inference helpers, exposed on `s` (a type-only namespace merged with the `s`
|
|
996
|
+
* value — the same trick Zod uses for `z.infer`). They accept fields, table/relation defs,
|
|
997
|
+
* and raw schemas alike:
|
|
998
|
+
* - `s.infer<T>` / `s.output<T>` / `s.TypeOf<T>` -> the decoded **app** type (== `App<T>`)
|
|
999
|
+
* - `s.input<T>` -> the **wire/DB** type (== `Wire<T>`)
|
|
1000
|
+
*/
|
|
1001
|
+
declare namespace s {
|
|
1002
|
+
type infer<T> = z.output<ZodOf<T>>;
|
|
1003
|
+
type output<T> = z.output<ZodOf<T>>;
|
|
1004
|
+
type input<T> = z.input<ZodOf<T>>;
|
|
1005
|
+
type TypeOf<T> = z.output<ZodOf<T>>;
|
|
1006
|
+
/** Any s field — the `z.ZodTypeAny` analogue, for typing generic schemas. */
|
|
1007
|
+
type Field = AnyField;
|
|
1008
|
+
}
|
|
1009
|
+
/** The typed input for creating a record (DB-filled fields optional). */
|
|
1010
|
+
type Create<T> = T extends TableDef<string, infer S> ? CreateShape<S> : never;
|
|
1011
|
+
/** The typed input for updating a record (partial; excludes id and readonly fields). */
|
|
1012
|
+
type Update<T> = T extends TableDef<string, infer S> ? UpdateShape<S> : never;
|
|
1013
|
+
|
|
1014
|
+
declare const surrealDriver: Driver<Surreal, TableDef<string, Shape>, StandaloneDef>;
|
|
1015
|
+
|
|
1016
|
+
/** Which level to authenticate at — mirrors `surreal sql --auth-level`. */
|
|
1017
|
+
type AuthLevel = "root" | "namespace" | "database";
|
|
1018
|
+
/** A SurrealDB connection's params (the surreal-specific half of a `surrealConnection` config). */
|
|
1019
|
+
interface SurrealZodConnection {
|
|
1020
|
+
/** Endpoint, e.g. `ws://localhost:8000` or `http://localhost:8000`. */
|
|
1021
|
+
url: string;
|
|
1022
|
+
/** Target namespace. */
|
|
1023
|
+
namespace: string;
|
|
1024
|
+
/** Target database. */
|
|
1025
|
+
database: string;
|
|
1026
|
+
/** Auth username. */
|
|
1027
|
+
username?: string;
|
|
1028
|
+
/** Auth password. */
|
|
1029
|
+
password?: string;
|
|
1030
|
+
/**
|
|
1031
|
+
* Level to sign in at: `root` (default), `namespace`, or `database`. Determines the
|
|
1032
|
+
* signin payload — `namespace`/`database` scope the credentials to that ns/db.
|
|
1033
|
+
*/
|
|
1034
|
+
authLevel?: AuthLevel;
|
|
1035
|
+
}
|
|
1036
|
+
/** An allow/deny list for a single capability — mirrors `@surrealdb/node`. */
|
|
1037
|
+
interface CapabilityList {
|
|
1038
|
+
allow?: boolean | string[];
|
|
1039
|
+
deny?: boolean | string[];
|
|
1040
|
+
}
|
|
1041
|
+
/** Capabilities for the embedded check engine — mirrors `@surrealdb/node`'s `capabilities` option. */
|
|
1042
|
+
interface EmbeddedCapabilities {
|
|
1043
|
+
scripting?: boolean;
|
|
1044
|
+
guest_access?: boolean;
|
|
1045
|
+
live_query_notifications?: boolean;
|
|
1046
|
+
functions?: boolean | string[] | CapabilityList;
|
|
1047
|
+
network_targets?: boolean | string[] | CapabilityList;
|
|
1048
|
+
experimental?: boolean | string[] | CapabilityList;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Run `schemic check`'s replay on an EMBEDDED in-process SurrealDB via the optional `@surrealdb/node`
|
|
1052
|
+
* package (install it yourself — `npm i -D @surrealdb/node`). Options pass through to
|
|
1053
|
+
* `createNodeEngines`; `backend`/`path` choose the storage. No external server, your data untouched.
|
|
1054
|
+
*/
|
|
1055
|
+
interface SurrealZodCheckEmbedded {
|
|
1056
|
+
/** Storage backend. `memory` (default) is throwaway in-RAM; the others persist to `path`. */
|
|
1057
|
+
backend?: "memory" | "surrealkv" | "surrealkv+versioned" | "rocksdb";
|
|
1058
|
+
/** Filesystem path for the persistent backends (ignored for `memory`). */
|
|
1059
|
+
path?: string;
|
|
1060
|
+
/** Capabilities for the instance. Default: all allowed, so asserts/defaults/functions work. */
|
|
1061
|
+
capabilities?: boolean | EmbeddedCapabilities;
|
|
1062
|
+
/** SurrealDB strict mode. */
|
|
1063
|
+
strict?: boolean;
|
|
1064
|
+
/** Query timeout. */
|
|
1065
|
+
query_timeout?: number;
|
|
1066
|
+
/** Transaction timeout. */
|
|
1067
|
+
transaction_timeout?: number;
|
|
1068
|
+
}
|
|
1069
|
+
/** `schemic check` options (lives on a SurrealDB connection's config; rides into `params.check`). */
|
|
1070
|
+
interface SurrealZodCheck {
|
|
1071
|
+
/**
|
|
1072
|
+
* Engine for the migration replay:
|
|
1073
|
+
* - `"auto"` (default) — if the `surreal` CLI is on PATH, spin up an ephemeral in-memory instance
|
|
1074
|
+
* (your EXACT SurrealDB version, no external server, your data untouched); otherwise fall back to
|
|
1075
|
+
* the `check.db` server.
|
|
1076
|
+
* - `"binary"` — require the local `surreal` CLI (error if it's missing).
|
|
1077
|
+
* - `"remote"` — always use the `check.db` server (throwaway scratch databases on it).
|
|
1078
|
+
* - an embedded object (`{ backend, capabilities, … }`) — run in-process via the optional
|
|
1079
|
+
* `@surrealdb/node` package. See {@link SurrealZodCheckEmbedded}.
|
|
1080
|
+
*/
|
|
1081
|
+
engine?: "auto" | "binary" | "remote" | SurrealZodCheckEmbedded;
|
|
1082
|
+
/** Path to the `surreal` CLI for the `auto`/`binary` engines. Default: `surreal` on PATH. */
|
|
1083
|
+
binary?: string;
|
|
1084
|
+
/**
|
|
1085
|
+
* Connection used for the `remote` engine, merged field-by-field over the connection's own params.
|
|
1086
|
+
* The replay spins up throwaway scratch databases and drops them — it NEVER reads or writes your real
|
|
1087
|
+
* database — but it DOES reach the server. Point this at a local/scratch SurrealDB so `schemic check`
|
|
1088
|
+
* never touches production. Falls back to the connection params for any field you omit.
|
|
1089
|
+
*/
|
|
1090
|
+
db?: Partial<SurrealZodConnection>;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* The SurrealDB-specific bag carried in `ResolvedConfig.params`: the connection params plus the optional
|
|
1094
|
+
* `check` replay config. `connect`/`introspect`/`checkReplay` read `config.params as SurrealParams`.
|
|
1095
|
+
*/
|
|
1096
|
+
interface SurrealParams extends SurrealZodConnection {
|
|
1097
|
+
/** `schemic check` overrides — e.g. a dedicated connection for its migration replay. */
|
|
1098
|
+
check?: SurrealZodCheck;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* A SurrealDB connection's config: the dialect-neutral base (`schema`, optional `key`/`migrations`)
|
|
1103
|
+
* plus the SurrealDB-specific connection params and the optional `check` replay config. Read env
|
|
1104
|
+
* yourself in a resolver if you need it — there is no implicit `SURREAL_*` magic. The resolution engine
|
|
1105
|
+
* strips the neutral base; the surreal half (url/namespace/…/check) lands in `ResolvedConfig.params`.
|
|
1106
|
+
*/
|
|
1107
|
+
interface SurrealConnectionConfig extends ConnectionConfigBase, SurrealZodConnection {
|
|
1108
|
+
/** `schemic check` overrides — e.g. a dedicated scratch connection for the migration replay. */
|
|
1109
|
+
check?: SurrealZodCheck;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Build a SurrealDB {@link ConnectionEntry} for a config's `connections` map. Three forms:
|
|
1113
|
+
* a single static config, a resolver returning one config, or a resolver returning a keyed
|
|
1114
|
+
* COLLECTION (one connection per entry — `key` is then required and addressable as `<name>:<key>`).
|
|
1115
|
+
*/
|
|
1116
|
+
declare function surrealConnection(config: SurrealConnectionConfig): ConnectionEntry;
|
|
1117
|
+
declare function surrealConnection(resolve: (ctx: ResolveContext) => SurrealConnectionConfig | Promise<SurrealConnectionConfig>): ConnectionEntry;
|
|
1118
|
+
declare function surrealConnection(resolve: (ctx: ResolveContext) => (SurrealConnectionConfig & {
|
|
1119
|
+
key: string;
|
|
1120
|
+
})[] | Promise<(SurrealConnectionConfig & {
|
|
1121
|
+
key: string;
|
|
1122
|
+
})[]>): ConnectionEntry;
|
|
1123
|
+
|
|
1124
|
+
/** Inline a BoundQuery's bindings into a literal SurrealQL string for DDL use. Exported so the
|
|
1125
|
+
* Struct-IR lowering (`fromTableDef`) renders DEFAULT/VALUE/COMPUTED/permission exprs identically. */
|
|
1126
|
+
declare function inline(query: BoundQuery): string;
|
|
1127
|
+
/**
|
|
1128
|
+
* The bare AND-joined `ASSERT` expression (no `ASSERT ` keyword): inline any `BoundQuery` entries
|
|
1129
|
+
* (custom `surql` asserts), keep strings (computed checks) as-is, dedupe while preserving order,
|
|
1130
|
+
* and AND-join. Each fragment is already a complete boolean expr. Returns "" when there are none.
|
|
1131
|
+
* Exported so the Struct-IR lowering (`fromTableDef`) can populate `StructField.assert` (the bare
|
|
1132
|
+
* expr) while the DDL emitter prepends the `ASSERT ` keyword via {@link renderAsserts}.
|
|
1133
|
+
*/
|
|
1134
|
+
declare function assertExpr(asserts: SurrealMeta["asserts"]): string;
|
|
1135
|
+
/**
|
|
1136
|
+
* The SurrealQL type of a field plus any nested fields it expands into:
|
|
1137
|
+
* object subfields (`path.key`) and array/record element fields (`path.*`).
|
|
1138
|
+
* Exported (with {@link inferField}) so the Struct-IR lowering walks the SAME child tree the
|
|
1139
|
+
* emitter does — so the two can't disagree on type strings or dotted field paths.
|
|
1140
|
+
*/
|
|
1141
|
+
interface FieldInfo {
|
|
1142
|
+
type: string;
|
|
1143
|
+
flexible: boolean;
|
|
1144
|
+
children: {
|
|
1145
|
+
suffix: string;
|
|
1146
|
+
info: FieldInfo;
|
|
1147
|
+
surreal?: SurrealMeta;
|
|
1148
|
+
}[];
|
|
1149
|
+
}
|
|
1150
|
+
/** Infer a field's SurrealQL type + nested structure from a Zod schema. Exported so the Struct-IR
|
|
1151
|
+
* lowering (`fromTableDef`) and the emitter share one source of truth for type strings + paths. */
|
|
1152
|
+
declare function inferField(schema: z.ZodType, seen?: Set<z.ZodType>): FieldInfo;
|
|
1153
|
+
/** DDL generation options. `exists: "overwrite"` -> OVERWRITE; "ignore" -> IF NOT EXISTS. */
|
|
1154
|
+
type DefineOptions = {
|
|
1155
|
+
exists?: "overwrite" | "ignore";
|
|
1156
|
+
};
|
|
1157
|
+
/**
|
|
1158
|
+
* One generated DDL statement, tied to the schema object it defines. `kind` is the object
|
|
1159
|
+
* kind; `name` identifies it within its scope (a table name, or a field path like
|
|
1160
|
+
* `settings.theme` / `tags.*`, already escaped as it appears in the DDL); `table` is the
|
|
1161
|
+
* owning table for fields. Used by the CLI's migration diff to add/change/remove objects
|
|
1162
|
+
* individually. `emitTable`/`emitField` are the string-joined views of these.
|
|
1163
|
+
*/
|
|
1164
|
+
interface DefineStatement {
|
|
1165
|
+
kind: "table" | "field" | "index" | "event" | "function" | "access" | "analyzer";
|
|
1166
|
+
name: string;
|
|
1167
|
+
table?: string;
|
|
1168
|
+
ddl: string;
|
|
1169
|
+
/**
|
|
1170
|
+
* Rendered clause fragments keyed by clause name (`TYPE`, `DEFAULT`, `ASSERT`, …) — only on
|
|
1171
|
+
* `field`/`table` statements. Each value is the exact fragment used in the DDL, which is also
|
|
1172
|
+
* the `ALTER … <set>` form, so the migration engine can compute a clause-level delta without
|
|
1173
|
+
* parsing SurrealQL. Absent on older snapshots (those changes fall back to `OVERWRITE`).
|
|
1174
|
+
*/
|
|
1175
|
+
clauses?: Record<string, string>;
|
|
1176
|
+
}
|
|
1177
|
+
/** The SurrealQL type of a field schema (e.g. `string`, `option<int>`, `record<user>`). */
|
|
1178
|
+
declare function fieldType(field: SField): string;
|
|
1179
|
+
/** Inline a single event clause (`when`/one `then`): a `BoundQuery` is inlined, a string passes
|
|
1180
|
+
* through. Exported so the Struct-IR lowering renders event/permission exprs identically. */
|
|
1181
|
+
declare function eventClause(e: Expr): string;
|
|
1182
|
+
/** A `{ … }` block body — wraps a bare statement list in braces; a `surql\`{ … }\`` passes through.
|
|
1183
|
+
* Exported so the Struct-IR lowering renders function/access blocks to match INFO's `{ … }` form. */
|
|
1184
|
+
declare function braceBody(e: Expr): string;
|
|
1185
|
+
/** The `DefineStatement` for a standalone def — `defineEvent`/`defineFunction`/`defineAccess`/`defineAnalyzer`. */
|
|
1186
|
+
declare function emitDefStatement(def: StandaloneDef, opts?: DefineOptions): DefineStatement;
|
|
1187
|
+
/** Structured `DEFINE FIELD` statements for a field (and its nested subfields). */
|
|
1188
|
+
declare function emitFieldStatements(name: string, table: string, field: SField, opts?: DefineOptions): DefineStatement[];
|
|
1189
|
+
/** `DEFINE FIELD ...` for a field (and any nested object/array/record subfields). */
|
|
1190
|
+
declare function emitField(name: string, table: string, field: SField, opts?: DefineOptions): string;
|
|
1191
|
+
/** Structured statements for a table: its `DEFINE TABLE` head, then one per (nested) field. */
|
|
1192
|
+
declare function emitStatements(t: TableDef<string, Shape>, opts?: DefineOptions): DefineStatement[];
|
|
1193
|
+
/** `DEFINE TABLE ...` plus a `DEFINE FIELD` per field. */
|
|
1194
|
+
declare function emitTable(t: TableDef<string, Shape>, opts?: DefineOptions): string;
|
|
1195
|
+
/** The `REMOVE ...` statement that drops the object a `DefineStatement` defines. */
|
|
1196
|
+
declare function removeStatement(s: Pick<DefineStatement, "kind" | "name" | "table">): string;
|
|
1197
|
+
/** Inject `OVERWRITE` into a plain `DEFINE <kind> …` statement (idempotent re-definition). */
|
|
1198
|
+
declare function overwriteStatement(ddl: string): string;
|
|
1199
|
+
/**
|
|
1200
|
+
* Emit an `ALTER FIELD` that turns the `prev` clause set into `next` — re-set changed/added
|
|
1201
|
+
* clauses, `DROP` removed ones (a true delta). Returns `null` (the caller should fall back to
|
|
1202
|
+
* `DEFINE … OVERWRITE`) when the delta touches a clause `ALTER FIELD` can't express (`COMPUTED`),
|
|
1203
|
+
* or when clause data is unavailable (e.g. an older snapshot without `clauses`).
|
|
1204
|
+
*/
|
|
1205
|
+
declare function alterField(table: string, path: string, prev: Record<string, string> | undefined, next: Record<string, string> | undefined): string | null;
|
|
1206
|
+
/**
|
|
1207
|
+
* Emit an `ALTER TABLE` that turns the `prev` clause set into `next`. Returns `null` (caller falls
|
|
1208
|
+
* back to `DEFINE … OVERWRITE`) when the delta touches a clause `ALTER TABLE` can't express
|
|
1209
|
+
* (`TYPE` NORMAL/RELATION/ANY, or the `DROP` flag), or when clause data is unavailable.
|
|
1210
|
+
*/
|
|
1211
|
+
declare function alterTable(name: string, prev: Record<string, string> | undefined, next: Record<string, string> | undefined): string | null;
|
|
1212
|
+
|
|
1213
|
+
/**
|
|
1214
|
+
* @schemic/surrealdb — author SurrealDB schemas with Zod, and the SurrealDB driver.
|
|
1215
|
+
*
|
|
1216
|
+
* Define tables/relations with `s.*` (a drop-in for `z.*`), generate SurrealQL DDL, and map JS <-> DB
|
|
1217
|
+
* across Zod's two channels via codecs (`decode`/`encode`). Importing this package registers the
|
|
1218
|
+
* SurrealDB driver with `@schemic/core` (so the CLI's `getDriver("surrealdb")` resolves).
|
|
1219
|
+
*/
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* Author SurrealQL expressions — the `s.*` authoring API takes these `BoundQuery` values everywhere a
|
|
1223
|
+
* dynamic expression is allowed (`$default`/`$value`/`$computed`/`$assert`, `reference({ onDelete })`,
|
|
1224
|
+
* event `when`/`then`, function bodies, permissions). A thin GENERIC wrapper over the SDK's tag so a
|
|
1225
|
+
* direct SDK query can also carry its RESULT type — one tuple entry per statement:
|
|
1226
|
+
* `db.query(surql<[string[]]>\`RETURN ['a', 'b', 'c']\`)`. Plain `surql\`…\`` (no type arg) is unchanged.
|
|
1227
|
+
* Provided here (typed) so you stay on a single import, decoupled from the SDK version.
|
|
1228
|
+
*/
|
|
1229
|
+
declare function surql<R extends unknown[] = unknown[]>(strings: TemplateStringsArray, ...values: unknown[]): BoundQuery<R>;
|
|
1230
|
+
|
|
1231
|
+
export { AccessDef, type AnalyzerConfig, AnalyzerDef, type App, type AuthLevel, type CapabilityList, type Create, type DefineOptions, type DefineStatement, type DiskannOptions, type EmbeddedCapabilities, EventDef, type Expr, type FieldInfo, type FulltextOptions, FunctionDef, type HnswOptions, RecordIdField, RelationDef, SField, type Shape, type StandaloneDef, type SurrealConnectionConfig, type SurrealMeta, type SurrealParams, type SurrealZodCheck, type SurrealZodCheckEmbedded, type SurrealZodConnection, SystemView, type TableConfig, TableDef, type TableEvent, type TableIndex, type Update, type Wire, alterField, alterTable, assertExpr, braceBody, defineAccess, defineAnalyzer, defineEvent, defineFunction, defineRelation, defineTable, defineView, emitDefStatement, emitField, emitFieldStatements, emitStatements, emitTable, eventClause, fieldType, formatForAssert, inferField, inline, objectFieldsRegistry, overwriteStatement, removeStatement, s, surql, surrealConnection, surrealDriver, surrealTypeRegistry };
|