zod-sqlite 1.0.2 → 1.0.3

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 CHANGED
@@ -1,6 +1,15 @@
1
- # Zod-SQLite
2
-
3
- Generate type-safe SQLite table schemas from Zod validation schemas. Define your database structure once using Zod, and automatically generate both SQL CREATE TABLE statements and runtime validation schemas with full TypeScript type inference.
1
+ <div align="center">
2
+ <h1>Zod-SQLite</h1>
3
+ <p><strong>Generate type-safe SQLite table schemas from Zod validation schemas. Define your database structure once using Zod, and automatically generate both SQL CREATE TABLE statements and runtime validation schemas with full TypeScript type inference.</strong></p>
4
+ <p>
5
+ <a href="https://github.com/favorodera/zod-sqlite/blob/main/LICENSE"><img src="https://img.shields.io/github/license/favorodera/zod-sqlite.svg?style=plastic&label=License&color=blue" alt="License"></a>
6
+ <a href="https://github.com/favorodera/zod-sqlite/stargazers"><img src="https://img.shields.io/github/stars/favorodera/zod-sqlite.svg?style=plastic&label=Stars&color=blue" alt="GitHub Stars"></a>
7
+ <a href="https://npmx.dev/package/zod-sqlite"><img src="https://img.shields.io/npm/dt/zod-sqlite.svg?style=plastic&label=NPM%20Downloads&color=blue" alt="NPM Downloads"></a>
8
+ <a href="https://npmx.dev/package/zod-sqlite"><img src="https://img.shields.io/npm/v/zod-sqlite.svg?style=plastic&label=Version&color=blue" alt="NPM Version"></a>
9
+ </p>
10
+ </div>
11
+
12
+ <br>
4
13
 
5
14
  ## Table of Contents
6
15
 
@@ -44,32 +53,25 @@ This tool bridges the gap between Zod schemas and SQLite database definitions. I
44
53
  npm install zod-sqlite
45
54
  ```
46
55
 
47
- Requires Zod v4 as a peer dependency:
48
-
49
- ```bash
50
- npm install zod
51
- ```
52
-
53
56
  ## Quick Start
54
57
 
55
58
  Here's a simple example creating a users table:
56
59
 
57
60
  ```typescript
58
- import { createTable } from 'zod-sqlite'
59
61
  import { z } from 'zod'
62
+ import { createTable } from 'zod-sqlite'
60
63
 
61
64
  const users = createTable({
62
- name: 'users',
63
65
  columns: [
64
66
  { name: 'id', schema: z.int() },
65
67
  { name: 'email', schema: z.email() },
66
- { name: 'username', schema: z.string().min(3).max(20) },
67
- { name: 'created_at', schema: z.date().default(new Date()) }
68
+ { name: 'username', schema: z.string().min(3)
69
+ .max(20) },
70
+ { name: 'created_at', schema: z.date().default(new Date()) },
68
71
  ],
72
+ indexes: [{ columns: ['email'], name: 'idx_users_email', unique: true }],
73
+ name: 'users',
69
74
  primaryKeys: ['id'],
70
- indexes: [
71
- { name: 'idx_users_email', columns: ['email'], unique: true }
72
- ]
73
75
  })
74
76
 
75
77
  // Use the generated SQL
@@ -87,10 +89,10 @@ console.log(users.indexes[0])
87
89
 
88
90
  // Validate data at runtime
89
91
  const result = users.schema.safeParse({
90
- id: 1,
92
+ created_at: new Date(),
91
93
  email: 'user@example.com',
94
+ id: 1,
92
95
  username: 'john',
93
- created_at: new Date()
94
96
  })
95
97
 
96
98
  // TypeScript type inference
@@ -140,7 +142,7 @@ Creates a table definition with SQL statements and validation schema.
140
142
 
141
143
  **Returns:**
142
144
 
