mutano 3.0.0 → 3.0.2
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 +110 -734
- package/dist/constants.d.ts +6 -0
- package/dist/database/connection.d.ts +25 -0
- package/dist/database/prisma.d.ts +20 -0
- package/dist/generators/content-generator.d.ts +12 -0
- package/dist/generators/type-generator.d.ts +9 -0
- package/dist/main.d.ts +14 -99
- package/dist/main.js +140 -914
- package/dist/types/index.d.ts +107 -0
- package/dist/types/mappings.d.ts +91 -0
- package/dist/utils/filters.d.ts +23 -0
- package/dist/utils/magic-comments.d.ts +33 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,182 +1,25 @@
|
|
|
1
1
|
# Mutano
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Convert database schemas to TypeScript types, Zod schemas, or Kysely definitions.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- Generates Zod schemas, Typescript interfaces or Kysely type definitions for MySQL, PostgreSQL, SQLite, and Prisma schemas
|
|
8
|
-
- **NEW: Database Views Support** - Extract and generate types for database views (read-only)
|
|
9
|
-
- Supports camelCase conversion
|
|
10
|
-
- Handles nullable, default, auto-increment and enum fields
|
|
11
|
-
- Supports custom type overrides via configuration or database comments
|
|
12
|
-
- Intelligently handles field nullability based on operation type (table, insertable, updateable, selectable)
|
|
13
|
-
- All fields in updateable schemas are automatically made optional
|
|
14
|
-
- Views are treated as read-only entities (no insertable/updateable schemas generated)
|
|
5
|
+
- **Supports:** MySQL, PostgreSQL, SQLite, Prisma
|
|
6
|
+
- **Features:** Views, Magic Comments, Type Overrides, Multiple Outputs
|
|
15
7
|
|
|
16
8
|
## Installation
|
|
17
9
|
|
|
18
|
-
Install `mutano` with npm
|
|
19
|
-
|
|
20
10
|
```bash
|
|
21
11
|
npm install mutano
|
|
22
12
|
```
|
|
23
13
|
|
|
24
|
-
##
|
|
25
|
-
|
|
26
|
-
Create user table:
|
|
27
|
-
|
|
28
|
-
```sql
|
|
29
|
-
CREATE TABLE `user` (
|
|
30
|
-
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
|
31
|
-
`name` varchar(255) NOT NULL COMMENT '@zod(z.string().min(10).max(255))', -- this will override the Zod type
|
|
32
|
-
`username` varchar(255) NOT NULL,
|
|
33
|
-
`password` varchar(255) NOT NULL,
|
|
34
|
-
`profile_picture` varchar(255) DEFAULT NULL,
|
|
35
|
-
`metadata` json NOT NULL COMMENT '@ts(Record<string, unknown>) @kysely(Record<string, string>)', -- this will override the TypeScript and Kysely type
|
|
36
|
-
`role` enum('admin','user') NOT NULL,
|
|
37
|
-
PRIMARY KEY (`id`)
|
|
38
|
-
);
|
|
39
|
-
```
|
|
40
|
-
Use the mutano API:
|
|
41
|
-
|
|
42
|
-
### MySQL Example with Zod Schemas
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
import { generate } from 'mutano'
|
|
46
|
-
|
|
47
|
-
await generate({
|
|
48
|
-
origin: {
|
|
49
|
-
type: 'mysql',
|
|
50
|
-
host: '127.0.0.1',
|
|
51
|
-
port: 3306,
|
|
52
|
-
user: 'root',
|
|
53
|
-
password: 'secret',
|
|
54
|
-
database: 'myapp',
|
|
55
|
-
overrideTypes: {
|
|
56
|
-
json: 'z.record(z.string())'
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
destinations: [{
|
|
60
|
-
type: 'zod',
|
|
61
|
-
useDateType: true,
|
|
62
|
-
useTrim: false,
|
|
63
|
-
nullish: false, // When true, nullable fields use nullish() instead of nullable()
|
|
64
|
-
folder: './generated',
|
|
65
|
-
suffix: 'schema'
|
|
66
|
-
}]
|
|
67
|
-
})
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### MySQL Example with TypeScript Type Aliases (Instead of Interfaces)
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
import { generate } from 'mutano'
|
|
74
|
-
|
|
75
|
-
await generate({
|
|
76
|
-
origin: {
|
|
77
|
-
type: 'mysql',
|
|
78
|
-
host: '127.0.0.1',
|
|
79
|
-
port: 3306,
|
|
80
|
-
user: 'root',
|
|
81
|
-
password: 'secret',
|
|
82
|
-
database: 'myapp',
|
|
83
|
-
overrideTypes: {
|
|
84
|
-
json: 'z.record(z.string())'
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
destinations: [{
|
|
88
|
-
type: 'ts',
|
|
89
|
-
modelType: 'type', // Generate TypeScript type aliases instead of interfaces
|
|
90
|
-
folder: './types',
|
|
91
|
-
suffix: 'types'
|
|
92
|
-
}]
|
|
93
|
-
})
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### MySQL Example with Custom Header for TypeScript
|
|
97
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
import { generate } from 'mutano'
|
|
100
|
-
|
|
101
|
-
await generate({
|
|
102
|
-
origin: {
|
|
103
|
-
type: 'mysql',
|
|
104
|
-
host: '127.0.0.1',
|
|
105
|
-
port: 3306,
|
|
106
|
-
user: 'root',
|
|
107
|
-
password: 'secret',
|
|
108
|
-
database: 'myapp',
|
|
109
|
-
overrideTypes: {
|
|
110
|
-
json: 'z.record(z.string())'
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
destinations: [{
|
|
114
|
-
type: 'ts',
|
|
115
|
-
header: "import type { CustomType } from './types';\nimport type { BaseModel } from './models';"
|
|
116
|
-
}]
|
|
117
|
-
})
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### MySQL Example with Custom Header for Zod
|
|
121
|
-
|
|
122
|
-
```typescript
|
|
123
|
-
import { generate } from 'mutano'
|
|
124
|
-
|
|
125
|
-
await generate({
|
|
126
|
-
origin: {
|
|
127
|
-
type: 'mysql',
|
|
128
|
-
host: '127.0.0.1',
|
|
129
|
-
port: 3306,
|
|
130
|
-
user: 'root',
|
|
131
|
-
password: 'secret',
|
|
132
|
-
database: 'myapp',
|
|
133
|
-
overrideTypes: {
|
|
134
|
-
json: 'z.record(z.string())'
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
destinations: [{
|
|
138
|
-
type: 'zod',
|
|
139
|
-
header: "import { z } from 'zod';\nimport { CustomValidator } from './validators';"
|
|
140
|
-
}]
|
|
141
|
-
})
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### MySQL Example with Kysely Type Definitions (Custom Schema Name)
|
|
14
|
+
## Quick Start
|
|
145
15
|
|
|
146
16
|
```typescript
|
|
147
17
|
import { generate } from 'mutano'
|
|
148
18
|
|
|
19
|
+
// Basic usage
|
|
149
20
|
await generate({
|
|
150
21
|
origin: {
|
|
151
|
-
type: 'mysql',
|
|
152
|
-
host: '127.0.0.1',
|
|
153
|
-
port: 3306,
|
|
154
|
-
user: 'root',
|
|
155
|
-
password: 'secret',
|
|
156
|
-
database: 'myapp',
|
|
157
|
-
overrideTypes: {
|
|
158
|
-
json: 'z.record(z.string())'
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
destinations: [{
|
|
162
|
-
type: 'kysely',
|
|
163
|
-
schemaName: 'Database', // Default is 'DB'
|
|
164
|
-
header: "import { Generated, ColumnType } from 'kysely';\nimport { CustomTypes } from './types';",
|
|
165
|
-
folder: './db/types',
|
|
166
|
-
suffix: 'db'
|
|
167
|
-
}]
|
|
168
|
-
})
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### Example with Dry Run Option
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
import { generate } from 'mutano'
|
|
175
|
-
|
|
176
|
-
// Generate without writing to disk
|
|
177
|
-
const output = await generate({
|
|
178
|
-
origin: {
|
|
179
|
-
type: 'mysql',
|
|
22
|
+
type: 'mysql', // or 'postgres', 'sqlite', 'prisma'
|
|
180
23
|
host: '127.0.0.1',
|
|
181
24
|
port: 3306,
|
|
182
25
|
user: 'root',
|
|
@@ -184,656 +27,189 @@ const output = await generate({
|
|
|
184
27
|
database: 'myapp'
|
|
185
28
|
},
|
|
186
29
|
destinations: [{
|
|
187
|
-
type: 'zod'
|
|
188
|
-
|
|
189
|
-
dryRun: true // Return content and don't write to files
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
// Output is an object where keys are filenames and values are file content
|
|
193
|
-
console.log(Object.keys(output)) // ['user.ts', 'product.ts', ...]
|
|
194
|
-
|
|
195
|
-
// You can access the content for a specific file
|
|
196
|
-
console.log(output['user.ts'])
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### PostgreSQL Example
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
import { generate } from 'mutano'
|
|
203
|
-
|
|
204
|
-
await generate({
|
|
205
|
-
origin: {
|
|
206
|
-
type: 'postgres',
|
|
207
|
-
host: '127.0.0.1',
|
|
208
|
-
port: 5432,
|
|
209
|
-
user: 'postgres',
|
|
210
|
-
password: 'secret',
|
|
211
|
-
database: 'myapp',
|
|
212
|
-
schema: 'public', // optional, defaults to 'public'
|
|
213
|
-
overrideTypes: {
|
|
214
|
-
jsonb: 'z.record(z.string())'
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
destinations: [{
|
|
218
|
-
type: 'zod',
|
|
219
|
-
useDateType: true
|
|
30
|
+
type: 'zod', // or 'ts', 'kysely'
|
|
31
|
+
folder: './generated'
|
|
220
32
|
}]
|
|
221
33
|
})
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### SQLite Example
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
import { generate } from 'mutano'
|
|
228
|
-
|
|
229
|
-
await generate({
|
|
230
|
-
origin: {
|
|
231
|
-
type: 'sqlite',
|
|
232
|
-
path: './myapp.db',
|
|
233
|
-
overrideTypes: {
|
|
234
|
-
json: 'z.record(z.string())'
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
destinations: [{
|
|
238
|
-
type: 'ts'
|
|
239
|
-
}]
|
|
240
|
-
})
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### Example with Multiple Destinations
|
|
244
|
-
|
|
245
|
-
```typescript
|
|
246
|
-
import { generate } from 'mutano'
|
|
247
34
|
|
|
35
|
+
// Multiple outputs
|
|
248
36
|
await generate({
|
|
249
|
-
origin: {
|
|
250
|
-
type: 'mysql',
|
|
251
|
-
host: '127.0.0.1',
|
|
252
|
-
port: 3306,
|
|
253
|
-
user: 'root',
|
|
254
|
-
password: 'secret',
|
|
255
|
-
database: 'myapp',
|
|
256
|
-
overrideTypes: {
|
|
257
|
-
json: 'z.record(z.string())'
|
|
258
|
-
}
|
|
259
|
-
},
|
|
37
|
+
origin: { /* ... */ },
|
|
260
38
|
destinations: [
|
|
261
|
-
{
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
folder: './generated/zod',
|
|
265
|
-
suffix: 'schema'
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
type: 'ts',
|
|
269
|
-
folder: './generated/types',
|
|
270
|
-
suffix: 'type'
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
type: 'kysely',
|
|
274
|
-
folder: './generated/kysely',
|
|
275
|
-
suffix: 'db'
|
|
276
|
-
}
|
|
39
|
+
{ type: 'zod', folder: './zod' },
|
|
40
|
+
{ type: 'ts', folder: './types' },
|
|
41
|
+
{ type: 'kysely', outFile: './db.ts' }
|
|
277
42
|
]
|
|
278
43
|
})
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
This will generate all three types of output files for each table in your database, placing them in separate folders with appropriate suffixes.
|
|
282
|
-
|
|
283
|
-
### Database Views Example
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
import { generate } from 'mutano'
|
|
287
44
|
|
|
45
|
+
// With views support
|
|
288
46
|
await generate({
|
|
289
|
-
origin: {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
password: 'secret',
|
|
295
|
-
database: 'myapp'
|
|
296
|
-
},
|
|
297
|
-
destinations: [{
|
|
298
|
-
type: 'zod',
|
|
299
|
-
folder: './generated/schemas',
|
|
300
|
-
suffix: 'schema'
|
|
301
|
-
}],
|
|
302
|
-
includeViews: true, // Enable views processing
|
|
303
|
-
views: ['user_profile_view', 'order_summary_view'], // Optional: specify which views to include
|
|
304
|
-
ignoreViews: ['temp_view'] // Optional: specify which views to ignore
|
|
47
|
+
origin: { /* ... */ },
|
|
48
|
+
destinations: [{ type: 'zod' }],
|
|
49
|
+
includeViews: true,
|
|
50
|
+
views: ['user_profile_view'], // optional filter
|
|
51
|
+
ignoreViews: ['temp_view'] // optional exclude
|
|
305
52
|
})
|
|
306
53
|
```
|
|
307
54
|
|
|
308
|
-
|
|
309
|
-
- **Read-only**: Views generate only selectable schemas (no insertable/updateable)
|
|
310
|
-
- **All database types**: Supports MySQL, PostgreSQL, SQLite, and Prisma views
|
|
311
|
-
- **Filtering**: Use `views` and `ignoreViews` options to control which views are processed
|
|
312
|
-
- **Type safety**: Full TypeScript/Zod/Kysely type generation for view columns
|
|
313
|
-
- **Prisma integration**: Automatically detects `view` blocks in Prisma schema files
|
|
314
|
-
|
|
315
|
-
### Prisma Views Integration
|
|
316
|
-
|
|
317
|
-
Mutano automatically detects and processes `view` blocks in your Prisma schema:
|
|
318
|
-
|
|
319
|
-
```prisma
|
|
320
|
-
// schema.prisma
|
|
321
|
-
generator client {
|
|
322
|
-
provider = "prisma-client-js"
|
|
323
|
-
previewFeatures = ["views"]
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
model User {
|
|
327
|
-
id Int @id @default(autoincrement())
|
|
328
|
-
email String @unique
|
|
329
|
-
name String?
|
|
330
|
-
profile Profile?
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
model Profile {
|
|
334
|
-
id Int @id @default(autoincrement())
|
|
335
|
-
bio String
|
|
336
|
-
user User @relation(fields: [userId], references: [id])
|
|
337
|
-
userId Int @unique
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// This view will be automatically processed by Mutano
|
|
341
|
-
view UserInfo {
|
|
342
|
-
id Int
|
|
343
|
-
email String
|
|
344
|
-
name String?
|
|
345
|
-
bio String?
|
|
346
|
-
}
|
|
347
|
-
```
|
|
55
|
+
## Output Examples
|
|
348
56
|
|
|
57
|
+
**Zod Schema:**
|
|
349
58
|
```typescript
|
|
350
|
-
// Generate types from Prisma schema with views
|
|
351
|
-
await generate({
|
|
352
|
-
origin: {
|
|
353
|
-
type: 'prisma',
|
|
354
|
-
path: './schema.prisma'
|
|
355
|
-
},
|
|
356
|
-
destinations: [{
|
|
357
|
-
type: 'zod',
|
|
358
|
-
useDateType: true
|
|
359
|
-
}],
|
|
360
|
-
includeViews: true
|
|
361
|
-
})
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
The generator will create `user.type.ts`, `user.schema.ts`, and `user.db.ts` files with the following contents:
|
|
365
|
-
|
|
366
|
-
### Database View Output Examples
|
|
367
|
-
|
|
368
|
-
For a database view like:
|
|
369
|
-
```sql
|
|
370
|
-
CREATE VIEW user_profile_view AS
|
|
371
|
-
SELECT
|
|
372
|
-
u.id,
|
|
373
|
-
u.name,
|
|
374
|
-
u.email,
|
|
375
|
-
p.bio,
|
|
376
|
-
p.avatar_url
|
|
377
|
-
FROM users u
|
|
378
|
-
LEFT JOIN profiles p ON u.id = p.user_id;
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### Zod Schema Output Example with Custom Header
|
|
382
|
-
|
|
383
|
-
```typescript
|
|
384
|
-
import { z } from 'zod';
|
|
385
|
-
import { CustomValidator } from './validators';
|
|
386
|
-
|
|
387
59
|
export const user = z.object({
|
|
388
60
|
id: z.number().nonnegative(),
|
|
389
|
-
name: z.string().min(
|
|
390
|
-
|
|
391
|
-
password: z.string(),
|
|
392
|
-
profile_picture: z.string().nullable(),
|
|
61
|
+
name: z.string().min(1),
|
|
62
|
+
email: z.string().email(),
|
|
393
63
|
role: z.enum(['admin', 'user']),
|
|
394
64
|
})
|
|
395
65
|
|
|
396
66
|
export const insertable_user = z.object({
|
|
397
|
-
name: z.string().min(
|
|
398
|
-
|
|
399
|
-
password: z.string(),
|
|
400
|
-
profile_picture: z.string().nullable(),
|
|
401
|
-
role: z.enum(['admin', 'user']),
|
|
402
|
-
})
|
|
403
|
-
|
|
404
|
-
export const updateable_user = z.object({
|
|
405
|
-
name: z.string().min(10).max(255).optional(),
|
|
406
|
-
username: z.string().optional(),
|
|
407
|
-
password: z.string().optional(),
|
|
408
|
-
profile_picture: z.string().nullable().optional(),
|
|
409
|
-
role: z.enum(['admin', 'user']).optional(),
|
|
410
|
-
})
|
|
411
|
-
|
|
412
|
-
export const selectable_user = z.object({
|
|
413
|
-
id: z.number().nonnegative(),
|
|
414
|
-
name: z.string(),
|
|
415
|
-
username: z.string(),
|
|
416
|
-
password: z.string(),
|
|
417
|
-
profile_picture: z.string().nullable(),
|
|
67
|
+
name: z.string().min(1),
|
|
68
|
+
email: z.string().email(),
|
|
418
69
|
role: z.enum(['admin', 'user']),
|
|
419
70
|
})
|
|
420
71
|
|
|
421
|
-
export type
|
|
422
|
-
export type InsertableUserType = z.infer<typeof insertable_user>
|
|
423
|
-
export type UpdateableUserType = z.infer<typeof updateable_user>
|
|
424
|
-
export type SelectableUserType = z.infer<typeof selectable_user>
|
|
72
|
+
export type UserType = z.infer<typeof user>
|
|
425
73
|
```
|
|
426
74
|
|
|
427
|
-
|
|
428
|
-
|
|
75
|
+
**TypeScript Interface:**
|
|
429
76
|
```typescript
|
|
430
|
-
import { CustomType } from './types';
|
|
431
|
-
import { BaseModel } from './models';
|
|
432
|
-
|
|
433
|
-
// TypeScript interfaces for user
|
|
434
|
-
|
|
435
77
|
export interface User {
|
|
436
78
|
id: number;
|
|
437
79
|
name: string;
|
|
438
|
-
|
|
439
|
-
password: string;
|
|
440
|
-
profile_picture: string | null;
|
|
441
|
-
metadata: Record<string, unknown>; // Custom type from @ts comment
|
|
80
|
+
email: string;
|
|
442
81
|
role: 'admin' | 'user';
|
|
443
82
|
}
|
|
444
83
|
|
|
445
84
|
export interface InsertableUser {
|
|
446
|
-
name: string | null; // Optional because it has a default value
|
|
447
|
-
username: string;
|
|
448
|
-
password: string;
|
|
449
|
-
profile_picture: string | null;
|
|
450
|
-
metadata: Record<string, unknown>; // Custom type from @ts comment
|
|
451
|
-
role: 'admin' | 'user';
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
export interface UpdateableUser {
|
|
455
|
-
name: string | null; // Optional for updates
|
|
456
|
-
username: string | null; // Optional for updates
|
|
457
|
-
password: string | null; // Optional for updates
|
|
458
|
-
profile_picture: string | null;
|
|
459
|
-
metadata: Record<string, unknown> | null; // Custom type from @ts comment, optional for updates
|
|
460
|
-
role: 'admin' | 'user' | null; // Optional for updates
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
export interface SelectableUser {
|
|
464
|
-
id: number;
|
|
465
85
|
name: string;
|
|
466
|
-
|
|
467
|
-
password: string;
|
|
468
|
-
profile_picture: string | null;
|
|
469
|
-
metadata: Record<string, unknown>; // Custom type from @ts comment
|
|
86
|
+
email: string;
|
|
470
87
|
role: 'admin' | 'user';
|
|
471
88
|
}
|
|
472
89
|
```
|
|
473
90
|
|
|
474
|
-
|
|
475
|
-
|
|
91
|
+
**Kysely Types:**
|
|
476
92
|
```typescript
|
|
477
|
-
import { Generated, ColumnType, Selectable, Insertable, Updateable } from 'kysely';
|
|
478
|
-
|
|
479
|
-
// JSON type definitions
|
|
480
|
-
export type Json = ColumnType<JsonValue, string, string>;
|
|
481
|
-
|
|
482
|
-
export type JsonArray = JsonValue[];
|
|
483
|
-
|
|
484
|
-
export type JsonObject = {
|
|
485
|
-
[x: string]: JsonValue | undefined;
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
export type JsonPrimitive = boolean | number | string | null;
|
|
489
|
-
|
|
490
|
-
export type JsonValue = JsonArray | JsonObject | JsonPrimitive;
|
|
491
|
-
|
|
492
|
-
// Kysely type definitions for user
|
|
493
|
-
|
|
494
|
-
// This interface defines the structure of the 'user' table
|
|
495
93
|
export interface UserTable {
|
|
496
94
|
id: Generated<number>;
|
|
497
95
|
name: string;
|
|
498
|
-
|
|
499
|
-
password: string;
|
|
500
|
-
profile_picture: string | null;
|
|
501
|
-
metadata: Record<string, unknown>; // Custom type from @kysely comment
|
|
96
|
+
email: string;
|
|
502
97
|
role: 'admin' | 'user';
|
|
503
98
|
}
|
|
504
99
|
|
|
505
|
-
// Define the database interface
|
|
506
|
-
export interface DB {
|
|
507
|
-
user: UserTable;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// Use these types for inserting, selecting and updating the table
|
|
511
100
|
export type User = Selectable<UserTable>;
|
|
512
101
|
export type NewUser = Insertable<UserTable>;
|
|
513
102
|
export type UserUpdate = Updateable<UserTable>;
|
|
514
103
|
```
|
|
515
104
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
#### Zod Schema for Views (Read-only)
|
|
519
|
-
|
|
520
|
-
```typescript
|
|
521
|
-
import { z } from 'zod';
|
|
522
|
-
|
|
523
|
-
// View schema (read-only)
|
|
524
|
-
export const user_profile_view = z.object({
|
|
525
|
-
id: z.number().nonnegative(),
|
|
526
|
-
name: z.string(),
|
|
527
|
-
email: z.string(),
|
|
528
|
-
bio: z.string().nullable(),
|
|
529
|
-
avatar_url: z.string().nullable(),
|
|
530
|
-
})
|
|
531
|
-
|
|
532
|
-
export type UserProfileViewType = z.infer<typeof user_profile_view>
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
#### TypeScript Interface for Views (Read-only)
|
|
536
|
-
|
|
537
|
-
```typescript
|
|
538
|
-
// TypeScript interface for user_profile_view (view - read-only)
|
|
539
|
-
export interface UserProfileView {
|
|
540
|
-
id: number;
|
|
541
|
-
name: string;
|
|
542
|
-
email: string;
|
|
543
|
-
bio: string | null;
|
|
544
|
-
avatar_url: string | null;
|
|
545
|
-
}
|
|
546
|
-
```
|
|
547
|
-
|
|
548
|
-
#### Kysely Type Definitions for Views (Read-only)
|
|
105
|
+
## Configuration
|
|
549
106
|
|
|
107
|
+
### Origin Options
|
|
550
108
|
```typescript
|
|
551
|
-
//
|
|
552
|
-
|
|
553
|
-
// This interface defines the structure of the 'user_profile_view' view (read-only)
|
|
554
|
-
export interface UserProfileView {
|
|
555
|
-
id: number;
|
|
556
|
-
name: string;
|
|
557
|
-
email: string;
|
|
558
|
-
bio: string | null;
|
|
559
|
-
avatar_url: string | null;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Helper types for user_profile_view (view - read-only)
|
|
563
|
-
export type SelectableUserProfileView = Selectable<UserProfileView>;
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
## Config
|
|
567
|
-
|
|
568
|
-
```json
|
|
569
|
-
{
|
|
570
|
-
"origin": {
|
|
571
|
-
"type": "mysql",
|
|
572
|
-
"host": "127.0.0.1",
|
|
573
|
-
"port": 3306,
|
|
574
|
-
"user": "root",
|
|
575
|
-
"password": "secret",
|
|
576
|
-
"database": "myapp",
|
|
577
|
-
"overrideTypes": {
|
|
578
|
-
"json": "z.record(z.string())"
|
|
579
|
-
},
|
|
580
|
-
"ssl": {
|
|
581
|
-
"ca": "path/to/ca.pem",
|
|
582
|
-
"cert": "path/to/cert.pem",
|
|
583
|
-
"key": "path/to/key.pem"
|
|
584
|
-
},
|
|
585
|
-
} | {
|
|
586
|
-
"type": "postgres",
|
|
587
|
-
"host": "127.0.0.1",
|
|
588
|
-
"port": 5432,
|
|
589
|
-
"user": "postgres",
|
|
590
|
-
"password": "secret",
|
|
591
|
-
"database": "myapp",
|
|
592
|
-
"schema": "public",
|
|
593
|
-
"overrideTypes": {
|
|
594
|
-
"jsonb": "z.record(z.string())"
|
|
595
|
-
},
|
|
596
|
-
"ssl": {
|
|
597
|
-
"ca": "path/to/ca.pem",
|
|
598
|
-
"cert": "path/to/cert.pem",
|
|
599
|
-
"key": "path/to/key.pem"
|
|
600
|
-
},
|
|
601
|
-
} | {
|
|
602
|
-
"type": "sqlite",
|
|
603
|
-
"path": "path/to/database.db",
|
|
604
|
-
"overrideTypes": {
|
|
605
|
-
"json": "z.record(z.string())"
|
|
606
|
-
}
|
|
607
|
-
} | {
|
|
608
|
-
"type": "prisma",
|
|
609
|
-
"path": "path/to/schema.prisma",
|
|
610
|
-
"overrideTypes": {
|
|
611
|
-
"Json": "z.record(z.string())"
|
|
612
|
-
}
|
|
613
|
-
},
|
|
614
|
-
"destinations": [
|
|
615
|
-
{
|
|
616
|
-
"type": "zod",
|
|
617
|
-
"useDateType": true,
|
|
618
|
-
"useTrim": false,
|
|
619
|
-
"nullish": false, // When true, nullable fields use nullish() instead of nullable()
|
|
620
|
-
"requiredString": false, // When true, adds min(1) validation to non-nullable string fields
|
|
621
|
-
"header": "import { z } from 'zod';\nimport { CustomValidator } from './validators';",
|
|
622
|
-
"folder": "@zod",
|
|
623
|
-
"suffix": "table"
|
|
624
|
-
},
|
|
625
|
-
{
|
|
626
|
-
"type": "ts",
|
|
627
|
-
"enumType": "union",
|
|
628
|
-
"modelType": "interface",
|
|
629
|
-
"header": "import { CustomType } from './types';\nimport { BaseModel } from './models';",
|
|
630
|
-
"folder": "types",
|
|
631
|
-
"suffix": "type"
|
|
632
|
-
},
|
|
633
|
-
{
|
|
634
|
-
"type": "kysely",
|
|
635
|
-
"schemaName": "Database",
|
|
636
|
-
"header": "import { Generated, ColumnType } from 'kysely';\nimport { CustomTypes } from './types';",
|
|
637
|
-
"outFile": "db.ts"
|
|
638
|
-
}
|
|
639
|
-
],
|
|
640
|
-
"tables": ["user", "log"],
|
|
641
|
-
"views": ["user_profile_view", "order_summary"],
|
|
642
|
-
"ignore": ["log", "/^temp/"],
|
|
643
|
-
"ignoreViews": ["temp_view", "/^debug_/"],
|
|
644
|
-
"includeViews": true,
|
|
645
|
-
"camelCase": false,
|
|
646
|
-
"silent": false,
|
|
647
|
-
"dryRun": false,
|
|
648
|
-
"magicComments": true
|
|
649
|
-
}
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
| Option | Description |
|
|
653
|
-
| ------ | ----------- |
|
|
654
|
-
| destinations | An array of destination configurations to generate multiple output formats from a single origin |
|
|
655
|
-
| destinations[].type | The type of output to generate: "zod", "ts", or "kysely" |
|
|
656
|
-
| destinations[].useDateType | (Zod only) Use a specialized Zod type for date-like fields instead of string |
|
|
657
|
-
| destinations[].useTrim | (Zod only) Use `z.string().trim()` instead of `z.string()` |
|
|
658
|
-
| destinations[].nullish | (Zod only) Use `nullish()` instead of `nullable()` for nullable fields. In updateable schemas, fields that were already nullable will become nullish |
|
|
659
|
-
| destinations[].version | (Zod only) Zod version to use. Defaults to 3. Set to 4 to use Zod v4 |
|
|
660
|
-
| destinations[].requiredString | (Zod only) Add `min(1)` for non-nullable string fields |
|
|
661
|
-
| destinations[].enumType | (TypeScript only) How to represent enum types: "union" (default) or "enum" |
|
|
662
|
-
| destinations[].modelType | (TypeScript only) How to represent models: "interface" (default) or "type" |
|
|
663
|
-
| destinations[].schemaName | (Kysely only) Name of the database interface (default: "DB") |
|
|
664
|
-
| destinations[].header | Custom header to include at the beginning of generated files (e.g., custom imports) |
|
|
665
|
-
| destinations[].folder | Specify the output directory for the generated files |
|
|
666
|
-
| destinations[].suffix | Suffix to the name of a generated file (eg: `user.table.ts`) |
|
|
667
|
-
| destinations[].outFile | (Kysely only) Specify the output file for the generated content. All tables will be written to this file |
|
|
668
|
-
| tables | Filter the tables to include only those specified |
|
|
669
|
-
| views | Filter the views to include only those specified (requires `includeViews: true`) |
|
|
670
|
-
| ignore | Filter the tables to exclude those specified. If a table name begins and ends with "/", it will be processed as a regular expression |
|
|
671
|
-
| ignoreViews | Filter the views to exclude those specified. If a view name begins and ends with "/", it will be processed as a regular expression |
|
|
672
|
-
| includeViews | When true, database views will be processed and included in the output. Views are read-only (no insertable/updateable schemas) |
|
|
673
|
-
| camelCase | Convert all table names and their properties to camelcase. (eg: `profile_picture` becomes `profilePicture`) |
|
|
674
|
-
| silent | Don't log anything to the console |
|
|
675
|
-
| dryRun | When true, doesn't write files to disk but returns an object with filenames as keys and generated content as values |
|
|
676
|
-
| magicComments | Use @zod and @ts comments to override types (unsupported by SQLite) |
|
|
677
|
-
|
|
678
|
-
## overrideTypes
|
|
679
|
-
|
|
680
|
-
You can override the default type for a specific column type. This is specific to each database type and is placed inside the origin object. Each database type has its own set of valid types that can be overridden:
|
|
681
|
-
|
|
682
|
-
### MySQL overrideTypes
|
|
683
|
-
|
|
684
|
-
```json
|
|
109
|
+
// MySQL/PostgreSQL
|
|
685
110
|
{
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
}
|
|
699
|
-
```
|
|
700
|
-
|
|
701
|
-
### PostgreSQL overrideTypes
|
|
702
|
-
|
|
703
|
-
```json
|
|
111
|
+
type: 'mysql' | 'postgres',
|
|
112
|
+
host: string,
|
|
113
|
+
port: number,
|
|
114
|
+
user: string,
|
|
115
|
+
password: string,
|
|
116
|
+
database: string,
|
|
117
|
+
schema?: string, // PostgreSQL only
|
|
118
|
+
ssl?: { ca, cert, key },
|
|
119
|
+
overrideTypes?: Record<string, string>
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// SQLite
|
|
704
123
|
{
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
"port": 5432,
|
|
709
|
-
"user": "postgres",
|
|
710
|
-
"password": "secret",
|
|
711
|
-
"database": "myapp",
|
|
712
|
-
"schema": "public",
|
|
713
|
-
"overrideTypes": {
|
|
714
|
-
"jsonb": "z.record(z.string())",
|
|
715
|
-
"uuid": "z.string().uuid()"
|
|
716
|
-
}
|
|
717
|
-
}
|
|
124
|
+
type: 'sqlite',
|
|
125
|
+
path: string,
|
|
126
|
+
overrideTypes?: Record<string, string>
|
|
718
127
|
}
|
|
719
|
-
```
|
|
720
128
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
```json
|
|
129
|
+
// Prisma
|
|
724
130
|
{
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
"overrideTypes": {
|
|
729
|
-
"json": "z.record(z.string())",
|
|
730
|
-
"text": "z.string().max(1000)"
|
|
731
|
-
}
|
|
732
|
-
}
|
|
131
|
+
type: 'prisma',
|
|
132
|
+
path: string,
|
|
133
|
+
overrideTypes?: Record<string, string>
|
|
733
134
|
}
|
|
734
135
|
```
|
|
735
136
|
|
|
736
|
-
###
|
|
737
|
-
|
|
738
|
-
```json
|
|
137
|
+
### Destination Options
|
|
138
|
+
```typescript
|
|
739
139
|
{
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
"String": "z.string().min(1)"
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
```
|
|
140
|
+
type: 'zod' | 'ts' | 'kysely',
|
|
141
|
+
folder?: string,
|
|
142
|
+
suffix?: string,
|
|
143
|
+
outFile?: string, // Kysely only
|
|
144
|
+
header?: string, // Custom imports
|
|
750
145
|
|
|
751
|
-
|
|
146
|
+
// Zod specific
|
|
147
|
+
useDateType?: boolean,
|
|
148
|
+
useTrim?: boolean,
|
|
149
|
+
nullish?: boolean,
|
|
150
|
+
requiredString?: boolean,
|
|
151
|
+
version?: 3 | 4,
|
|
752
152
|
|
|
753
|
-
|
|
153
|
+
// TypeScript specific
|
|
154
|
+
enumType?: 'union' | 'enum',
|
|
155
|
+
modelType?: 'interface' | 'type',
|
|
754
156
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
CREATE TABLE `user` (
|
|
759
|
-
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
|
760
|
-
`name` varchar(255) NOT NULL COMMENT '@zod(z.string().min(10).max(255))',
|
|
761
|
-
`email` varchar(255) NOT NULL COMMENT '@zod(z.string().email())',
|
|
762
|
-
PRIMARY KEY (`id`)
|
|
763
|
-
);
|
|
157
|
+
// Kysely specific
|
|
158
|
+
schemaName?: string // Default: 'DB'
|
|
159
|
+
}
|
|
764
160
|
```
|
|
765
161
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
162
|
+
### Global Options
|
|
163
|
+
| Option | Description |
|
|
164
|
+
|--------|-------------|
|
|
165
|
+
| `tables` | Include only specified tables |
|
|
166
|
+
| `views` | Include only specified views |
|
|
167
|
+
| `ignore` | Exclude specified tables (supports regex) |
|
|
168
|
+
| `ignoreViews` | Exclude specified views (supports regex) |
|
|
169
|
+
| `includeViews` | Process database views |
|
|
170
|
+
| `camelCase` | Convert to camelCase |
|
|
171
|
+
| `dryRun` | Return content without writing files |
|
|
172
|
+
| `magicComments` | Enable @zod/@ts/@kysely comments (Obs.: no SQLite support) |
|
|
775
173
|
|
|
776
|
-
|
|
174
|
+
## Magic Comments
|
|
777
175
|
|
|
778
|
-
|
|
176
|
+
Override types for specific columns using database comments (MySQL/PostgreSQL only):
|
|
779
177
|
|
|
780
178
|
```sql
|
|
781
179
|
CREATE TABLE `user` (
|
|
782
|
-
`id` int(11)
|
|
783
|
-
`
|
|
784
|
-
`
|
|
180
|
+
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
181
|
+
`name` varchar(255) COMMENT '@zod(z.string().min(2).max(50))',
|
|
182
|
+
`email` varchar(255) COMMENT '@ts(EmailAddress) @kysely(string)',
|
|
183
|
+
`metadata` json COMMENT '@ts(UserMetadata)',
|
|
785
184
|
PRIMARY KEY (`id`)
|
|
786
185
|
);
|
|
787
186
|
```
|
|
788
187
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
id: number;
|
|
794
|
-
metadata: Record<string, unknown>;
|
|
795
|
-
settings: UserSettings;
|
|
796
|
-
}
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
### @kysely Comments
|
|
188
|
+
**Supported Comments:**
|
|
189
|
+
- `@zod(...)` - Override Zod schema
|
|
190
|
+
- `@ts(...)` - Override TypeScript type
|
|
191
|
+
- `@kysely(...)` - Override Kysely type
|
|
800
192
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
```sql
|
|
804
|
-
CREATE TABLE `user` (
|
|
805
|
-
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
|
806
|
-
`metadata` json NOT NULL COMMENT '@kysely(Record<string, string>)',
|
|
807
|
-
PRIMARY KEY (`id`)
|
|
808
|
-
);
|
|
809
|
-
```
|
|
193
|
+
## Type Overrides
|
|
810
194
|
|
|
811
|
-
|
|
195
|
+
Override default types globally in your origin config:
|
|
812
196
|
|
|
813
197
|
```typescript
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
198
|
+
{
|
|
199
|
+
origin: {
|
|
200
|
+
type: 'mysql',
|
|
201
|
+
// ... connection config
|
|
202
|
+
overrideTypes: {
|
|
203
|
+
json: 'z.record(z.string())',
|
|
204
|
+
text: 'z.string().max(1000)',
|
|
205
|
+
decimal: 'z.number().positive()'
|
|
206
|
+
}
|
|
207
|
+
}
|
|
817
208
|
}
|
|
818
209
|
```
|
|
819
210
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
CREATE TABLE `product` (
|
|
826
|
-
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
|
827
|
-
`variants` json NOT NULL COMMENT '@ts(Array<{ id: string; price: number; stock: number }>)',
|
|
828
|
-
PRIMARY KEY (`id`)
|
|
829
|
-
);
|
|
830
|
-
```
|
|
831
|
-
|
|
832
|
-
This will generate:
|
|
833
|
-
|
|
834
|
-
```typescript
|
|
835
|
-
export interface Product {
|
|
836
|
-
id: number;
|
|
837
|
-
variants: Array<{ id: string; price: number; stock: number }>;
|
|
838
|
-
}
|
|
839
|
-
```
|
|
211
|
+
**Common Overrides:**
|
|
212
|
+
- **MySQL**: `json`, `text`, `decimal`, `enum`
|
|
213
|
+
- **PostgreSQL**: `jsonb`, `uuid`, `text`, `numeric`
|
|
214
|
+
- **SQLite**: `json`, `text`, `real`
|
|
215
|
+
- **Prisma**: `Json`, `String`, `Decimal`
|