cogsbox-shape 0.5.84 → 0.5.86

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
@@ -150,9 +150,9 @@ export type EnrichFields<T extends ShapeSchema> = {
150
150
  [K in keyof T]: K extends string ? EnrichedField<K, T[K], T> : T[K];
151
151
  };
152
152
  export declare const SchemaWrapperBrand: unique symbol;
153
- export declare function schema<T extends ShapeSchema>(schema: T): EnrichFields<T> & {
153
+ export declare function schema<T extends ShapeSchema>(schema: T): Prettify<EnrichFields<T> & {
154
154
  _tableName: T["_tableName"];
155
- } & Record<typeof SchemaWrapperBrand, true>;
155
+ }>;
156
156
  export type RelationType = "hasMany" | "hasOne" | "manyToMany";
157
157
  type BaseSchemaField<T extends SQLType = SQLType> = {
158
158
  type: "field";
@@ -184,10 +184,6 @@ type Relation<U extends Schema<any>> = {
184
184
  defaultCount?: number;
185
185
  };
186
186
  export declare function createMixedValidationSchema<T extends Schema<any>>(schema: T, clientSchema?: z.ZodObject<any>, dbSchema?: z.ZodObject<any>): z.ZodObject<any>;
187
- type SchemaDefinition = {
188
- _tableName: string;
189
- [key: string]: any;
190
- };
191
187
  type InferSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodValidationSchema", Depth extends any[] = []> = Depth["length"] extends 10 ? any : {
192
188
  [K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand ? never : K]: T[K] extends {
193
189
  config: {
@@ -223,30 +219,16 @@ type InferSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodVa
223
219
  type InferSqlSchema<T> = InferSchemaByKey<T, "zodSqlSchema">;
224
220
  type InferClientSchema<T> = InferSchemaByKey<T, "zodClientSchema">;
225
221
  type InferValidationSchema<T> = InferSchemaByKey<T, "zodValidationSchema">;
226
- type InferDefaultValues2<T> = {
227
- [K in keyof T as K extends "_tableName" ? never : K]: T[K] extends {
228
- config: {
229
- initialValue: infer D;
230
- };
231
- } ? D : T[K] extends () => {
232
- type: "hasMany" | "manyToMany";
233
- schema: infer S extends SchemaDefinition;
234
- defaultCount?: number;
235
- } ? Array<Prettify<InferDefaultValues2<S>>> : T[K] extends () => {
236
- type: "hasOne" | "belongsTo";
237
- schema: infer S extends SchemaDefinition;
238
- } ? Prettify<InferDefaultValues2<S>> : never;
239
- };
240
222
  export declare function createSchema<T extends {
241
223
  _tableName: string;
242
224
  [SchemaWrapperBrand]?: true;
243
225
  }, R extends Record<string, any> = {}, TActualSchema extends Omit<T & R, typeof SchemaWrapperBrand> = Omit<T & R, typeof SchemaWrapperBrand>>(schema: T, relations?: R): {
244
- sqlSchema: z.ZodObject<Prettify<InferSqlSchema<TActualSchema>>>;
245
- clientSchema: z.ZodObject<Prettify<InferClientSchema<TActualSchema>>>;
246
- validationSchema: z.ZodObject<Prettify<InferValidationSchema<TActualSchema>>>;
247
- defaultValues: Prettify<InferDefaultValues2<TActualSchema>>;
248
- toClient: (dbObject: z.infer<z.ZodObject<Prettify<InferSqlSchema<TActualSchema>>>>) => z.infer<z.ZodObject<Prettify<InferClientSchema<TActualSchema>>>>;
249
- toDb: (clientObject: z.infer<z.ZodObject<Prettify<InferClientSchema<TActualSchema>>>>) => z.infer<z.ZodObject<Prettify<InferSqlSchema<TActualSchema>>>>;
226
+ sqlSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>;
227
+ clientSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>;
228
+ validationSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>;
229
+ defaultValues: Prettify<DeriveDefaults<TActualSchema>>;
230
+ toClient: (dbObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>;
231
+ toDb: (clientObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
250
232
  };
251
233
  type RelationBuilders<TSchema> = {
252
234
  reference: <TField extends object>(fieldGetter: () => TField) => {
@@ -257,18 +239,23 @@ type RelationBuilders<TSchema> = {
257
239
  fromKey: keyof TSchema & string;
258
240
  toKey: () => TField;
259
241
  defaultCount?: number;
260
- }) => Builder<"relation", RelationConfig<TField["__parentTableType"]>, z.ZodArray<z.ZodObject<InferSqlSchema<TField["__parentTableType"]>>>, z.ZodArray<z.ZodObject<InferClientSchema<TField["__parentTableType"]>>>, any[], z.ZodArray<z.ZodObject<InferClientSchema<TField["__parentTableType"]>>>, z.ZodArray<z.ZodObject<InferValidationSchema<TField["__parentTableType"]>>>>;
261
- hasOne: <T extends Schema<any>>(config: {
242
+ }) => Builder<"relation", BaseRelationConfig<TField["__parentTableType"]> & {
243
+ type: "hasMany";
244
+ }, z.ZodArray<z.ZodObject<InferSqlSchema<TField["__parentTableType"]>>>, z.ZodArray<z.ZodObject<InferClientSchema<TField["__parentTableType"]>>>, any[], z.ZodArray<z.ZodObject<InferClientSchema<TField["__parentTableType"]>>>, z.ZodArray<z.ZodObject<InferValidationSchema<TField["__parentTableType"]>>>>;
245
+ hasOne: <T extends Schema<any>, K extends keyof T & string, TField extends EnrichedField<K, T[K], T>>(config: {
262
246
  fromKey: keyof TSchema & string;
263
- toKey: () => T[keyof T];
264
- schema: () => T;
265
- }) => Builder<"relation", RelationConfig<T>, z.ZodArray<any>, z.ZodArray<any>, any[], z.ZodArray<any>, z.ZodArray<any>>;
247
+ toKey: () => TField;
248
+ }) => Builder<"relation", BaseRelationConfig<TField["__parentTableType"]> & {
249
+ type: "hasOne";
250
+ }, z.ZodArray<z.ZodObject<InferSqlSchema<TField["__parentTableType"]>>>, z.ZodArray<z.ZodObject<InferClientSchema<TField["__parentTableType"]>>>, any, z.ZodArray<z.ZodObject<InferClientSchema<TField["__parentTableType"]>>>, z.ZodArray<z.ZodObject<InferValidationSchema<TField["__parentTableType"]>>>>;
266
251
  manyToMany: <T extends Schema<any>>(config: {
267
252
  fromKey: keyof TSchema & string;
268
253
  toKey: () => T[keyof T];
269
254
  schema: () => T;
270
255
  defaultCount?: number;
271
- }) => Builder<"relation", RelationConfig<T>, z.ZodOptional<z.ZodArray<z.ZodAny>>, z.ZodOptional<z.ZodArray<z.ZodAny>>, any[], z.ZodOptional<z.ZodArray<z.ZodAny>>, z.ZodOptional<z.ZodArray<z.ZodAny>>>;
256
+ }) => Builder<"relation", BaseRelationConfig<T> & {
257
+ type: "manyToMany";
258
+ }, z.ZodOptional<z.ZodArray<z.ZodAny>>, z.ZodOptional<z.ZodArray<z.ZodAny>>, any[], z.ZodOptional<z.ZodArray<z.ZodAny>>, z.ZodOptional<z.ZodArray<z.ZodAny>>>;
272
259
  };
273
260
  export declare function schemaRelations<TSchema extends Schema<any>, RefObject extends Record<string, any>>(baseSchema: TSchema, referencesBuilder: (rel: RelationBuilders<TSchema>) => RefObject): {
274
261
  [K in keyof RefObject]: RefObject[K] & {
@@ -282,6 +269,10 @@ export declare function schemaRelations<TSchema extends Schema<any>, RefObject e
282
269
  type Prettify<T> = {
283
270
  [K in keyof T]: T[K];
284
271
  } & {};
272
+ /**
273
+ * [INTERNAL] Recursively derives a Zod schema by inspecting the builder's config.
274
+ * This version correctly uses the `schema` property from the relation's config.
275
+ */
285
276
  type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodValidationSchema", Depth extends any[] = []> = Depth["length"] extends 10 ? any : {
286
277
  [K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand ? never : K]: T[K] extends {
287
278
  config: {
@@ -290,12 +281,11 @@ type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodV
290
281
  schema: () => infer S;
291
282
  };
292
283
  };
293
- } ? z.ZodArray<S extends {
284
+ } ? S extends {
294
285
  _tableName: string;
295
- } ? z.ZodObject<Prettify<DeriveSchemaByKey<S, Key, [...Depth, 1]>>> : z.ZodObject<any>> : T[K] extends {
286
+ } ? z.ZodArray<z.ZodObject<Prettify<DeriveSchemaByKey<S, Key, [...Depth, 1]>>>> : never : T[K] extends {
296
287
  config: {
297
288
  sql: {
298
- type: "hasOne" | "belongsTo";
299
289
  schema: () => infer S;
300
290
  };
301
291
  };
@@ -314,29 +304,36 @@ type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodV
314
304
  };
315
305
  } ? ZodSchema : never;
316
306
  };
