cogsbox-shape 0.5.204 → 0.5.206
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/README.md +43 -41
- package/cogsbox-shape-state/dist/example/type-hover-example.js +2 -2
- package/cogsbox-shape-state/dist/plugin.d.ts +1 -0
- package/cogsbox-shape-state/dist/plugin.js +24 -4
- package/dist/schema.d.ts +51 -50
- package/dist/schema.js +91 -84
- package/dist/vitest/fullSchema.test.js +249 -127
- package/dist/vitest/refineRuntime.test.js +85 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,14 +33,14 @@ Traditional approaches require defining these layers separately, leading to type
|
|
|
33
33
|
Define a field by chaining methods. Each step is optional — use only what you need.
|
|
34
34
|
|
|
35
35
|
```
|
|
36
|
-
s.sqlite()/s.postgres()/s.mysql() → .
|
|
36
|
+
s.sqlite()/s.postgres()/s.mysql() → .client() → .clientCheck() → .server() → .transform()
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
| Method | Purpose |
|
|
40
40
|
| --------------------------------- | -------------------------------------------------------------- |
|
|
41
41
|
| `s.sqlite/postgres/mysql({ type, sqlOnly })` | Database column type. `sqlOnly` excludes from client layer. |
|
|
42
|
-
| `.
|
|
43
|
-
| `.
|
|
42
|
+
| `.client({ value, schema })` | Client-side input schema and default value for new records. |
|
|
43
|
+
| `.clientCheck(fn)` | Client-side validation on the final client union type. |
|
|
44
44
|
| `.server(fn)` | Server-side validation. Stricter rules before database writes. |
|
|
45
45
|
| `.transform({ toClient, toDb })` | Converts between database and client representations. |
|
|
46
46
|
|
|
@@ -88,47 +88,49 @@ s.mysql({ type: "enum", values: ["draft", "published"] });
|
|
|
88
88
|
// SQL: ENUM('draft', 'published')
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
### 2. Client
|
|
91
|
+
### 2. Client — Defaults and Client-Side Validation
|
|
92
92
|
|
|
93
|
-
`.
|
|
93
|
+
`.client()` sets the default value and client-side validation type for new records.
|
|
94
94
|
|
|
95
95
|
```typescript
|
|
96
96
|
const userSchema = schema({
|
|
97
97
|
_tableName: "users",
|
|
98
98
|
// DB stores auto-increment integers, but new records need a temp string ID
|
|
99
|
-
id: s.sqlite({ type: "int", pk: true }).
|
|
99
|
+
id: s.sqlite({ type: "int", pk: true }).client({
|
|
100
100
|
value: () => crypto.randomUUID(),
|
|
101
101
|
schema: z.string(),
|
|
102
102
|
}),
|
|
103
|
-
//
|
|
103
|
+
// client type: string (just the user's schema)
|
|
104
104
|
// Default value: a generated UUID string
|
|
105
105
|
|
|
106
106
|
// Simple default without type override
|
|
107
|
-
name: s.sqlite({ type: "varchar" }).
|
|
108
|
-
//
|
|
107
|
+
name: s.sqlite({ type: "varchar" }).client({ value: "Anonymous" }),
|
|
108
|
+
// client type: string (inherits from SQL)
|
|
109
109
|
// Default value: "Anonymous"
|
|
110
110
|
|
|
111
|
-
// Type-only override
|
|
112
|
-
count: s.sqlite({ type: "int" }).
|
|
113
|
-
//
|
|
114
|
-
// Default value: inferred from
|
|
111
|
+
// Type-only override; default is inferred from the client schema
|
|
112
|
+
count: s.sqlite({ type: "int" }).client(() => z.number().min(0)),
|
|
113
|
+
// client type: number (with min validation)
|
|
114
|
+
// Default value: inferred from the client schema (0 for number)
|
|
115
115
|
});
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
**Note:** The final `client` schema is a union of `sql |
|
|
118
|
+
**Note:** The final `client` schema is a union of `sql | client` types, representing the complete app state after transforms.
|
|
119
|
+
|
|
120
|
+
`generateDefaults()` uses the client schema to pick a default when no explicit `value` is provided. `toClient()` stays for DB-shaped data.
|
|
119
121
|
|
|
120
|
-
### 3. Client — Client-Side Validation
|
|
122
|
+
### 3. Client Check — Client-Side Validation
|
|
121
123
|
|
|
122
|
-
`.
|
|
124
|
+
`.clientCheck()` adds validation rules to the final `client` schema (the union of sql | client). Use it for client-side validation that operates on the complete client type.
|
|
123
125
|
|
|
124
126
|
```typescript
|
|
125
127
|
name: s.sqlite({ type: "varchar" })
|
|
126
|
-
.
|
|
127
|
-
.
|
|
128
|
-
.server((tools) => tools.
|
|
128
|
+
.client({ value: "" })
|
|
129
|
+
.clientCheck((tools) => tools.client.min(3, "Too short"))
|
|
130
|
+
.server((tools) => tools.client.min(5, "Must be at least 5 chars")),
|
|
129
131
|
```
|
|
130
132
|
|
|
131
|
-
The `.
|
|
133
|
+
The `.clientCheck()` callback receives `tools` with `sql`, `client`, and `clientCheck` schemas.
|
|
132
134
|
|
|
133
135
|
### 4. Server — Server-Side Validation
|
|
134
136
|
|
|
@@ -152,8 +154,8 @@ The callback receives the previous schema in the chain so you can refine it:
|
|
|
152
154
|
```typescript
|
|
153
155
|
name: s
|
|
154
156
|
.sqlite({ type: "varchar" })
|
|
155
|
-
.
|
|
156
|
-
.server(({
|
|
157
|
+
.client(() => z.string().trim())
|
|
158
|
+
.server(({ client }) => client.min(2, "Too short")),
|
|
157
159
|
```
|
|
158
160
|
|
|
159
161
|
### 5. Transform — Convert Between Layers
|
|
@@ -163,7 +165,7 @@ name: s
|
|
|
163
165
|
```typescript
|
|
164
166
|
status: s
|
|
165
167
|
.sqlite({ type: "int" }) // DB: 0 or 1
|
|
166
|
-
.
|
|
168
|
+
.client(() => z.enum(["active", "inactive"])) // Client input: string enum
|
|
167
169
|
.transform({
|
|
168
170
|
toClient: (dbValue) => dbValue === 1 ? "active" : "inactive",
|
|
169
171
|
toDb: (clientValue) => clientValue === "active" ? 1 : 0,
|
|
@@ -193,13 +195,13 @@ const userSchema = schema({
|
|
|
193
195
|
|
|
194
196
|
#### Client-Only Fields
|
|
195
197
|
|
|
196
|
-
By skipping `s.sqlite()` entirely and just using `s.
|
|
198
|
+
By skipping `s.sqlite()` entirely and just using `s.client()`, you can define fields that exist purely on the client (like a temporary UI state or computed field) and will not be sent to the database.
|
|
197
199
|
|
|
198
200
|
```typescript
|
|
199
201
|
const products = schema({
|
|
200
202
|
_tableName: "products",
|
|
201
203
|
price: s.sqlite({ type: "int" }),
|
|
202
|
-
formattedPrice: s.
|
|
204
|
+
formattedPrice: s.client(""), // Client-only field!
|
|
203
205
|
});
|
|
204
206
|
```
|
|
205
207
|
|
|
@@ -213,11 +215,11 @@ const products = schema({
|
|
|
213
215
|
```typescript
|
|
214
216
|
const users = schema({
|
|
215
217
|
_tableName: "users",
|
|
216
|
-
firstName: s.sqlite({ type: "varchar" }).
|
|
217
|
-
lastName: s.sqlite({ type: "varchar" }).
|
|
218
|
+
firstName: s.sqlite({ type: "varchar" }).client({ value: "John" }),
|
|
219
|
+
lastName: s.sqlite({ type: "varchar" }).client({ value: "Doe" }),
|
|
218
220
|
|
|
219
|
-
// Virtual field. It exists in app/view state, not SQL.
|
|
220
|
-
fullName: s.
|
|
221
|
+
// Virtual field. It exists in app/view state, not SQL.
|
|
222
|
+
fullName: s.client(""),
|
|
221
223
|
|
|
222
224
|
// Hidden DB column. It is written to SQL, but not sent to the client.
|
|
223
225
|
searchIndex: s.sqlite({ type: "varchar", sqlOnly: true }),
|
|
@@ -235,19 +237,19 @@ During partial ORM updates, DB-backed derivations fetch only missing dependency
|
|
|
235
237
|
|
|
236
238
|
### 7. Refinement (`.refine()`)
|
|
237
239
|
|
|
238
|
-
`.refine()` adds cross-field validation rules that the entire row must satisfy. Unlike `.
|
|
240
|
+
`.refine()` adds cross-field validation rules that the entire row must satisfy. Unlike `.clientCheck()`/`.server()` which validate individual fields, `refine` can check relationships between fields.
|
|
239
241
|
|
|
240
242
|
```typescript
|
|
241
243
|
const events = schema({
|
|
242
244
|
_tableName: "events",
|
|
243
245
|
id: s.sqlite({ type: "int", pk: true }),
|
|
244
|
-
startDate: s.sqlite({ type: "varchar" }).
|
|
245
|
-
endDate: s.sqlite({ type: "varchar" }).
|
|
246
|
-
content: s.sqlite({ type: "varchar", nullable: true }).
|
|
246
|
+
startDate: s.sqlite({ type: "varchar" }).client({ value: "" }),
|
|
247
|
+
endDate: s.sqlite({ type: "varchar" }).client({ value: "" }),
|
|
248
|
+
content: s.sqlite({ type: "varchar", nullable: true }).client({
|
|
247
249
|
value: null,
|
|
248
250
|
schema: z.string().nullable(),
|
|
249
251
|
}),
|
|
250
|
-
isPublished: s.sqlite({ type: "boolean" }).
|
|
252
|
+
isPublished: s.sqlite({ type: "boolean" }).client({ value: false }),
|
|
251
253
|
}).refine((r) => [
|
|
252
254
|
r("server", (row) => {
|
|
253
255
|
const errors: { path: string[]; message: string }[] = [];
|
|
@@ -276,8 +278,8 @@ The `refine()` method takes a callback that receives an `r` helper function. Eac
|
|
|
276
278
|
| Layer | Applies to | Purpose |
|
|
277
279
|
|-------|-----------|---------|
|
|
278
280
|
| `"server"` | `parseForDb()`, `server` schema | Cross-field validation before DB writes |
|
|
279
|
-
| `"
|
|
280
|
-
| `"
|
|
281
|
+
| `"clientCheck"` | `clientCheck` schema | Cross-field validation on client output |
|
|
282
|
+
| `"client"` | `client` schema | Cross-field validation on raw client input |
|
|
281
283
|
| `"sql"` | `parseFromDb()`, `sql` schema | Cross-field validation on DB reads |
|
|
282
284
|
| `"all"` | all of the above | Universal cross-field validation |
|
|
283
285
|
| `string[]` | specified layers | Apply to multiple layers at once |
|
|
@@ -312,10 +314,10 @@ The returned schema object has a clear separation of concerns:
|
|
|
312
314
|
```typescript
|
|
313
315
|
const schema = createSchema(mySchema);
|
|
314
316
|
|
|
315
|
-
schema.schemas; // { sql,
|
|
317
|
+
schema.schemas; // { sql, client, clientChecked, server } — Zod schemas
|
|
316
318
|
schema.transforms; // { toClient, toDb, parseForDb, parseFromDb } — transformations
|
|
317
319
|
schema.defaults; // Default values for forms
|
|
318
|
-
schema.generateDefaults; // Function to generate fresh defaults (executes randomizers)
|
|
320
|
+
schema.generateDefaults; // Function to generate fresh client defaults (executes randomizers)
|
|
319
321
|
schema.pk; // Primary key field names
|
|
320
322
|
schema.clientPk; // Client-side primary key field names
|
|
321
323
|
schema.isClientRecord; // Function to check if a record is client-created
|
|
@@ -334,7 +336,7 @@ import { s, schema, createSchema } from "cogsbox-shape";
|
|
|
334
336
|
|
|
335
337
|
const contactSchema = schema({
|
|
336
338
|
_tableName: "contacts",
|
|
337
|
-
id: s.sqlite({ type: "int", pk: true }).
|
|
339
|
+
id: s.sqlite({ type: "int", pk: true }).client({
|
|
338
340
|
value: () => `new_${crypto.randomUUID().slice(0, 8)}`,
|
|
339
341
|
schema: z.string(),
|
|
340
342
|
}),
|
|
@@ -342,7 +344,7 @@ const contactSchema = schema({
|
|
|
342
344
|
email: s.sqlite({ type: "varchar" }).server(({ sql }) => sql.email()),
|
|
343
345
|
isActive: s
|
|
344
346
|
.sqlite({ type: "boolean", default: true })
|
|
345
|
-
.
|
|
347
|
+
.client(() => z.boolean())
|
|
346
348
|
.transform({
|
|
347
349
|
toClient: (val) => Boolean(val),
|
|
348
350
|
toDb: (val) => (val ? 1 : 0),
|
|
@@ -352,7 +354,7 @@ const contactSchema = schema({
|
|
|
352
354
|
const schema = createSchema(contactSchema);
|
|
353
355
|
|
|
354
356
|
// Access schemas directly
|
|
355
|
-
const { sql,
|
|
357
|
+
const { sql, client, clientChecked, server } = schema.schemas;
|
|
356
358
|
const { defaults, generateDefaults } = schema;
|
|
357
359
|
|
|
358
360
|
// Transforms for converting between layers
|
|
@@ -13,11 +13,11 @@ const taskItemSchema = z.object({
|
|
|
13
13
|
});
|
|
14
14
|
const taskManagerSchema = schema({
|
|
15
15
|
_tableName: "client",
|
|
16
|
-
tasks: s.
|
|
16
|
+
tasks: s.client({
|
|
17
17
|
value: [],
|
|
18
18
|
schema: z.array(taskItemSchema),
|
|
19
19
|
}),
|
|
20
|
-
filter: s.
|
|
20
|
+
filter: s.client({
|
|
21
21
|
value: "all",
|
|
22
22
|
schema: z.string(),
|
|
23
23
|
}),
|
|
@@ -41,6 +41,7 @@ type FormUpdateParams = {
|
|
|
41
41
|
message: string;
|
|
42
42
|
code?: string;
|
|
43
43
|
}>) => void;
|
|
44
|
+
clearZodErrors: (paths: string[][]) => void;
|
|
44
45
|
};
|
|
45
46
|
export declare function wireShapeValidationOptions(box: ShapeSchemaBox, params: TransformStateParams): void;
|
|
46
47
|
/** Cross-field refine errors only — field rules are handled by state via setOptions. */
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { createPluginContext } from "cogsbox-state";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
function pathKey(path) {
|
|
4
|
+
return path.join("\0");
|
|
5
|
+
}
|
|
6
|
+
function resolveRelatedPaths(blurPath, relatedFields) {
|
|
7
|
+
const parent = blurPath.slice(0, -1);
|
|
8
|
+
return [...relatedFields].map((field) => [...parent, field]);
|
|
9
|
+
}
|
|
3
10
|
function mapZodIssues(issues) {
|
|
4
11
|
return issues.map((issue) => ({
|
|
5
12
|
path: issue.path.map(String),
|
|
@@ -21,6 +28,10 @@ function getRelatedFields(entry, field) {
|
|
|
21
28
|
}
|
|
22
29
|
return related;
|
|
23
30
|
}
|
|
31
|
+
function issueMatchesRelatedFields(issue, relatedFields) {
|
|
32
|
+
const leaf = String(issue.path.at(-1) ?? "");
|
|
33
|
+
return relatedFields.has(leaf);
|
|
34
|
+
}
|
|
24
35
|
export function wireShapeValidationOptions(box, params) {
|
|
25
36
|
const entry = box[params.stateKey];
|
|
26
37
|
if (!entry)
|
|
@@ -46,12 +57,21 @@ export function validateShapeRefines(box, params) {
|
|
|
46
57
|
const relatedFields = getRelatedFields(entry, field);
|
|
47
58
|
if (!relatedFields)
|
|
48
59
|
return;
|
|
60
|
+
const relatedPaths = resolveRelatedPaths(params.path, relatedFields);
|
|
49
61
|
const result = clientSchema.safeParse(params.getState());
|
|
50
|
-
if (result.success)
|
|
62
|
+
if (result.success) {
|
|
63
|
+
params.clearZodErrors(relatedPaths);
|
|
51
64
|
return;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
}
|
|
66
|
+
const issues = result.error.issues.filter((issue) => issueMatchesRelatedFields(issue, relatedFields));
|
|
67
|
+
const mapped = mapZodIssues(issues);
|
|
68
|
+
const activeKeys = new Set(mapped.map((entry) => pathKey(entry.path)));
|
|
69
|
+
const stalePaths = relatedPaths.filter((targetPath) => !activeKeys.has(pathKey(targetPath)));
|
|
70
|
+
if (stalePaths.length > 0) {
|
|
71
|
+
params.clearZodErrors(stalePaths);
|
|
72
|
+
}
|
|
73
|
+
if (mapped.length > 0) {
|
|
74
|
+
params.addZodErrors(mapped);
|
|
55
75
|
}
|
|
56
76
|
}
|
|
57
77
|
function buildInitialState(box) {
|
package/dist/schema.d.ts
CHANGED
|
@@ -64,49 +64,49 @@ type SQLToZodType<T extends SQLTypeInput, TDefault extends boolean> = T["pk"] ex
|
|
|
64
64
|
type ZodTypeFromPrimitive<T> = T extends string ? z.ZodString : T extends number ? z.ZodNumber : T extends boolean ? z.ZodBoolean : T extends Date ? z.ZodDate : z.ZodAny;
|
|
65
65
|
type CollapsedUnion<A extends z.ZodTypeAny, B extends z.ZodTypeAny> = A extends B ? (B extends A ? A : z.ZodUnion<[A, B]>) : z.ZodUnion<[A, B]>;
|
|
66
66
|
export interface IBuilderMethods<T extends DbConfig, TSql extends z.ZodTypeAny, TInitialValue, TClient extends z.ZodTypeAny, TValidation extends z.ZodTypeAny> {
|
|
67
|
-
|
|
67
|
+
client<const TValue, const TSchema extends z.ZodTypeAny>(options: {
|
|
68
68
|
value: TValue | ((tools: {
|
|
69
69
|
uuid: () => string;
|
|
70
70
|
}) => TValue);
|
|
71
71
|
schema: TSchema | ((base: ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>) => TSchema);
|
|
72
72
|
clientPk?: boolean | ((val: any) => boolean);
|
|
73
|
-
}): Prettify<Builder<"
|
|
74
|
-
|
|
73
|
+
}): Prettify<Builder<"client", T, TSql, TValue extends () => infer R ? R : TValue, TSchema, CollapsedUnion<TSql, TSchema>>>;
|
|
74
|
+
client<const TValue>(options: {
|
|
75
75
|
value: TValue | ((tools: {
|
|
76
76
|
uuid: () => string;
|
|
77
77
|
}) => TValue);
|
|
78
78
|
schema?: never;
|
|
79
79
|
clientPk?: boolean | ((val: any) => boolean);
|
|
80
|
-
}): Prettify<Builder<"
|
|
81
|
-
|
|
80
|
+
}): Prettify<Builder<"client", T, TSql, TValue extends () => infer R ? R : TValue, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>>>>;
|
|
81
|
+
client<const TSchema extends z.ZodTypeAny>(options: {
|
|
82
82
|
value?: never;
|
|
83
83
|
schema: TSchema;
|
|
84
84
|
clientPk?: boolean | ((val: any) => boolean);
|
|
85
|
-
}): Prettify<Builder<"
|
|
86
|
-
|
|
85
|
+
}): Prettify<Builder<"client", T, TSql, z.infer<TSchema>, TSchema, CollapsedUnion<TSql, TSchema>>>;
|
|
86
|
+
client<const TSchema extends z.ZodTypeAny>(options: {
|
|
87
87
|
value?: never;
|
|
88
88
|
schema: TSchema | ((tools: any) => TSchema);
|
|
89
89
|
clientPk?: boolean | ((val: any) => boolean);
|
|
90
|
-
}): Prettify<Builder<"
|
|
91
|
-
|
|
90
|
+
}): Prettify<Builder<"client", T, TSql, z.infer<TSchema>, TSchema, CollapsedUnion<TSql, TSchema>>>;
|
|
91
|
+
client<const TValue>(options: {
|
|
92
92
|
value: TValue | ((tools: {
|
|
93
93
|
uuid: () => string;
|
|
94
94
|
}) => TValue);
|
|
95
95
|
schema?: never;
|
|
96
96
|
clientPk?: boolean | ((val: any) => boolean);
|
|
97
|
-
}): Prettify<Builder<"
|
|
98
|
-
|
|
97
|
+
}): Prettify<Builder<"client", T, TSql, TValue extends () => infer R ? R : TValue, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>, CollapsedUnion<TSql, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>>>>;
|
|
98
|
+
client(options: {
|
|
99
99
|
value?: never;
|
|
100
100
|
schema: (tools: any) => z.ZodTypeAny;
|
|
101
|
-
}): Prettify<Builder<"
|
|
102
|
-
|
|
101
|
+
}): Prettify<Builder<"client", T, TSql, unknown, z.ZodTypeAny, z.ZodTypeAny>>;
|
|
102
|
+
client<TClientNext extends z.ZodTypeAny>(schema: ((tools: {
|
|
103
103
|
sql: TSql;
|
|
104
|
-
}) => TClientNext) | TClientNext): Prettify<Builder<"
|
|
105
|
-
|
|
104
|
+
}) => TClientNext) | TClientNext): Prettify<Builder<"client", T, TSql, z.infer<TClientNext>, TClientNext, CollapsedUnion<TSql, TClientNext>>>;
|
|
105
|
+
clientCheck: <TClientNext extends z.ZodTypeAny>(schema: ((tools: {
|
|
106
106
|
sql: TSql;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}) => TClientNext) | TClientNext) => Prettify<Builder<"
|
|
107
|
+
client: TClient;
|
|
108
|
+
clientCheck: z.ZodUnion<[TSql, TClient]>;
|
|
109
|
+
}) => TClientNext) | TClientNext) => Prettify<Builder<"clientCheck", T, TSql, TInitialValue, TClient, z.ZodUnion<[TSql, TClientNext]>>>;
|
|
110
110
|
reference: <TRefSchema extends {
|
|
111
111
|
_tableName: string;
|
|
112
112
|
}>(fieldGetter: () => any) => Builder<"sql", T & {
|
|
@@ -114,8 +114,8 @@ export interface IBuilderMethods<T extends DbConfig, TSql extends z.ZodTypeAny,
|
|
|
114
114
|
}, TSql, TInitialValue, TClient, TValidation>;
|
|
115
115
|
server: <TValidationNext extends z.ZodTypeAny>(schema: ((tools: {
|
|
116
116
|
sql: TSql;
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
client: TClient;
|
|
118
|
+
clientCheck: z.ZodUnion<[TSql, TClient]>;
|
|
119
119
|
}) => TValidationNext) | TValidationNext) => Prettify<Builder<"server", T, TSql, TInitialValue, TClient, TValidationNext>>;
|
|
120
120
|
transform: (transforms: {
|
|
121
121
|
toClient: (dbValue: z.infer<TSql>) => z.infer<TClient>;
|
|
@@ -141,12 +141,12 @@ export type RelationConfig<T extends Schema<any>> = (BaseRelationConfig<T> & {
|
|
|
141
141
|
}) | (BaseRelationConfig<T> & {
|
|
142
142
|
type: "manyToMany";
|
|
143
143
|
});
|
|
144
|
-
type Stage = "sql" | "relation" | "
|
|
144
|
+
type Stage = "sql" | "relation" | "client" | "clientCheck" | "server" | "done";
|
|
145
145
|
type StageMethods = {
|
|
146
|
-
sql: "
|
|
147
|
-
relation: "
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
sql: "client" | "clientCheck" | "server" | "transform" | "reference";
|
|
147
|
+
relation: "client" | "clientCheck" | "server" | "transform";
|
|
148
|
+
client: "clientCheck" | "server" | "transform";
|
|
149
|
+
clientCheck: "server" | "transform";
|
|
150
150
|
server: "transform";
|
|
151
151
|
done: never;
|
|
152
152
|
};
|
|
@@ -154,8 +154,8 @@ type BuilderConfig<T extends DbConfig, TSql extends z.ZodTypeAny, TInitialValue,
|
|
|
154
154
|
sql: T;
|
|
155
155
|
zodSqlSchema: TSql;
|
|
156
156
|
initialValue: TInitialValue;
|
|
157
|
-
zodClientInputSchema: TClient;
|
|
158
157
|
zodClientSchema: TClient;
|
|
158
|
+
zodClientCheckedSchema: TClient;
|
|
159
159
|
zodValidationSchema: TValidation;
|
|
160
160
|
clientTransform?: (schema: z.ZodTypeAny) => z.ZodTypeAny;
|
|
161
161
|
validationTransform?: (schema: z.ZodTypeAny) => z.ZodTypeAny;
|
|
@@ -165,8 +165,8 @@ export type Builder<TStage extends Stage, T extends DbConfig, TSql extends z.Zod
|
|
|
165
165
|
sql: T;
|
|
166
166
|
zodSqlSchema: TSql;
|
|
167
167
|
initialValue: TInitialValue;
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
zodClientSchema: TClient;
|
|
169
|
+
zodClientCheckedSchema: TValidation;
|
|
170
170
|
zodValidationSchema: TValidation;
|
|
171
171
|
};
|
|
172
172
|
} & Pick<IBuilderMethods<T, TSql, TInitialValue, TClient, TValidation>, StageMethods[TStage]>;
|
|
@@ -179,28 +179,28 @@ export type Reference<TGetter extends () => any> = {
|
|
|
179
179
|
getter: TGetter;
|
|
180
180
|
};
|
|
181
181
|
interface ShapeAPI {
|
|
182
|
-
|
|
182
|
+
client<const TValue, const TSchema extends z.ZodTypeAny>(options: {
|
|
183
183
|
value: TValue | ((tools: {
|
|
184
184
|
uuid: () => string;
|
|
185
185
|
}) => TValue);
|
|
186
186
|
schema: TSchema | ((base: ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>) => TSchema);
|
|
187
187
|
clientPk?: boolean | ((val: any) => boolean);
|
|
188
|
-
}): Builder<"
|
|
189
|
-
|
|
188
|
+
}): Builder<"client", null, z.ZodUndefined, TValue extends () => infer R ? R : TValue, TSchema, TSchema>;
|
|
189
|
+
client<const TValue>(options: {
|
|
190
190
|
value: TValue | ((tools: {
|
|
191
191
|
uuid: () => string;
|
|
192
192
|
}) => TValue);
|
|
193
193
|
schema?: never;
|
|
194
194
|
clientPk?: boolean | ((val: any) => boolean);
|
|
195
|
-
}): Builder<"
|
|
196
|
-
|
|
195
|
+
}): Builder<"client", null, z.ZodUndefined, TValue extends () => infer R ? R : TValue, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>>;
|
|
196
|
+
client<const TSchema extends z.ZodTypeAny>(options: {
|
|
197
197
|
value?: never;
|
|
198
198
|
schema: TSchema;
|
|
199
199
|
clientPk?: boolean | ((val: any) => boolean);
|
|
200
|
-
}): Builder<"
|
|
201
|
-
|
|
200
|
+
}): Builder<"client", null, z.ZodUndefined, z.infer<TSchema>, TSchema, TSchema>;
|
|
201
|
+
client<const TValue>(value: TValue | ((tools: {
|
|
202
202
|
uuid: () => string;
|
|
203
|
-
}) => TValue)): Builder<"
|
|
203
|
+
}) => TValue)): Builder<"client", null, z.ZodUndefined, TValue extends () => infer R ? R : TValue, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>, ZodTypeFromPrimitive<TValue extends () => infer R ? R : TValue>>;
|
|
204
204
|
sqlite: <const T extends SQLTypeInput>(sqlConfig: T) => Builder<"sql", WithDialect<T, "sqlite">, SQLToZodType<T, false>, z.infer<SQLToZodType<T, false>>, SQLToZodType<T, false>, SQLToZodType<T, false>>;
|
|
205
205
|
postgres: <const T extends SQLTypeInput>(sqlConfig: T) => Builder<"sql", WithDialect<T, "postgres">, SQLToZodType<T, false>, z.infer<SQLToZodType<T, false>>, SQLToZodType<T, false>, SQLToZodType<T, false>>;
|
|
206
206
|
mysql: <const T extends SQLTypeInput>(sqlConfig: T) => Builder<"sql", WithDialect<T, "mysql">, SQLToZodType<T, false>, z.infer<SQLToZodType<T, false>>, SQLToZodType<T, false>, SQLToZodType<T, false>>;
|
|
@@ -228,15 +228,15 @@ export type RefinementError = {
|
|
|
228
228
|
path: string[];
|
|
229
229
|
message: string;
|
|
230
230
|
};
|
|
231
|
-
type RefineLayer = "client" | "
|
|
231
|
+
type RefineLayer = "client" | "clientCheck" | "server" | "sql" | "all";
|
|
232
232
|
type RefineEntry = {
|
|
233
233
|
layers: RefineLayer[];
|
|
234
234
|
deps: string[] | null;
|
|
235
235
|
check: (row: any) => RefinementError | RefinementError[] | undefined | null;
|
|
236
236
|
};
|
|
237
237
|
type RefineHelper<T extends ShapeSchema> = {
|
|
238
|
+
(layer: "clientCheck", check: (row: InferClientCheckedRow<T>) => RefinementError | RefinementError[] | undefined | null, deps?: string | string[]): RefineEntry;
|
|
238
239
|
(layer: "client", check: (row: InferClientRow<T>) => RefinementError | RefinementError[] | undefined | null, deps?: string | string[]): RefineEntry;
|
|
239
|
-
(layer: "clientInput", check: (row: InferClientInputRow<T>) => RefinementError | RefinementError[] | undefined | null, deps?: string | string[]): RefineEntry;
|
|
240
240
|
(layer: "server", check: (row: InferValidationRow<T>) => RefinementError | RefinementError[] | undefined | null, deps?: string | string[]): RefineEntry;
|
|
241
241
|
(layer: "sql", check: (row: InferSqlRow<T>) => RefinementError | RefinementError[] | undefined | null, deps?: string | string[]): RefineEntry;
|
|
242
242
|
(layer: "all", check: (row: InferClientRow<T>) => RefinementError | RefinementError[] | undefined | null, deps?: string | string[]): RefineEntry;
|
|
@@ -267,8 +267,8 @@ type PickDbFieldKeys<T extends ShapeSchema> = {
|
|
|
267
267
|
type: "hasMany" | "hasOne" | "belongsTo" | "manyToMany";
|
|
268
268
|
} ? never : K : never;
|
|
269
269
|
}[keyof T];
|
|
270
|
+
type InferClientCheckedRow<T extends ShapeSchema> = Prettify<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodClientCheckedSchema">>>>>;
|
|
270
271
|
type InferClientRow<T extends ShapeSchema> = Prettify<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodClientSchema">>>>>;
|
|
271
|
-
type InferClientInputRow<T extends ShapeSchema> = Prettify<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodClientInputSchema">>>>>;
|
|
272
272
|
type InferValidationRow<T extends ShapeSchema> = Prettify<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodValidationSchema">>>>>;
|
|
273
273
|
type InferSqlRow<T extends ShapeSchema> = Prettify<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<T, "zodSqlSchema">>>>>;
|
|
274
274
|
type SchemaBuilder<T extends ShapeSchema> = Prettify<EnrichFields<T>> & {
|
|
@@ -295,7 +295,7 @@ type BaseSchemaField<T extends SQLType = SQLType> = {
|
|
|
295
295
|
type: "field";
|
|
296
296
|
sql: T;
|
|
297
297
|
zodDbSchema: z.ZodType<any>;
|
|
298
|
-
|
|
298
|
+
zodClientCheckedSchema: z.ZodType<any>;
|
|
299
299
|
defaultValue?: any;
|
|
300
300
|
__fieldId?: string;
|
|
301
301
|
toClient?: (dbValue: any) => any;
|
|
@@ -333,17 +333,17 @@ export declare function createSchema<T extends {
|
|
|
333
333
|
};
|
|
334
334
|
isClientRecord: (record: any) => boolean;
|
|
335
335
|
sqlSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>;
|
|
336
|
-
clientInputSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientInputSchema">>>;
|
|
337
336
|
clientSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientSchema">>>;
|
|
337
|
+
clientCheckedSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientCheckedSchema">>>;
|
|
338
338
|
serverSchema: z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>;
|
|
339
339
|
defaultValues: Prettify<DeriveDefaults<TActualSchema>>;
|
|
340
340
|
stateType: Prettify<DeriveStateType<TActualSchema>>;
|
|
341
341
|
generateDefaults: () => Prettify<DeriveDefaults<TActualSchema>>;
|
|
342
|
-
toClient: (dbObject: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "
|
|
343
|
-
toDb: (clientObject: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "
|
|
342
|
+
toClient: (dbObject: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientCheckedSchema">>>>;
|
|
343
|
+
toDb: (clientObject: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientCheckedSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
|
|
344
344
|
parseForDb: (appData: z.input<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>;
|
|
345
345
|
parsePatchForDb: (patchData: Partial<z.input<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodValidationSchema">>>>>) => Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>;
|
|
346
|
-
parseFromDb: (dbData: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "
|
|
346
|
+
parseFromDb: (dbData: Partial<z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodSqlSchema">>>>>) => z.infer<z.ZodObject<Prettify<DeriveSchemaByKey<TActualSchema, "zodClientCheckedSchema">>>>;
|
|
347
347
|
};
|
|
348
348
|
export type PlaceholderReference = {
|
|
349
349
|
__type: "placeholder-reference";
|
|
@@ -397,8 +397,8 @@ type ResolvedRegistryWithSchemas<S extends Record<string, SchemaWithPlaceholders
|
|
|
397
397
|
rawSchema: ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>;
|
|
398
398
|
zodSchemas: {
|
|
399
399
|
sqlSchema: z.ZodObject<Prettify<DeriveSchemaByKey<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>, "zodSqlSchema">>>;
|
|
400
|
-
clientInputSchema: z.ZodObject<Prettify<DeriveSchemaByKey<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>, "zodClientInputSchema">>>;
|
|
401
400
|
clientSchema: z.ZodObject<Prettify<DeriveSchemaByKey<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>, "zodClientSchema">>>;
|
|
401
|
+
clientCheckedSchema: z.ZodObject<Prettify<DeriveSchemaByKey<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>, "zodClientCheckedSchema">>>;
|
|
402
402
|
serverSchema: z.ZodObject<Prettify<DeriveSchemaByKey<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>, "zodValidationSchema">>>;
|
|
403
403
|
defaultValues: Prettify<DeriveDefaults<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>>>;
|
|
404
404
|
stateType: Prettify<DeriveStateType<ResolveSchema<S[K], K extends keyof R ? (R[K] extends object ? R[K] : {}) : {}>>>;
|
|
@@ -442,8 +442,8 @@ type GetRelationRegistryKey<Field, TRegistry extends RegistryShape> = Field exte
|
|
|
442
442
|
type OmitRelationFields<Shape, RawSchema> = Omit<Shape, {
|
|
443
443
|
[K in keyof Shape]: K extends keyof RawSchema ? IsRelationField<RawSchema[K]> extends true ? K : never : never;
|
|
444
444
|
}[keyof Shape]>;
|
|
445
|
-
type _DeriveViewShape<TTableName extends keyof TRegistry, TSelection, TRegistry extends RegistryShape, TKey extends "clientSchema" | "serverSchema" | "sqlSchema", Depth extends any[] = []> = Depth["length"] extends 10 ? any : TKey extends "sqlSchema" ? TRegistry[TTableName]["zodSchemas"]["sqlSchema"] extends z.ZodObject<infer BaseShape> ? _DeriveViewShapeInner<BaseShape, TTableName, TSelection, TRegistry, TKey, Depth> : never : TRegistry[TTableName]["zodSchemas"][TKey] extends z.ZodObject<infer BaseShape> ? _DeriveViewShapeInner<BaseShape, TTableName, TSelection, TRegistry, TKey, Depth> : never;
|
|
446
|
-
type _DeriveViewShapeInner<BaseShape, TTableName extends keyof TRegistry, TSelection, TRegistry extends RegistryShape, TKey extends "clientSchema" | "serverSchema" | "sqlSchema", Depth extends any[] = []> = TSelection extends Record<string, any> ? Prettify<OmitRelationFields<BaseShape, TRegistry[TTableName]["rawSchema"]> & {
|
|
445
|
+
type _DeriveViewShape<TTableName extends keyof TRegistry, TSelection, TRegistry extends RegistryShape, TKey extends "clientSchema" | "clientCheckedSchema" | "serverSchema" | "sqlSchema", Depth extends any[] = []> = Depth["length"] extends 10 ? any : TKey extends "sqlSchema" ? TRegistry[TTableName]["zodSchemas"]["sqlSchema"] extends z.ZodObject<infer BaseShape> ? _DeriveViewShapeInner<BaseShape, TTableName, TSelection, TRegistry, TKey, Depth> : never : TRegistry[TTableName]["zodSchemas"][TKey] extends z.ZodObject<infer BaseShape> ? _DeriveViewShapeInner<BaseShape, TTableName, TSelection, TRegistry, TKey, Depth> : never;
|
|
446
|
+
type _DeriveViewShapeInner<BaseShape, TTableName extends keyof TRegistry, TSelection, TRegistry extends RegistryShape, TKey extends "clientSchema" | "clientCheckedSchema" | "serverSchema" | "sqlSchema", Depth extends any[] = []> = TSelection extends Record<string, any> ? Prettify<OmitRelationFields<BaseShape, TRegistry[TTableName]["rawSchema"]> & {
|
|
447
447
|
[K in keyof TSelection & keyof TRegistry[TTableName]["rawSchema"] as IsRelationField<TRegistry[TTableName]["rawSchema"][K]> extends true ? K : never]: GetRelationRegistryKey<TRegistry[TTableName]["rawSchema"][K], TRegistry> extends infer TargetKey ? TargetKey extends keyof TRegistry ? TRegistry[TTableName]["rawSchema"][K] extends {
|
|
448
448
|
config: {
|
|
449
449
|
sql: {
|
|
@@ -508,6 +508,7 @@ export type DeriveViewResult<TTableName extends keyof TRegistry, TSelection, TRe
|
|
|
508
508
|
schemas: {
|
|
509
509
|
sql: TRegistry[TTableName]["zodSchemas"]["sqlSchema"];
|
|
510
510
|
client: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientSchema">>;
|
|
511
|
+
clientChecked: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "clientCheckedSchema">>;
|
|
511
512
|
server: z.ZodObject<_DeriveViewShape<TTableName, TSelection, TRegistry, "serverSchema">>;
|
|
512
513
|
};
|
|
513
514
|
transforms: {
|
|
@@ -556,8 +557,8 @@ type RegistryShape = Record<string, {
|
|
|
556
557
|
rawSchema: any;
|
|
557
558
|
zodSchemas: {
|
|
558
559
|
sqlSchema: z.ZodObject<any>;
|
|
559
|
-
clientInputSchema: z.ZodObject<any>;
|
|
560
560
|
clientSchema: z.ZodObject<any>;
|
|
561
|
+
clientCheckedSchema: z.ZodObject<any>;
|
|
561
562
|
serverSchema: z.ZodObject<any>;
|
|
562
563
|
defaultValues: any;
|
|
563
564
|
stateType: any;
|
|
@@ -590,8 +591,8 @@ type CreateSchemaBoxReturn<S extends Record<string, SchemaWithPlaceholders>, R e
|
|
|
590
591
|
schemaKey: K;
|
|
591
592
|
schemas: {
|
|
592
593
|
sql: Resolved[K]["zodSchemas"]["sqlSchema"];
|
|
593
|
-
clientInput: Resolved[K]["zodSchemas"]["clientInputSchema"];
|
|
594
594
|
client: Resolved[K]["zodSchemas"]["clientSchema"];
|
|
595
|
+
clientChecked: Resolved[K]["zodSchemas"]["clientCheckedSchema"];
|
|
595
596
|
server: Resolved[K]["zodSchemas"]["serverSchema"];
|
|
596
597
|
};
|
|
597
598
|
transforms: {
|
|
@@ -636,7 +637,7 @@ type GetDbKey<K, Field> = Field extends Reference<infer TGetter> ? ReturnType<TG
|
|
|
636
637
|
};
|
|
637
638
|
};
|
|
638
639
|
} ? string extends F ? K : F : K;
|
|
639
|
-
type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "
|
|
640
|
+
type DeriveSchemaByKey<T, Key extends "zodSqlSchema" | "zodClientSchema" | "zodClientCheckedSchema" | "zodValidationSchema", Depth extends any[] = []> = Depth["length"] extends 10 ? any : {
|
|
640
641
|
[K in keyof T as K extends "_tableName" | typeof SchemaWrapperBrand | "__primaryKeySQL" | "primaryKeySQL" | "derive" | "__derives" | "refine" | "__refines" ? never : K extends keyof T ? T[K] extends {
|
|
641
642
|
config: {
|
|
642
643
|
sql: {
|