cogsbox-shape 0.5.186 → 0.5.187

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
@@ -1,4 +1,7 @@
1
1
  import { z } from "zod";
2
+ export type DeepPartial<T> = T extends object ? {
3
+ [P in keyof T]?: DeepPartial<T[P]>;
4
+ } : T;
2
5
  type CurrentTimestampConfig = {
3
6
  default: "CURRENT_TIMESTAMP";
4
7
  defaultValue: Date;
@@ -234,6 +237,7 @@ export declare function createSchema<T extends {
234
237
  }, R extends Record<string, any> = {}, TActualSchema extends Omit<T & R, typeof SchemaWrapperBrand> = Omit<T & R, typeof SchemaWrapperBrand>>(schema: T, relations?: R): {
235
238
  pk: string[] | null;
236
239
  clientPk: string[] | null;
240
+ deriveDependencies: Record<string, string[]>;
237
241
  isClientRecord: (record: any) => boolean;
238
242
  sqlSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>;
239
243
  clientInputSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientInputSchema">>>;
@@ -245,6 +249,7 @@ export declare function createSchema<T extends {
245
249
  toClient: (dbObject: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>;
246
250
  toDb: (clientObject: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
247
251
  parseForDb: (appData: z.input<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
252
+ parsePatchForDb: (patchData: Partial<z.input<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>>>) => Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>;
248
253
  parseFromDb: (dbData: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>>;
249
254
  };
250
255
  export type PlaceholderReference = {
@@ -309,6 +314,7 @@ type ResolvedRegistryWithSchemas<S extends Record<string, SchemaWithPlaceholders
309
314
  toClient: (dbObject: any) => any;
310
315
  toDb: (clientObject: any) => any;
311
316
  parseForDb: (appData: any) => any;
317
+ parsePatchForDb: (patchData: any) => any;
312
318
  parseFromDb: (dbData: any) => any;
313
319
  };
314
320
  pk: string[] | null;
@@ -411,8 +417,12 @@ export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRe
411
417
  toClient: TRegistry[TTableName]["transforms"]["toClient"];
412
418
  toDb: TRegistry[TTableName]["transforms"]["toDb"];
413
419
  parseForDb: (appData: z.input<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "serverSchema">>>) => z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "sqlSchema">>>;
420
+ parsePatchForDb: (patchData: Partial<z.input<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "serverSchema">>>>) => Partial<z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "sqlSchema">>>>;
414
421
  parseFromDb: (dbData: Partial<z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "sqlSchema">>>>) => z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>>;
415
422
  };
423
+ reconcile: (clientData: z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>> | z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>>[]) => {
424
+ withServer: (serverData: DeepPartial<z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "sqlSchema">>>> | DeepPartial<z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "sqlSchema">>>>[]) => z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>> | z.infer<z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>>[];
425
+ };
416
426
  defaults: () => DeriveViewDefaults<TTableName, TSelection, TRegistry>;
417
427
  defaultsDefinition: () => DeriveViewDefaultsDefinition<TTableName, TSelection, TRegistry>;
418
428
  pk: string[] | null;
@@ -454,19 +464,22 @@ type RegistryShape = Record<string, {
454
464
  serverSchema: z.ZodObject<any>;
455
465
  defaultValues: any;
456
466
  stateType: any;
467
+ deriveDependencies: Record<string, string[]>;
457
468
  };
458
469
  transforms: {
459
470
  toClient: (dbObject: any) => any;
460
471
  toDb: (clientObject: any) => any;
461
472
  parseForDb: (appData: any) => any;
473
+ parsePatchForDb: (patchData: any) => any;
462
474
  parseFromDb: (dbData: any) => any;
463
475
  };
464
476
  pk: string[] | null;
465
477
  clientPk: string[] | null;
478
+ deriveDependencies: Record<string, string[]>;
466
479
  isClientRecord: (record: any) => boolean;
467
480
  generateDefaults: () => any;
468
481
  }>;
469
- type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R extends ResolutionMap<S>, Resolved extends RegistryShape = ResolvedRegistryWithSchemas<S, R> extends RegistryShape ? ResolvedRegistryWithSchemas<S, R> : RegistryShape> = {
482
+ type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R extends ResolutionMap<S>, Resolved extends Record<string, any> = ResolvedRegistryWithSchemas<S, R>> = {
470
483
  [K in keyof Resolved]: {
471
484
  definition: Resolved[K]["rawSchema"];
472
485
  schemaKey: K;
@@ -480,6 +493,7 @@ type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R e
480
493
  toClient: (dbData: z.infer<Resolved[K]["zodSchemas"]["sqlSchema"]>) => z.infer<Resolved[K]["zodSchemas"]["clientSchema"]>;
481
494
  toDb: (clientData: z.infer<Resolved[K]["zodSchemas"]["clientSchema"]>) => z.infer<Resolved[K]["zodSchemas"]["sqlSchema"]>;
482
495
  parseForDb: (appData: z.input<Resolved[K]["zodSchemas"]["serverSchema"]>) => z.infer<Resolved[K]["zodSchemas"]["sqlSchema"]>;
496
+ parsePatchForDb: (patchData: Partial<z.input<Resolved[K]["zodSchemas"]["serverSchema"]>>) => Partial<z.infer<Resolved[K]["zodSchemas"]["sqlSchema"]>>;
483
497
  parseFromDb: (dbData: Partial<z.infer<Resolved[K]["zodSchemas"]["sqlSchema"]>>) => z.infer<Resolved[K]["zodSchemas"]["clientSchema"]>;
484
498
  };
485
499
  defaults: Resolved[K]["zodSchemas"]["defaultValues"];
package/dist/schema.js CHANGED
@@ -638,9 +638,30 @@ export function createSchema(schema, relations) {
638
638
  const finalClientInputSchema = z.object(clientInputFields);
639
639
  const finalClientSchema = z.object(clientFields);
640
640
  const finalValidationSchema = z.object(serverFields);
641
+ const deriveDependencies = {};
642
+ if (derives) {
643
+ const trackingSeed = { ...defaultValues };
644
+ for (const key in derives) {
645
+ const accessed = new Set();
646
+ const trackingRow = new Proxy(trackingSeed, {
647
+ get(target, prop, receiver) {
648
+ if (typeof prop === "string" && prop !== key) {
649
+ accessed.add(prop);
650
+ }
651
+ return Reflect.get(target, prop, receiver);
652
+ },
653
+ });
654
+ try {
655
+ derives[key](trackingRow);
656
+ }
657
+ catch (e) { }
658
+ deriveDependencies[key] = Array.from(accessed);
659
+ }
660
+ }
641
661
  return {
642
662
  pk: pkKeys.length ? pkKeys : null,
643
663
  clientPk: clientPkKeys.length ? clientPkKeys : null,
664
+ deriveDependencies,
644
665
  isClientRecord,
645
666
  sqlSchema: finalSqlSchema,
646
667
  clientInputSchema: finalClientInputSchema,
@@ -655,6 +676,10 @@ export function createSchema(schema, relations) {
655
676
  const validData = finalValidationSchema.parse(appData);
656
677
  return toDb(validData);
657
678
  },
679
+ parsePatchForDb: (patchData) => {
680
+ const validPatch = finalValidationSchema.partial().parse(patchData);
681
+ return toDb(validPatch);
682
+ },
658
683
  parseFromDb: (dbData) => {
659
684
  const parsed = finalSqlSchema.parse(dbData);
660
685
  return toClient(parsed);
@@ -798,10 +823,12 @@ export function createSchemaBox(schemas, resolutions) {
798
823
  toClient: zodSchemas.toClient,
799
824
  toDb: zodSchemas.toDb,
800
825
  parseForDb: zodSchemas.parseForDb,
826
+ parsePatchForDb: zodSchemas.parsePatchForDb,
801
827
  parseFromDb: zodSchemas.parseFromDb,
802
828
  },
803
829
  pk: zodSchemas.pk,
804
830
  clientPk: zodSchemas.clientPk,
831
+ deriveDependencies: zodSchemas.deriveDependencies,
805
832
  isClientRecord: zodSchemas.isClientRecord,
806
833
  generateDefaults: zodSchemas.generateDefaults,
807
834
  };
@@ -877,6 +904,7 @@ export function createSchemaBox(schemas, resolutions) {
877
904
  toClient: entry.transforms.toClient,
878
905
  toDb: entry.transforms.toDb,
879
906
  parseForDb: entry.transforms.parseForDb,
907
+ parsePatchForDb: entry.transforms.parsePatchForDb,
880
908
  parseFromDb: entry.transforms.parseFromDb,
881
909
  },
882
910
  defaults: entry.generateDefaults(),
@@ -885,6 +913,7 @@ export function createSchemaBox(schemas, resolutions) {
885
913
  generateDefaults: entry.generateDefaults,
886
914
  pk: entry.pk,
887
915
  clientPk: entry.clientPk,
916
+ deriveDependencies: entry.deriveDependencies,
888
917
  isClientRecord: entry.isClientRecord,
889
918
  nav: createNavProxy(tableName, finalRegistry),
890
919
  createView: (selection) => {
@@ -946,6 +975,64 @@ export function createSchemaBox(schemas, resolutions) {
946
975
  };
947
976
  const viewToClient = (dbData) => deepToClient(dbData, selection, tableName);
948
977
  const viewToDb = (clientData) => deepToDb(clientData, selection, tableName);
978
+ const reconcile = (clientData) => {
979
+ return {
980
+ withServer: (serverData) => {
981
+ const parsedServerData = viewToClient(serverData);
982
+ const mergeTrees = (cNode, sNode, tableKey, sel) => {
983
+ if (sNode === undefined || sNode === null)
984
+ return cNode;
985
+ if (cNode === undefined || cNode === null)
986
+ return sNode;
987
+ const regEntry = finalRegistry[tableKey];
988
+ const clientPkField = regEntry.clientPk?.[0] || regEntry.pk?.[0];
989
+ const dbPkField = regEntry.pk?.[0] || clientPkField;
990
+ if (Array.isArray(cNode)) {
991
+ if (!Array.isArray(sNode))
992
+ return cNode;
993
+ return cNode.map((cItem, index) => {
994
+ let sItem = undefined;
995
+ if (clientPkField && cItem[clientPkField] !== undefined) {
996
+ sItem = sNode.find((s) => s[clientPkField] === cItem[clientPkField]);
997
+ }
998
+ if (!sItem && dbPkField && cItem[dbPkField] !== undefined) {
999
+ sItem = sNode.find((s) => s[dbPkField] === cItem[dbPkField]);
1000
+ }
1001
+ if (!sItem && sNode[index]) {
1002
+ sItem = sNode[index];
1003
+ }
1004
+ return mergeTrees(cItem, sItem, tableKey, sel);
1005
+ });
1006
+ }
1007
+ if (typeof cNode === "object" && typeof sNode === "object") {
1008
+ const merged = { ...cNode };
1009
+ for (const key in sNode) {
1010
+ const selValue = typeof sel === "object" ? sel[key] : undefined;
1011
+ const relField = regEntry.rawSchema[key];
1012
+ const isRelation = !!(selValue && relField?.config?.sql?.schema);
1013
+ if (isRelation) {
1014
+ const nextTableKey = tableNameToRegistryKeyMap[relField.config.sql.schema()._tableName];
1015
+ merged[key] = mergeTrees(cNode[key], sNode[key], nextTableKey, selValue);
1016
+ }
1017
+ else {
1018
+ merged[key] = sNode[key];
1019
+ }
1020
+ }
1021
+ if (clientPkField &&
1022
+ dbPkField &&
1023
+ clientPkField !== dbPkField &&
1024
+ merged[dbPkField] !== undefined &&
1025
+ merged[dbPkField] !== null) {
1026
+ delete merged[clientPkField];
1027
+ }
1028
+ return merged;
1029
+ }
1030
+ return sNode !== undefined ? sNode : cNode;
1031
+ };
1032
+ return mergeTrees(clientData, parsedServerData, tableName, selection);
1033
+ },
1034
+ };
1035
+ };
949
1036
  return {
950
1037
  definition: entry.rawSchema,
951
1038
  schemaKey: tableName,
@@ -958,16 +1045,19 @@ export function createSchemaBox(schemas, resolutions) {
958
1045
  toClient: viewToClient,
959
1046
  toDb: viewToDb,
960
1047
  parseForDb: (appData) => {
961
- // FIX: Now correctly validates against the view's server schema first
962
1048
  const validData = view.server.parse(appData);
963
1049
  return viewToDb(validData);
964
1050
  },
1051
+ parsePatchForDb: (patchData) => {
1052
+ const validPatch = view.server.partial().parse(patchData);
1053
+ return viewToDb(validPatch);
1054
+ },
965
1055
  parseFromDb: (dbData) => {
966
- // FIX: Now correctly validates against the view's client schema after mapping
967
1056
  const mappedData = view.sql.parse(dbData);
968
1057
  return viewToClient(mappedData);
969
1058
  },
970
1059
  },
1060
+ reconcile,
971
1061
  defaults: () => computeViewDefaults(tableName, selection, finalRegistry, tableNameToRegistryKeyMap),
972
1062
  defaultsDefinition: () => computeViewDefaultsDefinition(tableName, selection, finalRegistry, tableNameToRegistryKeyMap),
973
1063
  pk: entry.zodSchemas.pk,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-shape",
3
- "version": "0.5.186",
3
+ "version": "0.5.187",
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",
@@ -12,7 +12,8 @@
12
12
  "build": " tsc",
13
13
  "lint": "eslint src --ext .ts",
14
14
  "format": "prettier --write \"src/**/*.ts\"",
15
- "test": "vitest "
15
+ "test": "vitest ",
16
+ "playground": "pnpm --filter cogsbox-shape-playground dev"
16
17
  },
17
18
  "bin": {
18
19
  "cogsbox-shape": "./dist/cli.js"
@@ -55,5 +56,10 @@
55
56
  "peerDependencies": {
56
57
  "zod": "^3.22.4 || ^4.0.0"
57
58
  },
59
+ "pnpm": {
60
+ "onlyBuiltDependencies": [
61
+ "better-sqlite3"
62
+ ]
63
+ },
58
64
  "type": "module"
59
65
  }