317
- type DeriveDefaults<T> = Prettify<{
307
+ type DeriveDefaults<T, Depth extends any[] = []> = Prettify<Depth["length"] extends 10 ? any : {
318
308
  [K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand ? never : K]: T[K] extends {
309
+ config: {
310
+ sql: infer SqlConfig;
311
+ initialValue: infer D;
312
+ };
313
+ } ? SqlConfig extends {
314
+ type: "hasMany" | "manyToMany";
315
+ schema: () => infer S;
316
+ } ? Array<DeriveDefaults<S, [...Depth, 1]>> : SqlConfig extends {
317
+ type: "hasOne" | "belongsTo";
318
+ schema: () => infer S;
319
+ } ? DeriveDefaults<S, [...Depth, 1]> : D extends () => infer R ? R : D : T[K] extends {
320
+ type: "reference";
321
+ to: () => infer RefField;
322
+ } ? RefField extends {
319
323
  config: {
320
324
  initialValue: infer D;
321
325
  };
322
- } ? D extends () => infer R ? R : D : never;
326
+ } ? D extends () => infer R ? R : D : never : never;
323
327
  }>;
324
328
  export type InferFromSchema<T extends {
325
329
  _tableName: string;
326
330
  }> = Prettify<{
327
- /** The Zod schema for the **SQL (database)** layer. */
328
331
  SqlSchema: z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodSqlSchema">>>;
329
- /** The Zod schema for the **Client** layer. */
330
332
  ClientSchema: z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodClientSchema">>>;
331
- /** The Zod schema for the **Validation** layer. */
332
333
  ValidationSchema: z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodValidationSchema">>>;
333
- /** The TypeScript type for data as it exists in the **database**. */
334
334
  Sql: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodSqlSchema">>>>;
335
- /** The TypeScript type for data as it is represented on the **client**. */
336
335
  Client: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodClientSchema">>>>;
337
- /** The TypeScript type for **validation** data, often the most flexible shape. */
338
336
  Validation: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodValidationSchema">>>>;
339
- /** The TypeScript type for the object of **default values**. */
340
337
  Defaults: DeriveDefaults<T>;
341
338
  }>;
