cogsbox-shape 0.5.156 → 0.5.158
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 +178 -128
- package/dist/schema.d.ts +5 -0
- package/dist/schema.js +10 -0
- package/package.json +57 -57
package/README.md
CHANGED
|
@@ -22,27 +22,29 @@ pnpm add cogsbox-shape
|
|
|
22
22
|
In full-stack applications, data flows through multiple layers:
|
|
23
23
|
|
|
24
24
|
- **Database** stores data in SQL types (integers, varchars, etc.)
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **Forms** need
|
|
25
|
+
- **Client** needs different types for UI work (booleans instead of 0/1, temp string IDs instead of auto-increment integers)
|
|
26
|
+
- **Validation** rules differ between client and server boundaries
|
|
27
|
+
- **Forms** need typed default values that match the client representation
|
|
28
28
|
|
|
29
|
-
Traditional approaches require defining these
|
|
29
|
+
Traditional approaches require defining these layers separately, leading to type mismatches and duplicated logic.
|
|
30
30
|
|
|
31
|
-
## The
|
|
31
|
+
## The Shape Flow
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Define a field by chaining methods. Each step is optional — use only what you need.
|
|
34
34
|
|
|
35
35
|
```
|
|
36
|
-
|
|
37
|
-
\
|
|
38
|
-
SQL ←→ Transform ←→ Client ←→ Server (Validation)
|
|
36
|
+
s.sql() → .initialState() → .client() → .server() → .transform()
|
|
39
37
|
```
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
| Method | Purpose |
|
|
40
|
+
| ---------------------------------- | -------------------------------------------------------------- |
|
|
41
|
+
| `s.sql({ type })` | Database column type. The starting point for every field. |
|
|
42
|
+
| `.initialState({ value, schema })` | Default value and type for new records created on the client. |
|
|
43
|
+
| `.client(fn)` | Client-side validation. Overrides the client type if needed. |
|
|
44
|
+
| `.server(fn)` | Server-side validation. Stricter rules before database writes. |
|
|
45
|
+
| `.transform({ toClient, toDb })` | Converts between database and client representations. |
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
### 1. SQL - Define Your Database Schema
|
|
47
|
+
### 1. SQL — Define Your Database Schema
|
|
46
48
|
|
|
47
49
|
Start with your database reality:
|
|
48
50
|
|
|
@@ -51,119 +53,192 @@ import { s, schema } from "cogsbox-shape";
|
|
|
51
53
|
|
|
52
54
|
const userSchema = schema({
|
|
53
55
|
_tableName: "users",
|
|
54
|
-
id: s.sql({ type: "int", pk: true }),
|
|
56
|
+
id: s.sql({ type: "int", pk: true }),
|
|
55
57
|
email: s.sql({ type: "varchar", length: 255 }),
|
|
56
58
|
createdAt: s.sql({ type: "datetime", default: "CURRENT_TIMESTAMP" }),
|
|
57
59
|
});
|
|
58
60
|
```
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
This generates a Zod schema matching your SQL types exactly.
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
### 2. Initial State — Defaults for New Records
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
When creating new records on the client, you often need different types than what the database stores. `.initialState()` sets the default value and optionally narrows or widens the client type.
|
|
65
67
|
|
|
66
68
|
```typescript
|
|
67
|
-
import { z } from "zod";
|
|
68
|
-
|
|
69
69
|
const userSchema = schema({
|
|
70
70
|
_tableName: "users",
|
|
71
|
-
// DB stores integers, but new records
|
|
71
|
+
// DB stores auto-increment integers, but new records need a temp string ID
|
|
72
72
|
id: s.sql({ type: "int", pk: true }).initialState({
|
|
73
73
|
value: () => crypto.randomUUID(),
|
|
74
74
|
schema: z.string(),
|
|
75
75
|
}),
|
|
76
|
-
//
|
|
76
|
+
// Client type becomes: string | number (union of SQL + initialState)
|
|
77
|
+
// Default value: a generated UUID string
|
|
77
78
|
});
|
|
78
79
|
```
|
|
79
80
|
|
|
80
|
-
|
|
81
|
+
If the type you pass to `.initialState()` matches the SQL type, no union is created:
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
```typescript
|
|
84
|
+
count: s.sql({ type: "int" }).initialState({ value: 0 }),
|
|
85
|
+
// Client type: number (no union, same type)
|
|
86
|
+
// Default value: 0
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 3. Client — Client-Side Validation
|
|
90
|
+
|
|
91
|
+
The client schema is automatically derived as a union of the SQL type (data fetched from the database) and the initial state type (data created on the client). `.client()` lets you override this to add client-side validation rules or declare a completely different type.
|
|
83
92
|
|
|
84
93
|
```typescript
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
// Without .client() — the type is inferred automatically
|
|
95
|
+
id: s.sql({ type: "int", pk: true }).initialState({
|
|
96
|
+
value: () => crypto.randomUUID(),
|
|
97
|
+
schema: z.string(),
|
|
98
|
+
}),
|
|
99
|
+
// Client type: string | number
|
|
100
|
+
// (string from initialState + number from SQL)
|
|
101
|
+
|
|
102
|
+
// With .client() — add validation rules
|
|
103
|
+
name: s
|
|
104
|
+
.sql({ type: "varchar" })
|
|
105
|
+
.client(({ sql }) => sql.min(2).max(100)),
|
|
106
|
+
// Client type: string (with min/max validation)
|
|
107
|
+
|
|
108
|
+
// With .client() — declare a different type entirely
|
|
109
|
+
// Pair with .transform() to convert between them
|
|
110
|
+
isActive: s
|
|
111
|
+
.sql({ type: "int" })
|
|
112
|
+
.client(() => z.boolean())
|
|
113
|
+
.transform({
|
|
114
|
+
toClient: (dbValue) => dbValue === 1,
|
|
115
|
+
toDb: (clientValue) => (clientValue ? 1 : 0),
|
|
90
116
|
}),
|
|
91
|
-
|
|
92
|
-
price: s
|
|
93
|
-
.sql({ type: "int" }) // Stored as cents in DB
|
|
94
|
-
.client(() => z.number().multipleOf(0.01)) // But dollars on client
|
|
95
|
-
.transform({
|
|
96
|
-
toClient: (cents) => cents / 100,
|
|
97
|
-
toDb: (dollars) => Math.round(dollars * 100),
|
|
98
|
-
}),
|
|
99
|
-
});
|
|
117
|
+
// Client type: boolean (DB stores 0/1, client works with true/false)
|
|
100
118
|
```
|
|
101
119
|
|
|
102
|
-
|
|
120
|
+
When `.client()` overrides the type without `.initialState()`, the default value is inferred from the client schema (e.g., `boolean` → `false`, `string` → `""`).
|
|
103
121
|
|
|
104
|
-
|
|
122
|
+
### 4. Server — Server-Side Validation
|
|
123
|
+
|
|
124
|
+
`.server()` adds validation rules that run at the server boundary before database writes. It builds on the client schema, adding stricter constraints.
|
|
105
125
|
|
|
106
126
|
```typescript
|
|
107
127
|
const userSchema = schema({
|
|
108
128
|
_tableName: "users",
|
|
109
129
|
email: s
|
|
110
130
|
.sql({ type: "varchar", length: 255 })
|
|
111
|
-
.server(({ sql }) => sql.email()
|
|
131
|
+
.server(({ sql }) => sql.email("Invalid email")),
|
|
112
132
|
|
|
113
|
-
age: s
|
|
133
|
+
age: s
|
|
134
|
+
.sql({ type: "int" })
|
|
135
|
+
.server(({ sql }) => sql.min(18, "Must be 18+").max(120)),
|
|
114
136
|
});
|
|
115
137
|
```
|
|
116
138
|
|
|
117
|
-
|
|
139
|
+
The callback receives the previous schema in the chain so you can refine it:
|
|
118
140
|
|
|
119
|
-
|
|
141
|
+
```typescript
|
|
142
|
+
name: s
|
|
143
|
+
.sql({ type: "varchar" })
|
|
144
|
+
.client(() => z.string().trim())
|
|
145
|
+
.server(({ client }) => client.min(2, "Too short")),
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 5. Transform — Convert Between Layers
|
|
149
|
+
|
|
150
|
+
`.transform()` defines bidirectional conversion functions. These run on the server when reading from or writing to the database.
|
|
120
151
|
|
|
121
152
|
```typescript
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
153
|
+
status: s
|
|
154
|
+
.sql({ type: "int" }) // DB: 0 or 1
|
|
155
|
+
.client(() => z.enum(["active", "inactive"])) // Client: string enum
|
|
156
|
+
.transform({
|
|
157
|
+
toClient: (dbValue) => dbValue === 1 ? "active" : "inactive",
|
|
158
|
+
toDb: (clientValue) => clientValue === "active" ? 1 : 0,
|
|
159
|
+
}),
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Transforms are optional — only needed when the client type differs from the SQL type.
|
|
163
|
+
|
|
164
|
+
## Using Schemas
|
|
165
|
+
|
|
166
|
+
### Single Schema with `createSchema`
|
|
167
|
+
|
|
168
|
+
For standalone schemas without relationships:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { s, schema, createSchema } from "cogsbox-shape";
|
|
172
|
+
|
|
173
|
+
const contactSchema = schema({
|
|
174
|
+
_tableName: "contacts",
|
|
175
|
+
id: s.sql({ type: "int", pk: true }).initialState({
|
|
176
|
+
value: () => `new_${crypto.randomUUID().slice(0, 8)}`,
|
|
177
|
+
schema: z.string(),
|
|
178
|
+
}),
|
|
179
|
+
name: s.sql({ type: "varchar" }).server(({ sql }) => sql.min(2)),
|
|
180
|
+
email: s.sql({ type: "varchar" }).server(({ sql }) => sql.email()),
|
|
181
|
+
isArchived: s
|
|
182
|
+
.sql({ type: "int" })
|
|
183
|
+
.client(() => z.boolean())
|
|
127
184
|
.transform({
|
|
128
|
-
toClient: (
|
|
129
|
-
toDb: (
|
|
185
|
+
toClient: (val) => val === 1,
|
|
186
|
+
toDb: (val) => (val ? 1 : 0),
|
|
130
187
|
}),
|
|
131
188
|
});
|
|
189
|
+
|
|
190
|
+
const {
|
|
191
|
+
clientSchema, // Zod schema for client-side validation
|
|
192
|
+
validationSchema, // Zod schema with .server() rules
|
|
193
|
+
sqlSchema, // Zod schema matching DB column types
|
|
194
|
+
defaultValues, // Typed defaults matching clientSchema
|
|
195
|
+
toClient, // DB row → client object
|
|
196
|
+
toDb, // Client object → DB row
|
|
197
|
+
} = createSchema(contactSchema);
|
|
198
|
+
|
|
199
|
+
// Use in a form
|
|
200
|
+
const [data, setData] = useState(defaultValues);
|
|
201
|
+
// { id: "new_a1b2c3d4", name: "", email: "", isArchived: false }
|
|
202
|
+
|
|
203
|
+
// Validate
|
|
204
|
+
const result = validationSchema.safeParse(data);
|
|
205
|
+
|
|
206
|
+
// Transform (on the server)
|
|
207
|
+
const dbRow = toDb(data); // { isArchived: 0, ... }
|
|
208
|
+
const clientObj = toClient(row); // { isArchived: true, ... }
|
|
132
209
|
```
|
|
133
210
|
|
|
134
211
|
## Relationships and Views
|
|
135
212
|
|
|
136
|
-
|
|
213
|
+
For schemas with relationships, use `createSchemaBox`.
|
|
137
214
|
|
|
138
215
|
### 1. Define Schemas with Placeholders
|
|
139
216
|
|
|
140
217
|
```typescript
|
|
141
218
|
import { s, schema, createSchemaBox } from "cogsbox-shape";
|
|
142
219
|
|
|
143
|
-
// Define schemas with relationship placeholders
|
|
144
220
|
const users = schema({
|
|
145
221
|
_tableName: "users",
|
|
146
222
|
id: s.sql({ type: "int", pk: true }),
|
|
147
223
|
name: s.sql({ type: "varchar" }),
|
|
148
|
-
posts: s.hasMany(), // Placeholder
|
|
224
|
+
posts: s.hasMany(), // Placeholder — resolved later
|
|
149
225
|
});
|
|
150
226
|
|
|
151
227
|
const posts = schema({
|
|
152
228
|
_tableName: "posts",
|
|
153
229
|
id: s.sql({ type: "int", pk: true }),
|
|
154
230
|
title: s.sql({ type: "varchar" }),
|
|
155
|
-
authorId: s.reference(() => users.id), // Foreign key
|
|
231
|
+
authorId: s.reference(() => users.id), // Foreign key
|
|
156
232
|
});
|
|
157
233
|
```
|
|
158
234
|
|
|
159
|
-
### 2. Create the Registry
|
|
235
|
+
### 2. Create the Registry
|
|
160
236
|
|
|
161
|
-
The `createSchemaBox` function
|
|
237
|
+
The `createSchemaBox` function resolves relationships and gives you a type-safe API:
|
|
162
238
|
|
|
163
239
|
```typescript
|
|
164
240
|
const box = createSchemaBox({ users, posts }, (s) => ({
|
|
165
241
|
users: {
|
|
166
|
-
// Resolve the 'posts' relation on the 'users' schema
|
|
167
242
|
posts: { fromKey: "id", toKey: s.posts.authorId },
|
|
168
243
|
},
|
|
169
244
|
}));
|
|
@@ -171,47 +246,37 @@ const box = createSchemaBox({ users, posts }, (s) => ({
|
|
|
171
246
|
|
|
172
247
|
### 3. Access Base Schemas
|
|
173
248
|
|
|
174
|
-
|
|
249
|
+
Base schemas **exclude relations** by default, preventing circular dependencies:
|
|
175
250
|
|
|
176
251
|
```typescript
|
|
177
|
-
|
|
178
|
-
const userSchemas = box.users.schemas;
|
|
252
|
+
const { schemas, defaults } = box.users;
|
|
179
253
|
|
|
180
|
-
|
|
181
|
-
type UserClient = z.infer<typeof userSchemas.client>;
|
|
254
|
+
type UserClient = z.infer<typeof schemas.client>;
|
|
182
255
|
// { id: number; name: string; }
|
|
256
|
+
// No 'posts' — relations are excluded from base schemas
|
|
183
257
|
```
|
|
184
258
|
|
|
185
259
|
### 4. Create Views to Include Relations
|
|
186
260
|
|
|
187
|
-
|
|
261
|
+
Explicitly select which relations to include:
|
|
188
262
|
|
|
189
263
|
```typescript
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
posts: true, // Select the 'posts' relation
|
|
264
|
+
const userWithPosts = box.users.createView({
|
|
265
|
+
posts: true,
|
|
193
266
|
});
|
|
194
267
|
|
|
195
|
-
|
|
196
|
-
type UserWithPosts = z.infer<typeof userWithPostsView.schemas.client>;
|
|
268
|
+
type UserWithPosts = z.infer<typeof userWithPosts.schemas.client>;
|
|
197
269
|
// {
|
|
198
270
|
// id: number;
|
|
199
271
|
// name: string;
|
|
200
|
-
// posts: {
|
|
201
|
-
// id: number;
|
|
202
|
-
// title: string;
|
|
203
|
-
// authorId: number;
|
|
204
|
-
// }[];
|
|
272
|
+
// posts: { id: number; title: string; authorId: number; }[]
|
|
205
273
|
// }
|
|
206
274
|
|
|
207
|
-
|
|
208
|
-
const defaults = userWithPostsView.defaults;
|
|
275
|
+
const defaults = userWithPosts.defaults;
|
|
209
276
|
// { id: 0, name: '', posts: [] }
|
|
210
277
|
```
|
|
211
278
|
|
|
212
|
-
##
|
|
213
|
-
|
|
214
|
-
Here's a complete example showing the power of the flow:
|
|
279
|
+
## Complete Example
|
|
215
280
|
|
|
216
281
|
```typescript
|
|
217
282
|
import { s, schema, createSchemaBox } from "cogsbox-shape";
|
|
@@ -223,40 +288,23 @@ const users = schema({
|
|
|
223
288
|
value: () => `user_${crypto.randomUUID()}`,
|
|
224
289
|
schema: z.string(),
|
|
225
290
|
}),
|
|
226
|
-
|
|
227
291
|
email: s
|
|
228
292
|
.sql({ type: "varchar", length: 255 })
|
|
229
293
|
.server(({ sql }) => sql.email()),
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
.
|
|
233
|
-
.client(
|
|
234
|
-
z.object({
|
|
235
|
-
preferences: z.object({
|
|
236
|
-
theme: z.enum(["light", "dark"]),
|
|
237
|
-
notifications: z.boolean(),
|
|
238
|
-
}),
|
|
239
|
-
}),
|
|
240
|
-
)
|
|
294
|
+
isActive: s
|
|
295
|
+
.sql({ type: "int" })
|
|
296
|
+
.client(() => z.boolean())
|
|
241
297
|
.transform({
|
|
242
|
-
toClient: (
|
|
243
|
-
toDb: (
|
|
298
|
+
toClient: (val) => val === 1,
|
|
299
|
+
toDb: (val) => (val ? 1 : 0),
|
|
244
300
|
}),
|
|
245
|
-
|
|
246
|
-
posts: s.hasMany({ count: 0 }), // Default to an empty array
|
|
301
|
+
posts: s.hasMany({ count: 0 }),
|
|
247
302
|
});
|
|
248
303
|
|
|
249
304
|
const posts = schema({
|
|
250
305
|
_tableName: "posts",
|
|
251
306
|
id: s.sql({ type: "int", pk: true }),
|
|
252
307
|
title: s.sql({ type: "varchar" }),
|
|
253
|
-
published: s
|
|
254
|
-
.sql({ type: "int" }) // 0 or 1 in DB
|
|
255
|
-
.client(() => z.boolean())
|
|
256
|
-
.transform({
|
|
257
|
-
toClient: (int) => Boolean(int),
|
|
258
|
-
toDb: (bool) => (bool ? 1 : 0),
|
|
259
|
-
}),
|
|
260
308
|
authorId: s.reference(() => users.id),
|
|
261
309
|
});
|
|
262
310
|
|
|
@@ -266,48 +314,50 @@ const box = createSchemaBox({ users, posts }, (s) => ({
|
|
|
266
314
|
},
|
|
267
315
|
}));
|
|
268
316
|
|
|
269
|
-
//
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
317
|
+
// Base schema (no relations)
|
|
318
|
+
const { schemas, defaults, transforms } = box.users;
|
|
319
|
+
|
|
320
|
+
// View with relations
|
|
321
|
+
const userView = box.users.createView({ posts: true });
|
|
322
|
+
const { client, server } = userView.schemas;
|
|
273
323
|
|
|
274
|
-
//
|
|
275
|
-
type
|
|
324
|
+
// Type inference
|
|
325
|
+
type User = z.infer<typeof client>;
|
|
276
326
|
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
const validated = server.parse(userInput);
|
|
327
|
+
// Validation
|
|
328
|
+
const result = server.safeParse(formData);
|
|
280
329
|
|
|
281
|
-
//
|
|
282
|
-
const
|
|
283
|
-
const
|
|
330
|
+
// Transformation (server-side)
|
|
331
|
+
const dbRow = transforms.toDb(validated);
|
|
332
|
+
const apiResponse = transforms.toClient(dbRow);
|
|
284
333
|
```
|
|
285
334
|
|
|
286
335
|
## API Reference
|
|
287
336
|
|
|
288
337
|
### Schema Definition
|
|
289
338
|
|
|
290
|
-
- `s.sql(config)
|
|
291
|
-
- `.initialState({ value, schema })
|
|
292
|
-
- `.client(schema | fn)
|
|
293
|
-
- `.server(schema | fn)
|
|
294
|
-
- `.transform(
|
|
339
|
+
- `s.sql(config)` — Define SQL column type. The starting point for every field.
|
|
340
|
+
- `.initialState({ value, schema })` — Set default value for new records. Optionally provide a Zod schema to widen or narrow the client type.
|
|
341
|
+
- `.client(schema | fn)` — Define the client-side Zod schema for validation. Use when the client type differs from SQL.
|
|
342
|
+
- `.server(schema | fn)` — Add server-side validation rules. Receives the previous schema in the chain for refinement.
|
|
343
|
+
- `.transform({ toClient, toDb })` — Define bidirectional conversion between SQL and client types. Runs on the server.
|
|
295
344
|
|
|
296
345
|
### Relationships
|
|
297
346
|
|
|
298
|
-
- `s.reference(getter)
|
|
299
|
-
- `s.hasMany(config)
|
|
300
|
-
- `s.hasOne(config)
|
|
301
|
-
- `s.manyToMany(config)
|
|
347
|
+
- `s.reference(getter)` — Create a foreign key reference to another schema's field.
|
|
348
|
+
- `s.hasMany(config)` — Declare a one-to-many relationship placeholder.
|
|
349
|
+
- `s.hasOne(config)` — Declare a one-to-one relationship placeholder.
|
|
350
|
+
- `s.manyToMany(config)` — Declare a many-to-many relationship placeholder.
|
|
302
351
|
|
|
303
352
|
### Schema Processing
|
|
304
353
|
|
|
305
|
-
- `schema(definition)
|
|
306
|
-
- `
|
|
307
|
-
-
|
|
308
|
-
- `.schemas
|
|
309
|
-
- `.defaults
|
|
310
|
-
- `.
|
|
354
|
+
- `schema(definition)` — Create a schema definition from field declarations.
|
|
355
|
+
- `createSchema(schema)` — Process a single schema. Returns `clientSchema`, `validationSchema`, `sqlSchema`, `defaultValues`, `toClient`, `toDb`.
|
|
356
|
+
- `createSchemaBox(schemas, resolver)` — Process multiple schemas with relationships. Returns a registry with:
|
|
357
|
+
- `.schemas` — Base Zod schemas (excludes relations).
|
|
358
|
+
- `.defaults` — Typed default values.
|
|
359
|
+
- `.transforms` — `toClient` and `toDb` functions.
|
|
360
|
+
- `.createView(selection)` — Create a view including selected relations.
|
|
311
361
|
|
|
312
362
|
## License
|
|
313
363
|
|
package/dist/schema.d.ts
CHANGED
|
@@ -453,6 +453,11 @@ type DeriveDefaults<T, Depth extends any[] = []> = Prettify<Depth["length"] exte
|
|
|
453
453
|
initialValue: infer D;
|
|
454
454
|
};
|
|
455
455
|
} ? D extends () => infer R ? R : D : never : T[K] extends {
|
|
456
|
+
config: {
|
|
457
|
+
transforms: any;
|
|
458
|
+
zodClientSchema: infer TClient extends z.ZodTypeAny;
|
|
459
|
+
};
|
|
460
|
+
} ? z.infer<TClient> : T[K] extends {
|
|
456
461
|
config: {
|
|
457
462
|
initialValue: infer D;
|
|
458
463
|
};
|
package/dist/schema.js
CHANGED
|
@@ -521,6 +521,11 @@ export function createSchema(schema, relations) {
|
|
|
521
521
|
: initialValueOrFn;
|
|
522
522
|
}
|
|
523
523
|
}
|
|
524
|
+
} // Apply transforms to default values so they match client schema
|
|
525
|
+
for (const key in fieldTransforms) {
|
|
526
|
+
if (key in defaultValues && defaultValues[key] !== undefined) {
|
|
527
|
+
defaultValues[key] = fieldTransforms[key].toClient(defaultValues[key]);
|
|
528
|
+
}
|
|
524
529
|
}
|
|
525
530
|
const generateDefaults = () => {
|
|
526
531
|
const freshDefaults = {};
|
|
@@ -530,6 +535,11 @@ export function createSchema(schema, relations) {
|
|
|
530
535
|
? generatorOrValue() // Call the function to get a fresh value
|
|
531
536
|
: generatorOrValue; // Use the static value
|
|
532
537
|
}
|
|
538
|
+
for (const key in fieldTransforms) {
|
|
539
|
+
if (key in freshDefaults && freshDefaults[key] !== undefined) {
|
|
540
|
+
freshDefaults[key] = fieldTransforms[key].toClient(freshDefaults[key]);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
533
543
|
return freshDefaults;
|
|
534
544
|
};
|
|
535
545
|
const toClient = (dbObject) => {
|
package/package.json
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
2
|
+
"name": "cogsbox-shape",
|
|
3
|
+
"version": "0.5.158",
|
|
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
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"repository": "github:cogsbox/cogsbox-shape",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": " tsc",
|
|
13
|
+
"lint": "eslint src --ext .ts",
|
|
14
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
15
|
+
"test": "vitest "
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"cogsbox-shape": "./dist/cli.js"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"typescript",
|
|
25
|
+
"orm",
|
|
26
|
+
"database",
|
|
27
|
+
"full-stack",
|
|
28
|
+
"type-safe",
|
|
29
|
+
"client-server",
|
|
30
|
+
"zod",
|
|
31
|
+
"validation",
|
|
32
|
+
"cogs",
|
|
33
|
+
"schema",
|
|
34
|
+
"types"
|
|
35
|
+
],
|
|
36
|
+
"author": "",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"commander": "^13.1.0",
|
|
40
|
+
"tsx": "^4.19.3",
|
|
41
|
+
"uuid": "^9.0.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^20.10.5",
|
|
45
|
+
"@types/uuid": "^9.0.7",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
|
47
|
+
"@typescript-eslint/parser": "^6.15.0",
|
|
48
|
+
"eslint": "^8.56.0",
|
|
49
|
+
"expect-type": "^1.2.1",
|
|
50
|
+
"prettier": "^3.1.1",
|
|
51
|
+
"typescript": "^5.3.3",
|
|
52
|
+
"vitest": "^3.2.0",
|
|
53
|
+
"zod": "^3.25.0 || ^4.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"zod": "^3.22.4 || ^4.0.0"
|
|
57
|
+
},
|
|
58
|
+
"type": "module"
|
|
59
59
|
}
|