webspresso 0.0.21 → 0.0.23
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.
|
@@ -51,6 +51,250 @@ function getColumnMeta(schema) {
|
|
|
51
51
|
return decodeColumnMeta(schema.description);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* SchemaBuilder - Chainable wrapper for Zod schemas with validation and UI metadata
|
|
56
|
+
* @class
|
|
57
|
+
*/
|
|
58
|
+
class SchemaBuilder {
|
|
59
|
+
/**
|
|
60
|
+
* @param {import('zod').ZodTypeAny} schema - Base Zod schema
|
|
61
|
+
* @param {import('./types').ColumnMeta} baseMeta - Base column metadata
|
|
62
|
+
* @param {typeof import('zod').z} z - Zod instance
|
|
63
|
+
*/
|
|
64
|
+
constructor(schema, baseMeta, z) {
|
|
65
|
+
this._schema = schema;
|
|
66
|
+
this._baseMeta = { ...baseMeta };
|
|
67
|
+
this._validations = {};
|
|
68
|
+
this._ui = {};
|
|
69
|
+
this._z = z;
|
|
70
|
+
this._finalized = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Proxy all Zod validation methods
|
|
75
|
+
*/
|
|
76
|
+
min(value) {
|
|
77
|
+
this._validations.min = value;
|
|
78
|
+
if (typeof this._schema.min === 'function') {
|
|
79
|
+
this._schema = this._schema.min(value);
|
|
80
|
+
}
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
max(value) {
|
|
85
|
+
this._validations.max = value;
|
|
86
|
+
if (typeof this._schema.max === 'function') {
|
|
87
|
+
this._schema = this._schema.max(value);
|
|
88
|
+
}
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
length(value) {
|
|
93
|
+
this._validations.length = value;
|
|
94
|
+
if (typeof this._schema.length === 'function') {
|
|
95
|
+
this._schema = this._schema.length(value);
|
|
96
|
+
}
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
minLength(value) {
|
|
101
|
+
this._validations.minLength = value;
|
|
102
|
+
if (typeof this._schema.min === 'function') {
|
|
103
|
+
this._schema = this._schema.min(value);
|
|
104
|
+
}
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
maxLength(value) {
|
|
109
|
+
this._validations.maxLength = value;
|
|
110
|
+
if (typeof this._schema.max === 'function') {
|
|
111
|
+
this._schema = this._schema.max(value);
|
|
112
|
+
}
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
email() {
|
|
117
|
+
this._validations.email = true;
|
|
118
|
+
if (typeof this._schema.email === 'function') {
|
|
119
|
+
this._schema = this._schema.email();
|
|
120
|
+
}
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
url() {
|
|
125
|
+
this._validations.url = true;
|
|
126
|
+
if (typeof this._schema.url === 'function') {
|
|
127
|
+
this._schema = this._schema.url();
|
|
128
|
+
}
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
pattern(regex) {
|
|
133
|
+
const patternStr = regex instanceof RegExp ? regex.source : regex;
|
|
134
|
+
this._validations.pattern = patternStr;
|
|
135
|
+
if (typeof this._schema.regex === 'function') {
|
|
136
|
+
this._schema = this._schema.regex(regex);
|
|
137
|
+
}
|
|
138
|
+
return this;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
includes(str) {
|
|
142
|
+
this._validations.includes = str;
|
|
143
|
+
if (typeof this._schema.includes === 'function') {
|
|
144
|
+
this._schema = this._schema.includes(str);
|
|
145
|
+
}
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
startsWith(str) {
|
|
150
|
+
this._validations.startsWith = str;
|
|
151
|
+
if (typeof this._schema.startsWith === 'function') {
|
|
152
|
+
this._schema = this._schema.startsWith(str);
|
|
153
|
+
}
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
endsWith(str) {
|
|
158
|
+
this._validations.endsWith = str;
|
|
159
|
+
if (typeof this._schema.endsWith === 'function') {
|
|
160
|
+
this._schema = this._schema.endsWith(str);
|
|
161
|
+
}
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
positive() {
|
|
166
|
+
this._validations.positive = true;
|
|
167
|
+
if (typeof this._schema.positive === 'function') {
|
|
168
|
+
this._schema = this._schema.positive();
|
|
169
|
+
}
|
|
170
|
+
return this;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
negative() {
|
|
174
|
+
this._validations.negative = true;
|
|
175
|
+
if (typeof this._schema.negative === 'function') {
|
|
176
|
+
this._schema = this._schema.negative();
|
|
177
|
+
}
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
int() {
|
|
182
|
+
this._validations.int = true;
|
|
183
|
+
if (typeof this._schema.int === 'function') {
|
|
184
|
+
this._schema = this._schema.int();
|
|
185
|
+
}
|
|
186
|
+
return this;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
step(value) {
|
|
190
|
+
this._validations.step = value;
|
|
191
|
+
// Zod doesn't have step, but we store it for UI
|
|
192
|
+
return this;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
nonempty() {
|
|
196
|
+
this._validations.nonempty = true;
|
|
197
|
+
if (typeof this._schema.min === 'function') {
|
|
198
|
+
this._schema = this._schema.min(1);
|
|
199
|
+
} else if (typeof this._schema.length === 'function') {
|
|
200
|
+
this._schema = this._schema.min(1);
|
|
201
|
+
}
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
nullable() {
|
|
206
|
+
this._baseMeta.nullable = true;
|
|
207
|
+
if (this._schema.nullable) {
|
|
208
|
+
this._schema = this._schema.nullable();
|
|
209
|
+
}
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
optional() {
|
|
214
|
+
if (this._schema.optional) {
|
|
215
|
+
this._schema = this._schema.optional();
|
|
216
|
+
}
|
|
217
|
+
return this;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Configure UI metadata
|
|
222
|
+
* @param {import('./types').UIMeta} options - UI configuration options
|
|
223
|
+
* @returns {SchemaBuilder}
|
|
224
|
+
*/
|
|
225
|
+
config(options) {
|
|
226
|
+
if (options.label !== undefined) this._ui.label = options.label;
|
|
227
|
+
if (options.placeholder !== undefined) this._ui.placeholder = options.placeholder;
|
|
228
|
+
if (options.hint !== undefined) this._ui.hint = options.hint;
|
|
229
|
+
if (options.inputType !== undefined) this._ui.inputType = options.inputType;
|
|
230
|
+
if (options.hidden !== undefined) this._ui.hidden = options.hidden;
|
|
231
|
+
if (options.readonly !== undefined) this._ui.readonly = options.readonly;
|
|
232
|
+
if (options.width !== undefined) this._ui.width = options.width;
|
|
233
|
+
if (options.rows !== undefined) this._ui.rows = options.rows;
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Finalize the schema and return Zod schema with metadata
|
|
239
|
+
* @returns {import('zod').ZodTypeAny}
|
|
240
|
+
*/
|
|
241
|
+
_finalize() {
|
|
242
|
+
if (this._finalized) {
|
|
243
|
+
return this._schema;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Merge validations and UI into base metadata
|
|
247
|
+
const finalMeta = {
|
|
248
|
+
...this._baseMeta,
|
|
249
|
+
...(Object.keys(this._validations).length > 0 && { validations: this._validations }),
|
|
250
|
+
...(Object.keys(this._ui).length > 0 && { ui: this._ui }),
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// Apply metadata to schema
|
|
254
|
+
this._schema = this._schema.describe(encodeColumnMeta(finalMeta));
|
|
255
|
+
this._finalized = true;
|
|
256
|
+
return this._schema;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Proxy unknown methods to underlying Zod schema
|
|
261
|
+
*/
|
|
262
|
+
_proxyMethod(name, args) {
|
|
263
|
+
if (typeof this._schema[name] === 'function') {
|
|
264
|
+
this._schema = this._schema[name](...args);
|
|
265
|
+
return this;
|
|
266
|
+
}
|
|
267
|
+
throw new Error(`Method ${name} is not available on this schema type`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Proxy handler for unknown methods
|
|
272
|
+
const handler = {
|
|
273
|
+
get(target, prop) {
|
|
274
|
+
if (prop in target) {
|
|
275
|
+
return target[prop];
|
|
276
|
+
}
|
|
277
|
+
// Proxy unknown methods to Zod schema
|
|
278
|
+
if (typeof target._schema[prop] === 'function') {
|
|
279
|
+
return function(...args) {
|
|
280
|
+
return target._proxyMethod(prop, args);
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return target._schema[prop];
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Create a proxied SchemaBuilder instance
|
|
289
|
+
* @param {import('zod').ZodTypeAny} schema - Base Zod schema
|
|
290
|
+
* @param {import('./types').ColumnMeta} baseMeta - Base column metadata
|
|
291
|
+
* @param {typeof import('zod').z} z - Zod instance
|
|
292
|
+
* @returns {SchemaBuilder}
|
|
293
|
+
*/
|
|
294
|
+
function createSchemaBuilder(schema, baseMeta, z) {
|
|
295
|
+
return new Proxy(new SchemaBuilder(schema, baseMeta, z), handler);
|
|
296
|
+
}
|
|
297
|
+
|
|
54
298
|
/**
|
|
55
299
|
* Create schema helpers bound to a Zod instance
|
|
56
300
|
* @param {typeof import('zod').z} z - Zod instance
|
|
@@ -70,45 +314,55 @@ function createSchemaHelpers(z) {
|
|
|
70
314
|
const helpers = {
|
|
71
315
|
/**
|
|
72
316
|
* Create a Zod object schema with database metadata
|
|
73
|
-
*
|
|
317
|
+
* Automatically finalizes SchemaBuilder instances in the shape
|
|
318
|
+
* @param {Object} shape - Object shape with zdb fields (can be SchemaBuilder instances)
|
|
74
319
|
* @returns {import('zod').ZodObject}
|
|
75
320
|
*/
|
|
76
321
|
schema(shape) {
|
|
77
|
-
|
|
322
|
+
const finalizedShape = {};
|
|
323
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
324
|
+
// If it's a SchemaBuilder, finalize it
|
|
325
|
+
if (value && typeof value._finalize === 'function') {
|
|
326
|
+
finalizedShape[key] = value._finalize();
|
|
327
|
+
} else {
|
|
328
|
+
finalizedShape[key] = value;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return z.object(finalizedShape);
|
|
78
332
|
},
|
|
79
333
|
/**
|
|
80
334
|
* Primary key column (bigint, auto-increment)
|
|
81
335
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
82
|
-
* @returns {
|
|
336
|
+
* @returns {SchemaBuilder}
|
|
83
337
|
*/
|
|
84
338
|
id(options = {}) {
|
|
85
339
|
const schema = z.number().int().positive().optional();
|
|
86
|
-
return
|
|
340
|
+
return createSchemaBuilder(schema, {
|
|
87
341
|
type: 'bigint',
|
|
88
342
|
primary: true,
|
|
89
343
|
autoIncrement: true,
|
|
90
344
|
...options,
|
|
91
|
-
});
|
|
345
|
+
}, z);
|
|
92
346
|
},
|
|
93
347
|
|
|
94
348
|
/**
|
|
95
349
|
* UUID primary key column
|
|
96
350
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
97
|
-
* @returns {
|
|
351
|
+
* @returns {SchemaBuilder}
|
|
98
352
|
*/
|
|
99
353
|
uuid(options = {}) {
|
|
100
354
|
const schema = z.string().uuid().optional();
|
|
101
|
-
return
|
|
355
|
+
return createSchemaBuilder(schema, {
|
|
102
356
|
type: 'uuid',
|
|
103
357
|
primary: true,
|
|
104
358
|
...options,
|
|
105
|
-
});
|
|
359
|
+
}, z);
|
|
106
360
|
},
|
|
107
361
|
|
|
108
362
|
/**
|
|
109
363
|
* String column (varchar)
|
|
110
364
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
111
|
-
* @returns {
|
|
365
|
+
* @returns {SchemaBuilder}
|
|
112
366
|
*/
|
|
113
367
|
string(options = {}) {
|
|
114
368
|
const { maxLength = 255, nullable = false, ...rest } = options;
|
|
@@ -116,18 +370,18 @@ function createSchemaHelpers(z) {
|
|
|
116
370
|
if (nullable) {
|
|
117
371
|
schema = schema.nullable().optional();
|
|
118
372
|
}
|
|
119
|
-
return
|
|
373
|
+
return createSchemaBuilder(schema, {
|
|
120
374
|
type: 'string',
|
|
121
375
|
maxLength,
|
|
122
376
|
nullable,
|
|
123
377
|
...rest,
|
|
124
|
-
});
|
|
378
|
+
}, z);
|
|
125
379
|
},
|
|
126
380
|
|
|
127
381
|
/**
|
|
128
382
|
* Text column (unlimited length)
|
|
129
383
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
130
|
-
* @returns {
|
|
384
|
+
* @returns {SchemaBuilder}
|
|
131
385
|
*/
|
|
132
386
|
text(options = {}) {
|
|
133
387
|
const { nullable = false, ...rest } = options;
|
|
@@ -135,17 +389,17 @@ function createSchemaHelpers(z) {
|
|
|
135
389
|
if (nullable) {
|
|
136
390
|
schema = schema.nullable().optional();
|
|
137
391
|
}
|
|
138
|
-
return
|
|
392
|
+
return createSchemaBuilder(schema, {
|
|
139
393
|
type: 'text',
|
|
140
394
|
nullable,
|
|
141
395
|
...rest,
|
|
142
|
-
});
|
|
396
|
+
}, z);
|
|
143
397
|
},
|
|
144
398
|
|
|
145
399
|
/**
|
|
146
400
|
* Integer column
|
|
147
401
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
148
|
-
* @returns {
|
|
402
|
+
* @returns {SchemaBuilder}
|
|
149
403
|
*/
|
|
150
404
|
integer(options = {}) {
|
|
151
405
|
const { nullable = false, ...rest } = options;
|
|
@@ -153,17 +407,17 @@ function createSchemaHelpers(z) {
|
|
|
153
407
|
if (nullable) {
|
|
154
408
|
schema = schema.nullable().optional();
|
|
155
409
|
}
|
|
156
|
-
return
|
|
410
|
+
return createSchemaBuilder(schema, {
|
|
157
411
|
type: 'integer',
|
|
158
412
|
nullable,
|
|
159
413
|
...rest,
|
|
160
|
-
});
|
|
414
|
+
}, z);
|
|
161
415
|
},
|
|
162
416
|
|
|
163
417
|
/**
|
|
164
418
|
* Big integer column
|
|
165
419
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
166
|
-
* @returns {
|
|
420
|
+
* @returns {SchemaBuilder}
|
|
167
421
|
*/
|
|
168
422
|
bigint(options = {}) {
|
|
169
423
|
const { nullable = false, ...rest } = options;
|
|
@@ -171,17 +425,17 @@ function createSchemaHelpers(z) {
|
|
|
171
425
|
if (nullable) {
|
|
172
426
|
schema = schema.nullable().optional();
|
|
173
427
|
}
|
|
174
|
-
return
|
|
428
|
+
return createSchemaBuilder(schema, {
|
|
175
429
|
type: 'bigint',
|
|
176
430
|
nullable,
|
|
177
431
|
...rest,
|
|
178
|
-
});
|
|
432
|
+
}, z);
|
|
179
433
|
},
|
|
180
434
|
|
|
181
435
|
/**
|
|
182
436
|
* Float column
|
|
183
437
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
184
|
-
* @returns {
|
|
438
|
+
* @returns {SchemaBuilder}
|
|
185
439
|
*/
|
|
186
440
|
float(options = {}) {
|
|
187
441
|
const { nullable = false, ...rest } = options;
|
|
@@ -189,17 +443,17 @@ function createSchemaHelpers(z) {
|
|
|
189
443
|
if (nullable) {
|
|
190
444
|
schema = schema.nullable().optional();
|
|
191
445
|
}
|
|
192
|
-
return
|
|
446
|
+
return createSchemaBuilder(schema, {
|
|
193
447
|
type: 'float',
|
|
194
448
|
nullable,
|
|
195
449
|
...rest,
|
|
196
|
-
});
|
|
450
|
+
}, z);
|
|
197
451
|
},
|
|
198
452
|
|
|
199
453
|
/**
|
|
200
454
|
* Decimal column
|
|
201
455
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
202
|
-
* @returns {
|
|
456
|
+
* @returns {SchemaBuilder}
|
|
203
457
|
*/
|
|
204
458
|
decimal(options = {}) {
|
|
205
459
|
const { precision = 10, scale = 2, nullable = false, ...rest } = options;
|
|
@@ -207,19 +461,19 @@ function createSchemaHelpers(z) {
|
|
|
207
461
|
if (nullable) {
|
|
208
462
|
schema = schema.nullable().optional();
|
|
209
463
|
}
|
|
210
|
-
return
|
|
464
|
+
return createSchemaBuilder(schema, {
|
|
211
465
|
type: 'decimal',
|
|
212
466
|
precision,
|
|
213
467
|
scale,
|
|
214
468
|
nullable,
|
|
215
469
|
...rest,
|
|
216
|
-
});
|
|
470
|
+
}, z);
|
|
217
471
|
},
|
|
218
472
|
|
|
219
473
|
/**
|
|
220
474
|
* Boolean column
|
|
221
475
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
222
|
-
* @returns {
|
|
476
|
+
* @returns {SchemaBuilder}
|
|
223
477
|
*/
|
|
224
478
|
boolean(options = {}) {
|
|
225
479
|
const { nullable = false, default: defaultValue, ...rest } = options;
|
|
@@ -230,18 +484,18 @@ function createSchemaHelpers(z) {
|
|
|
230
484
|
if (nullable) {
|
|
231
485
|
schema = schema.nullable().optional();
|
|
232
486
|
}
|
|
233
|
-
return
|
|
487
|
+
return createSchemaBuilder(schema, {
|
|
234
488
|
type: 'boolean',
|
|
235
489
|
nullable,
|
|
236
490
|
default: defaultValue,
|
|
237
491
|
...rest,
|
|
238
|
-
});
|
|
492
|
+
}, z);
|
|
239
493
|
},
|
|
240
494
|
|
|
241
495
|
/**
|
|
242
496
|
* Date column (date only, no time)
|
|
243
497
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
244
|
-
* @returns {
|
|
498
|
+
* @returns {SchemaBuilder}
|
|
245
499
|
*/
|
|
246
500
|
date(options = {}) {
|
|
247
501
|
const { nullable = false, ...rest } = options;
|
|
@@ -249,17 +503,17 @@ function createSchemaHelpers(z) {
|
|
|
249
503
|
if (nullable) {
|
|
250
504
|
schema = schema.nullable().optional();
|
|
251
505
|
}
|
|
252
|
-
return
|
|
506
|
+
return createSchemaBuilder(schema, {
|
|
253
507
|
type: 'date',
|
|
254
508
|
nullable,
|
|
255
509
|
...rest,
|
|
256
|
-
});
|
|
510
|
+
}, z);
|
|
257
511
|
},
|
|
258
512
|
|
|
259
513
|
/**
|
|
260
514
|
* Datetime column
|
|
261
515
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
262
|
-
* @returns {
|
|
516
|
+
* @returns {SchemaBuilder}
|
|
263
517
|
*/
|
|
264
518
|
datetime(options = {}) {
|
|
265
519
|
const { nullable = false, ...rest } = options;
|
|
@@ -267,17 +521,17 @@ function createSchemaHelpers(z) {
|
|
|
267
521
|
if (nullable) {
|
|
268
522
|
schema = schema.nullable().optional();
|
|
269
523
|
}
|
|
270
|
-
return
|
|
524
|
+
return createSchemaBuilder(schema, {
|
|
271
525
|
type: 'datetime',
|
|
272
526
|
nullable,
|
|
273
527
|
...rest,
|
|
274
|
-
});
|
|
528
|
+
}, z);
|
|
275
529
|
},
|
|
276
530
|
|
|
277
531
|
/**
|
|
278
532
|
* Timestamp column (with optional auto behavior)
|
|
279
533
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
280
|
-
* @returns {
|
|
534
|
+
* @returns {SchemaBuilder}
|
|
281
535
|
*/
|
|
282
536
|
timestamp(options = {}) {
|
|
283
537
|
const { nullable = false, auto, ...rest } = options;
|
|
@@ -286,18 +540,18 @@ function createSchemaHelpers(z) {
|
|
|
286
540
|
if (nullable || auto) {
|
|
287
541
|
schema = schema.nullable().optional();
|
|
288
542
|
}
|
|
289
|
-
return
|
|
543
|
+
return createSchemaBuilder(schema, {
|
|
290
544
|
type: 'timestamp',
|
|
291
545
|
nullable: nullable || !!auto,
|
|
292
546
|
auto,
|
|
293
547
|
...rest,
|
|
294
|
-
});
|
|
548
|
+
}, z);
|
|
295
549
|
},
|
|
296
550
|
|
|
297
551
|
/**
|
|
298
552
|
* JSON column
|
|
299
553
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
300
|
-
* @returns {
|
|
554
|
+
* @returns {SchemaBuilder}
|
|
301
555
|
*/
|
|
302
556
|
json(options = {}) {
|
|
303
557
|
const { nullable = false, ...rest } = options;
|
|
@@ -305,18 +559,18 @@ function createSchemaHelpers(z) {
|
|
|
305
559
|
if (nullable) {
|
|
306
560
|
schema = schema.nullable().optional();
|
|
307
561
|
}
|
|
308
|
-
return
|
|
562
|
+
return createSchemaBuilder(schema, {
|
|
309
563
|
type: 'json',
|
|
310
564
|
nullable,
|
|
311
565
|
...rest,
|
|
312
|
-
});
|
|
566
|
+
}, z);
|
|
313
567
|
},
|
|
314
568
|
|
|
315
569
|
/**
|
|
316
570
|
* Array column (stored as JSON in database)
|
|
317
571
|
* @param {import('zod').ZodTypeAny} [itemSchema] - Schema for array items (default: z.any())
|
|
318
572
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
319
|
-
* @returns {
|
|
573
|
+
* @returns {SchemaBuilder}
|
|
320
574
|
*/
|
|
321
575
|
array(itemSchema, options = {}) {
|
|
322
576
|
// If first argument is options object (backward compatibility)
|
|
@@ -333,18 +587,18 @@ function createSchemaHelpers(z) {
|
|
|
333
587
|
schema = schema.nullable().optional();
|
|
334
588
|
}
|
|
335
589
|
|
|
336
|
-
return
|
|
590
|
+
return createSchemaBuilder(schema, {
|
|
337
591
|
type: 'array',
|
|
338
592
|
nullable,
|
|
339
593
|
...rest,
|
|
340
|
-
});
|
|
594
|
+
}, z);
|
|
341
595
|
},
|
|
342
596
|
|
|
343
597
|
/**
|
|
344
598
|
* Enum column
|
|
345
599
|
* @param {string[]} values - Allowed enum values
|
|
346
600
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
347
|
-
* @returns {
|
|
601
|
+
* @returns {SchemaBuilder}
|
|
348
602
|
*/
|
|
349
603
|
enum(values, options = {}) {
|
|
350
604
|
const { nullable = false, default: defaultValue, ...rest } = options;
|
|
@@ -355,20 +609,20 @@ function createSchemaHelpers(z) {
|
|
|
355
609
|
if (nullable) {
|
|
356
610
|
schema = schema.nullable().optional();
|
|
357
611
|
}
|
|
358
|
-
return
|
|
612
|
+
return createSchemaBuilder(schema, {
|
|
359
613
|
type: 'enum',
|
|
360
614
|
enumValues: values,
|
|
361
615
|
nullable,
|
|
362
616
|
default: defaultValue,
|
|
363
617
|
...rest,
|
|
364
|
-
});
|
|
618
|
+
}, z);
|
|
365
619
|
},
|
|
366
620
|
|
|
367
621
|
/**
|
|
368
622
|
* Foreign key column (references another table)
|
|
369
623
|
* @param {string} references - Referenced table name
|
|
370
624
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
371
|
-
* @returns {
|
|
625
|
+
* @returns {SchemaBuilder}
|
|
372
626
|
*/
|
|
373
627
|
foreignKey(references, options = {}) {
|
|
374
628
|
const { referenceColumn = 'id', nullable = false, ...rest } = options;
|
|
@@ -376,20 +630,20 @@ function createSchemaHelpers(z) {
|
|
|
376
630
|
if (nullable) {
|
|
377
631
|
schema = schema.nullable().optional();
|
|
378
632
|
}
|
|
379
|
-
return
|
|
633
|
+
return createSchemaBuilder(schema, {
|
|
380
634
|
type: 'bigint',
|
|
381
635
|
references,
|
|
382
636
|
referenceColumn,
|
|
383
637
|
nullable,
|
|
384
638
|
...rest,
|
|
385
|
-
});
|
|
639
|
+
}, z);
|
|
386
640
|
},
|
|
387
641
|
|
|
388
642
|
/**
|
|
389
643
|
* UUID foreign key column
|
|
390
644
|
* @param {string} references - Referenced table name
|
|
391
645
|
* @param {Partial<import('./types').ColumnMeta>} [options={}]
|
|
392
|
-
* @returns {
|
|
646
|
+
* @returns {SchemaBuilder}
|
|
393
647
|
*/
|
|
394
648
|
foreignUuid(references, options = {}) {
|
|
395
649
|
const { referenceColumn = 'id', nullable = false, ...rest } = options;
|
|
@@ -397,13 +651,13 @@ function createSchemaHelpers(z) {
|
|
|
397
651
|
if (nullable) {
|
|
398
652
|
schema = schema.nullable().optional();
|
|
399
653
|
}
|
|
400
|
-
return
|
|
654
|
+
return createSchemaBuilder(schema, {
|
|
401
655
|
type: 'uuid',
|
|
402
656
|
references,
|
|
403
657
|
referenceColumn,
|
|
404
658
|
nullable,
|
|
405
659
|
...rest,
|
|
406
|
-
});
|
|
660
|
+
}, z);
|
|
407
661
|
},
|
|
408
662
|
};
|
|
409
663
|
|
package/core/orm/types.js
CHANGED
|
@@ -12,6 +12,38 @@
|
|
|
12
12
|
* @typedef {'id'|'string'|'text'|'integer'|'bigint'|'float'|'decimal'|'boolean'|'date'|'datetime'|'timestamp'|'json'|'array'|'enum'|'uuid'} ColumnType
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {Object} ValidationMeta
|
|
17
|
+
* @property {number} [min] - Minimum value/length
|
|
18
|
+
* @property {number} [max] - Maximum value/length
|
|
19
|
+
* @property {number} [minLength] - Minimum length (for strings/arrays)
|
|
20
|
+
* @property {number} [maxLength] - Maximum length (for strings/arrays)
|
|
21
|
+
* @property {number} [length] - Exact length
|
|
22
|
+
* @property {string} [pattern] - Regex pattern (as string)
|
|
23
|
+
* @property {boolean} [email] - Must be valid email
|
|
24
|
+
* @property {boolean} [url] - Must be valid URL
|
|
25
|
+
* @property {boolean} [positive] - Must be positive number
|
|
26
|
+
* @property {boolean} [negative] - Must be negative number
|
|
27
|
+
* @property {boolean} [int] - Must be integer
|
|
28
|
+
* @property {number} [step] - Step value for numbers
|
|
29
|
+
* @property {boolean} [nonempty] - Cannot be empty
|
|
30
|
+
* @property {string} [includes] - String must include this
|
|
31
|
+
* @property {string} [startsWith] - String must start with this
|
|
32
|
+
* @property {string} [endsWith] - String must end with this
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {Object} UIMeta
|
|
37
|
+
* @property {string} [label] - Form label text
|
|
38
|
+
* @property {string} [placeholder] - Input placeholder
|
|
39
|
+
* @property {string} [hint] - Help text shown below input
|
|
40
|
+
* @property {string} [inputType] - HTML input type (email, tel, url, currency, etc.)
|
|
41
|
+
* @property {boolean} [hidden] - Hide field in forms
|
|
42
|
+
* @property {boolean} [readonly] - Make field read-only
|
|
43
|
+
* @property {string} [width] - Input width (half, third, full)
|
|
44
|
+
* @property {number} [rows] - Number of rows for textarea
|
|
45
|
+
*/
|
|
46
|
+
|
|
15
47
|
/**
|
|
16
48
|
* @typedef {Object} ColumnMeta
|
|
17
49
|
* @property {ColumnType} type - Database column type
|
|
@@ -28,6 +60,8 @@
|
|
|
28
60
|
* @property {string} [references] - Referenced table for foreign keys
|
|
29
61
|
* @property {string} [referenceColumn='id'] - Referenced column name
|
|
30
62
|
* @property {'create'|'update'} [auto] - Auto-set on create or update (for timestamps)
|
|
63
|
+
* @property {ValidationMeta} [validations] - Validation rules
|
|
64
|
+
* @property {UIMeta} [ui] - UI metadata for admin panel
|
|
31
65
|
*/
|
|
32
66
|
|
|
33
67
|
/**
|
package/package.json
CHANGED