342
339
  export {};
package/dist/schema.js CHANGED
@@ -273,7 +273,6 @@ export const SchemaWrapperBrand = Symbol("SchemaWrapper");
273
273
  export function schema(schema) {
274
274
  const enrichedSchema = {
275
275
  _tableName: schema._tableName,
276
- [SchemaWrapperBrand]: true, // Add the symbol property
277
276
  };
278
277
  for (const key in schema) {
279
278
  if (key !== "_tableName" &&
@@ -288,6 +287,7 @@ export function schema(schema) {
288
287
  };
289
288
  }
290
289
  }
290
+ enrichedSchema[SchemaWrapperBrand] = true;
291
291
  return enrichedSchema;
292
292
  }
293
293
  function inferDefaultFromZod(zodType, sqlConfig) {
@@ -301,10 +301,19 @@ function inferDefaultFromZod(zodType, sqlConfig) {
301
301
  }
302
302
  return sqlConfig.default;
303
303
  }
304
- // Check if it's a relation config (this logic is fine)
305
304
  if (typeof sqlConfig.type === "string" &&
306
305
  ["hasMany", "hasOne", "belongsTo", "manyToMany"].includes(sqlConfig.type)) {
307
- // ... your existing relation logic is fine ...
306
+ const relationConfig = sqlConfig;
307
+ if (relationConfig.type === "hasMany" ||
308
+ relationConfig.type === "manyToMany") {
309
+ // For hasMany/manyToMany, default to an array based on defaultCount.
310
+ return Array.from({ length: relationConfig.defaultCount || 0 }, () => ({}));
311
+ }
312
+ if (relationConfig.type === "hasOne" ||
313
+ relationConfig.type === "belongsTo") {
314
+ // For hasOne/belongsTo, default to a single empty object.
315
+ return {};
316
+ }
308
317
  }
