mutano 1.0.8 → 2.0.0

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