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 +15 -1
- package/dist/schema.js +92 -2
- package/package.json +8 -2
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
|
|
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.
|
|
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
|
}
|