cogsbox-shape 0.5.169 → 0.5.171

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/index.d.ts CHANGED
@@ -1 +1 @@
1
- export * from "./schema";
1
+ export * from "./schema.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export * from "./schema";
1
+ export * from "./schema.js";
package/dist/schema.d.ts CHANGED
@@ -28,8 +28,11 @@ export type SQLType = ({
28
28
  nullable?: boolean;
29
29
  length?: number;
30
30
  default?: string;
31
- }) & {
31
+ }) & BaseConfig;
32
+ type BaseConfig = {
33
+ nullable?: boolean;
32
34
  pk?: true;
35
+ field?: string;
33
36
  };
34
37
  type SQLToZodType<T extends SQLType, TDefault extends boolean> = T["pk"] extends true ? TDefault extends true ? z.ZodString : z.ZodNumber : T["nullable"] extends true ? T["type"] extends "varchar" | "char" | "text" | "longtext" ? z.ZodNullable<z.ZodString> : T["type"] extends "int" ? z.ZodNullable<z.ZodNumber> : T["type"] extends "boolean" ? z.ZodNullable<z.ZodBoolean> : T["type"] extends "date" | "datetime" | "timestamp" ? T extends {
35
38
  default: "CURRENT_TIMESTAMP";
@@ -206,7 +209,6 @@ type Relation<U extends Schema<any>> = {
206
209
  schema: U;
207
210
  defaultCount?: number;
208
211
  };
209
- export declare function createMixedValidationSchema<T extends Schema<any>>(schema: T, clientSchema?: z.ZodObject<any>, dbSchema?: z.ZodObject<any>): z.ZodObject<any>;
210
212
  export declare function createSchema<T extends {
211
213
  _tableName: string;
212
214
  [SchemaWrapperBrand]?: true;
@@ -220,8 +222,10 @@ export declare function createSchema<T extends {
220
222
  defaultValues: Prettify<DeriveDefaults<TActualSchema>>;
221
223
  stateType: Prettify<DeriveStateType<TActualSchema>>;
222
224
  generateDefaults: () => Prettify<DeriveDefaults<TActualSchema>>;
223
- toClient: (dbObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>;
224
- toDb: (clientObject: z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
225
+ toClient: (dbObject: any) => any;
226
+ toDb: (clientObject: any) => any;
227
+ parseForDb: (appData: z.input<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
228
+ parseFromDb: (dbData: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>;
225
229
  };
226
230
  export type PlaceholderReference = {
227
231
  __type: "placeholder-reference";
@@ -289,6 +293,12 @@ type ResolvedRegistryWithSchemas<S extends Record<string, SchemaWithPlaceholders
289
293
  stateType: Prettify<DeriveStateType<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>>>;
290
294
  toClient: (dbObject: any) => any;
291
295
  toDb: (clientObject: any) => any;
296
+ parseForDb: (appData: any) => any;
297
+ parseFromDb: (dbData: any) => any;
298
+ pk: string[] | null;
299
+ clientPk: string[] | null;
300
+ isClientRecord: ((record: any) => boolean) | undefined;
301
+ generateDefaults: () => Prettify<DeriveDefaults<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>>>;
292
302
  };
293
303
  };
294
304
  };
@@ -357,7 +367,12 @@ export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRe
357
367
  toClient: TRegistry[TTableName]["zodSchemas"]["toClient"];
358
368
  toDb: TRegistry[TTableName]["zodSchemas"]["toDb"];
359
369
  };
370
+ parseForDb: (appData: z.input<TRegistry[TTableName]["zodSchemas"]["validationSchema"]>) => z.infer<TRegistry[TTableName]["zodSchemas"]["sqlSchema"]>;
371
+ parseFromDb: (dbData: Partial<z.infer<TRegistry[TTableName]["zodSchemas"]["sqlSchema"]>>) => z.infer<TRegistry[TTableName]["zodSchemas"]["clientSchema"]>;
360
372
  defaults: DeriveViewDefaults<TTableName, TSelection, TRegistry>;
373
+ pk: string[] | null;
374
+ clientPk: string[] | null;
375
+ supportsReconciliation: boolean;
361
376
  isView: true;
362
377
  viewSelection: TSelection;
363
378
  baseTable: TTableName;
@@ -395,6 +410,12 @@ type RegistryShape = Record<string, {
395
410
  stateType: any;
396
411
  toClient: (dbObject: any) => any;
397
412
  toDb: (clientObject: any) => any;
413
+ parseForDb: (appData: any) => any;
414
+ parseFromDb: (dbData: any) => any;
415
+ pk: string[] | null;
416
+ clientPk: string[] | null;
417
+ isClientRecord: ((record: any) => boolean) | undefined;
418
+ generateDefaults: () => any;
398
419
  };
399
420
  }>;
400
421
  type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R extends ResolutionMap<S>, Resolved extends RegistryShape = ResolvedRegistryWithSchemas<S, R> extends RegistryShape ? ResolvedRegistryWithSchemas<S, R> : RegistryShape> = {
@@ -410,9 +431,14 @@ type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R e
410
431
  toClient: Resolved[K]["zodSchemas"]["toClient"];
411
432
  toDb: Resolved[K]["zodSchemas"]["toDb"];
412
433
  };
434
+ parseForDb: (appData: z.input<Resolved[K]["zodSchemas"]["validationSchema"]>) => z.infer<Resolved[K]["zodSchemas"]["sqlSchema"]>;
435
+ parseFromDb: (dbData: Partial<z.infer<Resolved[K]["zodSchemas"]["sqlSchema"]>>) => z.infer<Resolved[K]["zodSchemas"]["clientSchema"]>;
413
436
  defaults: Resolved[K]["zodSchemas"]["defaultValues"];
414
437
  stateType: Resolved[K]["zodSchemas"]["stateType"];
415
438
  generateDefaults: () => Resolved[K]["zodSchemas"]["defaultValues"];
439
+ pk: string[] | null;
440
+ clientPk: string[] | null;
441
+ isClientRecord: ((record: any) => boolean) | undefined;
416
442
  nav: NavigationProxy<K & string, Resolved>;
417
443
  RelationSelection: NavigationToSelection<NavigationProxy<K & string, Resolved>>;
418
444
  createView: <const TSelection extends NavigationToSelection<NavigationProxy<K & string, Resolved>>>(selection: TSelection) => DeriveViewResult<K & string, TSelection, Resolved>;
package/dist/schema.js CHANGED
@@ -33,16 +33,13 @@ export const s = {
33
33
  }
34
34
  return createBuilder({
35
35
  stage: "new",
36
- // THE MAGIC: There is no SQL config and the SQL schema is z.undefined()
37
- // This guarantees the field will be stripped from the final SQL schema object.
38
36
  sqlConfig: null,
39
37
  sqlZod: z.undefined(),
40
- // The rest of the schemas are based on the inferred type
41
38
  newZod: inferredZodType,
42
39
  initialValue: actualValue,
43
40
  clientZod: inferredZodType,
44
- validationZod: inferredZodType, // This is our internal name
45
- }); // Using `as any` to simplify the complex return type
41
+ validationZod: inferredZodType,
42
+ });
46
43
  },
