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 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 SQLType | RelationConfig<any>, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> {
42
- initialState: {
43
- <const TValue>(value: TValue extends (...args: any[]) => void | undefined ? never : TValue): TValue extends (...args: any[]) => infer R ? R extends void | undefined ? never : TValue extends z.ZodTypeAny ? Prettify<Builder<"new", T, TSql, TValue, z.infer<TValue>, CollapsedUnion<TSql, TValue>, CollapsedUnion<TSql, TValue>>> : R extends string | number | boolean ? Prettify<Builder<"new", T, TSql, ZodTypeFromPrimitive<R>, NonLiteral<R>, CollapsedUnion<TSql, ZodTypeFromPrimitive<R>>, CollapsedUnion<TSql, ZodTypeFromPrimitive<R>>>> : Prettify<Builder<"new", T, TSql, ZodTypeFromPrimitive<R>, NonLiteral<R>, CollapsedUnion<TSql, ZodTypeFromPrimitive<R>>, CollapsedUnion<TSql, ZodTypeFromPrimitive<R>>>> : TValue extends z.ZodTypeAny ? Prettify<Builder<"new", T, TSql, NonLiteral<TValue>, z.infer<TValue>, CollapsedUnion<TSql, TValue>, CollapsedUnion<TSql, TValue>>> : TValue extends string | number | boolean ? Prettify<Builder<"new", T, TSql, ZodTypeFromPrimitive<TValue>, NonLiteral<TValue>, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue>>, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue>>>> : Prettify<Builder<"new", T, TSql, ZodTypeFromPrimitive<TValue>, NonLiteral<TValue>, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue>>, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue>>>>;
44
- <const TValue, TSchema extends z.ZodTypeAny>(value: TValue extends (...args: any[]) => void | undefined ? never : TValue, schema: TSchema): Prettify<Builder<"new", T, TSql, TSchema, TValue extends () => infer R ? R : TValue, CollapsedUnion<TSql, TSchema>, CollapsedUnion<TSql, TSchema>>>;
45
- <const TValue, TSchema extends z.ZodTypeAny>(value: TValue extends (...args: any[]) => void | undefined ? never : TValue, schemaModifier: (baseSchema: TValue extends () => infer R ? R extends string | number | boolean ? z.ZodLiteral<R> : ZodTypeFromPrimitive<R> : TValue extends string | number | boolean ? z.ZodLiteral<TValue> : ZodTypeFromPrimitive<TValue>) => TSchema): Prettify<Builder<"new", T, TSql, TSchema, TValue extends () => infer R ? R : TValue, CollapsedUnion<TSql, TSchema>, CollapsedUnion<TSql, TSchema>>>;
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
- validation: <TValidationNext extends z.ZodTypeAny>(schema: ((tools: {
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<"validation", T, TSql, TNew, TInitialValue, TClient, TValidationNext>>;
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" | "validation" | "done";
96
+ type Stage = "sql" | "relation" | "new" | "client" | "server" | "done";
86
97
  type StageMethods = {
87
- sql: "initialState" | "client" | "validation" | "transform" | "reference";
88
- relation: "validation" | "transform";
89
- new: "client" | "validation" | "transform";
90
- client: "validation" | "transform";
91
- validation: "transform";
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 SQLType | RelationConfig<any>, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> = {
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 SQLType | RelationConfig<any>, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> = {
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
- export declare function schema<T extends string, U extends ShapeSchema<T>>(schema: U): Prettify<EnrichFields<U>>;
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
- validation: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "validationSchema">>;
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
- validation: Resolved[K]["zodSchemas"]["validationSchema"];
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: (value, schemaOrModifier) => {
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
- // Check if value is a Zod schema (single argument case)
96
- if (value && typeof value === "object" && "_def" in value) {
97
- // It's a Zod schema - infer the default value
98
- baseSchema = value;
99
- actualValue = inferDefaultFromZod(baseSchema, config.sqlConfig);
100
- finalSchema = baseSchema;
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
- // Get the actual value
104
- actualValue = isFunction(value) ? value() : value;
105
- // If second parameter is provided and is a Zod schema, use it directly
106
- if (schemaOrModifier &&
107
- typeof schemaOrModifier === "object" &&
108
- "_def" in schemaOrModifier) {
109
- finalSchema = schemaOrModifier;
110
- }
111
- else if (isFunction(schemaOrModifier)) {
112
- // It's a schema modifier function
113
- // Create base Zod schema from the value type
114
- if (typeof actualValue === "string") {
115
- baseSchema = z.string();
116
- }
117
- else if (typeof actualValue === "number") {
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 provided, create from value type
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 for client/validation
167
- const clientValidationSchema = z.union([config.sqlZod, finalSchema]);
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: clientValidationSchema,
174
- validationZod: clientValidationSchema,
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("validation")) {
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
- validation: (
240
+ server: (
228
241
  // ... this validation function remains unchanged ...
229
242
  assert) => {
230
- if (completedStages.has("validation")) {
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("validation");
254
+ newCompletedStages.add("server");
242
255
  return createBuilder({
243
256
  ...config,
244
- stage: "validation",
257
+ stage: "server",
245
258
  validationZod: validationSchema,
246
259
  completedStages: newCompletedStages,
247
260
  });
248
261
  },
249
262
  transform: (transforms) => {
250
- if (!completedStages.has("validation") &&
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 (sqlConfig.default === "CURRENT_TIMESTAMP") {
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
- const relationConfig = sqlConfig;
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 validationFields = {};
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
- validationFields[key] = config.zodValidationSchema;
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
- // Handle old-style references (for backward compatibility)
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
- console.log(`Skipping relation: ${key}`);
500
+ // This is for relations, which also aren't PKs, so we just continue.
470
501
  continue;
471
502
  }
472
503
  else {
473
- // Handle regular fields
504
+ // This is for regular s.sql() fields
474
505
  sqlFields[key] = config.zodSqlSchema;
475
506
  clientFields[key] = config.zodClientSchema;
476
- validationFields[key] = config.zodValidationSchema;
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(validationFields),
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 = registryEntry.zodSchemas[`${schemaType}Schema`];
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
- validation: buildView(initialRegistryKey, selection, "validation"),
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
- resolvedSchemas[tableName][fieldName] = targetField;
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
- validation: entry.zodSchemas.validationSchema,
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
- validation: view.validation,
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.145",
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",