cogsbox-shape 0.5.145 → 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 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 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, 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
- validation: <TValidationNext extends z.ZodTypeAny>(schema: ((tools: {
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<"validation", T, TSql, TNew, TInitialValue, TClient, TValidationNext>>;
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" | "validation" | "done";
95
+ type Stage = "sql" | "relation" | "new" | "client" | "server" | "done";
86
96
  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";
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 SQLType | RelationConfig<any>, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> = {
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 SQLType | RelationConfig<any>, TSql extends z.ZodTypeAny, TNew extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> = {
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
- export declare function schema<T extends string, U extends ShapeSchema<T>>(schema: U): Prettify<EnrichFields<U>>;
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
  };
@@ -316,20 +350,20 @@ export type DeriveViewResultFromBox<TBox extends CreateSchemaBoxReturn<any, any>
316
350
  zodSchemas: {
317
351
  sqlSchema: TBox[K]["schemas"]["sql"];
318
352
  clientSchema: TBox[K]["schemas"]["client"];
319
- validationSchema: TBox[K]["schemas"]["validation"];
353
+ validationSchema: TBox[K]["schemas"]["server"];
320
354
  defaultValues: TBox[K]["defaults"];
321
355
  toClient: TBox[K]["transforms"]["toClient"];
322
356
  toDb: TBox[K]["transforms"]["toDb"];
323
357
  };
324
358
  };
325
359
  }, "clientSchema">>;
326
- validation: z.ZodObject<_DeriveViewShape<TTableName, TSelection, {
360
+ server: z.ZodObject<_DeriveViewShape<TTableName, TSelection, {
327
361
  [K in keyof TBox]: {
328
362
  rawSchema: TBox[K]["definition"];
329
363
  zodSchemas: {
330
364
  sqlSchema: TBox[K]["schemas"]["sql"];
331
365
  clientSchema: TBox[K]["schemas"]["client"];
332
- validationSchema: TBox[K]["schemas"]["validation"];
366
+ validationSchema: TBox[K]["schemas"]["server"];
333
367
  defaultValues: TBox[K]["defaults"];
334
368
  toClient: TBox[K]["transforms"]["toClient"];
335
369
  toDb: TBox[K]["transforms"]["toDb"];
@@ -347,7 +381,7 @@ export type DeriveViewResultFromBox<TBox extends CreateSchemaBoxReturn<any, any>
347
381
  zodSchemas: {
348
382
  sqlSchema: TBox[K]["schemas"]["sql"];
349
383
  clientSchema: TBox[K]["schemas"]["client"];
350
- validationSchema: TBox[K]["schemas"]["validation"];
384
+ validationSchema: TBox[K]["schemas"]["server"];
351
385
  defaultValues: TBox[K]["defaults"];
352
386
  toClient: TBox[K]["transforms"]["toClient"];
353
387
  toDb: TBox[K]["transforms"]["toDb"];
@@ -368,7 +402,7 @@ export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRe
368
402
  schemas: {
369
403
  sql: TRegistry[TTableName]["zodSchemas"]["sqlSchema"];
370
404
  client: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>;
371
- validation: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "validationSchema">>;
405
+ server: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "validationSchema">>;
372
406
  };
373
407
  transforms: {
374
408
  toClient: TRegistry[TTableName]["zodSchemas"]["toClient"];
@@ -428,7 +462,7 @@ type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R e
428
462
  schemas: {
429
463
  sql: Resolved[K]["zodSchemas"]["sqlSchema"];
430
464
  client: Resolved[K]["zodSchemas"]["clientSchema"];
431
- validation: Resolved[K]["zodSchemas"]["validationSchema"];
465
+ server: Resolved[K]["zodSchemas"]["validationSchema"];
432
466
  };
433
467
  transforms: {
434
468
  toClient: Resolved[K]["zodSchemas"]["toClient"];
@@ -459,7 +493,7 @@ type Prettify<T> = {
459
493
  [K in keyof T]: T[K];
460
494
  } & {};
461
495
  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 {
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 {
463
497
  config: {
464
498
  sql: {
465
499
  type: "hasMany" | "manyToMany" | "hasOne" | "belongsTo";
@@ -476,7 +510,7 @@ type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodV
476
510
  } ? ZodSchema : never;
477
511
  };
478
512
  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 {
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 {
480
514
  config: {
481
515
  sql: {
482
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: (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,14 +449,19 @@ 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("__") ||
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
- validationFields[key] = config.zodValidationSchema;
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
- // 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)
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
- console.log(`Skipping relation: ${key}`);
501
+ // This is for relations, which also aren't PKs, so we just continue.
470
502
  continue;
471
503
  }
472
504
  else {
473
- // Handle regular fields
505
+ // This is for regular s.sql() fields
474
506
  sqlFields[key] = config.zodSqlSchema;
475
507
  clientFields[key] = config.zodClientSchema;
476
- validationFields[key] = config.zodValidationSchema;
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(validationFields),
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 = registryEntry.zodSchemas[`${schemaType}Schema`];
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
- validation: buildView(initialRegistryKey, selection, "validation"),
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
- resolvedSchemas[tableName][fieldName] = targetField;
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
- validation: entry.zodSchemas.validationSchema,
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
- validation: view.validation,
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.145",
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",