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 +15 -1
- package/dist/schema.js +106 -15
- 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
|
@@ -9,21 +9,21 @@ export function currentTimeStamp() {
|
|
|
9
9
|
}
|
|
10
10
|
export const s = {
|
|
11
11
|
clientInput: (value) => {
|
|
12
|
-
const
|
|
12
|
+
const sample = isFunction(value) ? value({ uuid }) : value;
|
|
13
13
|
let inferredZodType;
|
|
14
|
-
if (typeof
|
|
14
|
+
if (typeof sample === "string") {
|
|
15
15
|
inferredZodType = z.string();
|
|
16
16
|
}
|
|
17
|
-
else if (typeof
|
|
17
|
+
else if (typeof sample === "number") {
|
|
18
18
|
inferredZodType = z.number();
|
|
19
19
|
}
|
|
20
|
-
else if (typeof
|
|
20
|
+
else if (typeof sample === "boolean") {
|
|
21
21
|
inferredZodType = z.boolean();
|
|
22
22
|
}
|
|
23
|
-
else if (
|
|
23
|
+
else if (sample instanceof Date) {
|
|
24
24
|
inferredZodType = z.date();
|
|
25
25
|
}
|
|
26
|
-
else if (
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
206
|
+
const sample = isFunction(value) ? value({ uuid }) : value;
|
|
207
|
+
if (typeof sample === "string")
|
|
207
208
|
baseSchema = z.string();
|
|
208
|
-
else if (typeof
|
|
209
|
+
else if (typeof sample === "number")
|
|
209
210
|
baseSchema = z.number();
|
|
210
|
-
else if (typeof
|
|
211
|
+
else if (typeof sample === "boolean")
|
|
211
212
|
baseSchema = z.boolean();
|
|
212
|
-
else if (
|
|
213
|
+
else if (sample instanceof Date)
|
|
213
214
|
baseSchema = z.date();
|
|
214
|
-
else if (
|
|
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.
|
|
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
|
}
|