surreal-zod 0.0.0-alpha.1 → 0.0.0-alpha.11
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/lib/index.d.ts +3 -0
- package/lib/index.js +1 -1
- package/lib/print.d.ts +2 -0
- package/lib/surql.d.ts +77 -0
- package/lib/surql.js +379 -288
- package/lib/zod/schema.d.ts +314 -0
- package/lib/zod/schema.js +603 -0
- package/lib/zod/utils.d.ts +2 -0
- package/lib/zod/utils.js +2 -0
- package/package.json +6 -4
- package/src/index.ts +1 -1
- package/src/surql.ts +544 -379
- package/src/zod/schema.ts +1605 -0
- package/src/zod/utils.ts +6 -0
- package/lib/zod.js +0 -126
- package/src/zod.ts +0 -302
package/lib/surql.js
CHANGED
|
@@ -2,350 +2,441 @@ import { BoundQuery, escapeIdent, escapeIdPart, RecordId, surql, Table, } from "
|
|
|
2
2
|
import * as z4 from "zod/v4/core";
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import dedent from "dedent";
|
|
5
|
-
export function
|
|
6
|
-
|
|
7
|
-
|
|
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.");
|
|
5
|
+
export function tableToSurql(table, statement, options) {
|
|
6
|
+
if (statement === "define") {
|
|
7
|
+
return defineTable(table, options);
|
|
12
8
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
if (statement === "info") {
|
|
10
|
+
return infoTable(table);
|
|
11
|
+
}
|
|
12
|
+
if (statement === "structure") {
|
|
13
|
+
return structureTable(table);
|
|
14
|
+
}
|
|
15
|
+
if (statement === "remove") {
|
|
16
|
+
return removeTable(table, options);
|
|
18
17
|
}
|
|
19
|
-
|
|
20
|
-
return [schema.extend({ id: z.any() }), query];
|
|
18
|
+
throw new Error(`Invalid statement: ${statement}`);
|
|
21
19
|
}
|
|
22
|
-
function
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
export function removeTable(table, options) {
|
|
21
|
+
const name = table._zod.def.name;
|
|
22
|
+
const query = surql `REMOVE TABLE`;
|
|
23
|
+
const removeOptions = options;
|
|
24
|
+
if (removeOptions?.missing === "ignore") {
|
|
25
|
+
query.append(" IF EXISTS");
|
|
26
|
+
}
|
|
27
|
+
query.append(` ${escapeIdent(name)}`);
|
|
28
|
+
query.append(";");
|
|
29
|
+
return query;
|
|
30
|
+
}
|
|
31
|
+
export function infoTable(table) {
|
|
32
|
+
const name = table._zod.def.name;
|
|
33
|
+
const query = surql `INFO FOR TABLE`;
|
|
34
|
+
query.append(` ${escapeIdent(name)}`);
|
|
35
|
+
query.append(";");
|
|
36
|
+
return query;
|
|
37
|
+
}
|
|
38
|
+
export function structureTable(table) {
|
|
39
|
+
const name = table._zod.def.name;
|
|
40
|
+
const query = surql `INFO FOR TABLE`;
|
|
41
|
+
query.append(` ${escapeIdent(name)}`);
|
|
42
|
+
query.append(" STRUCTURE;");
|
|
43
|
+
return query;
|
|
44
|
+
}
|
|
45
|
+
export function defineTable(schema, options) {
|
|
46
|
+
const def = schema._zod.def;
|
|
47
|
+
const surreal = schema._zod.def.surreal;
|
|
48
|
+
const table = new Table(def.name);
|
|
26
49
|
const query = surql `DEFINE TABLE`;
|
|
27
|
-
if (options
|
|
50
|
+
if (options?.exists === "ignore") {
|
|
28
51
|
query.append(" IF NOT EXISTS");
|
|
29
52
|
}
|
|
30
|
-
else if (options
|
|
53
|
+
else if (options?.exists === "overwrite") {
|
|
31
54
|
query.append(" OVERWRITE");
|
|
32
55
|
}
|
|
33
56
|
// Looks like passing Table instance is not supported yet
|
|
34
57
|
query.append(` ${escapeIdPart(table.name)}`);
|
|
35
|
-
|
|
58
|
+
query.append(` TYPE ${surreal.tableType.toUpperCase()}`);
|
|
59
|
+
if (isRelationTable(schema)) {
|
|
60
|
+
const fromTables = schema._zod.def.fields.in._zod.def.table;
|
|
61
|
+
if (fromTables) {
|
|
62
|
+
query.append(` FROM ${fromTables.map(escapeIdent).join(" | ")}`);
|
|
63
|
+
}
|
|
64
|
+
const toTables = schema._zod.def.fields.out._zod.def.table;
|
|
65
|
+
if (toTables) {
|
|
66
|
+
query.append(` TO ${toTables.map(escapeIdent).join(" | ")}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (surreal.drop) {
|
|
36
70
|
query.append(" DROP");
|
|
37
71
|
}
|
|
38
|
-
if (
|
|
72
|
+
if (surreal.schemafull) {
|
|
39
73
|
query.append(" SCHEMAFULL");
|
|
40
74
|
}
|
|
41
75
|
else {
|
|
42
76
|
query.append(" SCHEMALESS");
|
|
43
77
|
}
|
|
44
|
-
if (
|
|
45
|
-
query.append(surql ` COMMENT ${
|
|
78
|
+
if (surreal.comment) {
|
|
79
|
+
query.append(surql ` COMMENT ${surreal.comment}`);
|
|
46
80
|
}
|
|
47
81
|
query.append(";\n");
|
|
82
|
+
if (options?.fields) {
|
|
83
|
+
for (const [fieldName, fieldSchema] of Object.entries(def.fields)) {
|
|
84
|
+
query.append(defineField(fieldName, table.name, fieldName === "id"
|
|
85
|
+
? fieldSchema._zod.def.innerType
|
|
86
|
+
: fieldSchema, {
|
|
87
|
+
exists: options.exists,
|
|
88
|
+
schemafull: surreal.schemafull,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
48
92
|
return query;
|
|
49
93
|
}
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
transforms: [],
|
|
66
|
-
};
|
|
94
|
+
export function isNormalTable(table) {
|
|
95
|
+
return table._zod.def.surreal.tableType === "normal";
|
|
96
|
+
}
|
|
97
|
+
export function isRelationTable(table) {
|
|
98
|
+
return table._zod.def.surreal.tableType === "relation";
|
|
99
|
+
}
|
|
100
|
+
function defineField(name, table, schema, options) {
|
|
101
|
+
// const context: ZodSurrealTypeContext = {
|
|
102
|
+
// name,
|
|
103
|
+
// table,
|
|
104
|
+
// rootSchema: schema,
|
|
105
|
+
// children: [],
|
|
106
|
+
// asserts: [],
|
|
107
|
+
// transforms: [],
|
|
108
|
+
// };
|
|
67
109
|
const query = surql `DEFINE FIELD`;
|
|
68
|
-
if (options
|
|
110
|
+
if (options?.exists === "ignore") {
|
|
69
111
|
query.append(" IF NOT EXISTS");
|
|
70
112
|
}
|
|
71
|
-
else if (options
|
|
113
|
+
else if (options?.exists === "overwrite") {
|
|
72
114
|
query.append(" OVERWRITE");
|
|
73
115
|
}
|
|
74
|
-
query.append(` ${name} ON TABLE ${table
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
if (context.
|
|
83
|
-
query.append(
|
|
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(`}`);
|
|
116
|
+
query.append(` ${name} ON TABLE ${escapeIdent(table)}`);
|
|
117
|
+
const context = {
|
|
118
|
+
type: new Set(),
|
|
119
|
+
depth: 0,
|
|
120
|
+
children: [],
|
|
121
|
+
flexible: false,
|
|
122
|
+
};
|
|
123
|
+
query.append(` TYPE ${inferSurrealType(schema, context)}`);
|
|
124
|
+
if (options?.schemafull && context.flexible) {
|
|
125
|
+
query.append(" FLEXIBLE");
|
|
99
126
|
}
|
|
127
|
+
// if (options.exists === "ignore") {
|
|
128
|
+
// query.append(" IF NOT EXISTS");
|
|
129
|
+
// } else if (options.exists === "overwrite") {
|
|
130
|
+
// query.append(" OVERWRITE");
|
|
131
|
+
// }
|
|
132
|
+
// query.append(` ${name} ON TABLE ${table.name}`);
|
|
133
|
+
// const type =
|
|
134
|
+
// name === "id"
|
|
135
|
+
// ? inferSurrealType(
|
|
136
|
+
// (schema as unknown as SurrealZodRecordId)._zod.def.innerType,
|
|
137
|
+
// [],
|
|
138
|
+
// context,
|
|
139
|
+
// )
|
|
140
|
+
// : inferSurrealType(schema, [], context);
|
|
141
|
+
// query.append(` TYPE ${type}`);
|
|
142
|
+
// if (context.default) {
|
|
143
|
+
// query.append(
|
|
144
|
+
// context.default.always
|
|
145
|
+
// ? ` DEFAULT ALWAYS ${JSON.stringify(context.default.value)}`
|
|
146
|
+
// : ` DEFAULT ${JSON.stringify(context.default.value)}`,
|
|
147
|
+
// );
|
|
148
|
+
// }
|
|
149
|
+
// if (context.transforms.length > 0) {
|
|
150
|
+
// query.append(` VALUE {\n`);
|
|
151
|
+
// for (const transform of context.transforms) {
|
|
152
|
+
// query.append(
|
|
153
|
+
// dedent.withOptions({ alignValues: true })`
|
|
154
|
+
// //
|
|
155
|
+
// ${transform}\n`.slice(3),
|
|
156
|
+
// );
|
|
157
|
+
// }
|
|
158
|
+
// query.append(`}`);
|
|
159
|
+
// }
|
|
160
|
+
// if (context.asserts.length > 0) {
|
|
161
|
+
// query.append(` ASSERT {\n`);
|
|
162
|
+
// for (const assert of context.asserts) {
|
|
163
|
+
// query.append(
|
|
164
|
+
// dedent.withOptions({ alignValues: true })`
|
|
165
|
+
// //
|
|
166
|
+
// ${assert}\n`.slice(3),
|
|
167
|
+
// );
|
|
168
|
+
// }
|
|
169
|
+
// query.append(`}`);
|
|
170
|
+
// }
|
|
100
171
|
query.append(`;\n`);
|
|
101
172
|
if (context.children.length > 0) {
|
|
102
173
|
for (const { name: childName, type: childType } of context.children) {
|
|
103
|
-
query.append(defineField({
|
|
104
|
-
|
|
105
|
-
table,
|
|
106
|
-
type: childType,
|
|
107
|
-
exists: options.exists,
|
|
174
|
+
query.append(defineField(`${escapeIdent(name)}.${escapeIdent(childName)}`, table, childType, {
|
|
175
|
+
exists: options?.exists,
|
|
108
176
|
}));
|
|
109
177
|
}
|
|
110
178
|
}
|
|
111
179
|
return query;
|
|
112
180
|
}
|
|
113
|
-
export function
|
|
181
|
+
export function inferSurrealType(type, context) {
|
|
114
182
|
const schema = type;
|
|
115
183
|
if (!("_zod" in schema)) {
|
|
116
184
|
throw new Error("Invalid schema provided, make sure you are using zod v4 as zod v3 is currently not supported.");
|
|
117
185
|
}
|
|
186
|
+
// if ("surreal" in schema._zod.def) {
|
|
187
|
+
// return schema._zod.def.surreal.type;
|
|
188
|
+
// } else {
|
|
189
|
+
// throw new Error(
|
|
190
|
+
// // @ts-expect-error - zod core not supported
|
|
191
|
+
// `Invalid surreal schema provided. Received ${schema._zod.def.type}`,
|
|
192
|
+
// );
|
|
193
|
+
// }
|
|
118
194
|
const def = schema._zod.def;
|
|
119
|
-
const
|
|
120
|
-
|
|
195
|
+
const childIndent = " ".repeat(context.depth + 1);
|
|
196
|
+
// const checks = getChecks(schema);
|
|
197
|
+
// parseChecks(context.name, checks, context, def.type);
|
|
121
198
|
// console.log(zodToSexpr(type));
|
|
122
|
-
switch (def.type) {
|
|
123
|
-
case "
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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";
|
|
199
|
+
switch (def.surreal?.type ?? def.type) {
|
|
200
|
+
case "any":
|
|
201
|
+
case "unknown": {
|
|
202
|
+
context.type.add("any");
|
|
203
|
+
break;
|
|
162
204
|
}
|
|
205
|
+
case "never":
|
|
163
206
|
case "undefined": {
|
|
164
|
-
|
|
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`;
|
|
207
|
+
context.type.add("none");
|
|
208
|
+
break;
|
|
189
209
|
}
|
|
190
210
|
case "optional": {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (parents.includes("optional") || parents.includes("nonoptional")) {
|
|
195
|
-
return inner;
|
|
196
|
-
}
|
|
197
|
-
return `option<${inner}>`;
|
|
211
|
+
inferSurrealType(type._zod.def.innerType, context);
|
|
212
|
+
context.type.add("none");
|
|
213
|
+
break;
|
|
198
214
|
}
|
|
199
215
|
case "nonoptional": {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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";
|
|
216
|
+
inferSurrealType(type._zod.def.innerType, context);
|
|
217
|
+
if (context.type.size > 1 && context.type.has("none")) {
|
|
218
|
+
context.type.delete("none");
|
|
219
|
+
}
|
|
220
|
+
break;
|
|
224
221
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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);
|
|
222
|
+
case "null": {
|
|
223
|
+
context.type.add("null");
|
|
224
|
+
break;
|
|
240
225
|
}
|
|
241
|
-
|
|
242
|
-
|
|
226
|
+
case "nullable": {
|
|
227
|
+
inferSurrealType(type._zod.def.innerType, context);
|
|
228
|
+
context.type.add("null");
|
|
229
|
+
break;
|
|
243
230
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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"}' };`;
|
|
231
|
+
case "boolean": {
|
|
232
|
+
context.type.add("bool");
|
|
233
|
+
break;
|
|
250
234
|
}
|
|
251
|
-
|
|
252
|
-
|
|
235
|
+
case "string": {
|
|
236
|
+
context.type.add("string");
|
|
237
|
+
break;
|
|
253
238
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return `$value.len() <= ${value} || { THROW 'Field "${name}" must have at most ${value} ${value === 1 ? "item" : "items"}' };`;
|
|
239
|
+
case "bigint":
|
|
240
|
+
case "number": {
|
|
241
|
+
context.type.add("number");
|
|
242
|
+
break;
|
|
259
243
|
}
|
|
260
|
-
|
|
261
|
-
|
|
244
|
+
case "object": {
|
|
245
|
+
const _schema = schema;
|
|
246
|
+
const shape = _schema._zod.def.shape;
|
|
247
|
+
const catchall = _schema._zod.def.catchall;
|
|
248
|
+
const isStrict = catchall?._zod.traits.has("$ZodNever");
|
|
249
|
+
const isLoose = catchall?._zod.traits.has("$ZodUnknown");
|
|
250
|
+
// buggy syntax
|
|
251
|
+
// if (isStrict) {
|
|
252
|
+
// let type = "{";
|
|
253
|
+
// if (Object.keys(shape).length > 0) {
|
|
254
|
+
// type += "\n";
|
|
255
|
+
// }
|
|
256
|
+
// for (const [key, value] of Object.entries(shape)) {
|
|
257
|
+
// const childContext: ZodSurrealTypeContext = {
|
|
258
|
+
// type: new Set(),
|
|
259
|
+
// depth: context.depth + 1,
|
|
260
|
+
// children: [],
|
|
261
|
+
// };
|
|
262
|
+
// type += `${childIndent}${escapeIdent(key)}: ${inferSurrealType(value, childContext)},\n`;
|
|
263
|
+
// }
|
|
264
|
+
// type += "}";
|
|
265
|
+
// context.type.add(type);
|
|
266
|
+
// break;
|
|
267
|
+
// }
|
|
268
|
+
context.type.add("object");
|
|
269
|
+
if (isLoose)
|
|
270
|
+
context.flexible = true;
|
|
271
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
272
|
+
context.children.push({ name: key, type: value });
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
262
275
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (type === "array") {
|
|
273
|
-
return `$value.len() == ${value} || { THROW 'Field "${name}" must have exactly ${value} ${value === 1 ? "item" : "items"}' };`;
|
|
276
|
+
case "record_id": {
|
|
277
|
+
const table = def.table;
|
|
278
|
+
if (table) {
|
|
279
|
+
context.type.add(`record<${table.map(escapeIdent).join(" | ")}>`);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
context.type.add("record");
|
|
283
|
+
}
|
|
284
|
+
break;
|
|
274
285
|
}
|
|
275
|
-
|
|
276
|
-
|
|
286
|
+
case "table": {
|
|
287
|
+
throw new Error("Table type cannot be used as a field type");
|
|
277
288
|
}
|
|
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
289
|
}
|
|
335
|
-
|
|
336
|
-
|
|
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}';` };
|
|
290
|
+
if (context.type.has("any")) {
|
|
291
|
+
return "any";
|
|
350
292
|
}
|
|
293
|
+
return Array.from(context.type).join(" | ");
|
|
351
294
|
}
|
|
295
|
+
// function getChecks(_schema: z4.$ZodType | SurrealZodType) {
|
|
296
|
+
// const schema = _schema as z4.$ZodTypes | SurrealZodTypes;
|
|
297
|
+
// const checks = schema._zod.def.checks ?? [];
|
|
298
|
+
// if ("check" in schema._zod.def) {
|
|
299
|
+
// checks.unshift(schema as z4.$ZodCheck);
|
|
300
|
+
// }
|
|
301
|
+
// return checks;
|
|
302
|
+
// }
|
|
303
|
+
// function parseChecks(
|
|
304
|
+
// name: string,
|
|
305
|
+
// checks: z4.$ZodCheck[],
|
|
306
|
+
// context: ZodSurrealTypeContext,
|
|
307
|
+
// type: ZodTypeName | SurrealZodTypeName,
|
|
308
|
+
// ) {
|
|
309
|
+
// for (const check of checks) {
|
|
310
|
+
// const { transform, assert } = parseCheck(name, check, type);
|
|
311
|
+
// if (transform) {
|
|
312
|
+
// context.transforms.push(transform);
|
|
313
|
+
// }
|
|
314
|
+
// if (assert) {
|
|
315
|
+
// context.asserts.push(assert);
|
|
316
|
+
// }
|
|
317
|
+
// }
|
|
318
|
+
// }
|
|
319
|
+
// export const checkMap = {
|
|
320
|
+
// never(name: string) {
|
|
321
|
+
// return `THROW 'Field "${name}" must never be present'`;
|
|
322
|
+
// },
|
|
323
|
+
// min_length(name: string, value: number, type: ZodTypeName) {
|
|
324
|
+
// if (type === "array") {
|
|
325
|
+
// return `$value.len() >= ${value} || { THROW 'Field "${name}" must have at least ${value} ${value === 1 ? "item" : "items"}' };`;
|
|
326
|
+
// }
|
|
327
|
+
// if (type === "string") {
|
|
328
|
+
// return `$value.len() >= ${value} || { THROW 'Field "${name}" must be at least ${value} ${value === 1 ? "character" : "characters"} long' };`;
|
|
329
|
+
// }
|
|
330
|
+
// throw new Error(`Invalid type: ${type}`);
|
|
331
|
+
// },
|
|
332
|
+
// max_length(name: string, value: number, type: ZodTypeName) {
|
|
333
|
+
// if (type === "array") {
|
|
334
|
+
// return `$value.len() <= ${value} || { THROW 'Field "${name}" must have at most ${value} ${value === 1 ? "item" : "items"}' };`;
|
|
335
|
+
// }
|
|
336
|
+
// if (type === "string") {
|
|
337
|
+
// return `$value.len() <= ${value} || { THROW 'Field "${name}" must be at most ${value} ${value === 1 ? "character" : "characters"} long' };`;
|
|
338
|
+
// }
|
|
339
|
+
// throw new Error(`Invalid type: ${type}`);
|
|
340
|
+
// },
|
|
341
|
+
// greater_than(name: string, value: z4.util.Numeric, inclusive: boolean) {
|
|
342
|
+
// return `$value ${inclusive ? ">=" : ">"} ${value} || { THROW 'Field "${name}" must be greater than ${inclusive ? "or equal to" : ""} ${value}' };`;
|
|
343
|
+
// },
|
|
344
|
+
// less_than(name: string, value: z4.util.Numeric, inclusive: boolean) {
|
|
345
|
+
// return `$value ${inclusive ? "<=" : "<"} ${value} || { THROW 'Field "${name}" must be less than ${inclusive ? "or equal to" : ""} ${value}' };`;
|
|
346
|
+
// },
|
|
347
|
+
// length_equals(name: string, value: number, type: ZodTypeName = "string") {
|
|
348
|
+
// if (type === "array") {
|
|
349
|
+
// return `$value.len() == ${value} || { THROW 'Field "${name}" must have exactly ${value} ${value === 1 ? "item" : "items"}' };`;
|
|
350
|
+
// }
|
|
351
|
+
// if (type === "string") {
|
|
352
|
+
// return `$value.len() == ${value} || { THROW 'Field "${name}" must be exactly ${value} ${value === 1 ? "character" : "characters"} long' };`;
|
|
353
|
+
// }
|
|
354
|
+
// throw new Error(`Invalid type: ${type}`);
|
|
355
|
+
// },
|
|
356
|
+
// string_format: {
|
|
357
|
+
// email: (name: string) => {
|
|
358
|
+
// const regex =
|
|
359
|
+
// /^[A-Za-z0-9'_+-]+(?:\.[A-Za-z0-9'_+-]+)*@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$/;
|
|
360
|
+
// return `string::matches($value, ${regex}) || { THROW "Field '${name}' must be a valid email address" };`;
|
|
361
|
+
// },
|
|
362
|
+
// url: (
|
|
363
|
+
// name: string,
|
|
364
|
+
// def?: Pick<z4.$ZodCheckURLParams, "hostname" | "protocol" | "normalize">,
|
|
365
|
+
// ) => {
|
|
366
|
+
// return dedent`
|
|
367
|
+
// LET $url = {
|
|
368
|
+
// scheme: parse::url::scheme($value),
|
|
369
|
+
// host: parse::url::host($value),
|
|
370
|
+
// domain: parse::url::domain($value),
|
|
371
|
+
// path: parse::url::path($value),
|
|
372
|
+
// port: parse::url::port($value),
|
|
373
|
+
// query: parse::url::query($value),
|
|
374
|
+
// hash: parse::url::fragment($value),
|
|
375
|
+
// };
|
|
376
|
+
// $url.scheme || { THROW "Field '${name}' must be a valid URL" };
|
|
377
|
+
// ${
|
|
378
|
+
// def?.hostname
|
|
379
|
+
// ? `($url.host ?? "").matches(${def.hostname}) || { THROW "Field '${name}' must match hostname ${def.hostname.toString().replace(/\\/g, "\\\\")}" };`
|
|
380
|
+
// : ""
|
|
381
|
+
// }
|
|
382
|
+
// ${
|
|
383
|
+
// def?.protocol
|
|
384
|
+
// ? `($url.scheme ?? "").matches(${def.protocol}) || { THROW "Field '${name}' must match protocol ${def.protocol.toString().replace(/\\/g, "\\\\")}" };`
|
|
385
|
+
// : ""
|
|
386
|
+
// }
|
|
387
|
+
// $url.scheme + "://" + ($url.host ?? "") + (
|
|
388
|
+
// IF $url.port && (
|
|
389
|
+
// ($url.scheme == "http" && $url.port != 80) ||
|
|
390
|
+
// ($url.scheme == "https" && $url.port != 443)
|
|
391
|
+
// ) { ":" + <string>$url.port } ?? ""
|
|
392
|
+
// )
|
|
393
|
+
// + ($url.path ?? "")
|
|
394
|
+
// + (IF $url.query { "?" + $url.query } ?? "")
|
|
395
|
+
// + (IF $url.fragment { "#" + $url.fragment } ?? "");
|
|
396
|
+
// `;
|
|
397
|
+
// },
|
|
398
|
+
// },
|
|
399
|
+
// };
|
|
400
|
+
// function parseCheck(
|
|
401
|
+
// name: string,
|
|
402
|
+
// _check: z4.$ZodCheck,
|
|
403
|
+
// type: ZodTypeName,
|
|
404
|
+
// ): { transform?: string; assert?: string } {
|
|
405
|
+
// const check = _check as z4.$ZodChecks;
|
|
406
|
+
// const def = check._zod.def;
|
|
407
|
+
// switch (def.check) {
|
|
408
|
+
// case "min_length":
|
|
409
|
+
// return { assert: checkMap.min_length(name, def.minimum, type) };
|
|
410
|
+
// case "max_length":
|
|
411
|
+
// return { assert: checkMap.max_length(name, def.maximum, type) };
|
|
412
|
+
// case "greater_than":
|
|
413
|
+
// return { assert: checkMap.greater_than(name, def.value, def.inclusive) };
|
|
414
|
+
// case "less_than":
|
|
415
|
+
// return { assert: checkMap.less_than(name, def.value, def.inclusive) };
|
|
416
|
+
// case "length_equals":
|
|
417
|
+
// return { assert: checkMap.length_equals(name, def.length, type) };
|
|
418
|
+
// case "string_format":
|
|
419
|
+
// return assertionForStringFormat(name, check);
|
|
420
|
+
// default:
|
|
421
|
+
// return { assert: `THROW 'Unknown check: ${def.check}';` };
|
|
422
|
+
// }
|
|
423
|
+
// }
|
|
424
|
+
// // Remove look-around, look-behind, and look-ahead as they are not supported by SurrealDB
|
|
425
|
+
// function assertionForStringFormat(
|
|
426
|
+
// name: string,
|
|
427
|
+
// _check: z4.$ZodCheck,
|
|
428
|
+
// ): { transform?: string; assert?: string } {
|
|
429
|
+
// const check = _check as z4.$ZodStringFormatChecks;
|
|
430
|
+
// const def = check._zod.def;
|
|
431
|
+
// switch (def.format) {
|
|
432
|
+
// case "email": {
|
|
433
|
+
// return { assert: checkMap.string_format.email(name) };
|
|
434
|
+
// }
|
|
435
|
+
// case "url": {
|
|
436
|
+
// const code = checkMap.string_format.url(name, def);
|
|
437
|
+
// return def.normalize ? { transform: code } : { assert: code };
|
|
438
|
+
// }
|
|
439
|
+
// default:
|
|
440
|
+
// return { assert: `THROW 'Unsupported string format: ${def.format}';` };
|
|
441
|
+
// }
|
|
442
|
+
// }
|