cogsbox-shape 0.5.145 → 0.5.147
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 +53 -87
- package/dist/schema.js +172 -116
- 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,24 @@ 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, z.infer<TSchema>, // <-- THIS IS THE FIX: Use schema's type, not literal value
|
|
57
|
+
CollapsedUnion<TSql, TSchema>, CollapsedUnion<TSql, TSchema>>>;
|
|
47
58
|
reference: <TRefSchema extends {
|
|
48
59
|
_tableName: string;
|
|
49
60
|
}>(fieldGetter: () => any) => Builder<"sql", T & {
|
|
@@ -53,11 +64,11 @@ export interface IBuilderMethods<T extends SQLType | RelationConfig<any>, TSql e
|
|
|
53
64
|
sql: TSql;
|
|
54
65
|
initialState: TNew;
|
|
55
66
|
}) => TClientNext) | TClientNext) => Prettify<Builder<"client", T, TSql, TNew, TInitialValue, TClientNext, TClientNext>>;
|
|
56
|
-
|
|
67
|
+
server: <TValidationNext extends z.ZodTypeAny>(schema: ((tools: {
|
|
57
68
|
sql: TSql;
|
|
58
69
|
initialState: TNew;
|
|
59
70
|
client: TClient;
|
|
60
|
-
}) => TValidationNext) | TValidationNext) => Prettify<Builder<"
|
|
71
|
+
}) => TValidationNext) | TValidationNext) => Prettify<Builder<"server", T, TSql, TNew, TInitialValue, TClient, TValidationNext>>;
|
|
61
72
|
transform: (transforms: {
|
|
62
73
|
toClient: (dbValue: z.infer<TSql>) => z.infer<TClient>;
|
|
63
74
|
toDb: (clientValue: z.infer<TClient>) => z.infer<TSql>;
|
|
@@ -82,16 +93,16 @@ export type RelationConfig<T extends Schema<any>> = (BaseRelationConfig<T> & {
|
|
|
82
93
|
}) | (BaseRelationConfig<T> & {
|
|
83
94
|
type: "manyToMany";
|
|
84
95
|
});
|
|
85
|
-
type Stage = "sql" | "relation" | "new" | "client" | "
|
|
96
|
+
type Stage = "sql" | "relation" | "new" | "client" | "server" | "done";
|
|
86
97
|
type StageMethods = {
|
|
87
|
-
sql: "initialState" | "client" | "
|
|
88
|
-
relation: "
|
|
89
|
-
new: "client" | "
|
|
90
|
-
client: "
|
|
91
|
-
|
|
98
|
+
sql: "initialState" | "client" | "server" | "transform" | "reference";
|
|
99
|
+
relation: "server" | "transform";
|
|
100
|
+
new: "client" | "server" | "transform";
|
|
101
|
+
client: "server" | "transform";
|
|
102
|
+
server: "transform";
|
|
92
103
|
done: never;
|
|
93
104
|
};
|
|
94
|
-
type BuilderConfig<T extends
|
|
105
|
+
type BuilderConfig<T extends DbConfig, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> = {
|
|
95
106
|
sql: T;
|
|
96
107
|
zodSqlSchema: TSql;
|
|
97
108
|
zodNewSchema: TNew;
|
|
@@ -101,7 +112,7 @@ type BuilderConfig<T extends SQLType | RelationConfig<any>, TSql extends z.ZodTy
|
|
|
101
112
|
clientTransform?: (schema: z.ZodTypeAny) => z.ZodTypeAny;
|
|
102
113
|
validationTransform?: (schema: z.ZodTypeAny) => z.ZodTypeAny;
|
|
103
114
|
};
|
|
104
|
-
export type Builder<TStage extends Stage, T extends
|
|
115
|
+
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
116
|
config: {
|
|
106
117
|
sql: T;
|
|
107
118
|
zodSqlSchema: TSql;
|
|
@@ -120,6 +131,8 @@ export type Reference<TGetter extends () => any> = {
|
|
|
120
131
|
getter: TGetter;
|
|
121
132
|
};
|
|
122
133
|
interface ShapeAPI {
|
|
134
|
+
initialState: <const TValue>(value: TValue | (() => TValue)) => Builder<"new", null, z.ZodUndefined, // No SQL schema
|
|
135
|
+
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
136
|
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
137
|
reference: <TGetter extends () => any>(getter: TGetter) => Reference<TGetter>;
|
|
125
138
|
hasMany: <T extends HasManyDefault>(config?: T) => PlaceholderRelation<"hasMany">;
|
|
@@ -141,7 +154,22 @@ export type EnrichFields<T extends ShapeSchema> = {
|
|
|
141
154
|
[K in keyof T]: K extends "_tableName" ? T[K] : K extends string ? EnrichedField<K, T[K], T> : T[K];
|
|
142
155
|
};
|
|
143
156
|
export declare const SchemaWrapperBrand: unique symbol;
|
|
144
|
-
|
|
157
|
+
type PickPrimaryKeys<T extends ShapeSchema> = {
|
|
158
|
+
[K in keyof T as T[K] extends {
|
|
159
|
+
config: {
|
|
160
|
+
sql: {
|
|
161
|
+
pk: true;
|
|
162
|
+
};
|
|
163
|
+
};
|
|
164
|
+
} ? K : never]: T[K];
|
|
165
|
+
};
|
|
166
|
+
type SchemaBuilder<T extends ShapeSchema> = Prettify<EnrichFields<T>> & {
|
|
167
|
+
__primaryKeySQL?: string;
|
|
168
|
+
__isClientChecker?: (record: any) => boolean;
|
|
169
|
+
primaryKeySQL: (definer: (pkFields: PickPrimaryKeys<T>) => string) => SchemaBuilder<T>;
|
|
170
|
+
isClient: (checker: (record: Prettify<z.infer<z.ZodObject<DeriveSchemaByKey<T, "zodSqlSchema">>> | z.infer<z.ZodObject<DeriveSchemaByKey<T, "zodClientSchema">>>>) => boolean) => SchemaBuilder<T>;
|
|
171
|
+
};
|
|
172
|
+
export declare function schema<T extends string, U extends ShapeSchema<T>>(schema: U): SchemaBuilder<U>;
|
|
145
173
|
export type RelationType = "hasMany" | "hasOne" | "manyToMany";
|
|
146
174
|
type BaseSchemaField<T extends SQLType = SQLType> = {
|
|
147
175
|
type: "field";
|
|
@@ -177,10 +205,13 @@ export declare function createSchema<T extends {
|
|
|
177
205
|
_tableName: string;
|
|
178
206
|
[SchemaWrapperBrand]?: true;
|
|
179
207
|
}, R extends Record<string, any> = {}, TActualSchema extends Omit<T & R, typeof SchemaWrapperBrand> = Omit<T & R, typeof SchemaWrapperBrand>>(schema: T, relations?: R): {
|
|
208
|
+
pk: string[] | null;
|
|
209
|
+
clientPk: string[] | null;
|
|
180
210
|
sqlSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>;
|
|
181
211
|
clientSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>;
|
|
182
212
|
validationSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>;
|
|
183
213
|
defaultValues: Prettify<DeriveDefaults<TActualSchema>>;
|
|
214
|
+
generateDefaults: () => Prettify<DeriveDefaults<TActualSchema>>;
|
|
184
215
|
toClient: (dbObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>;
|
|
185
216
|
toDb: (clientObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
|
|
186
217
|
};
|
|
@@ -305,70 +336,13 @@ type DeriveViewDefaults<TTableName extends keyof TRegistry, TSelection, TRegistr
|
|
|
305
336
|
1
|
|
306
337
|
]> | null : never : never : never;
|
|
307
338
|
} : {})>;
|
|
308
|
-
export type DeriveViewResultFromBox<TBox extends CreateSchemaBoxReturn<any, any>, TTableName extends keyof TBox, TSelection extends TBox[TTableName]["RelationSelection"]> = {
|
|
309
|
-
definition: TBox[TTableName]["definition"];
|
|
310
|
-
schemaKey: TTableName;
|
|
311
|
-
schemas: {
|
|
312
|
-
sql: TBox[TTableName]["schemas"]["sql"];
|
|
313
|
-
client: z.ZodObject<_DeriveViewShape<TTableName, TSelection, {
|
|
314
|
-
[K in keyof TBox]: {
|
|
315
|
-
rawSchema: TBox[K]["definition"];
|
|
316
|
-
zodSchemas: {
|
|
317
|
-
sqlSchema: TBox[K]["schemas"]["sql"];
|
|
318
|
-
clientSchema: TBox[K]["schemas"]["client"];
|
|
319
|
-
validationSchema: TBox[K]["schemas"]["validation"];
|
|
320
|
-
defaultValues: TBox[K]["defaults"];
|
|
321
|
-
toClient: TBox[K]["transforms"]["toClient"];
|
|
322
|
-
toDb: TBox[K]["transforms"]["toDb"];
|
|
323
|
-
};
|
|
324
|
-
};
|
|
325
|
-
}, "clientSchema">>;
|
|
326
|
-
validation: z.ZodObject<_DeriveViewShape<TTableName, TSelection, {
|
|
327
|
-
[K in keyof TBox]: {
|
|
328
|
-
rawSchema: TBox[K]["definition"];
|
|
329
|
-
zodSchemas: {
|
|
330
|
-
sqlSchema: TBox[K]["schemas"]["sql"];
|
|
331
|
-
clientSchema: TBox[K]["schemas"]["client"];
|
|
332
|
-
validationSchema: TBox[K]["schemas"]["validation"];
|
|
333
|
-
defaultValues: TBox[K]["defaults"];
|
|
334
|
-
toClient: TBox[K]["transforms"]["toClient"];
|
|
335
|
-
toDb: TBox[K]["transforms"]["toDb"];
|
|
336
|
-
};
|
|
337
|
-
};
|
|
338
|
-
}, "validationSchema">>;
|
|
339
|
-
};
|
|
340
|
-
transforms: {
|
|
341
|
-
toClient: TBox[TTableName]["transforms"]["toClient"];
|
|
342
|
-
toDb: TBox[TTableName]["transforms"]["toDb"];
|
|
343
|
-
};
|
|
344
|
-
defaults: DeriveViewDefaults<TTableName, TSelection, {
|
|
345
|
-
[K in keyof TBox]: {
|
|
346
|
-
rawSchema: TBox[K]["definition"];
|
|
347
|
-
zodSchemas: {
|
|
348
|
-
sqlSchema: TBox[K]["schemas"]["sql"];
|
|
349
|
-
clientSchema: TBox[K]["schemas"]["client"];
|
|
350
|
-
validationSchema: TBox[K]["schemas"]["validation"];
|
|
351
|
-
defaultValues: TBox[K]["defaults"];
|
|
352
|
-
toClient: TBox[K]["transforms"]["toClient"];
|
|
353
|
-
toDb: TBox[K]["transforms"]["toDb"];
|
|
354
|
-
};
|
|
355
|
-
};
|
|
356
|
-
}>;
|
|
357
|
-
isView: true;
|
|
358
|
-
viewSelection: TSelection;
|
|
359
|
-
baseTable: TTableName;
|
|
360
|
-
nav?: undefined;
|
|
361
|
-
createView?: undefined;
|
|
362
|
-
RelationSelection?: undefined;
|
|
363
|
-
__registry: TBox;
|
|
364
|
-
};
|
|
365
339
|
export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRegistry extends RegistryShape> = {
|
|
366
340
|
definition: TRegistry[TTableName]["rawSchema"];
|
|
367
341
|
schemaKey: TTableName;
|
|
368
342
|
schemas: {
|
|
369
343
|
sql: TRegistry[TTableName]["zodSchemas"]["sqlSchema"];
|
|
370
344
|
client: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>;
|
|
371
|
-
|
|
345
|
+
server: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "validationSchema">>;
|
|
372
346
|
};
|
|
373
347
|
transforms: {
|
|
374
348
|
toClient: TRegistry[TTableName]["zodSchemas"]["toClient"];
|
|
@@ -383,14 +357,6 @@ export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRe
|
|
|
383
357
|
RelationSelection?: undefined;
|
|
384
358
|
__registry: TRegistry;
|
|
385
359
|
};
|
|
386
|
-
export type DeriveViewFromSchema<TSchema extends {
|
|
387
|
-
schemaKey: string;
|
|
388
|
-
__registry: RegistryShape;
|
|
389
|
-
RelationSelection: any;
|
|
390
|
-
}, TSelection extends TSchema["RelationSelection"]> = TSchema extends {
|
|
391
|
-
schemaKey: infer TKey;
|
|
392
|
-
__registry: infer TRegistry;
|
|
393
|
-
} ? TKey extends keyof TRegistry ? TRegistry extends RegistryShape ? DeriveViewResult<TKey, TSelection, TRegistry> : never : never : never;
|
|
394
360
|
type RelationKeysOf<Cur extends string, Reg extends RegistryShape> = Cur extends keyof Reg ? {
|
|
395
361
|
[K in keyof Reg[Cur]["rawSchema"]]: IsRelationField<Reg[Cur]["rawSchema"][K]> extends true ? K : never;
|
|
396
362
|
}[keyof Reg[Cur]["rawSchema"]] : never;
|
|
@@ -428,7 +394,7 @@ type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R e
|
|
|
428
394
|
schemas: {
|
|
429
395
|
sql: Resolved[K]["zodSchemas"]["sqlSchema"];
|
|
430
396
|
client: Resolved[K]["zodSchemas"]["clientSchema"];
|
|
431
|
-
|
|
397
|
+
server: Resolved[K]["zodSchemas"]["validationSchema"];
|
|
432
398
|
};
|
|
433
399
|
transforms: {
|
|
434
400
|
toClient: Resolved[K]["zodSchemas"]["toClient"];
|
|
@@ -459,7 +425,7 @@ type Prettify<T> = {
|
|
|
459
425
|
[K in keyof T]: T[K];
|
|
460
426
|
} & {};
|
|
461
427
|
type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodValidationSchema", Depth extends any[] = []> = Depth["length"] extends 10 ? any : {
|
|
462
|
-
[K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand ? never : K extends keyof T ? T[K] extends Reference<any> ? K : T[K] extends {
|
|
428
|
+
[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 {
|
|
463
429
|
config: {
|
|
464
430
|
sql: {
|
|
465
431
|
type: "hasMany" | "manyToMany" | "hasOne" | "belongsTo";
|
|
@@ -476,7 +442,7 @@ type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodV
|
|
|
476
442
|
} ? ZodSchema : never;
|
|
477
443
|
};
|
|
478
444
|
type DeriveDefaults<T, Depth extends any[] = []> = Prettify<Depth["length"] extends 10 ? any : {
|
|
479
|
-
[K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand ? never : K extends keyof T ? T[K] extends Reference<any> ? K : T[K] extends {
|
|
445
|
+
[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 {
|
|
480
446
|
config: {
|
|
481
447
|
sql: {
|
|
482
448
|
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,10 +449,14 @@ 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("__") ||
|
|
@@ -438,7 +470,9 @@ export function createSchema(schema, relations) {
|
|
|
438
470
|
const config = targetField.config;
|
|
439
471
|
sqlFields[key] = config.zodSqlSchema;
|
|
440
472
|
clientFields[key] = config.zodClientSchema;
|
|
441
|
-
|
|
473
|
+
serverFields[key] = config.zodValidationSchema;
|
|
474
|
+
const initialValueOrFn = config.initialValue;
|
|
475
|
+
defaultGenerators[key] = initialValueOrFn;
|
|
442
476
|
defaultValues[key] = inferDefaultFromZod(config.zodClientSchema, {
|
|
443
477
|
...config.sql,
|
|
444
478
|
default: undefined,
|
|
@@ -447,43 +481,51 @@ export function createSchema(schema, relations) {
|
|
|
447
481
|
fieldTransforms[key] = config.transforms;
|
|
448
482
|
}
|
|
449
483
|
}
|
|
450
|
-
continue;
|
|
484
|
+
continue; // Skip the rest of the logic for references
|
|
451
485
|
}
|
|
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)
|
|
486
|
+
// THEN, handle all other fields that have a config (builders, relations, etc.)
|
|
463
487
|
if (definition && definition.config) {
|
|
464
488
|
const config = definition.config;
|
|
489
|
+
if (config.sql?.pk && !config.sql?.isForeignKey) {
|
|
490
|
+
pkKeys.push(key);
|
|
491
|
+
}
|
|
492
|
+
if (config.sql?.isClientPk) {
|
|
493
|
+
clientPkKeys.push(key);
|
|
494
|
+
}
|
|
495
|
+
// The rest of the logic for builders
|
|
465
496
|
const sqlConfig = config.sql;
|
|
466
497
|
if (sqlConfig &&
|
|
467
498
|
typeof sqlConfig === "object" &&
|
|
468
499
|
["hasMany", "hasOne", "belongsTo", "manyToMany"].includes(sqlConfig.type)) {
|
|
469
|
-
|
|
500
|
+
// This is for relations, which also aren't PKs, so we just continue.
|
|
470
501
|
continue;
|
|
471
502
|
}
|
|
472
503
|
else {
|
|
473
|
-
//
|
|
504
|
+
// This is for regular s.sql() fields
|
|
474
505
|
sqlFields[key] = config.zodSqlSchema;
|
|
475
506
|
clientFields[key] = config.zodClientSchema;
|
|
476
|
-
|
|
507
|
+
serverFields[key] = config.zodValidationSchema;
|
|
477
508
|
if (config.transforms) {
|
|
478
509
|
fieldTransforms[key] = config.transforms;
|
|
479
510
|
}
|
|
480
511
|
const initialValueOrFn = config.initialValue;
|
|
512
|
+
defaultGenerators[key] = initialValueOrFn;
|
|
481
513
|
defaultValues[key] = isFunction(initialValueOrFn)
|
|
482
514
|
? initialValueOrFn()
|
|
483
515
|
: initialValueOrFn;
|
|
484
516
|
}
|
|
485
517
|
}
|
|
486
518
|
}
|
|
519
|
+
const generateDefaults = () => {
|
|
520
|
+
const freshDefaults = {};
|
|
521
|
+
for (const key in defaultGenerators) {
|
|
522
|
+
const generatorOrValue = defaultGenerators[key];
|
|
523
|
+
freshDefaults[key] = isFunction(generatorOrValue)
|
|
524
|
+
? generatorOrValue() // Call the function to get a fresh value
|
|
525
|
+
: generatorOrValue; // Use the static value
|
|
526
|
+
}
|
|
527
|
+
return freshDefaults;
|
|
528
|
+
};
|
|
487
529
|
const toClient = (dbObject) => {
|
|
488
530
|
const clientObject = { ...dbObject };
|
|
489
531
|
for (const key in fieldTransforms) {
|
|
@@ -503,10 +545,13 @@ export function createSchema(schema, relations) {
|
|
|
503
545
|
return dbObject;
|
|
504
546
|
};
|
|
505
547
|
return {
|
|
548
|
+
pk: pkKeys?.length ? pkKeys : null,
|
|
549
|
+
clientPk: clientPkKeys ? clientPkKeys : null,
|
|
506
550
|
sqlSchema: z.object(sqlFields),
|
|
507
551
|
clientSchema: z.object(clientFields),
|
|
508
|
-
validationSchema: z.object(
|
|
552
|
+
validationSchema: z.object(serverFields),
|
|
509
553
|
defaultValues: defaultValues,
|
|
554
|
+
generateDefaults,
|
|
510
555
|
toClient,
|
|
511
556
|
toDb,
|
|
512
557
|
};
|
|
@@ -530,7 +575,9 @@ selection, registry, tableNameToRegistryKeyMap // The lookup map
|
|
|
530
575
|
throw new Error(`Schema with key "${currentRegistryKey}" not found in the registry.`);
|
|
531
576
|
}
|
|
532
577
|
// 2. Get the base Zod schema (primitives and references only) for the current level.
|
|
533
|
-
const baseSchema =
|
|
578
|
+
const baseSchema = schemaType === "server"
|
|
579
|
+
? registryEntry.zodSchemas.validationSchema
|
|
580
|
+
: registryEntry.zodSchemas.clientSchema;
|
|
534
581
|
const primitiveShape = baseSchema.shape;
|
|
535
582
|
// 3. If the selection is just `true`, we are done at this level. Return the base primitive schema.
|
|
536
583
|
if (subSelection === true) {
|
|
@@ -574,7 +621,7 @@ selection, registry, tableNameToRegistryKeyMap // The lookup map
|
|
|
574
621
|
return {
|
|
575
622
|
sql: registry[initialRegistryKey].zodSchemas.sqlSchema,
|
|
576
623
|
client: buildView(initialRegistryKey, selection, "client"),
|
|
577
|
-
|
|
624
|
+
server: buildView(initialRegistryKey, selection, "server"),
|
|
578
625
|
};
|
|
579
626
|
}
|
|
580
627
|
export function createSchemaBox(schemas, resolver) {
|
|
@@ -611,7 +658,12 @@ export function createSchemaBox(schemas, resolver) {
|
|
|
611
658
|
if (isReference(field)) {
|
|
612
659
|
const targetField = field.getter();
|
|
613
660
|
if (targetField && targetField.config) {
|
|
614
|
-
|
|
661
|
+
const newConfig = JSON.parse(JSON.stringify(targetField.config));
|
|
662
|
+
newConfig.sql.isForeignKey = true; // Add the tag
|
|
663
|
+
resolvedSchemas[tableName][fieldName] = {
|
|
664
|
+
...targetField,
|
|
665
|
+
config: newConfig,
|
|
666
|
+
};
|
|
615
667
|
}
|
|
616
668
|
else {
|
|
617
669
|
throw new Error(`Could not resolve reference for ${tableName}.${fieldName}`);
|
|
@@ -700,13 +752,17 @@ export function createSchemaBox(schemas, resolver) {
|
|
|
700
752
|
schemas: {
|
|
701
753
|
sql: entry.zodSchemas.sqlSchema,
|
|
702
754
|
client: entry.zodSchemas.clientSchema,
|
|
703
|
-
|
|
755
|
+
server: entry.zodSchemas.validationSchema,
|
|
704
756
|
},
|
|
705
757
|
transforms: {
|
|
706
758
|
toClient: entry.zodSchemas.toClient,
|
|
707
759
|
toDb: entry.zodSchemas.toDb,
|
|
708
760
|
},
|
|
709
761
|
defaults: entry.zodSchemas.defaultValues,
|
|
762
|
+
generateDefaults: entry.zodSchemas.generateDefaults,
|
|
763
|
+
// ADD: Expose PK info and resolver
|
|
764
|
+
pk: entry.zodSchemas.pk,
|
|
765
|
+
clientPk: entry.zodSchemas.clientPk,
|
|
710
766
|
nav: createNavProxy(tableName, finalRegistry),
|
|
711
767
|
// Add this
|
|
712
768
|
createView: (selection) => {
|
|
@@ -719,7 +775,7 @@ export function createSchemaBox(schemas, resolver) {
|
|
|
719
775
|
schemas: {
|
|
720
776
|
sql: view.sql,
|
|
721
777
|
client: view.client,
|
|
722
|
-
|
|
778
|
+
server: view.server,
|
|
723
779
|
},
|
|
724
780
|
transforms: {
|
|
725
781
|
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.147",
|
|
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",
|