143
- ```typescript
145
+ ```
144
146
  {
145
147
  table: string // CREATE TABLE SQL statement
146
148
  indexes: string[] // Array of CREATE INDEX statements
@@ -151,14 +153,14 @@ Creates a table definition with SQL statements and validation schema.
151
153
  **Example:**
152
154
 
153
155
  ```typescript
154
- const { table, indexes, schema } = createTable({
155
- name: 'products',
156
+ const { indexes, schema, table } = createTable({
156
157
  columns: [
157
158
  { name: 'id', schema: z.int() },
158
159
  { name: 'name', schema: z.string() },
159
- { name: 'price', schema: z.number().min(0) }
160
+ { name: 'price', schema: z.number().min(0) },
160
161
  ],
161
- primaryKeys: ['id']
162
+ name: 'products',
163
+ primaryKeys: ['id'],
162
164
  })
163
165
  ```
164
166
 
@@ -167,11 +169,11 @@ const { table, indexes, schema } = createTable({
167
169
  Configuration object for table creation.
168
170
 
169
171
  ```typescript
170
- type TableConfig = {
171
- name: string // Table name
172
- columns: ColumnConfig[] // Array of column definitions
173
- primaryKeys: string[] // Column names forming primary key
174
- indexes?: IndexConfig[] // Optional index configurations
172
+ interface TableConfig {
173
+ columns: Array<ColumnConfig> // Array of column definitions
174
+ indexes?: Array<IndexConfig> // Optional index configurations
175
+ name: string // Table name
176
+ primaryKeys: Array<string> // Column names forming primary key
175
177
  }
176
178
  ```
177
179
 
@@ -180,11 +182,11 @@ type TableConfig = {
180
182
  Configuration for a single column.
181
183
 
182
184
  ```typescript
183
- type ColumnConfig = {
184
- name: string // Column name
185
- schema: ZodType // Zod schema defining type and validation
186
- unique?: boolean // Whether values must be unique
185
+ interface ColumnConfig {
186
+ name: string // Column name
187
187
  references?: ForeignKeyReference // Foreign key configuration
188
+ schema: ZodType // Zod schema defining type and validation
189
+ unique?: boolean // Whether values must be unique
188
190
  }
189
191
  ```
190
192
 
@@ -193,19 +195,19 @@ type ColumnConfig = {
193
195
  Foreign key constraint configuration.
194
196
 
195
197
  ```typescript
196
- type ForeignKeyReference = {
197
- table: string // Referenced table name
198
- column: string // Referenced column name
199
- onDelete?: ForeignKeyAction // Action on parent deletion
200
- onUpdate?: ForeignKeyAction // Action on parent update
198
+ interface ForeignKeyReference {
199
+ column: string // Referenced column name
200
+ onDelete?: ForeignKeyAction // Action on parent deletion
201
+ onUpdate?: ForeignKeyAction // Action on parent update
202
+ table: string // Referenced table name
201
203
  }
202
204
 
203
- type ForeignKeyAction =
204
- | 'NO ACTION'
205
- | 'RESTRICT'
206
- | 'SET NULL'
207
- | 'SET DEFAULT'
208
- | 'CASCADE'
205
+ type ForeignKeyAction
206
+ = | 'CASCADE'
207
+ | 'NO ACTION'
208
+ | 'RESTRICT'
209
+ | 'SET DEFAULT'
210
+ | 'SET NULL'
209
211
  ```
210
212
 
211
213
  ### IndexConfig
@@ -213,11 +215,11 @@ type ForeignKeyAction =
213
215
  Index configuration for query optimization.
214
216
 
215
217
  ```typescript
216
- type IndexConfig = {
217
- name: string // Index name
218
- columns: string[] // Indexed column names
219
- unique?: boolean // Whether this is a unique index
220
- where?: string // Optional WHERE clause for partial index
218
+ interface IndexConfig {
219
+ columns: Array<string> // Indexed column names
220
+ name: string // Index name
221
+ unique?: boolean // Whether this is a unique index
222
+ where?: string // Optional WHERE clause for partial index
221
223
  }
222
224
  ```
223
225
 
@@ -269,23 +271,24 @@ These Zod wrappers are automatically unwrapped:
269
271
  - `.default(value)` - Adds DEFAULT clause
270
272
 
271
273
  ```typescript
272
- z.string().optional() // TEXT (nullable)
273
- z.number().default(0) // REAL NOT NULL DEFAULT 0
274
- z.string().nullable().default('n/a') // TEXT DEFAULT 'n/a'
274
+ z.string().optional() // TEXT (nullable)
275
+ z.number().default(0) // REAL NOT NULL DEFAULT 0
276
+ z.string().nullable()
277
+ .default('n/a') // TEXT DEFAULT 'n/a'
275
278
  ```
276
279
 
277
280
  ## Column Configuration
278
281
 
279
282
  ### Basic Columns
280
283
 
281
- ```typescript
284
+ ```
282
285
  { name: 'email', schema: z.email() }
283
286
  // SQL: email TEXT NOT NULL
284
287
  ```
285
288
 
286
289
  ### Optional and Nullable Columns
287
290
 
288
- ```typescript
291
+ ```
289
292
  { name: 'bio', schema: z.string().optional() }
290
293
  // SQL: bio TEXT
291
294
 
@@ -295,7 +298,7 @@ z.string().nullable().default('n/a') // TEXT DEFAULT 'n/a'
295
298
 
296
299
  ### Columns with Default Values
297
300
 
298
- ```typescript
301
+ ```
299
302
  { name: 'status', schema: z.enum(['active', 'inactive']).default('active') }
300
303
  // SQL: status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'inactive'))
301
304
 
@@ -305,7 +308,7 @@ z.string().nullable().default('n/a') // TEXT DEFAULT 'n/a'
305
308
 
306
309
  ### Unique Columns
307
310
 
308
- ```typescript
311
+ ```
309
312
  { name: 'username', schema: z.string(), unique: true }
310
313
  // SQL: username TEXT NOT NULL UNIQUE
311
314
  ```
@@ -316,7 +319,7 @@ SQL CHECK constraints are automatically generated from Zod validation rules.
316
319
 
317
320
  ### Enum Constraints
318
321
 
319
- ```typescript
322
+ ```
320
323
  {
321
324
  name: 'role',
322
325
  schema: z.enum(['admin', 'user', 'guest'])
@@ -326,7 +329,7 @@ SQL CHECK constraints are automatically generated from Zod validation rules.
326
329
 
327
330
  ### Literal Constraints
328
331
 
329
- ```typescript
332
+ ```
330
333
  {
331
334
  name: 'type',
332
335
  schema: z.literal('premium')
@@ -346,7 +349,7 @@ SQL CHECK constraints are automatically generated from Zod validation rules.
346
349
 
347
350
  ### Numeric Range Constraints
348
351
 
349
- ```typescript
352
+ ```
350
353
  {
351
354
  name: 'age',
352
355
  schema: z.int().min(18).max(120)
@@ -362,7 +365,7 @@ SQL CHECK constraints are automatically generated from Zod validation rules.
362
365
 
363
366
  ### String Length Constraints
364
367
 
365
- ```typescript
368
+ ```
366
369
  {
367
370
  name: 'username',
368
371
  schema: z.string().min(3).max(20)
@@ -384,12 +387,12 @@ The most common pattern for entity tables:
384
387
 
385
388
  ```typescript
386
389
  createTable({
387
- name: 'users',
388
390
  columns: [
389
391
  { name: 'id', schema: z.int() },
390
- { name: 'email', schema: z.string() }
392
+ { name: 'email', schema: z.string() },
391
393
  ],
392
- primaryKeys: ['id']
394
+ name: 'users',
395
+ primaryKeys: ['id'],
393
396
  })
394
397
  // SQL: PRIMARY KEY (id)
395
398
  ```
@@ -400,12 +403,15 @@ Used for junction tables and multi-tenant data:
400
403
 
401
404
  ```typescript
402
405
  createTable({
403
- name: 'user_roles',
404
406
  columns: [
405
407
  { name: 'user_id', schema: z.int() },
406
- { name: 'role_id', schema: z.int() }
408
+ { name: 'role_id', schema: z.int() },
409
+ ],
410
+ name: 'user_roles',
411
+ primaryKeys: [
412
+ 'user_id',
413
+ 'role_id',
407
414
  ],
408
- primaryKeys: ['user_id', 'role_id']
409
415
  })
410
416
  // SQL: PRIMARY KEY (user_id, role_id)
411
417
  ```
@@ -414,13 +420,16 @@ createTable({
414
420
 
415
421
  ```typescript
416
422
  createTable({
417
- name: 'documents',
418
423
  columns: [
419
424
  { name: 'tenant_id', schema: z.string() },
420
425
  { name: 'doc_id', schema: z.int() },
421
- { name: 'title', schema: z.string() }
426
+ { name: 'title', schema: z.string() },
427
+ ],
428
+ name: 'documents',
429
+ primaryKeys: [
430
+ 'tenant_id',
431
+ 'doc_id',
422
432
  ],
423
- primaryKeys: ['tenant_id', 'doc_id']
424
433
  })
425
434
  // SQL: PRIMARY KEY (tenant_id, doc_id)
426
435
  ```
@@ -431,19 +440,19 @@ createTable({
431
440
 
432
441
  ```typescript
433
442
  createTable({
434
- name: 'posts',
435
443
  columns: [
436
444
  { name: 'id', schema: z.int() },
437
- {
438
- name: 'author_id',
439
- schema: z.int(),
445
+ {
446
+ name: 'author_id',
440
447
  references: {
448
+ column: 'id',
441
449
  table: 'users',
442
- column: 'id'
443
- }
444
- }
450
+ },
451
+ schema: z.int(),
452
+ },
445
453
  ],
446
- primaryKeys: ['id']
454
+ name: 'posts',
455
+ primaryKeys: ['id'],
447
456
  })
448
457
  // SQL: author_id INTEGER NOT NULL REFERENCES users(id)
449
458
  ```
@@ -452,7 +461,7 @@ createTable({
452
461
 
453
462
  Automatically delete child records when parent is deleted:
454
463
 
455
- ```typescript
464
+ ```
456
465
  {
457
466
  name: 'user_id',
458
467
  schema: z.int(),
@@ -469,7 +478,7 @@ Automatically delete child records when parent is deleted:
469
478
 
470
479
  Prevent deletion of parent if children exist:
471
480
 
472
- ```typescript
481
+ ```
473
482
  {
474
483
  name: 'category_id',
475
484
  schema: z.int(),
@@ -486,7 +495,7 @@ Prevent deletion of parent if children exist:
486
495
 
487
496
  Set foreign key to NULL when parent is deleted:
488
497
 
489
- ```typescript
498
+ ```
490
499
  {
491
500
  name: 'manager_id',
492
501
  schema: z.int().nullable(),
@@ -503,7 +512,7 @@ Set foreign key to NULL when parent is deleted:
503
512
 
504
513
  Propagate updates to child records:
505
514
 
506
- ```typescript
515
+ ```
507
516
  {
508
517
  name: 'parent_id',
509
518
  schema: z.int(),
@@ -521,12 +530,12 @@ Propagate updates to child records:
521
530
 
522
531
  ### Simple Index
523
532
 
524
- ```typescript
533
+ ```
525
534
  indexes: [
526
- {
527
- name: 'idx_users_email',
528
- columns: ['email']
529
- }
535
+ {
536
+ columns: ['email'],
537
+ name: 'idx_users_email',
538
+ },
530
539
  ]
531
540
  // SQL: CREATE INDEX idx_users_email ON users (email);
532
541
  ```
@@ -537,11 +546,11 @@ Enforce uniqueness at the database level:
537
546
 
538
547
  ```typescript
539
548
  indexes: [
540
- {
541
- name: 'idx_users_username',
542
- columns: ['username'],
543
- unique: true
544
- }
549
+ {
550
+ columns: ['username'],
551
+ name: 'idx_users_username',
552
+ unique: true,
553
+ },
545
554
  ]
546
555
  // SQL: CREATE UNIQUE INDEX idx_users_username ON users (username);
547
556
  ```
@@ -552,10 +561,13 @@ Index multiple columns together for multi-column queries:
552
561
 
553
562
  ```typescript
554
563
  indexes: [
555
- {
556
- name: 'idx_posts_author_date',
557
- columns: ['author_id', 'created_at']
558
- }
564
+ {
565
+ columns: [
566
+ 'author_id',
567
+ 'created_at',
568
+ ],
569
+ name: 'idx_posts_author_date',
570
+ },
559
571
  ]
560
572
  // SQL: CREATE INDEX idx_posts_author_date ON posts (author_id, created_at);
561
573
  ```
@@ -572,11 +584,11 @@ Index only rows matching a condition:
572
584
 
573
585
  ```typescript
574
586
  indexes: [
575
- {
576
- name: 'idx_active_users',
587
+ {
577
588
  columns: ['last_login'],
578
- where: 'deleted_at IS NULL'
579
- }
589
+ name: 'idx_active_users',
590
+ where: 'deleted_at IS NULL',
591
+ },
580
592
  ]
581
593
  // SQL: CREATE INDEX idx_active_users ON posts (last_login) WHERE deleted_at IS NULL;
582
594
  ```
@@ -593,78 +605,94 @@ Benefits:
593
605
  ```typescript
594
606
  // Users table
595
607
  const users = createTable({
596
- name: 'users',
597
608
  columns: [
598
609
  { name: 'id', schema: z.int() },
599
610
  { name: 'email', schema: z.email(), unique: true },
600
- { name: 'username', schema: z.string().min(3).max(20), unique: true },
601
- { name: 'role', schema: z.enum(['admin', 'author', 'reader']).default('reader') },
602
- { name: 'created_at', schema: z.date().default(new Date()) }
611
+ { name: 'username', schema: z.string().min(3)
612
+ .max(20), unique: true },
613
+ { name: 'role', schema: z.enum([
614
+ 'admin',
615
+ 'author',
616
+ 'reader',
617
+ ]).default('reader') },
618
+ { name: 'created_at', schema: z.date().default(new Date()) },
603
619
  ],
604
- primaryKeys: ['id'],
605
620
  indexes: [
606
- { name: 'idx_users_email', columns: ['email'], unique: true },
607
- { name: 'idx_users_role', columns: ['role'] }
608
- ]
621
+ { columns: ['email'], name: 'idx_users_email', unique: true },
622
+ { columns: ['role'], name: 'idx_users_role' },
623
+ ],
624
+ name: 'users',
625
+ primaryKeys: ['id'],
609
626
  })
610
627
 
611
628
  // Posts table with foreign key
612
629
  const posts = createTable({
613
- name: 'posts',
614
630
  columns: [
615
631
  { name: 'id', schema: z.int() },
616
- { name: 'title', schema: z.string().min(1).max(200) },
632
+ { name: 'title', schema: z.string().min(1)
633
+ .max(200) },
617
634
  { name: 'content', schema: z.string() },
618
- { name: 'status', schema: z.enum(['draft', 'published', 'archived']).default('draft') },
619
- {
620
- name: 'author_id',
621
- schema: z.int(),
635
+ { name: 'status', schema: z.enum([
636
+ 'draft',
637
+ 'published',
638
+ 'archived',
639
+ ]).default('draft') },
640
+ {
641
+ name: 'author_id',
622
642
  references: {
623
- table: 'users',
624
643
  column: 'id',
625
- onDelete: 'CASCADE'
626
- }
644
+ onDelete: 'CASCADE',
645
+ table: 'users',
646
+ },
647
+ schema: z.int(),
627
648
  },
628
649
  { name: 'published_at', schema: z.date().nullable() },
629
- { name: 'created_at', schema: z.date().default(new Date()) }
650
+ { name: 'created_at', schema: z.date().default(new Date()) },
630
651
  ],
631
- primaryKeys: ['id'],
632
652
  indexes: [
633
- { name: 'idx_posts_author', columns: ['author_id'] },
634
- {
635
- name: 'idx_posts_published',
653
+ { columns: ['author_id'], name: 'idx_posts_author' },
654
+ {
636
655
  columns: ['published_at'],
637
- where: "status = 'published'"
656
+ name: 'idx_posts_published',
657
+ where: 'status = \'published\'',
638
658
  },
639
- { name: 'idx_posts_status_date', columns: ['status', 'created_at'] }
640
- ]
659
+ { columns: [
660
+ 'status',
661
+ 'created_at',
662
+ ], name: 'idx_posts_status_date' },
663
+ ],
664
+ name: 'posts',
665
+ primaryKeys: ['id'],
641
666
  })
642
667
 
643
668
  // Junction table for tags (many-to-many)
644
669
  const postTags = createTable({
645
- name: 'post_tags',
646
670
  columns: [
647
- {
648
- name: 'post_id',
649
- schema: z.int(),
671
+ {
672
+ name: 'post_id',
650
673
  references: {
651
- table: 'posts',
652
674
  column: 'id',
653
- onDelete: 'CASCADE'
654
- }
655
- },
656
- {
657
- name: 'tag_id',
675
+ onDelete: 'CASCADE',
676
+ table: 'posts',
677
+ },
658
678
  schema: z.int(),
679
+ },
680
+ {
681
+ name: 'tag_id',
659
682
  references: {
660
- table: 'tags',
661
683
  column: 'id',
662
- onDelete: 'CASCADE'
663
- }
684
+ onDelete: 'CASCADE',
685
+ table: 'tags',
686
+ },
687
+ schema: z.int(),
664
688
  },
665
- { name: 'created_at', schema: z.date().default(new Date()) }
689
+ { name: 'created_at', schema: z.date().default(new Date()) },
690
+ ],
691
+ name: 'post_tags',
692
+ primaryKeys: [
693
+ 'post_id',
694
+ 'tag_id',
666
695
  ],
667
- primaryKeys: ['post_id', 'tag_id']
668
696
  })
669
697
  ```
670
698
 
@@ -672,35 +700,39 @@ const postTags = createTable({
672
700
 
673
701
  ```typescript
674
702
  const products = createTable({
675
- name: 'products',
676
703
  columns: [
677
704
  { name: 'id', schema: z.int() },
678
705
  { name: 'sku', schema: z.string().length(10), unique: true },
679
706
  { name: 'name', schema: z.string().min(1) },
680
707
  { name: 'description', schema: z.string().optional() },
681
708
  { name: 'price', schema: z.number().min(0) },
682
- { name: 'stock', schema: z.int().min(0).default(0) },
709
+ { name: 'stock', schema: z.int().min(0)
710
+ .default(0) },
683
711
  { name: 'active', schema: z.boolean().default(true) },
684
- {
685
- name: 'category_id',
686
- schema: z.int(),
712
+ {
713
+ name: 'category_id',
687
714
  references: {
688
- table: 'categories',
689
715
  column: 'id',
690
- onDelete: 'RESTRICT'
691
- }
692
- }
716
+ onDelete: 'RESTRICT',
717
+ table: 'categories',
718
+ },
719
+ schema: z.int(),
720
+ },
693
721
  ],
694
- primaryKeys: ['id'],
695
722
  indexes: [
696
- { name: 'idx_products_sku', columns: ['sku'], unique: true },
697
- { name: 'idx_products_category', columns: ['category_id'] },
698
- {
699
- name: 'idx_products_active',
700
- columns: ['price', 'stock'],
701
- where: 'active = 1'
702
- }
703
- ]
723
+ { columns: ['sku'], name: 'idx_products_sku', unique: true },
724
+ { columns: ['category_id'], name: 'idx_products_category' },
725
+ {
726
+ columns: [
727
+ 'price',
728
+ 'stock',
729
+ ],
730
+ name: 'idx_products_active',
731
+ where: 'active = 1',
732
+ },
733
+ ],
734
+ name: 'products',
735
+ primaryKeys: ['id'],
704
736
  })
705
737
  ```
706
738
 
@@ -708,25 +740,23 @@ const products = createTable({
708
740
 
709
741
  ```typescript
710
742
  const employees = createTable({
711
- name: 'employees',
712
743
  columns: [
713
744
  { name: 'id', schema: z.int() },
714
745
  { name: 'name', schema: z.string() },
715
746
  { name: 'email', schema: z.email(), unique: true },
716
- {
717
- name: 'manager_id',
718
- schema: z.int().nullable(),
747
+ {
748
+ name: 'manager_id',
719
749
  references: {
720
- table: 'employees',
721
750
  column: 'id',
722
- onDelete: 'SET NULL'
723
- }
724
- }
751
+ onDelete: 'SET NULL',
752
+ table: 'employees',
753
+ },
754
+ schema: z.int().nullable(),
755
+ },
725
756
  ],
757
+ indexes: [{ columns: ['manager_id'], name: 'idx_employees_manager' }],
758
+ name: 'employees',
726
759
  primaryKeys: ['id'],
727
- indexes: [
728
- { name: 'idx_employees_manager', columns: ['manager_id'] }
729
- ]
730
760
  })
731
761
  ```
732
762
 
@@ -738,16 +768,21 @@ const employees = createTable({
738
768
 
739
769
  2. **Use appropriate types**: Choose the most specific Zod type that matches your data:
740
770
  ```typescript
741
- z.int() // For IDs and counts
742
- z.number().min(0) // For prices and quantities
743
- z.enum(['a', 'b']) // For status fields
744
- z.email() // For email addresses
771
+ z.int() // For IDs and counts
772
+ z.number().min(0) // For prices and quantities
773
+ z.enum([
774
+ 'a',
775
+ 'b',
776
+ ]) // For status fields
777
+ z.email() // For email addresses
745
778
  ```
746
779
 
747
780
  3. **Add validation at the schema level**: Leverage Zod's validation to prevent invalid data:
748
781
  ```typescript
749
- z.string().min(3).max(50) // Username length
750
- z.number().min(0).max(5) // Rating scale
782
+ z.string().min(3)
783
+ .max(50) // Username length
784
+ z.number().min(0)
785
+ .max(5) // Rating scale
751
786
  ```
752
787
 
753
788
  ### Foreign Keys
@@ -774,18 +809,21 @@ const employees = createTable({
774
809
  ```typescript
775
810
  indexes: [
776
811
  // Good: Filters by tenant first (high selectivity)
777
- { name: 'idx_tenant_user', columns: ['tenant_id', 'user_id'] }
812
+ { columns: [
813
+ 'tenant_id',
814
+ 'user_id',
815
+ ], name: 'idx_tenant_user' },
778
816
  ]
779
817
  ```
780
818
 
781
819
  4. **Consider partial indexes**: Reduce index size for filtered queries:
782
820
  ```typescript
783
821
  indexes: [
784
- {
785
- name: 'idx_active_records',
822
+ {
786
823
  columns: ['created_at'],
787
- where: 'deleted_at IS NULL' // Only index active records
788
- }
824
+ name: 'idx_active_records',
825
+ where: 'deleted_at IS NULL', // Only index active records
826
+ },
789
827
  ]
790
828
  ```
791
829
 
@@ -834,24 +872,27 @@ Single-column foreign keys are supported at the column level. Composite foreign
834
872
  ```typescript
835
873
  // 1. Create parent table with composite primary key
836
874
  const { table: ordersTable } = createTable({
837
- name: 'orders',
838
875
  columns: [
839
876
  { name: 'tenant_id', schema: z.string() },
840
877
  { name: 'order_id', schema: z.int() },
841
878
  { name: 'total', schema: z.number() },
842
879
  ],
843
- primaryKeys: ['tenant_id', 'order_id'],
880
+ name: 'orders',
881
+ primaryKeys: [
882
+ 'tenant_id',
883
+ 'order_id',
884
+ ],
844
885
  })
845
886
 
846
887
  // 2. Create child table with matching columns
847
888
  const { table: itemsTable } = createTable({
848
- name: 'order_items',
849
889
  columns: [
850
890
  { name: 'id', schema: z.int() },
851
891
  { name: 'tenant_id', schema: z.string() },
852
892
  { name: 'order_id', schema: z.int() },
853
893
  { name: 'product', schema: z.string() },
854
894
  ],
895
+ name: 'order_items',
855
896
  primaryKeys: ['id'],
856
897
  })
857
898
 
@@ -878,7 +919,7 @@ Only specific Zod validations generate CHECK constraints:
878
919
 
879
920
  Custom refinements and complex validations work at the application level but don't generate SQL constraints:
880
921
 
881
- ```typescript
922
+ ```
882
923
  {
883
924
  name: 'email',
884
925
  schema: z.string().refine(val => val.includes('@'), 'Must contain @')
@@ -894,7 +935,7 @@ Custom refinements and complex validations work at the application level but don
894
935
 
895
936
  Arrays and objects are stored as TEXT with JSON serialization. You must handle serialization manually:
896
937
 
897
- ```typescript
938
+ ```
898
939
  { name: 'tags', schema: z.array(z.string()) }
899
940
  // SQL: tags TEXT NOT NULL
900
941
 
@@ -916,7 +957,7 @@ const tags = JSON.parse(result.tags) // ['tech', 'news']
916
957
 
917
958
  Dates are stored as TEXT in ISO 8601 format. SQLite doesn't have a native DATE type:
918
959
 
919
- ```typescript
960
+ ```
920
961
  { name: 'created_at', schema: z.date() }
921
962
  // SQL: created_at DATE NOT NULL
922
963
  // Stored as TEXT: '2026-01-07T12:30:00.000Z'
@@ -962,7 +1003,7 @@ This tool is designed specifically for SQLite. Some features may not translate t
962
1003
 
963
1004
  ```typescript
964
1005
  // Example using db0
965
- const db = createDatabase(sqlite({
1006
+ const db = createDatabase(sqlite({
966
1007
  name: './db.sqlite',
967
1008
  }))
968
1009