47
44
  reference: (getter) => ({
48
45
  __type: "reference",
@@ -384,77 +381,6 @@ function inferDefaultFromZod(zodType, sqlConfig) {
384
381
  }
385
382
  return undefined;
386
383
  }
387
- export function createMixedValidationSchema(schema, clientSchema, dbSchema) {
388
- // If schemas are provided, use them (to avoid circular calls)
389
- if (clientSchema && dbSchema) {
390
- const mixedFields = {};
391
- const allKeys = new Set([
392
- ...Object.keys(clientSchema.shape),
393
- ...Object.keys(dbSchema.shape),
394
- ]);
395
- for (const key of allKeys) {
396
- const clientField = clientSchema.shape[key];
397
- const dbField = dbSchema.shape[key];
398
- if (clientField && dbField) {
399
- mixedFields[key] = z.union([clientField, dbField]);
400
- }
401
- else {
402
- mixedFields[key] = clientField || dbField;
403
- }
404
- }
405
- return z.object(mixedFields);
406
- }
407
- // Build schemas manually without calling createSchema
408
- const clientFields = {};
409
- const dbFields = {};
410
- for (const [key, value] of Object.entries(schema)) {
411
- if (key === "_tableName")
412
- continue;
413
- if (typeof value === "function") {
414
- const relation = value();
415
- if (!isRelation(relation))
416
- continue;
417
- // For relations, create mixed schemas recursively
418
- const childMixedSchema = createMixedValidationSchema(relation.schema);
419
- if (relation.type === "hasMany") {
420
- clientFields[key] = z.array(childMixedSchema);
421
- dbFields[key] = z.array(childMixedSchema);
422
- }
423
- else {
424
- clientFields[key] = childMixedSchema;
425
- dbFields[key] = childMixedSchema;
426
- }
427
- continue;
428
- }
429
- clientFields[key] = value.zodClientSchema;
430
- dbFields[key] = value.zodDbSchema;
431
- }
432
- // Now create mixed fields
433
- const mixedFields = {};
434
- const allKeys = new Set([
435
- ...Object.keys(clientFields),
436
- ...Object.keys(dbFields),
437
- ]);
438
- for (const key of allKeys) {
439
- const clientField = clientFields[key];
440
- const dbField = dbFields[key];
441
- if (clientField && dbField) {
442
- mixedFields[key] = z.union([clientField, dbField]);
443
- }
444
- else {
445
- mixedFields[key] = (clientField || dbField);
446
- }
447
- }
448
- return z.object(mixedFields);
449
- }
450
- function isRelation(value) {
451
- return (value &&
452
- typeof value === "object" &&
453
- "type" in value &&
454
- "fromKey" in value &&
455
- "toKey" in value &&
456
- "schema" in value);
457
- }
458
384
  // Helper to check if something is a reference
459
385
  function isReference(value) {
460
386
  return value && typeof value === "object" && value.__type === "reference";
@@ -466,10 +392,12 @@ export function createSchema(schema, relations) {
466
392
  const defaultValues = {};
467
393
  const defaultGenerators = {};
468
394
  const fieldTransforms = {};
395
+ // NEW: Track the runtime mappings
396
+ const clientToDbKeys = {};
397
+ const dbToClientKeys = {};
469
398
  const fullSchema = { ...schema, ...(relations || {}) };
470
399
  let pkKeys = [];
471
400
  let clientPkKeys = [];
472
- // FIRST PASS: Collect all fields and PKs
473
401
  for (const key in fullSchema) {
474
402
  const value = fullSchema[key];
475
403
  if (key === "_tableName" ||
@@ -484,12 +412,16 @@ export function createSchema(schema, relations) {
484
412
  const targetField = definition.getter();
485
413
  if (targetField && targetField.config) {
486
414
  const config = targetField.config;
415
+ // Track mapping
416
+ const dbFieldName = config.sql?.field || key;
417
+ clientToDbKeys[key] = dbFieldName;
418
+ dbToClientKeys[dbFieldName] = key;
419
+ // ALL SCHEMAS STRICTLY USE THE JS KEY
487
420
  sqlFields[key] = config.zodSqlSchema;
488
421
  clientFields[key] = config.zodClientSchema;
489
422
  serverFields[key] = config.zodValidationSchema;
490
423
  const initialValueOrFn = config.initialValue;
491
424
  defaultGenerators[key] = initialValueOrFn;
492
- // FIX: Call the function with { uuid } if it's a function
493
425
  let rawDefault = isFunction(initialValueOrFn)
494
426
  ? initialValueOrFn({ uuid })
495
427
  : initialValueOrFn;
@@ -502,13 +434,10 @@ export function createSchema(schema, relations) {
502
434
  }
503
435
  if (definition && definition.config) {
504
436
  const config = definition.config;
505
- // PK collection logic
506
- if (config.sql?.pk && !config.sql?.isForeignKey) {
437
+ if (config.sql?.pk && !config.sql?.isForeignKey)
507
438
  pkKeys.push(key);
508
- }
509
- if (config.sql?.isClientPk) {
439
+ if (config.sql?.isClientPk)
510
440
  clientPkKeys.push(key);
511
- }
512
441
  const sqlConfig = config.sql;
513
442
  if (sqlConfig &&
514
443
  typeof sqlConfig === "object" &&
@@ -516,6 +445,11 @@ export function createSchema(schema, relations) {
516
445
  continue;
517
446
  }
518
447
  else {
448
+ // Track mapping
449
+ const dbFieldName = sqlConfig?.field || key;
450
+ clientToDbKeys[key] = dbFieldName;
451
+ dbToClientKeys[dbFieldName] = key;
452
+ // ALL SCHEMAS STRICTLY USE THE JS KEY
519
453
  sqlFields[key] = config.zodSqlSchema;
520
454
  clientFields[key] = config.zodClientSchema;
521
455
  serverFields[key] = config.zodValidationSchema;
@@ -524,11 +458,9 @@ export function createSchema(schema, relations) {
524
458
  }
525
459
  const initialValueOrFn = config.initialValue;
526
460
  defaultGenerators[key] = initialValueOrFn;
527
- // Get the raw default value
528
461
  let rawDefault = isFunction(initialValueOrFn)
529
462
  ? initialValueOrFn({ uuid })
530
463
  : initialValueOrFn;
531
- // Apply toClient transform if it exists
532
464
  if (config.transforms?.toClient && rawDefault !== undefined) {
533
465
  defaultValues[key] = config.transforms.toClient(rawDefault);
534
466
  }
@@ -538,7 +470,6 @@ export function createSchema(schema, relations) {
538
470
  }
539
471
  }
540
472
  }
541
- // AFTER THE LOOP: Build isClientRecord checker
542
473
  let isClientRecord;
543
474
  const explicitChecker = fullSchema.__isClientChecker;
544
475
  if (explicitChecker) {
@@ -550,9 +481,7 @@ export function createSchema(schema, relations) {
550
481
  const field = fullSchema[key];
551
482
  const sqlType = field?.config?.sql?.type;
552
483
  const initialValue = field?.config?.initialValue;
553
- const dbIsNumeric = sqlType === "int";
554
- const clientIsString = typeof initialValue === "string";
555
- if (dbIsNumeric && clientIsString) {
484
+ if (sqlType === "int" && typeof initialValue === "string") {
556
485
  autoChecks.push({ key, check: (val) => typeof val === "string" });
557
486
  }
558
487
  }
@@ -565,47 +494,65 @@ export function createSchema(schema, relations) {
565
494
  for (const key in defaultGenerators) {
566
495
  const generatorOrValue = defaultGenerators[key];
567
496
  let rawValue = isFunction(generatorOrValue)
568
- ? generatorOrValue({ uuid }) // Pass the tools
497
+ ? generatorOrValue({ uuid })
569
498
  : generatorOrValue;
570
- if (fieldTransforms[key]?.toClient && rawValue !== undefined) {
571
- freshDefaults[key] = fieldTransforms[key].toClient(rawValue);
572
- }
573
- else {
574
- freshDefaults[key] = rawValue;
575
- }
499
+ freshDefaults[key] = fieldTransforms[key]?.toClient
500
+ ? fieldTransforms[key].toClient(rawValue)
501
+ : rawValue;
576
502
  }
577
503
  return freshDefaults;
578
504
  };
505
+ // --- RUNTIME TRANSFORMERS: Map keys and apply value transforms ---
579
506
  const toClient = (dbObject) => {
580
- const clientObject = { ...dbObject };
581
- for (const key in fieldTransforms) {
582
- if (key in clientObject && clientObject[key] !== undefined) {
583
- clientObject[key] = fieldTransforms[key].toClient(clientObject[key]);
584
- }
507
+ const clientObject = {};
508
+ for (const dbKey in dbObject) {
509
+ if (dbObject[dbKey] === undefined)
510
+ continue;
511
+ const clientKey = dbToClientKeys[dbKey] || dbKey;
512
+ const transform = fieldTransforms[clientKey]?.toClient;
513
+ clientObject[clientKey] = transform
514
+ ? transform(dbObject[dbKey])
515
+ : dbObject[dbKey];
585
516
  }
586
517
  return clientObject;
587
518
  };
588
519
  const toDb = (clientObject) => {
589
- const dbObject = { ...clientObject };
590
- for (const key in fieldTransforms) {
591
- if (key in dbObject && dbObject[key] !== undefined) {
592
- dbObject[key] = fieldTransforms[key].toDb(dbObject[key]);
593
- }
520
+ const dbObject = {};
521
+ for (const clientKey in clientObject) {
522
+ if (clientObject[clientKey] === undefined)
523
+ continue;
524
+ const dbKey = clientToDbKeys[clientKey] || clientKey;
525
+ const transform = fieldTransforms[clientKey]?.toDb;
526
+ dbObject[dbKey] = transform
527
+ ? transform(clientObject[clientKey])
528
+ : clientObject[clientKey];
594
529
  }
595
530
  return dbObject;
596
531
  };
532
+ // Create the final Zod objects once
533
+ const finalSqlSchema = z.object(sqlFields);
534
+ const finalClientSchema = z.object(clientFields);
535
+ const finalValidationSchema = z.object(serverFields);
597
536
  return {
598
537
  pk: pkKeys.length ? pkKeys : null,
599
538
  clientPk: clientPkKeys.length ? clientPkKeys : null,
600
539
  isClientRecord,
601
- sqlSchema: z.object(sqlFields),
602
- clientSchema: z.object(clientFields),
603
- validationSchema: z.object(serverFields),
540
+ sqlSchema: finalSqlSchema,
541
+ clientSchema: finalClientSchema,
542
+ validationSchema: finalValidationSchema,
604
543
  defaultValues: defaultValues,
605
544
  stateType: {},
606
545
  generateDefaults,
607
546
  toClient,
608
547
  toDb,
548
+ parseForDb: (appData) => {
549
+ const validData = finalValidationSchema.parse(appData);
550
+ return toDb(validData);
551
+ },
552
+ parseFromDb: (dbData) => {
553
+ const mappedData = toClient(dbData);
554
+ return finalClientSchema.parse(mappedData);
555
+ },
609
556
  };
610
557
  }
611
558
  function createViewObject(initialRegistryKey, selection, registry, tableNameToRegistryKeyMap) {
@@ -707,8 +654,11 @@ export function createSchemaBox(schemas, resolver) {
707
654
  if (isReference(field)) {
708
655
  const targetField = field.getter();
709
656
  if (targetField && targetField.config) {
710
- const newConfig = JSON.parse(JSON.stringify(targetField.config));
711
- newConfig.sql.isForeignKey = true; // Add the tag
657
+ // FIX: Shallow copy preserving Zod instances
658
+ const newConfig = {
659
+ ...targetField.config,
660
+ sql: { ...targetField.config.sql, isForeignKey: true },
661
+ };
712
662
  resolvedSchemas[tableName][fieldName] = {
713
663
  ...targetField,
714
664
  config: newConfig,
@@ -794,10 +744,12 @@ export function createSchemaBox(schemas, resolver) {
794
744
  const tableName = finalRegistry[key].rawSchema._tableName;
795
745
  tableNameToRegistryKeyMap[tableName] = key;
796
746
  }
747
+ // Inside createSchemaBox, in the cleanerRegistry loop:
797
748
  for (const tableName in finalRegistry) {
798
749
  const entry = finalRegistry[tableName];
799
750
  cleanerRegistry[tableName] = {
800
751
  definition: entry.rawSchema,
752
+ schemaKey: tableName, // ADD THIS - was missing from runtime
801
753
  schemas: {
802
754
  sql: entry.zodSchemas.sqlSchema,
803
755
  client: entry.zodSchemas.clientSchema,
@@ -807,14 +759,17 @@ export function createSchemaBox(schemas, resolver) {
807
759
  toClient: entry.zodSchemas.toClient,
808
760
  toDb: entry.zodSchemas.toDb,
809
761
  },
762
+ // ADD: parse functions
763
+ parseForDb: entry.zodSchemas.parseForDb,
764
+ parseFromDb: entry.zodSchemas.parseFromDb,
810
765
  defaults: entry.zodSchemas.defaultValues,
811
766
  stateType: entry.zodSchemas.stateType,
812
767
  generateDefaults: entry.zodSchemas.generateDefaults,
813
- // ADD: Expose PK info and resolver
768
+ // ADD: PK info
814
769
  pk: entry.zodSchemas.pk,
815
770
  clientPk: entry.zodSchemas.clientPk,
771
+ isClientRecord: entry.zodSchemas.isClientRecord,
816
772
  nav: createNavProxy(tableName, finalRegistry),
817
- // Add this
818
773
  createView: (selection) => {
819
774
  const view = createViewObject(tableName, selection, finalRegistry, tableNameToRegistryKeyMap);
820
775
  const defaults = computeViewDefaults(tableName, selection, finalRegistry, tableNameToRegistryKeyMap);
@@ -829,12 +784,12 @@ export function createSchemaBox(schemas, resolver) {
829
784
  transforms: {
830
785
  toClient: entry.zodSchemas.toClient,
831
786
  toDb: entry.zodSchemas.toDb,
787
+ parseForDb: entry.zodSchemas.parseForDb,
788
+ parseFromDb: entry.zodSchemas.parseFromDb,
832
789
  },
833
790
  defaults: defaults,
834
- // Include the pk and clientPk arrays
835
791
  pk: entry.zodSchemas.pk,
836
792
  clientPk: entry.zodSchemas.clientPk,
837
- // ADD THIS - the boolean from createViewObject
838
793
  supportsReconciliation: view.supportsReconciliation,
839
794
  isView: true,
840
795
  viewSelection: selection,
@@ -843,6 +798,7 @@ export function createSchemaBox(schemas, resolver) {
843
798
  };
844
799
  },
845
800
  RelationSelection: {},
801
+ __registry: finalRegistry, // ADD THIS - was in type but not runtime
846
802
  };
847
803
  }
848
804
  return cleanerRegistry;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-shape",
3
- "version": "0.5.169",
3
+ "version": "0.5.171",
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",