cogsbox-shape 0.5.185 → 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
@@ -9,21 +9,21 @@ export function currentTimeStamp() {
9
9
  }
10
10
  export const s = {
11
11
  clientInput: (value) => {
12
- const actualValue = isFunction(value) ? value({ uuid }) : value;
12
+ const sample = isFunction(value) ? value({ uuid }) : value;
13
13
  let inferredZodType;
14
- if (typeof actualValue === "string") {
14
+ if (typeof sample === "string") {
15
15
  inferredZodType = z.string();
16
16
  }
17
- else if (typeof actualValue === "number") {
17
+ else if (typeof sample === "number") {
18
18
  inferredZodType = z.number();
19
19
  }
20
- else if (typeof actualValue === "boolean") {
20
+ else if (typeof sample === "boolean") {
21
21
  inferredZodType = z.boolean();
22
22
  }
23
- else if (actualValue instanceof Date) {
23
+ else if (sample instanceof Date) {
24
24
  inferredZodType = z.date();
25
25
  }
26
- else if (actualValue === null) {
26
+ else if (sample === null) {
27
27
  inferredZodType = z.null();
28
28
  }
29
29
  else {
@@ -33,7 +33,7 @@ export const s = {
33
33
  stage: "clientInput",
34
34
  sqlConfig: null,
35
35
  sqlZod: z.undefined(),
36
- initialValue: actualValue,
36
+ initialValue: value,
37
37
  clientZod: inferredZodType,
38
38
  validationZod: inferredZodType,
39
39
  });
@@ -185,7 +185,7 @@ function createBuilder(config) {
185
185
  let actualValue = config.initialValue;
186
186
  let finalSchema;
187
187
  if (value !== undefined) {
188
- actualValue = isFunction(value) ? value({ uuid }) : value;
188
+ actualValue = value;
189
189
  }
190
190
  else if (schemaOrModifier &&
191
191
  typeof schemaOrModifier === "object" &&
@@ -203,15 +203,16 @@ function createBuilder(config) {
203
203
  }
204
204
  else {
205
205
  if (value !== undefined) {
206
- if (typeof actualValue === "string")
206
+ const sample = isFunction(value) ? value({ uuid }) : value;
207
+ if (typeof sample === "string")
207
208
  baseSchema = z.string();
208
- else if (typeof actualValue === "number")
209
+ else if (typeof sample === "number")
209
210
  baseSchema = z.number();
210
- else if (typeof actualValue === "boolean")
211
+ else if (typeof sample === "boolean")
211
212
  baseSchema = z.boolean();
212
- else if (actualValue instanceof Date)
213
+ else if (sample instanceof Date)
213
214
  baseSchema = z.date();
214
- else if (actualValue === null)
215
+ else if (sample === null)
215
216
  baseSchema = z.null();
216
217
  else
217
218
  baseSchema = z.any();
@@ -637,9 +638,30 @@ export function createSchema(schema, relations) {
637
638
  const finalClientInputSchema = z.object(clientInputFields);
638
639
  const finalClientSchema = z.object(clientFields);
639
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
+ }
640
661
  return {
641
662
  pk: pkKeys.length ? pkKeys : null,
642
663
  clientPk: clientPkKeys.length ? clientPkKeys : null,
664
+ deriveDependencies,
643
665
  isClientRecord,
644
666
  sqlSchema: finalSqlSchema,
645
667
  clientInputSchema: finalClientInputSchema,
@@ -654,6 +676,10 @@ export function createSchema(schema, relations) {
654
676
  const validData = finalValidationSchema.parse(appData);
655
677
  return toDb(validData);
656
678
  },
679
+ parsePatchForDb: (patchData) => {
680
+ const validPatch = finalValidationSchema.partial().parse(patchData);
681
+ return toDb(validPatch);
682
+ },
657
683
  parseFromDb: (dbData) => {
658
684
  const parsed = finalSqlSchema.parse(dbData);
659
685
  return toClient(parsed);
@@ -797,10 +823,12 @@ export function createSchemaBox(schemas, resolutions) {
797
823
  toClient: zodSchemas.toClient,
798
824
  toDb: zodSchemas.toDb,
799
825
  parseForDb: zodSchemas.parseForDb,
826
+ parsePatchForDb: zodSchemas.parsePatchForDb,
800
827
  parseFromDb: zodSchemas.parseFromDb,
801
828
  },
802
829
  pk: zodSchemas.pk,
803
830
  clientPk: zodSchemas.clientPk,
831
+ deriveDependencies: zodSchemas.deriveDependencies,
804
832
  isClientRecord: zodSchemas.isClientRecord,
805
833
  generateDefaults: zodSchemas.generateDefaults,
806
834
  };
@@ -876,6 +904,7 @@ export function createSchemaBox(schemas, resolutions) {
876
904
  toClient: entry.transforms.toClient,
877
905
  toDb: entry.transforms.toDb,
878
906
  parseForDb: entry.transforms.parseForDb,
907
+ parsePatchForDb: entry.transforms.parsePatchForDb,
879
908
  parseFromDb: entry.transforms.parseFromDb,
880
909
  },
881
910
  defaults: entry.generateDefaults(),
@@ -884,6 +913,7 @@ export function createSchemaBox(schemas, resolutions) {
884
913
  generateDefaults: entry.generateDefaults,
885
914
  pk: entry.pk,
886
915
  clientPk: entry.clientPk,
916
+ deriveDependencies: entry.deriveDependencies,
887
917
  isClientRecord: entry.isClientRecord,
888
918
  nav: createNavProxy(tableName, finalRegistry),
889
919
  createView: (selection) => {
@@ -945,6 +975,64 @@ export function createSchemaBox(schemas, resolutions) {
945
975
  };
946
976
  const viewToClient = (dbData) => deepToClient(dbData, selection, tableName);
947
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
+ };
948
1036
  return {
949
1037
  definition: entry.rawSchema,
950
1038
  schemaKey: tableName,
@@ -957,16 +1045,19 @@ export function createSchemaBox(schemas, resolutions) {
957
1045
  toClient: viewToClient,
958
1046
  toDb: viewToDb,
959
1047
  parseForDb: (appData) => {
960
- // FIX: Now correctly validates against the view's server schema first
961
1048
  const validData = view.server.parse(appData);
962
1049
  return viewToDb(validData);
963
1050
  },
1051
+ parsePatchForDb: (patchData) => {
1052
+ const validPatch = view.server.partial().parse(patchData);
1053
+ return viewToDb(validPatch);
1054
+ },
964
1055
  parseFromDb: (dbData) => {
965
- // FIX: Now correctly validates against the view's client schema after mapping
966
1056
  const mappedData = view.sql.parse(dbData);
967
1057
  return viewToClient(mappedData);
968
1058
  },
969
1059
  },
1060
+ reconcile,
970
1061
  defaults: () => computeViewDefaults(tableName, selection, finalRegistry, tableNameToRegistryKeyMap),
971
1062
  defaultsDefinition: () => computeViewDefaultsDefinition(tableName, selection, finalRegistry, tableNameToRegistryKeyMap),
972
1063
  pk: entry.zodSchemas.pk,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-shape",
3
- "version": "0.5.185",
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
  }