cogsbox-shape 0.5.144 → 0.5.146
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/dist/schema.d.ts +100 -48
- package/dist/schema.js +176 -117
- package/package.json +1 -1
package/dist/schema.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ type CurrentTimestampConfig = {
|
|
|
5
5
|
};
|
|
6
6
|
export declare const isFunction: (fn: unknown) => fn is Function;
|
|
7
7
|
export declare function currentTimeStamp(): CurrentTimestampConfig;
|
|
8
|
+
type DbConfig = SQLType | RelationConfig<any> | null;
|
|
8
9
|
export type SQLType = ({
|
|
9
10
|
type: "int";
|
|
10
11
|
nullable?: boolean;
|
|
@@ -36,14 +37,23 @@ type SQLToZodType<T extends SQLType, TDefault extends boolean> = T["pk"] extends
|
|
|
36
37
|
default: "CURRENT_TIMESTAMP";
|
|
37
38
|
} ? TDefault extends true ? never : z.ZodDate : z.ZodDate : never;
|
|
38
39
|
type ZodTypeFromPrimitive<T> = T extends string ? z.ZodString : T extends number ? z.ZodNumber : T extends boolean ? z.ZodBoolean : T extends Date ? z.ZodDate : z.ZodAny;
|
|
39
|
-
type NonLiteral<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : T;
|
|
40
40
|
type CollapsedUnion<A extends z.ZodTypeAny, B extends z.ZodTypeAny> = A extends B ? (B extends A ? A : z.ZodUnion<[A, B]>) : z.ZodUnion<[A, B]>;
|
|
41
|
-
export interface IBuilderMethods<T extends
|
|
42
|
-
initialState: {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
41
|
+
export interface IBuilderMethods<T extends DbConfig, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> {
|
|
42
|
+
initialState<const TValue>(options: {
|
|
43
|
+
value: TValue | (() => TValue);
|
|
44
|
+
schema?: never;
|
|
45
|
+
clientPk?: boolean;
|
|
46
|
+
}): Prettify<Builder<"new", T, TSql, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>, TValue extends () => infer R ? R : TValue, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>>, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>>>>;
|
|
47
|
+
initialState<const TSchema extends z.ZodTypeAny>(options: {
|
|
48
|
+
value?: never;
|
|
49
|
+
schema: TSchema;
|
|
50
|
+
clientPk?: boolean;
|
|
51
|
+
}): Prettify<Builder<"new", T, TSql, TSchema, z.infer<TSchema>, CollapsedUnion<TSql, TSchema>, CollapsedUnion<TSql, TSchema>>>;
|
|
52
|
+
initialState<const TValue, const TSchema extends z.ZodTypeAny>(options: {
|
|
53
|
+
value: TValue | (() => TValue);
|
|
54
|
+
schema: TSchema | ((base: ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>) => TSchema);
|
|
55
|
+
clientPk?: boolean;
|
|
56
|
+
}): Prettify<Builder<"new", T, TSql, TSchema, TValue extends () => infer R ? R : TValue, CollapsedUnion<TSql, TSchema>, CollapsedUnion<TSql, TSchema>>>;
|
|
47
57
|
reference: <TRefSchema extends {
|
|
48
58
|
_tableName: string;
|
|
49
59
|
}>(fieldGetter: () => any) => Builder<"sql", T & {
|
|
@@ -53,11 +63,11 @@ export interface IBuilderMethods<T extends SQLType | RelationConfig<any>, TSql e
|
|
|
53
63
|
sql: TSql;
|
|
54
64
|
initialState: TNew;
|
|
55
65
|
}) => TClientNext) | TClientNext) => Prettify<Builder<"client", T, TSql, TNew, TInitialValue, TClientNext, TClientNext>>;
|
|
56
|
-
|
|
66
|
+
server: <TValidationNext extends z.ZodTypeAny>(schema: ((tools: {
|
|
57
67
|
sql: TSql;
|
|
58
68
|
initialState: TNew;
|
|
59
69
|
client: TClient;
|
|
60
|
-
}) => TValidationNext) | TValidationNext) => Prettify<Builder<"
|
|
70
|
+
}) => TValidationNext) | TValidationNext) => Prettify<Builder<"server", T, TSql, TNew, TInitialValue, TClient, TValidationNext>>;
|
|
61
71
|
transform: (transforms: {
|
|
62
72
|
toClient: (dbValue: z.infer<TSql>) => z.infer<TClient>;
|
|
63
73
|
toDb: (clientValue: z.infer<TClient>) => z.infer<TSql>;
|
|
@@ -82,16 +92,16 @@ export type RelationConfig<T extends Schema<any>> = (BaseRelationConfig<T> & {
|
|
|
82
92
|
}) | (BaseRelationConfig<T> & {
|
|
83
93
|
type: "manyToMany";
|
|
84
94
|
});
|
|
85
|
-
type Stage = "sql" | "relation" | "new" | "client" | "
|
|
95
|
+
type Stage = "sql" | "relation" | "new" | "client" | "server" | "done";
|
|
86
96
|
type StageMethods = {
|
|
87
|
-
sql: "initialState" | "client" | "
|
|
88
|
-
relation: "
|
|
89
|
-
new: "client" | "
|
|
90
|
-
client: "
|
|
91
|
-
|
|
97
|
+
sql: "initialState" | "client" | "server" | "transform" | "reference";
|
|
98
|
+
relation: "server" | "transform";
|
|
99
|
+
new: "client" | "server" | "transform";
|
|
100
|
+
client: "server" | "transform";
|
|
101
|
+
server: "transform";
|
|
92
102
|
done: never;
|
|
93
103
|
};
|
|
94
|
-
type BuilderConfig<T extends
|
|
104
|
+
type BuilderConfig<T extends DbConfig, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> = {
|
|
95
105
|
sql: T;
|
|
96
106
|
zodSqlSchema: TSql;
|
|
97
107
|
zodNewSchema: TNew;
|
|
@@ -101,7 +111,7 @@ type BuilderConfig<T extends SQLType | RelationConfig<any>, TSql extends z.ZodTy
|
|
|
101
111
|
clientTransform?: (schema: z.ZodTypeAny) => z.ZodTypeAny;
|
|
102
112
|
validationTransform?: (schema: z.ZodTypeAny) => z.ZodTypeAny;
|
|
103
113
|
};
|
|
104
|
-
export type Builder<TStage extends Stage, T extends
|
|
114
|
+
export type Builder<TStage extends Stage, T extends DbConfig, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> = {
|
|
105
115
|
config: {
|
|
106
116
|
sql: T;
|
|
107
117
|
zodSqlSchema: TSql;
|
|
@@ -120,6 +130,8 @@ export type Reference<TGetter extends () => any> = {
|
|
|
120
130
|
getter: TGetter;
|
|
121
131
|
};
|
|
122
132
|
interface ShapeAPI {
|
|
133
|
+
initialState: <const TValue>(value: TValue | (() => TValue)) => Builder<"new", null, z.ZodUndefined, // No SQL schema
|
|
134
|
+
ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>, TValue extends () => infer R ? R : TValue, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>>;
|
|
123
135
|
sql: <T extends SQLType>(sqlConfig: T) => Builder<"sql", T, SQLToZodType<T, false>, SQLToZodType<T, false>, z.infer<SQLToZodType<T, false>>, SQLToZodType<T, false>, SQLToZodType<T, false>>;
|
|
124
136
|
reference: <TGetter extends () => any>(getter: TGetter) => Reference<TGetter>;
|
|
125
137
|
hasMany: <T extends HasManyDefault>(config?: T) => PlaceholderRelation<"hasMany">;
|
|
@@ -141,7 +153,22 @@ export type EnrichFields<T extends ShapeSchema> = {
|
|
|
141
153
|
[K in keyof T]: K extends "_tableName" ? T[K] : K extends string ? EnrichedField<K, T[K], T> : T[K];
|
|
142
154
|
};
|
|
143
155
|
export declare const SchemaWrapperBrand: unique symbol;
|
|
144
|
-
|
|
156
|
+
type PickPrimaryKeys<T extends ShapeSchema> = {
|
|
157
|
+
[K in keyof T as T[K] extends {
|
|
158
|
+
config: {
|
|
159
|
+
sql: {
|
|
160
|
+
pk: true;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
} ? K : never]: T[K];
|
|
164
|
+
};
|
|
165
|
+
type SchemaBuilder<T extends ShapeSchema> = Prettify<EnrichFields<T>> & {
|
|
166
|
+
__primaryKeySQL?: string;
|
|
167
|
+
__isClientChecker?: (record: any) => boolean;
|
|
168
|
+
primaryKeySQL: (definer: (pkFields: PickPrimaryKeys<T>) => string) => SchemaBuilder<T>;
|
|
169
|
+
isClient: (checker: (record: Prettify<z.infer<z.ZodObject<DeriveSchemaByKey<T, "zodSqlSchema">>> | z.infer<z.ZodObject<DeriveSchemaByKey<T, "zodClientSchema">>>>) => boolean) => SchemaBuilder<T>;
|
|
170
|
+
};
|
|
171
|
+
export declare function schema<T extends string, U extends ShapeSchema<T>>(schema: U): SchemaBuilder<U>;
|
|
145
172
|
export type RelationType = "hasMany" | "hasOne" | "manyToMany";
|
|
146
173
|
type BaseSchemaField<T extends SQLType = SQLType> = {
|
|
147
174
|
type: "field";
|
|
@@ -177,10 +204,17 @@ export declare function createSchema<T extends {
|
|
|
177
204
|
_tableName: string;
|
|
178
205
|
[SchemaWrapperBrand]?: true;
|
|
179
206
|
}, R extends Record<string, any> = {}, TActualSchema extends Omit<T & R, typeof SchemaWrapperBrand> = Omit<T & R, typeof SchemaWrapperBrand>>(schema: T, relations?: R): {
|
|
207
|
+
pk: string[];
|
|
208
|
+
clientPk: string[];
|
|
209
|
+
resolvePKs?: (record: any) => {
|
|
210
|
+
clientPk: any[];
|
|
211
|
+
dbPk: any[];
|
|
212
|
+
};
|
|
180
213
|
sqlSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>;
|
|
181
214
|
clientSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>;
|
|
182
215
|
validationSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>;
|
|
183
216
|
defaultValues: Prettify<DeriveDefaults<TActualSchema>>;
|
|
217
|
+
generateDefaults: () => Prettify<DeriveDefaults<TActualSchema>>;
|
|
184
218
|
toClient: (dbObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>;
|
|
185
219
|
toDb: (clientObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
|
|
186
220
|
};
|
|
@@ -306,46 +340,61 @@ type DeriveViewDefaults<TTableName extends keyof TRegistry, TSelection, TRegistr
|
|
|
306
340
|
]> | null : never : never : never;
|
|
307
341
|
} : {})>;
|
|
308
342
|
export type DeriveViewResultFromBox<TBox extends CreateSchemaBoxReturn<any, any>, TTableName extends keyof TBox, TSelection extends TBox[TTableName]["RelationSelection"]> = {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
343
|
+
definition: TBox[TTableName]["definition"];
|
|
344
|
+
schemaKey: TTableName;
|
|
345
|
+
schemas: {
|
|
346
|
+
sql: TBox[TTableName]["schemas"]["sql"];
|
|
347
|
+
client: z.ZodObject<_DeriveViewShape<TTableName, TSelection, {
|
|
348
|
+
[K in keyof TBox]: {
|
|
349
|
+
rawSchema: TBox[K]["definition"];
|
|
350
|
+
zodSchemas: {
|
|
351
|
+
sqlSchema: TBox[K]["schemas"]["sql"];
|
|
352
|
+
clientSchema: TBox[K]["schemas"]["client"];
|
|
353
|
+
validationSchema: TBox[K]["schemas"]["server"];
|
|
354
|
+
defaultValues: TBox[K]["defaults"];
|
|
355
|
+
toClient: TBox[K]["transforms"]["toClient"];
|
|
356
|
+
toDb: TBox[K]["transforms"]["toDb"];
|
|
357
|
+
};
|
|
320
358
|
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
359
|
+
}, "clientSchema">>;
|
|
360
|
+
server: z.ZodObject<_DeriveViewShape<TTableName, TSelection, {
|
|
361
|
+
[K in keyof TBox]: {
|
|
362
|
+
rawSchema: TBox[K]["definition"];
|
|
363
|
+
zodSchemas: {
|
|
364
|
+
sqlSchema: TBox[K]["schemas"]["sql"];
|
|
365
|
+
clientSchema: TBox[K]["schemas"]["client"];
|
|
366
|
+
validationSchema: TBox[K]["schemas"]["server"];
|
|
367
|
+
defaultValues: TBox[K]["defaults"];
|
|
368
|
+
toClient: TBox[K]["transforms"]["toClient"];
|
|
369
|
+
toDb: TBox[K]["transforms"]["toDb"];
|
|
370
|
+
};
|
|
333
371
|
};
|
|
334
|
-
}
|
|
335
|
-
}
|
|
372
|
+
}, "validationSchema">>;
|
|
373
|
+
};
|
|
374
|
+
transforms: {
|
|
375
|
+
toClient: TBox[TTableName]["transforms"]["toClient"];
|
|
376
|
+
toDb: TBox[TTableName]["transforms"]["toDb"];
|
|
377
|
+
};
|
|
336
378
|
defaults: DeriveViewDefaults<TTableName, TSelection, {
|
|
337
379
|
[K in keyof TBox]: {
|
|
338
380
|
rawSchema: TBox[K]["definition"];
|
|
339
381
|
zodSchemas: {
|
|
340
382
|
sqlSchema: TBox[K]["schemas"]["sql"];
|
|
341
383
|
clientSchema: TBox[K]["schemas"]["client"];
|
|
342
|
-
validationSchema: TBox[K]["schemas"]["
|
|
384
|
+
validationSchema: TBox[K]["schemas"]["server"];
|
|
343
385
|
defaultValues: TBox[K]["defaults"];
|
|
344
386
|
toClient: TBox[K]["transforms"]["toClient"];
|
|
345
387
|
toDb: TBox[K]["transforms"]["toDb"];
|
|
346
388
|
};
|
|
347
389
|
};
|
|
348
390
|
}>;
|
|
391
|
+
isView: true;
|
|
392
|
+
viewSelection: TSelection;
|
|
393
|
+
baseTable: TTableName;
|
|
394
|
+
nav?: undefined;
|
|
395
|
+
createView?: undefined;
|
|
396
|
+
RelationSelection?: undefined;
|
|
397
|
+
__registry: TBox;
|
|
349
398
|
};
|
|
350
399
|
export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRegistry extends RegistryShape> = {
|
|
351
400
|
definition: TRegistry[TTableName]["rawSchema"];
|
|
@@ -353,7 +402,7 @@ export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRe
|
|
|
353
402
|
schemas: {
|
|
354
403
|
sql: TRegistry[TTableName]["zodSchemas"]["sqlSchema"];
|
|
355
404
|
client: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>;
|
|
356
|
-
|
|
405
|
+
server: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "validationSchema">>;
|
|
357
406
|
};
|
|
358
407
|
transforms: {
|
|
359
408
|
toClient: TRegistry[TTableName]["zodSchemas"]["toClient"];
|
|
@@ -363,6 +412,9 @@ export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRe
|
|
|
363
412
|
isView: true;
|
|
364
413
|
viewSelection: TSelection;
|
|
365
414
|
baseTable: TTableName;
|
|
415
|
+
nav?: undefined;
|
|
416
|
+
createView?: undefined;
|
|
417
|
+
RelationSelection?: undefined;
|
|
366
418
|
__registry: TRegistry;
|
|
367
419
|
};
|
|
368
420
|
export type DeriveViewFromSchema<TSchema extends {
|
|
@@ -410,7 +462,7 @@ type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R e
|
|
|
410
462
|
schemas: {
|
|
411
463
|
sql: Resolved[K]["zodSchemas"]["sqlSchema"];
|
|
412
464
|
client: Resolved[K]["zodSchemas"]["clientSchema"];
|
|
413
|
-
|
|
465
|
+
server: Resolved[K]["zodSchemas"]["validationSchema"];
|
|
414
466
|
};
|
|
415
467
|
transforms: {
|
|
416
468
|
toClient: Resolved[K]["zodSchemas"]["toClient"];
|
|
@@ -441,7 +493,7 @@ type Prettify<T> = {
|
|
|
441
493
|
[K in keyof T]: T[K];
|
|
442
494
|
} & {};
|
|
443
495
|
type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodValidationSchema", Depth extends any[] = []> = Depth["length"] extends 10 ? any : {
|
|
444
|
-
[K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand ? never : K extends keyof T ? T[K] extends Reference<any> ? K : T[K] extends {
|
|
496
|
+
[K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand | "__primaryKeySQL" | "__isClientChecker" | "primaryKeySQL" | "isClient" ? never : K extends keyof T ? T[K] extends Reference<any> ? K : T[K] extends {
|
|
445
497
|
config: {
|
|
446
498
|
sql: {
|
|
447
499
|
type: "hasMany" | "manyToMany" | "hasOne" | "belongsTo";
|
|
@@ -458,7 +510,7 @@ type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodV
|
|
|
458
510
|
} ? ZodSchema : never;
|
|
459
511
|
};
|
|
460
512
|
type DeriveDefaults<T, Depth extends any[] = []> = Prettify<Depth["length"] extends 10 ? any : {
|
|
461
|
-
[K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand ? never : K extends keyof T ? T[K] extends Reference<any> ? K : T[K] extends {
|
|
513
|
+
[K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand | "__primaryKeySQL" | "__isClientChecker" | "primaryKeySQL" | "isClient" ? never : K extends keyof T ? T[K] extends Reference<any> ? K : T[K] extends {
|
|
462
514
|
config: {
|
|
463
515
|
sql: {
|
|
464
516
|
type: "hasMany" | "manyToMany" | "hasOne" | "belongsTo";
|
package/dist/schema.js
CHANGED
|
@@ -8,6 +8,41 @@ export function currentTimeStamp() {
|
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
export const s = {
|
|
11
|
+
initialState: (value) => {
|
|
12
|
+
const actualValue = isFunction(value) ? value() : value;
|
|
13
|
+
// Infer the Zod type from the primitive value
|
|
14
|
+
let inferredZodType;
|
|
15
|
+
if (typeof actualValue === "string") {
|
|
16
|
+
inferredZodType = z.string();
|
|
17
|
+
}
|
|
18
|
+
else if (typeof actualValue === "number") {
|
|
19
|
+
inferredZodType = z.number();
|
|
20
|
+
}
|
|
21
|
+
else if (typeof actualValue === "boolean") {
|
|
22
|
+
inferredZodType = z.boolean();
|
|
23
|
+
}
|
|
24
|
+
else if (actualValue instanceof Date) {
|
|
25
|
+
inferredZodType = z.date();
|
|
26
|
+
}
|
|
27
|
+
else if (actualValue === null) {
|
|
28
|
+
inferredZodType = z.null();
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
inferredZodType = z.any();
|
|
32
|
+
}
|
|
33
|
+
return createBuilder({
|
|
34
|
+
stage: "new",
|
|
35
|
+
// THE MAGIC: There is no SQL config and the SQL schema is z.undefined()
|
|
36
|
+
// This guarantees the field will be stripped from the final SQL schema object.
|
|
37
|
+
sqlConfig: null,
|
|
38
|
+
sqlZod: z.undefined(),
|
|
39
|
+
// The rest of the schemas are based on the inferred type
|
|
40
|
+
newZod: inferredZodType,
|
|
41
|
+
initialValue: actualValue,
|
|
42
|
+
clientZod: inferredZodType,
|
|
43
|
+
validationZod: inferredZodType, // This is our internal name
|
|
44
|
+
}); // Using `as any` to simplify the complex return type
|
|
45
|
+
},
|
|
11
46
|
reference: (getter) => ({
|
|
12
47
|
__type: "reference",
|
|
13
48
|
getter: getter,
|
|
@@ -85,93 +120,71 @@ function createBuilder(config) {
|
|
|
85
120
|
clientTransform: config.clientTransform, // <-- FIX: Make sure transform is passed through
|
|
86
121
|
validationTransform: config.validationTransform, // <-- FIX: Make sure transform is passed through
|
|
87
122
|
},
|
|
88
|
-
initialState: (
|
|
123
|
+
initialState: (options) => {
|
|
89
124
|
if (completedStages.has("new")) {
|
|
90
125
|
throw new Error("initialState() can only be called once in the chain");
|
|
91
126
|
}
|
|
127
|
+
const { value, schema: schemaOrModifier, clientPk } = options;
|
|
92
128
|
let actualValue;
|
|
93
|
-
let baseSchema;
|
|
94
129
|
let finalSchema;
|
|
95
|
-
//
|
|
96
|
-
if (value
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
130
|
+
// 1. Determine the actual value
|
|
131
|
+
if (value !== undefined) {
|
|
132
|
+
actualValue = isFunction(value) ? value() : value;
|
|
133
|
+
}
|
|
134
|
+
else if (schemaOrModifier &&
|
|
135
|
+
typeof schemaOrModifier === "object" &&
|
|
136
|
+
"_def" in schemaOrModifier) {
|
|
137
|
+
// If only a schema is provided, infer the default from it
|
|
138
|
+
actualValue = inferDefaultFromZod(schemaOrModifier, config.sqlConfig);
|
|
139
|
+
}
|
|
140
|
+
// 2. Determine the final schema
|
|
141
|
+
let baseSchema;
|
|
142
|
+
if (schemaOrModifier &&
|
|
143
|
+
typeof schemaOrModifier === "object" &&
|
|
144
|
+
"_def" in schemaOrModifier) {
|
|
145
|
+
// A raw Zod schema was passed
|
|
146
|
+
finalSchema = schemaOrModifier;
|
|
101
147
|
}
|
|
102
148
|
else {
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
baseSchema = z.number();
|
|
119
|
-
}
|
|
120
|
-
else if (typeof actualValue === "boolean") {
|
|
121
|
-
baseSchema = z.boolean();
|
|
122
|
-
}
|
|
123
|
-
else if (actualValue instanceof Date) {
|
|
124
|
-
baseSchema = z.date();
|
|
125
|
-
}
|
|
126
|
-
else if (actualValue === null) {
|
|
127
|
-
baseSchema = z.null();
|
|
128
|
-
}
|
|
129
|
-
else if (actualValue === undefined) {
|
|
130
|
-
baseSchema = z.undefined();
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
baseSchema = z.any();
|
|
134
|
-
}
|
|
135
|
-
// Apply the modifier
|
|
149
|
+
// Base schema must be inferred from the value type
|
|
150
|
+
if (typeof actualValue === "string")
|
|
151
|
+
baseSchema = z.string();
|
|
152
|
+
else if (typeof actualValue === "number")
|
|
153
|
+
baseSchema = z.number();
|
|
154
|
+
else if (typeof actualValue === "boolean")
|
|
155
|
+
baseSchema = z.boolean();
|
|
156
|
+
else if (actualValue instanceof Date)
|
|
157
|
+
baseSchema = z.date();
|
|
158
|
+
else if (actualValue === null)
|
|
159
|
+
baseSchema = z.null();
|
|
160
|
+
else
|
|
161
|
+
baseSchema = z.any();
|
|
162
|
+
if (isFunction(schemaOrModifier)) {
|
|
163
|
+
// A modifier function was passed
|
|
136
164
|
finalSchema = schemaOrModifier(baseSchema);
|
|
137
165
|
}
|
|
138
166
|
else {
|
|
139
|
-
// No schema
|
|
140
|
-
if (typeof actualValue === "string") {
|
|
141
|
-
baseSchema = z.string();
|
|
142
|
-
}
|
|
143
|
-
else if (typeof actualValue === "number") {
|
|
144
|
-
baseSchema = z.number();
|
|
145
|
-
}
|
|
146
|
-
else if (typeof actualValue === "boolean") {
|
|
147
|
-
baseSchema = z.boolean();
|
|
148
|
-
}
|
|
149
|
-
else if (actualValue instanceof Date) {
|
|
150
|
-
baseSchema = z.date();
|
|
151
|
-
}
|
|
152
|
-
else if (actualValue === null) {
|
|
153
|
-
baseSchema = z.null();
|
|
154
|
-
}
|
|
155
|
-
else if (actualValue === undefined) {
|
|
156
|
-
baseSchema = z.undefined();
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
baseSchema = z.any();
|
|
160
|
-
}
|
|
167
|
+
// No schema/modifier, use the inferred base schema
|
|
161
168
|
finalSchema = baseSchema;
|
|
162
169
|
}
|
|
163
170
|
}
|
|
164
171
|
const newCompletedStages = new Set(completedStages);
|
|
165
172
|
newCompletedStages.add("new");
|
|
166
|
-
// Create union
|
|
167
|
-
const
|
|
173
|
+
// Create union of the SQL type and the new client type
|
|
174
|
+
const clientAndServerSchema = z.union([config.sqlZod, finalSchema]);
|
|
175
|
+
const newConfig = { ...config.sqlConfig };
|
|
176
|
+
if (clientPk) {
|
|
177
|
+
// Add our metadata flag to the config
|
|
178
|
+
newConfig.isClientPk = true;
|
|
179
|
+
}
|
|
168
180
|
return createBuilder({
|
|
169
181
|
...config,
|
|
170
182
|
stage: "new",
|
|
183
|
+
sqlConfig: newConfig,
|
|
171
184
|
newZod: finalSchema,
|
|
172
185
|
initialValue: actualValue,
|
|
173
|
-
clientZod:
|
|
174
|
-
validationZod:
|
|
186
|
+
clientZod: clientAndServerSchema,
|
|
187
|
+
validationZod: clientAndServerSchema, // Our internal name
|
|
175
188
|
completedStages: newCompletedStages,
|
|
176
189
|
});
|
|
177
190
|
},
|
|
@@ -188,7 +201,7 @@ function createBuilder(config) {
|
|
|
188
201
|
if (completedStages.has("client")) {
|
|
189
202
|
throw new Error("client() can only be called once in the chain");
|
|
190
203
|
}
|
|
191
|
-
if (completedStages.has("
|
|
204
|
+
if (completedStages.has("server")) {
|
|
192
205
|
throw new Error("client() must be called before validation()");
|
|
193
206
|
}
|
|
194
207
|
const newCompletedStages = new Set(completedStages);
|
|
@@ -224,10 +237,10 @@ function createBuilder(config) {
|
|
|
224
237
|
completedStages: newCompletedStages,
|
|
225
238
|
});
|
|
226
239
|
},
|
|
227
|
-
|
|
240
|
+
server: (
|
|
228
241
|
// ... this validation function remains unchanged ...
|
|
229
242
|
assert) => {
|
|
230
|
-
if (completedStages.has("
|
|
243
|
+
if (completedStages.has("server")) {
|
|
231
244
|
throw new Error("validation() can only be called once in the chain");
|
|
232
245
|
}
|
|
233
246
|
const validationSchema = isFunction(assert)
|
|
@@ -238,17 +251,16 @@ function createBuilder(config) {
|
|
|
238
251
|
})
|
|
239
252
|
: assert;
|
|
240
253
|
const newCompletedStages = new Set(completedStages);
|
|
241
|
-
newCompletedStages.add("
|
|
254
|
+
newCompletedStages.add("server");
|
|
242
255
|
return createBuilder({
|
|
243
256
|
...config,
|
|
244
|
-
stage: "
|
|
257
|
+
stage: "server",
|
|
245
258
|
validationZod: validationSchema,
|
|
246
259
|
completedStages: newCompletedStages,
|
|
247
260
|
});
|
|
248
261
|
},
|
|
249
262
|
transform: (transforms) => {
|
|
250
|
-
if (!completedStages.has("
|
|
251
|
-
!completedStages.has("client")) {
|
|
263
|
+
if (!completedStages.has("server") && !completedStages.has("client")) {
|
|
252
264
|
throw new Error("transform() requires at least client() or validation() to be called first");
|
|
253
265
|
}
|
|
254
266
|
return {
|
|
@@ -265,50 +277,65 @@ function createBuilder(config) {
|
|
|
265
277
|
return builderObject;
|
|
266
278
|
}
|
|
267
279
|
export const SchemaWrapperBrand = Symbol("SchemaWrapper");
|
|
268
|
-
// Update the schema function
|
|
269
280
|
export function schema(schema) {
|
|
281
|
+
// Create the enriched schema with all fields
|
|
270
282
|
const enrichedSchema = {};
|
|
271
283
|
for (const key in schema) {
|
|
272
284
|
if (Object.prototype.hasOwnProperty.call(schema, key)) {
|
|
273
285
|
if (key === "_tableName") {
|
|
274
|
-
// Don't enrich _tableName, keep it as a simple string
|
|
275
286
|
enrichedSchema[key] = schema[key];
|
|
276
287
|
}
|
|
277
288
|
else {
|
|
278
|
-
// Enrich other fields
|
|
279
289
|
enrichedSchema[key] = {
|
|
280
290
|
...schema[key],
|
|
281
|
-
__meta: {
|
|
282
|
-
_key: key,
|
|
283
|
-
_fieldType: schema[key],
|
|
284
|
-
},
|
|
291
|
+
__meta: { _key: key, _fieldType: schema[key] },
|
|
285
292
|
__parentTableType: schema,
|
|
286
293
|
};
|
|
287
294
|
}
|
|
288
295
|
}
|
|
289
296
|
}
|
|
290
297
|
enrichedSchema[SchemaWrapperBrand] = true;
|
|
298
|
+
// Add private properties
|
|
299
|
+
enrichedSchema.__primaryKeySQL = undefined;
|
|
300
|
+
enrichedSchema.__isClientChecker = undefined;
|
|
301
|
+
// Add methods directly
|
|
302
|
+
enrichedSchema.primaryKeySQL = function (definer) {
|
|
303
|
+
const pkFieldsOnly = {};
|
|
304
|
+
// Find all PK fields
|
|
305
|
+
for (const key in schema) {
|
|
306
|
+
const field = schema[key];
|
|
307
|
+
if (field &&
|
|
308
|
+
typeof field === "object" &&
|
|
309
|
+
field.config?.sql?.pk === true) {
|
|
310
|
+
pkFieldsOnly[key] = schema[key];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
enrichedSchema.__primaryKeySQL = definer(pkFieldsOnly);
|
|
314
|
+
return enrichedSchema;
|
|
315
|
+
};
|
|
316
|
+
enrichedSchema.isClient = function (checker) {
|
|
317
|
+
enrichedSchema.__isClientChecker = checker;
|
|
318
|
+
return enrichedSchema;
|
|
319
|
+
};
|
|
291
320
|
return enrichedSchema;
|
|
292
321
|
}
|
|
293
322
|
function inferDefaultFromZod(zodType, sqlConfig) {
|
|
323
|
+
// --- START OF FIX ---
|
|
324
|
+
// If the database is responsible for the default, the client shouldn't generate a value.
|
|
325
|
+
if (sqlConfig &&
|
|
326
|
+
"default" in sqlConfig &&
|
|
327
|
+
sqlConfig.default === "CURRENT_TIMESTAMP") {
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
// --- END OF FIX ---
|
|
294
331
|
if (sqlConfig && typeof sqlConfig === "object" && "type" in sqlConfig) {
|
|
295
332
|
if ("default" in sqlConfig && sqlConfig.default !== undefined) {
|
|
296
|
-
if
|
|
297
|
-
return undefined;
|
|
298
|
-
}
|
|
333
|
+
// This part now runs only if default is not CURRENT_TIMESTAMP
|
|
299
334
|
return sqlConfig.default;
|
|
300
335
|
}
|
|
301
336
|
if (typeof sqlConfig.type === "string" &&
|
|
302
337
|
["hasMany", "hasOne", "belongsTo", "manyToMany"].includes(sqlConfig.type)) {
|
|
303
|
-
|
|
304
|
-
if (relationConfig.type === "hasMany" ||
|
|
305
|
-
relationConfig.type === "manyToMany") {
|
|
306
|
-
return Array.from({ length: relationConfig.defaultCount || 0 }, () => ({}));
|
|
307
|
-
}
|
|
308
|
-
if (relationConfig.type === "hasOne" ||
|
|
309
|
-
relationConfig.type === "belongsTo") {
|
|
310
|
-
return {};
|
|
311
|
-
}
|
|
338
|
+
// ... (rest of the function is unchanged)
|
|
312
339
|
}
|
|
313
340
|
const sqlTypeConfig = sqlConfig;
|
|
314
341
|
if (sqlTypeConfig.type && !sqlTypeConfig.nullable) {
|
|
@@ -324,6 +351,7 @@ function inferDefaultFromZod(zodType, sqlConfig) {
|
|
|
324
351
|
return false;
|
|
325
352
|
case "date":
|
|
326
353
|
case "datetime":
|
|
354
|
+
case "timestamp": // Added timestamp here for completeness
|
|
327
355
|
return new Date();
|
|
328
356
|
}
|
|
329
357
|
}
|
|
@@ -421,14 +449,19 @@ function isReference(value) {
|
|
|
421
449
|
export function createSchema(schema, relations) {
|
|
422
450
|
const sqlFields = {};
|
|
423
451
|
const clientFields = {};
|
|
424
|
-
const
|
|
452
|
+
const serverFields = {};
|
|
425
453
|
const defaultValues = {};
|
|
454
|
+
const defaultGenerators = {};
|
|
426
455
|
const fieldTransforms = {};
|
|
427
456
|
const fullSchema = { ...schema, ...(relations || {}) };
|
|
457
|
+
let pkKeys = [];
|
|
458
|
+
let clientPkKeys = [];
|
|
459
|
+
const pkResolver = schema.__pkResolver;
|
|
428
460
|
for (const key in fullSchema) {
|
|
429
461
|
if (key === "_tableName" ||
|
|
430
462
|
key.startsWith("__") ||
|
|
431
|
-
key === String(SchemaWrapperBrand)
|
|
463
|
+
key === String(SchemaWrapperBrand) ||
|
|
464
|
+
key === "resolvePKs")
|
|
432
465
|
continue;
|
|
433
466
|
const definition = fullSchema[key];
|
|
434
467
|
// Handle new-style references
|
|
@@ -438,7 +471,9 @@ export function createSchema(schema, relations) {
|
|
|
438
471
|
const config = targetField.config;
|
|
439
472
|
sqlFields[key] = config.zodSqlSchema;
|
|
440
473
|
clientFields[key] = config.zodClientSchema;
|
|
441
|
-
|
|
474
|
+
serverFields[key] = config.zodValidationSchema;
|
|
475
|
+
const initialValueOrFn = config.initialValue;
|
|
476
|
+
defaultGenerators[key] = initialValueOrFn;
|
|
442
477
|
defaultValues[key] = inferDefaultFromZod(config.zodClientSchema, {
|
|
443
478
|
...config.sql,
|
|
444
479
|
default: undefined,
|
|
@@ -447,43 +482,51 @@ export function createSchema(schema, relations) {
|
|
|
447
482
|
fieldTransforms[key] = config.transforms;
|
|
448
483
|
}
|
|
449
484
|
}
|
|
450
|
-
continue;
|
|
485
|
+
continue; // Skip the rest of the logic for references
|
|
451
486
|
}
|
|
452
|
-
//
|
|
453
|
-
if (definition && definition.type === "reference") {
|
|
454
|
-
const referencedFieldBuilder = definition.to();
|
|
455
|
-
const referencedConfig = referencedFieldBuilder.config;
|
|
456
|
-
sqlFields[key] = referencedConfig.zodSqlSchema;
|
|
457
|
-
clientFields[key] = referencedConfig.zodClientSchema;
|
|
458
|
-
validationFields[key] = referencedConfig.zodValidationSchema;
|
|
459
|
-
defaultValues[key] = inferDefaultFromZod(referencedConfig.zodClientSchema, { ...referencedConfig.sql, default: undefined });
|
|
460
|
-
continue;
|
|
461
|
-
}
|
|
462
|
-
// Handle fields with a config property (builders)
|
|
487
|
+
// THEN, handle all other fields that have a config (builders, relations, etc.)
|
|
463
488
|
if (definition && definition.config) {
|
|
464
489
|
const config = definition.config;
|
|
490
|
+
if (config.sql?.pk && !config.sql?.isForeignKey) {
|
|
491
|
+
pkKeys.push(key);
|
|
492
|
+
}
|
|
493
|
+
if (config.sql?.isClientPk) {
|
|
494
|
+
clientPkKeys.push(key);
|
|
495
|
+
}
|
|
496
|
+
// The rest of the logic for builders
|
|
465
497
|
const sqlConfig = config.sql;
|
|
466
498
|
if (sqlConfig &&
|
|
467
499
|
typeof sqlConfig === "object" &&
|
|
468
500
|
["hasMany", "hasOne", "belongsTo", "manyToMany"].includes(sqlConfig.type)) {
|
|
469
|
-
|
|
501
|
+
// This is for relations, which also aren't PKs, so we just continue.
|
|
470
502
|
continue;
|
|
471
503
|
}
|
|
472
504
|
else {
|
|
473
|
-
//
|
|
505
|
+
// This is for regular s.sql() fields
|
|
474
506
|
sqlFields[key] = config.zodSqlSchema;
|
|
475
507
|
clientFields[key] = config.zodClientSchema;
|
|
476
|
-
|
|
508
|
+
serverFields[key] = config.zodValidationSchema;
|
|
477
509
|
if (config.transforms) {
|
|
478
510
|
fieldTransforms[key] = config.transforms;
|
|
479
511
|
}
|
|
480
512
|
const initialValueOrFn = config.initialValue;
|
|
513
|
+
defaultGenerators[key] = initialValueOrFn;
|
|
481
514
|
defaultValues[key] = isFunction(initialValueOrFn)
|
|
482
515
|
? initialValueOrFn()
|
|
483
516
|
: initialValueOrFn;
|
|
484
517
|
}
|
|
485
518
|
}
|
|
486
519
|
}
|
|
520
|
+
const generateDefaults = () => {
|
|
521
|
+
const freshDefaults = {};
|
|
522
|
+
for (const key in defaultGenerators) {
|
|
523
|
+
const generatorOrValue = defaultGenerators[key];
|
|
524
|
+
freshDefaults[key] = isFunction(generatorOrValue)
|
|
525
|
+
? generatorOrValue() // Call the function to get a fresh value
|
|
526
|
+
: generatorOrValue; // Use the static value
|
|
527
|
+
}
|
|
528
|
+
return freshDefaults;
|
|
529
|
+
};
|
|
487
530
|
const toClient = (dbObject) => {
|
|
488
531
|
const clientObject = { ...dbObject };
|
|
489
532
|
for (const key in fieldTransforms) {
|
|
@@ -503,10 +546,14 @@ export function createSchema(schema, relations) {
|
|
|
503
546
|
return dbObject;
|
|
504
547
|
};
|
|
505
548
|
return {
|
|
549
|
+
pk: pkKeys,
|
|
550
|
+
clientPk: clientPkKeys,
|
|
551
|
+
resolvePKs: pkResolver,
|
|
506
552
|
sqlSchema: z.object(sqlFields),
|
|
507
553
|
clientSchema: z.object(clientFields),
|
|
508
|
-
validationSchema: z.object(
|
|
554
|
+
validationSchema: z.object(serverFields),
|
|
509
555
|
defaultValues: defaultValues,
|
|
556
|
+
generateDefaults,
|
|
510
557
|
toClient,
|
|
511
558
|
toDb,
|
|
512
559
|
};
|
|
@@ -530,7 +577,9 @@ selection, registry, tableNameToRegistryKeyMap // The lookup map
|
|
|
530
577
|
throw new Error(`Schema with key "${currentRegistryKey}" not found in the registry.`);
|
|
531
578
|
}
|
|
532
579
|
// 2. Get the base Zod schema (primitives and references only) for the current level.
|
|
533
|
-
const baseSchema =
|
|
580
|
+
const baseSchema = schemaType === "server"
|
|
581
|
+
? registryEntry.zodSchemas.validationSchema
|
|
582
|
+
: registryEntry.zodSchemas.clientSchema;
|
|
534
583
|
const primitiveShape = baseSchema.shape;
|
|
535
584
|
// 3. If the selection is just `true`, we are done at this level. Return the base primitive schema.
|
|
536
585
|
if (subSelection === true) {
|
|
@@ -574,7 +623,7 @@ selection, registry, tableNameToRegistryKeyMap // The lookup map
|
|
|
574
623
|
return {
|
|
575
624
|
sql: registry[initialRegistryKey].zodSchemas.sqlSchema,
|
|
576
625
|
client: buildView(initialRegistryKey, selection, "client"),
|
|
577
|
-
|
|
626
|
+
server: buildView(initialRegistryKey, selection, "server"),
|
|
578
627
|
};
|
|
579
628
|
}
|
|
580
629
|
export function createSchemaBox(schemas, resolver) {
|
|
@@ -611,7 +660,12 @@ export function createSchemaBox(schemas, resolver) {
|
|
|
611
660
|
if (isReference(field)) {
|
|
612
661
|
const targetField = field.getter();
|
|
613
662
|
if (targetField && targetField.config) {
|
|
614
|
-
|
|
663
|
+
const newConfig = JSON.parse(JSON.stringify(targetField.config));
|
|
664
|
+
newConfig.sql.isForeignKey = true; // Add the tag
|
|
665
|
+
resolvedSchemas[tableName][fieldName] = {
|
|
666
|
+
...targetField,
|
|
667
|
+
config: newConfig,
|
|
668
|
+
};
|
|
615
669
|
}
|
|
616
670
|
else {
|
|
617
671
|
throw new Error(`Could not resolve reference for ${tableName}.${fieldName}`);
|
|
@@ -700,13 +754,18 @@ export function createSchemaBox(schemas, resolver) {
|
|
|
700
754
|
schemas: {
|
|
701
755
|
sql: entry.zodSchemas.sqlSchema,
|
|
702
756
|
client: entry.zodSchemas.clientSchema,
|
|
703
|
-
|
|
757
|
+
server: entry.zodSchemas.validationSchema,
|
|
704
758
|
},
|
|
705
759
|
transforms: {
|
|
706
760
|
toClient: entry.zodSchemas.toClient,
|
|
707
761
|
toDb: entry.zodSchemas.toDb,
|
|
708
762
|
},
|
|
709
763
|
defaults: entry.zodSchemas.defaultValues,
|
|
764
|
+
generateDefaults: entry.zodSchemas.generateDefaults,
|
|
765
|
+
// ADD: Expose PK info and resolver
|
|
766
|
+
pk: entry.zodSchemas.pk,
|
|
767
|
+
clientPk: entry.zodSchemas.clientPk,
|
|
768
|
+
resolvePKs: entry.zodSchemas.resolvePKs,
|
|
710
769
|
nav: createNavProxy(tableName, finalRegistry),
|
|
711
770
|
// Add this
|
|
712
771
|
createView: (selection) => {
|
|
@@ -719,7 +778,7 @@ export function createSchemaBox(schemas, resolver) {
|
|
|
719
778
|
schemas: {
|
|
720
779
|
sql: view.sql,
|
|
721
780
|
client: view.client,
|
|
722
|
-
|
|
781
|
+
server: view.server,
|
|
723
782
|
},
|
|
724
783
|
transforms: {
|
|
725
784
|
toClient: entry.zodSchemas.toClient, // May need composition for nested
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cogsbox-shape",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.146",
|
|
4
4
|
"description": "A TypeScript library for creating type-safe database schemas with Zod validation, SQL type definitions, and automatic client/server transformations. Unifies client, server, and database types through a single schema definition, with built-in support for relationships and serialization.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|