surreal-zod 0.0.0-alpha.1

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/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # surreal-zod
2
+
3
+ To install dependencies:
4
+
5
+ ```bash
6
+ bun install
7
+ ```
8
+
9
+ To run:
10
+
11
+ ```bash
12
+ bun run index.ts
13
+ ```
14
+
15
+ This project was created using `bun init` in bun v1.3.0. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import * as sz from "./zod";
2
+ export { sz };
3
+ export default sz;
package/lib/print.js ADDED
@@ -0,0 +1,166 @@
1
+ export function zodToSexpr(schema) {
2
+ if ("_zod" in schema) {
3
+ return zod4ToSexpr(schema);
4
+ }
5
+ throw new Error("Zod 3 not yet supported");
6
+ }
7
+ function zod4ToSexpr(_schema, depth = 0) {
8
+ const indent = " ".repeat(depth);
9
+ const childIndent = " ".repeat(depth + 1);
10
+ const schema = _schema;
11
+ const def = schema._zod.def;
12
+ const checks = def.checks ?? [];
13
+ if ("check" in def) {
14
+ checks.push(schema);
15
+ }
16
+ const type = def.type;
17
+ if (type === "object") {
18
+ return `(object)`;
19
+ }
20
+ // Primitives
21
+ switch (type) {
22
+ case "string": {
23
+ const constraints = formatChecks(checks);
24
+ return constraints.length > 0 ? `(string [${constraints}])` : `(string)`;
25
+ }
26
+ case "number": {
27
+ // const constraints = formatChecks(checks);
28
+ // return constraints.length > 0 ? `(number [${constraints}])` : `(number)`;
29
+ return `(number)`;
30
+ }
31
+ case "optional": {
32
+ const inner = zod4ToSexpr(def.innerType, depth + 1);
33
+ return `(optional ${inner})`;
34
+ }
35
+ case "nullable": {
36
+ const inner = zod4ToSexpr(def.innerType, depth + 1);
37
+ return `(nullable ${inner})`;
38
+ }
39
+ case "nonoptional": {
40
+ const inner = zod4ToSexpr(def.innerType, depth + 1);
41
+ return `(nonoptional ${inner})`;
42
+ }
43
+ case "array": {
44
+ const inner = zod4ToSexpr(def.element, depth + 1);
45
+ return `(array ${inner})`;
46
+ }
47
+ case "bigint": {
48
+ return `(bigint)`;
49
+ }
50
+ case "boolean": {
51
+ return `(boolean)`;
52
+ }
53
+ case "symbol": {
54
+ return `(symbol)`;
55
+ }
56
+ case "undefined": {
57
+ return `(undefined)`;
58
+ }
59
+ case "null": {
60
+ return `(null)`;
61
+ }
62
+ case "any": {
63
+ return `(any)`;
64
+ }
65
+ default: {
66
+ return `(unknown-type ${type || "?"})`;
67
+ }
68
+ }
69
+ // console.log("unknown type", def);
70
+ // if (type === "number") {
71
+ // const constraints = formatChecks(checks);
72
+ // return constraints.length > 0 ? `(number [${constraints}])` : `(number)`;
73
+ // }
74
+ }
75
+ function breakLine(sexpr, depth) {
76
+ // return sexpr.length > 80
77
+ // ? `\n${" ".repeat(depth)}${sexpr}\n${" ".repeat(depth)}`
78
+ // : sexpr;
79
+ return sexpr;
80
+ }
81
+ function formatChecks(checks) {
82
+ return checks.map((check) => formatCheck(check)).join(" ");
83
+ }
84
+ function formatCheck(_check) {
85
+ const check = _check;
86
+ const def = check._zod.def;
87
+ switch (def.check) {
88
+ case "min_length":
89
+ return `min:${def.minimum}`;
90
+ case "max_length":
91
+ return `max:${def.maximum}`;
92
+ case "length_equals":
93
+ return `length:${def.length}`;
94
+ case "string_format":
95
+ return parseStringFormat(check);
96
+ // case "bigint_format":
97
+ // return `bigint_format=${def.format}`;
98
+ // case "number_format":
99
+ // return `number_format=${def.format}`;
100
+ case "greater_than":
101
+ return `${def.inclusive ? ">=" : ">"}${def.value}`;
102
+ case "less_than":
103
+ return `${def.inclusive ? "<=" : "<"}${def.value}`;
104
+ // case "max_size":
105
+ // return `max_size=${def.maximum}`;
106
+ // case "min_size":
107
+ // return `min_size=${def.minimum}`;
108
+ // case "mime_type":
109
+ // return `mime_type=${def.mime}`;
110
+ // case "multiple_of":
111
+ // return `multiple_of=${def.value}`;
112
+ // case "size_equals":
113
+ // return `size_equals=${def.size}`;
114
+ // case undefined: {
115
+ // return `[unknown ${inspect(def, { colors: true })}]`;
116
+ // }
117
+ default:
118
+ return `[${def.check} ?]`;
119
+ }
120
+ }
121
+ function parseStringFormat(_check) {
122
+ const check = _check;
123
+ const def = check._zod.def;
124
+ const coerce = "coerce" in def ? `coerce:${def.coerce} ` : "";
125
+ if (def.format === "starts_with") {
126
+ return `starts_with:"${def.prefix}"`;
127
+ }
128
+ else if (def.format === "ends_with") {
129
+ return `ends_with:"${def.suffix}"`;
130
+ }
131
+ else if (def.format === "includes") {
132
+ return `includes:"${def.includes}"`;
133
+ }
134
+ else if (def.format === "regex") {
135
+ return `regex:${def.pattern}`;
136
+ }
137
+ else if (def.format === "uuid") {
138
+ return `format:uuid${def.version || ""}`;
139
+ }
140
+ else if (def.format === "xid") {
141
+ return `format:xid`;
142
+ }
143
+ else if (def.format === "url") {
144
+ const opts = [
145
+ def.normalize ? `normalize` : null,
146
+ def.hostname ? `hostname:${def.hostname}` : null,
147
+ def.protocol ? `protocol:${def.protocol}` : null,
148
+ ]
149
+ .filter(Boolean)
150
+ .join(", ");
151
+ return `format:url${opts.length > 0 ? `(${opts})` : ""}`;
152
+ }
153
+ return `${coerce}format:${def.format}`;
154
+ }
155
+ function zodObjectToSexpr(schema, level = 0) {
156
+ if (!("_zod" in schema)) {
157
+ throw new Error("Invalid schema provided, make sure you are using zod v4 as zod v3 is currently not supported.");
158
+ }
159
+ const def = schema._zod.def;
160
+ let sexpr = `(${def.type}${def.checks ? ` ${formatChecks(def.checks)}` : ""}`;
161
+ for (const [propName, propSchema] of Object.entries(def.shape)) {
162
+ sexpr += `${zod4ToSexpr(propSchema, level + 1)}\n`;
163
+ }
164
+ sexpr += ")";
165
+ return sexpr;
166
+ }
package/lib/surql.js ADDED
@@ -0,0 +1,351 @@
1
+ import { BoundQuery, escapeIdent, escapeIdPart, RecordId, surql, Table, } from "surrealdb";
2
+ import * as z4 from "zod/v4/core";
3
+ import z from "zod";
4
+ import dedent from "dedent";
5
+ export function zodToSurql(options) {
6
+ const table = typeof options.table === "string"
7
+ ? new Table(options.table)
8
+ : options.table;
9
+ const schema = options.schema;
10
+ if (!("_zod" in schema)) {
11
+ throw new Error("Invalid schema provided, make sure you are using zod v4 as zod v3 is currently not supported.");
12
+ }
13
+ const def = schema._zod.def;
14
+ const shape = def.shape;
15
+ const query = defineTable(options);
16
+ for (const [key, value] of Object.entries(shape)) {
17
+ query.append(defineField({ name: key, table, type: value, exists: options.exists }));
18
+ }
19
+ // @ts-expect-error - extend is not a method of z4.$ZodObject
20
+ return [schema.extend({ id: z.any() }), query];
21
+ }
22
+ function defineTable(options) {
23
+ const table = typeof options.table === "string"
24
+ ? new Table(options.table)
25
+ : options.table;
26
+ const query = surql `DEFINE TABLE`;
27
+ if (options.exists === "ignore") {
28
+ query.append(" IF NOT EXISTS");
29
+ }
30
+ else if (options.exists === "overwrite") {
31
+ query.append(" OVERWRITE");
32
+ }
33
+ // Looks like passing Table instance is not supported yet
34
+ query.append(` ${escapeIdPart(table.name)}`);
35
+ if (options.drop) {
36
+ query.append(" DROP");
37
+ }
38
+ if (options.schemafull) {
39
+ query.append(" SCHEMAFULL");
40
+ }
41
+ else {
42
+ query.append(" SCHEMALESS");
43
+ }
44
+ if (options.comment) {
45
+ query.append(surql ` COMMENT ${options.comment}`);
46
+ }
47
+ query.append(";\n");
48
+ return query;
49
+ }
50
+ function defineField(options) {
51
+ const name = options.name;
52
+ const table = typeof options.table === "string"
53
+ ? new Table(options.table)
54
+ : options.table;
55
+ const schema = options.type;
56
+ if (!("_zod" in schema)) {
57
+ throw new Error("Invalid field schema provided, make sure you are using zod v4 as zod v3 is currently not supported.");
58
+ }
59
+ const context = {
60
+ name,
61
+ table,
62
+ rootSchema: schema,
63
+ children: [],
64
+ asserts: [],
65
+ transforms: [],
66
+ };
67
+ const query = surql `DEFINE FIELD`;
68
+ if (options.exists === "ignore") {
69
+ query.append(" IF NOT EXISTS");
70
+ }
71
+ else if (options.exists === "overwrite") {
72
+ query.append(" OVERWRITE");
73
+ }
74
+ query.append(` ${name} ON TABLE ${table.name}`);
75
+ const type = zodTypeToSurrealType(schema, [], context);
76
+ query.append(` TYPE ${type}`);
77
+ if (context.default) {
78
+ query.append(context.default.always
79
+ ? ` DEFAULT ALWAYS ${JSON.stringify(context.default.value)}`
80
+ : ` DEFAULT ${JSON.stringify(context.default.value)}`);
81
+ }
82
+ if (context.transforms.length > 0) {
83
+ query.append(` VALUE {\n`);
84
+ for (const transform of context.transforms) {
85
+ query.append(dedent.withOptions({ alignValues: true }) `
86
+ //
87
+ ${transform}\n`.slice(3));
88
+ }
89
+ query.append(`}`);
90
+ }
91
+ if (context.asserts.length > 0) {
92
+ query.append(` ASSERT {\n`);
93
+ for (const assert of context.asserts) {
94
+ query.append(dedent.withOptions({ alignValues: true }) `
95
+ //
96
+ ${assert}\n`.slice(3));
97
+ }
98
+ query.append(`}`);
99
+ }
100
+ query.append(`;\n`);
101
+ if (context.children.length > 0) {
102
+ for (const { name: childName, type: childType } of context.children) {
103
+ query.append(defineField({
104
+ name: `${name}.${childName}`,
105
+ table,
106
+ type: childType,
107
+ exists: options.exists,
108
+ }));
109
+ }
110
+ }
111
+ return query;
112
+ }
113
+ export function zodTypeToSurrealType(type, parents = [], context) {
114
+ const schema = type;
115
+ if (!("_zod" in schema)) {
116
+ throw new Error("Invalid schema provided, make sure you are using zod v4 as zod v3 is currently not supported.");
117
+ }
118
+ const def = schema._zod.def;
119
+ const checks = getChecks(schema);
120
+ parseChecks(context.name, checks, context, def.type);
121
+ // console.log(zodToSexpr(type));
122
+ switch (def.type) {
123
+ case "string":
124
+ return "string";
125
+ case "boolean":
126
+ return "bool";
127
+ case "object": {
128
+ const isInArray = context.rootSchema._zod.def.type === "array";
129
+ // TODO: remove any
130
+ for (const [key, value] of Object.entries(def.shape)) {
131
+ context.children.push({
132
+ name: isInArray ? `*.${key}` : key,
133
+ // TODO: remove as
134
+ type: value,
135
+ });
136
+ }
137
+ return "object";
138
+ }
139
+ case "number":
140
+ return "number";
141
+ case "null":
142
+ return "NULL";
143
+ // case "bigint":
144
+ // return "bigint";
145
+ // case "symbol":
146
+ // return "symbol";
147
+ case "any": {
148
+ //===============================
149
+ // Surreal Specific Types
150
+ //===============================
151
+ if ("surrealType" in def) {
152
+ if (def.surrealType === "record_id") {
153
+ if (def.what) {
154
+ return `record<${Object.keys(def.what).join(" | ")}>`;
155
+ }
156
+ else {
157
+ return "record";
158
+ }
159
+ }
160
+ }
161
+ return "any";
162
+ }
163
+ case "undefined": {
164
+ return "NONE";
165
+ }
166
+ case "default": {
167
+ // if (typeof def.defaultValue === "function") {
168
+ // context.default = { value: def.defaultValue(), always: false };
169
+ // } else {
170
+ // console.log(
171
+ // "default",
172
+ // Object.getOwnPropertyDescriptor(def, "defaultValue").get?.toString(),
173
+ // );
174
+ // TODO: remove any
175
+ context.default = { value: def.defaultValue, always: false };
176
+ // }
177
+ return zodTypeToSurrealType(
178
+ // TODO: remove any
179
+ def.innerType, [...parents, def.type], context);
180
+ }
181
+ case "nullable": {
182
+ const inner = zodTypeToSurrealType(
183
+ // TODO: remove any
184
+ def.innerType, [...parents, def.type], context);
185
+ if (parents.includes("nullable")) {
186
+ return inner;
187
+ }
188
+ return `${inner} | NULL`;
189
+ }
190
+ case "optional": {
191
+ const inner = zodTypeToSurrealType(
192
+ // TODO: remove any
193
+ def.innerType, [...parents, def.type], context);
194
+ if (parents.includes("optional") || parents.includes("nonoptional")) {
195
+ return inner;
196
+ }
197
+ return `option<${inner}>`;
198
+ }
199
+ case "nonoptional": {
200
+ // just a marker for children optional to skip the option<...> wrapper
201
+ return zodTypeToSurrealType(
202
+ // TODO: remove any
203
+ def.innerType, [...parents, def.type], context);
204
+ }
205
+ case "union": {
206
+ // TODO: remove any
207
+ return (def.options
208
+ // TODO: remove any
209
+ .map((option) => zodTypeToSurrealType(option, [...parents, def.type], context))
210
+ .join(" | "));
211
+ }
212
+ case "array": {
213
+ const inner = zodTypeToSurrealType(
214
+ // TODO: remove any
215
+ def.element, [...parents, def.type], context);
216
+ return `array<${inner}>`;
217
+ }
218
+ case "custom": {
219
+ return "any";
220
+ }
221
+ default: {
222
+ console.log("unknown type", def.type);
223
+ return "any";
224
+ }
225
+ }
226
+ }
227
+ function getChecks(_schema) {
228
+ const schema = _schema;
229
+ const checks = schema._zod.def.checks ?? [];
230
+ if ("check" in schema._zod.def) {
231
+ checks.unshift(schema);
232
+ }
233
+ return checks;
234
+ }
235
+ function parseChecks(name, checks, context, type) {
236
+ for (const check of checks) {
237
+ const { transform, assert } = parseCheck(name, check, type);
238
+ if (transform) {
239
+ context.transforms.push(transform);
240
+ }
241
+ if (assert) {
242
+ context.asserts.push(assert);
243
+ }
244
+ }
245
+ }
246
+ export const checkMap = {
247
+ min_length(name, value, type) {
248
+ if (type === "array") {
249
+ return `$value.len() >= ${value} || { THROW 'Field "${name}" must have at least ${value} ${value === 1 ? "item" : "items"}' };`;
250
+ }
251
+ if (type === "string") {
252
+ return `$value.len() >= ${value} || { THROW 'Field "${name}" must be at least ${value} ${value === 1 ? "character" : "characters"} long' };`;
253
+ }
254
+ throw new Error(`Invalid type: ${type}`);
255
+ },
256
+ max_length(name, value, type) {
257
+ if (type === "array") {
258
+ return `$value.len() <= ${value} || { THROW 'Field "${name}" must have at most ${value} ${value === 1 ? "item" : "items"}' };`;
259
+ }
260
+ if (type === "string") {
261
+ return `$value.len() <= ${value} || { THROW 'Field "${name}" must be at most ${value} ${value === 1 ? "character" : "characters"} long' };`;
262
+ }
263
+ throw new Error(`Invalid type: ${type}`);
264
+ },
265
+ greater_than(name, value, inclusive) {
266
+ return `$value ${inclusive ? ">=" : ">"} ${value} || { THROW 'Field "${name}" must be greater than ${inclusive ? "or equal to" : ""} ${value}' };`;
267
+ },
268
+ less_than(name, value, inclusive) {
269
+ return `$value ${inclusive ? "<=" : "<"} ${value} || { THROW 'Field "${name}" must be less than ${inclusive ? "or equal to" : ""} ${value}' };`;
270
+ },
271
+ length_equals(name, value, type = "string") {
272
+ if (type === "array") {
273
+ return `$value.len() == ${value} || { THROW 'Field "${name}" must have exactly ${value} ${value === 1 ? "item" : "items"}' };`;
274
+ }
275
+ if (type === "string") {
276
+ return `$value.len() == ${value} || { THROW 'Field "${name}" must be exactly ${value} ${value === 1 ? "character" : "characters"} long' };`;
277
+ }
278
+ throw new Error(`Invalid type: ${type}`);
279
+ },
280
+ string_format: {
281
+ email: (name) => {
282
+ const regex = /^[A-Za-z0-9'_+-]+(?:\.[A-Za-z0-9'_+-]+)*@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
283
+ return `string::matches($value, ${regex}) || { THROW "Field '${name}' must be a valid email address" };`;
284
+ },
285
+ url: (name, def) => {
286
+ return dedent `
287
+ LET $url = {
288
+ scheme: parse::url::scheme($value),
289
+ host: parse::url::host($value),
290
+ domain: parse::url::domain($value),
291
+ path: parse::url::path($value),
292
+ port: parse::url::port($value),
293
+ query: parse::url::query($value),
294
+ hash: parse::url::fragment($value),
295
+ };
296
+ $url.scheme || { THROW "Field '${name}' must be a valid URL" };
297
+ ${def?.hostname
298
+ ? `($url.host ?? "").matches(${def.hostname}) || { THROW "Field '${name}' must match hostname ${def.hostname.toString().replace(/\\/g, "\\\\")}" };`
299
+ : ""}
300
+ ${def?.protocol
301
+ ? `($url.scheme ?? "").matches(${def.protocol}) || { THROW "Field '${name}' must match protocol ${def.protocol.toString().replace(/\\/g, "\\\\")}" };`
302
+ : ""}
303
+ $url.scheme + "://" + ($url.host ?? "") + (
304
+ IF $url.port && (
305
+ ($url.scheme == "http" && $url.port != 80) ||
306
+ ($url.scheme == "https" && $url.port != 443)
307
+ ) { ":" + <string>$url.port } ?? ""
308
+ )
309
+ + ($url.path ?? "")
310
+ + (IF $url.query { "?" + $url.query } ?? "")
311
+ + (IF $url.fragment { "#" + $url.fragment } ?? "");
312
+ `;
313
+ },
314
+ },
315
+ };
316
+ function parseCheck(name, _check, type) {
317
+ const check = _check;
318
+ const def = check._zod.def;
319
+ switch (def.check) {
320
+ case "min_length":
321
+ return { assert: checkMap.min_length(name, def.minimum, type) };
322
+ case "max_length":
323
+ return { assert: checkMap.max_length(name, def.maximum, type) };
324
+ case "greater_than":
325
+ return { assert: checkMap.greater_than(name, def.value, def.inclusive) };
326
+ case "less_than":
327
+ return { assert: checkMap.less_than(name, def.value, def.inclusive) };
328
+ case "length_equals":
329
+ return { assert: checkMap.length_equals(name, def.length, type) };
330
+ case "string_format":
331
+ return assertionForStringFormat(name, check);
332
+ default:
333
+ return { assert: `THROW 'Unknown check: ${def.check}';` };
334
+ }
335
+ }
336
+ // Remove look-around, look-behind, and look-ahead as they are not supported by SurrealDB
337
+ function assertionForStringFormat(name, _check) {
338
+ const check = _check;
339
+ const def = check._zod.def;
340
+ switch (def.format) {
341
+ case "email": {
342
+ return { assert: checkMap.string_format.email(name) };
343
+ }
344
+ case "url": {
345
+ const code = checkMap.string_format.url(name, def);
346
+ return def.normalize ? { transform: code } : { assert: code };
347
+ }
348
+ default:
349
+ return { assert: `THROW 'Unsupported string format: ${def.format}';` };
350
+ }
351
+ }
package/lib/zod.js ADDED
@@ -0,0 +1,126 @@
1
+ import { RecordId } from "surrealdb";
2
+ import z4 from "zod/v4";
3
+ import * as core from "zod/v4/core";
4
+ export const SurrealZodType = core.$constructor("SurrealZodType", (inst, def) => {
5
+ // @ts-expect-error - unknown assertion error
6
+ core.$ZodType.init(inst, def);
7
+ inst._surreal = true;
8
+ return inst;
9
+ });
10
+ export const SurrealZodAny = core.$constructor("SurrealZodAny", (inst, def) => {
11
+ // @ts-expect-error - unknown assertion error
12
+ core.$ZodAny.init(inst, def);
13
+ SurrealZodType.init(inst, def);
14
+ });
15
+ export function any() {
16
+ return core._any(SurrealZodAny);
17
+ }
18
+ export const SurrealZodBoolean = core.$constructor("SurrealZodBoolean", (inst, def) => {
19
+ // @ts-expect-error - unknown assertion error
20
+ core.$ZodBoolean.init(inst, def);
21
+ SurrealZodType.init(inst, def);
22
+ // const originalDefault = inst.default;
23
+ // inst.default = (defaultValue?: any) => {
24
+ // if (typeof defaultValue === "function") {
25
+ // throw new TypeError(
26
+ // "Functions for default values are not supported in surreal-zod",
27
+ // );
28
+ // }
29
+ // return originalDefault(defaultValue);
30
+ // };
31
+ });
32
+ export function boolean(params) {
33
+ return core._boolean(SurrealZodBoolean, params);
34
+ }
35
+ export const SurrealZodString = core.$constructor("SurrealZodString", (inst, def) => {
36
+ // @ts-expect-error - unknown assertion error
37
+ core.$ZodString.init(inst, def);
38
+ SurrealZodType.init(inst, def);
39
+ });
40
+ export function string(params) {
41
+ return core._string(SurrealZodString, params);
42
+ }
43
+ export const SurrealZodObject = core.$constructor("SurrealZodObject", (inst, def) => {
44
+ // TODO: Inline implementation and use core instead
45
+ // @ts-expect-error - unknown assertion error
46
+ z4.ZodObject.init(inst, def);
47
+ SurrealZodType.init(inst, def);
48
+ });
49
+ export function object(shape, params) {
50
+ const def = {
51
+ type: "object",
52
+ shape: shape ?? {},
53
+ ...core.util.normalizeParams(params),
54
+ };
55
+ return new SurrealZodObject(def);
56
+ }
57
+ export const SurrealZodRecordId = core.$constructor("SurrealZodRecordId", (inst, def) => {
58
+ // @ts-expect-error - unknown assertion error
59
+ core.$ZodAny.init(inst, def);
60
+ SurrealZodType.init(inst, def);
61
+ inst._surreal = true;
62
+ inst._zod.parse = (payload, _ctx) => {
63
+ if (payload.value instanceof RecordId) {
64
+ if (def.what) {
65
+ if (def.what[payload.value.table.name] === undefined) {
66
+ payload.issues.push({
67
+ code: "invalid_value",
68
+ values: Object.keys(def.what),
69
+ input: payload.value.table.name,
70
+ message: `Expected record table to be one of ${Object.keys(def.what).join(" | ")} but found ${payload.value.table.name}`,
71
+ });
72
+ }
73
+ }
74
+ // } else if (typeof payload.value === "string") {
75
+ // let tablePart = '';
76
+ // let idPart = '';
77
+ // let quote = '';
78
+ // for (let i = 0; i < payload.value.length; i++) {
79
+ // const char = payload.value[i];
80
+ // if (char === '`') {
81
+ // if (quote === '`') {
82
+ // tablePart = payload.value.slice(1, i);
83
+ // } else quote = '`';
84
+ // }
85
+ // if (char === ':') {
86
+ // tablePart = payload.value.slice(0, charIndex);
87
+ // idPart = payload.value.slice(tablePart.length + 1);
88
+ // break;
89
+ // }
90
+ // tablePart += char;
91
+ // }
92
+ // for (const char of payload.value.slice(tablePart.length + 1)) {
93
+ // idPart += char;
94
+ // }
95
+ // if (/^(`|\u27e8)/.test(payload.value)) {
96
+ // payload.value = new RecordId(payload.value.split(":")[0], payload.value.split(":")[1]);
97
+ // } else {
98
+ // payload.issues.push({
99
+ // code: 'invalid_format',
100
+ // format: 'record_id',
101
+ // message: 'Invalid record id format',
102
+ // });
103
+ // }
104
+ }
105
+ else {
106
+ payload.issues.push({
107
+ code: "invalid_type",
108
+ expected: "custom",
109
+ input: payload.value,
110
+ });
111
+ }
112
+ return payload;
113
+ };
114
+ return inst;
115
+ });
116
+ export function recordId(what, innerType) {
117
+ return new SurrealZodRecordId({
118
+ // Zod would not be happy if we have a custom type here, so we use any
119
+ type: "any",
120
+ surrealType: "record_id",
121
+ what: what
122
+ ? Object.freeze(Object.fromEntries(what.map((v) => [v, v])))
123
+ : undefined,
124
+ innerType: innerType ?? any(),
125
+ });
126
+ }