309
318
  // Handle SQL type-based generation (this is the fallback)
310
319
  const sqlTypeConfig = sqlConfig;
@@ -416,91 +425,77 @@ function isRelation(value) {
416
425
  "toKey" in value &&
417
426
  "schema" in value);
418
427
  }
428
+ // PASTE THIS ENTIRE FUNCTION OVER YOUR EXISTING createSchema FUNCTION
429
+ // The only change is the `if` condition inside the loop.
419
430
  export function createSchema(schema, relations) {
420
431
  const sqlFields = {};
421
432
  const clientFields = {};
422
433
  const validationFields = {};
423
434
  const defaultValues = {};
424
435
  const fieldTransforms = {};
425
- // --- PASS 1: Process main schema fields (no relations here) ---
426
- for (const key in schema) {
427
- if (key === "_tableName" || key.startsWith("__"))
436
+ const fullSchema = { ...schema, ...(relations || {}) };
437
+ for (const key in fullSchema) {
438
+ if (key === "_tableName" ||
439
+ key.startsWith("__") ||
440
+ key === String(SchemaWrapperBrand))
441
+ continue;
442
+ const definition = fullSchema[key];
443
+ // --- THIS IS THE FIX ---
444
+ // The condition now correctly checks for EITHER a `reference` type OR a builder with a `.config`.
445
+ if (!definition ||
446
+ (definition.type !== "reference" && !definition.config)) {
428
447
  continue;
429
- const definition = schema[key];
430
- if (definition && definition.type === "reference") {
431
- // Handle reference fields
448
+ }
449
+ if (definition.type === "reference") {
450
+ // This block now correctly processes `testId`.
432
451
  const referencedFieldBuilder = definition.to();
433
452
  const referencedConfig = referencedFieldBuilder.config;
434
453
  sqlFields[key] = referencedConfig.zodSqlSchema;
435
454
  clientFields[key] = referencedConfig.zodClientSchema;
436
455
  validationFields[key] = referencedConfig.zodValidationSchema;
437
- // Foreign key fields should get their own default, not the referenced field's default
438
456
  defaultValues[key] = inferDefaultFromZod(referencedConfig.zodClientSchema, { ...referencedConfig.sql, default: undefined });
439
457
  }
440
- else if (definition && definition.config) {
441
- // Handle regular fields with builder pattern
458
+ else {
459
+ // This block handles fields with a `.config` property, like `pets`.
442
460
  const config = definition.config;
443
- sqlFields[key] = config.zodSqlSchema;
444
- clientFields[key] = config.zodClientSchema;
445
- validationFields[key] = config.zodValidationSchema;
446
- if (config.transforms) {
447
- fieldTransforms[key] = config.transforms;
448
- }
449
- // Handle initial value
450
- const initialValueOrFn = config.initialValue;
451
- if (isFunction(initialValueOrFn)) {
452
- defaultValues[key] = initialValueOrFn();
461
+ const sqlConfig = config.sql;
462
+ if (sqlConfig &&
463
+ typeof sqlConfig === "object" &&
464
+ ["hasMany", "hasOne", "belongsTo", "manyToMany"].includes(sqlConfig.type)) {
465
+ const relatedSchemaFactory = sqlConfig.schema;
466
+ const childSchemaResult = createSchema(relatedSchemaFactory());
467
+ let baseSqlSchema;
468
+ let baseClientSchema;
469
+ if (sqlConfig.type === "hasMany" || sqlConfig.type === "manyToMany") {
470
+ baseSqlSchema = z.array(childSchemaResult.sqlSchema);
471
+ baseClientSchema = z.array(childSchemaResult.clientSchema);
472
+ defaultValues[key] = Array.from({ length: sqlConfig.defaultCount || 0 }, () => childSchemaResult.defaultValues);
473
+ }
474
+ else {
475
+ baseSqlSchema = childSchemaResult.sqlSchema;
476
+ baseClientSchema = childSchemaResult.clientSchema;
477
+ defaultValues[key] = childSchemaResult.defaultValues;
478
+ }
479
+ sqlFields[key] = baseSqlSchema.optional();
480
+ clientFields[key] = config.clientTransform
481
+ ? config.clientTransform(baseClientSchema)
482
+ : baseClientSchema;
483
+ validationFields[key] = clientFields[key];
453
484
  }
454
485
  else {
455
- defaultValues[key] = initialValueOrFn;
456
- }
457
- }
458
- }
459
- // --- PASS 2: Process relations if provided ---
460
- if (relations) {
461
- for (const key in relations) {
462
- const relationDefinition = relations[key];
463
- if (relationDefinition && relationDefinition.config) {
464
- const config = relationDefinition.config;
465
- const sqlConfig = config.sql;
466
- if (sqlConfig &&
467
- typeof sqlConfig === "object" &&
468
- ["hasMany", "hasOne", "belongsTo", "manyToMany"].includes(sqlConfig.type)) {
469
- const relationConfig = sqlConfig;
470
- const childSchemaResult = createSchema(relationConfig.schema());
471
- // Create the base schemas based on relation type
472
- let baseSqlSchema;
473
- let baseClientSchema;
474
- let baseValidationSchema;
475
- if (relationConfig.type === "hasMany" ||
476
- relationConfig.type === "manyToMany") {
477
- baseSqlSchema = z.array(childSchemaResult.sqlSchema);
478
- baseClientSchema = z.array(childSchemaResult.clientSchema);
479
- baseValidationSchema = z.array(childSchemaResult.validationSchema);
480
- defaultValues[key] = Array.from({ length: relationConfig.defaultCount || 0 }, () => childSchemaResult.defaultValues);
481
- }
482
- else {
483
- baseSqlSchema = childSchemaResult.sqlSchema;
484
- baseClientSchema = childSchemaResult.clientSchema;
485
- baseValidationSchema = childSchemaResult.validationSchema;
486
- defaultValues[key] = childSchemaResult.defaultValues;
487
- }
488
- // Apply transforms if they exist
489
- const finalClientSchema = config.clientTransform
490
- ? config.clientTransform(baseClientSchema)
491
- : baseClientSchema;
492
- const finalValidationSchema = config.validationTransform
493
- ? config.validationTransform(baseValidationSchema)
494
- : finalClientSchema;
495
- // Assign the schemas
496
- sqlFields[key] = baseSqlSchema.optional(); // SQL fields are optional for lazy loading
497
- clientFields[key] = finalClientSchema;
498
- validationFields[key] = finalValidationSchema;
486
+ sqlFields[key] = config.zodSqlSchema;
487
+ clientFields[key] = config.zodClientSchema;
488
+ validationFields[key] = config.zodValidationSchema;
489
+ if (config.transforms) {
490
+ fieldTransforms[key] = config.transforms;
499
491
  }
492
+ const initialValueOrFn = config.initialValue;
493
+ defaultValues[key] = isFunction(initialValueOrFn)
494
+ ? initialValueOrFn()
495
+ : initialValueOrFn;
500
496
  }
501
497
  }
502
498
  }
503
- // Create transform functions
504
499
  const toClient = (dbObject) => {
505
500
  const clientObject = { ...dbObject };
506
501
  for (const key in fieldTransforms) {
@@ -558,7 +553,7 @@ export function schemaRelations(baseSchema, referencesBuilder) {
558
553
  type: "hasOne",
559
554
  fromKey: config.fromKey,
560
555
  toKey: config.toKey,
561
- schema: config.schema,
556
+ schema: () => config.toKey.__parentTableType,
562
557
  };
563
558
  const relationZodType = z.any();
564
559
  return createBuilder({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-shape",
3
- "version": "0.5.84",
3
+ "version": "0.5.86",
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",