zod-sqlite 0.1.0-alpha.1 → 1.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 (2) hide show
  1. package/README.md +121 -34
  2. package/package.json +2 -1
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Zod to SQLite
1
+ # Zod-SQLite
2
2
 
3
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.
4
4
 
@@ -41,13 +41,13 @@ This tool bridges the gap between Zod schemas and SQLite database definitions. I
41
41
  ## Installation
42
42
 
43
43
  ```bash
44
- npm install zod-to-sqlite
44
+ npm install zod-sqlite
45
45
  ```
46
46
 
47
47
  Requires Zod v4 as a peer dependency:
48
48
 
49
49
  ```bash
50
- npm install zod@^4.0.0
50
+ npm install zod
51
51
  ```
52
52
 
53
53
  ## Quick Start
@@ -55,7 +55,7 @@ npm install zod@^4.0.0
55
55
  Here's a simple example creating a users table:
56
56
 
57
57
  ```typescript
58
- import { createTable } from 'zod-to-sqlite'
58
+ import { createTable } from 'zod-sqlite'
59
59
  import { z } from 'zod'
60
60
 
61
61
  const users = createTable({
@@ -823,72 +823,159 @@ const employees = createTable({
823
823
 
824
824
  ## Limitations
825
825
 
826
- ### Composite Foreign Keys
826
+ ### Composite Foreign Keys (By Design)
827
827
 
828
- Currently only single-column foreign keys are supported. Composite foreign keys must be added manually:
828
+ Single-column foreign keys are supported at the column level. Composite foreign keys require table-level constraints that reference multiple tables, which is outside the scope of single-table schema generation.
829
+
830
+ **Why this is intentional:** `createTable` generates schema for one table at a time. Composite foreign keys are cross-table relationships that should be managed explicitly by developers as part of overall database design.
831
+
832
+ **Pattern for composite foreign keys:**
829
833
 
830
834
  ```typescript
831
- // Not supported in column config
832
- // Workaround: Add after table creation
833
- ALTER TABLE order_items
834
- ADD CONSTRAINT fk_order
835
- FOREIGN KEY (tenant_id, order_id)
836
- REFERENCES orders(tenant_id, id);
835
+ // 1. Create parent table with composite primary key
836
+ const { table: ordersTable } = createTable({
837
+ name: 'orders',
838
+ columns: [
839
+ { name: 'tenant_id', schema: z.string() },
840
+ { name: 'order_id', schema: z.int() },
841
+ { name: 'total', schema: z.number() },
842
+ ],
843
+ primaryKeys: ['tenant_id', 'order_id'],
844
+ })
845
+
846
+ // 2. Create child table with matching columns
847
+ const { table: itemsTable } = createTable({
848
+ name: 'order_items',
849
+ columns: [
850
+ { name: 'id', schema: z.int() },
851
+ { name: 'tenant_id', schema: z.string() },
852
+ { name: 'order_id', schema: z.int() },
853
+ { name: 'product', schema: z.string() },
854
+ ],
855
+ primaryKeys: ['id'],
856
+ })
857
+
858
+ // 3. Execute table creation
859
+ db.exec(ordersTable)
860
+ db.exec(itemsTable)
861
+
862
+ // 4. Add composite foreign key constraint
863
+ db.exec(`
864
+ ALTER TABLE order_items
865
+ ADD CONSTRAINT fk_order
866
+ FOREIGN KEY (tenant_id, order_id)
867
+ REFERENCES orders(tenant_id, order_id)
868
+ ON DELETE CASCADE
869
+ `)
837
870
  ```
838
871
 
839
872
  ### Complex CHECK Constraints
840
873
 
841
- Only specific Zod validations are converted to CHECK constraints:
842
- - Enums and literals
843
- - Numeric min/max
844
- - String length min/max/equals
874
+ Only specific Zod validations generate CHECK constraints:
875
+ - **Enums and literals**: `z.enum(['a', 'b'])`, `z.literal('value')`
876
+ - **Numeric ranges**: `.min()`, `.max()` on numbers
877
+ - **String length**: `.min()`, `.max()`, `.length()` on strings
845
878
 
846
- Custom refinements and complex validations are not converted:
879
+ Custom refinements and complex validations work at the application level but don't generate SQL constraints:
847
880
 
848
881
  ```typescript
849
- z.string().refine(val => val.includes('@'), 'Must contain @')
850
- // This validation works in TypeScript but won't create a CHECK constraint
882
+ {
883
+ name: 'email',
884
+ schema: z.string().refine(val => val.includes('@'), 'Must contain @')
885
+ }
886
+ // ✅ Runtime validation works
887
+ // ❌ No CHECK constraint in SQL
888
+ // Still stored as: email TEXT NOT NULL
851
889
  ```
852
890
 
891
+ **Why:** SQL CHECK constraints are limited compared to JavaScript validation. Complex rules should be validated in application code using the generated Zod schema.
892
+
853
893
  ### Array and Object Storage
854
894
 
855
- Arrays and objects are stored as TEXT (JSON). You must handle serialization:
895
+ Arrays and objects are stored as TEXT with JSON serialization. You must handle serialization manually:
856
896
 
857
897
  ```typescript
858
898
  { name: 'tags', schema: z.array(z.string()) }
859
- // Stored as TEXT, you need to JSON.stringify/parse manually
899
+ // SQL: tags TEXT NOT NULL
900
+
901
+ // You need to handle:
902
+ const data = { tags: ['tech', 'news'] }
903
+ db.exec(`INSERT INTO posts (tags) VALUES (?)`, [JSON.stringify(data.tags)])
904
+
905
+ const result = db.query(`SELECT tags FROM posts`)
906
+ const tags = JSON.parse(result.tags) // ['tech', 'news']
907
+ ```
908
+
909
+ **Recommendation:** For better queryability, consider separate tables for array data:
910
+ ```typescript
911
+ // Instead of storing tags as JSON array
912
+ // Use a junction table: post_tags (post_id, tag_id)
860
913
  ```
861
914
 
862
915
  ### Date Handling
863
916
 
864
- Dates are stored as TEXT in ISO 8601 format. SQLite has limited native date support:
917
+ Dates are stored as TEXT in ISO 8601 format. SQLite doesn't have a native DATE type:
865
918
 
866
919
  ```typescript
867
920
  { name: 'created_at', schema: z.date() }
868
- // Stored as TEXT: '2026-01-06T12:30:00.000Z'
869
- // Use SQLite date functions for queries: date(created_at)
921
+ // SQL: created_at DATE NOT NULL
922
+ // Stored as TEXT: '2026-01-07T12:30:00.000Z'
923
+ ```
924
+
925
+ **Querying dates:** Use SQLite's date functions:
926
+ ```sql
927
+ -- Filter by date
928
+ SELECT * FROM posts WHERE date(created_at) = '2026-01-07'
929
+
930
+ -- Date arithmetic
931
+ SELECT * FROM posts WHERE date(created_at) > date('now', '-7 days')
932
+
933
+ -- Extract parts
934
+ SELECT strftime('%Y', created_at) as year FROM posts
870
935
  ```
871
936
 
872
937
  ### No Migration Support
873
938
 
874
- This generates CREATE TABLE statements but doesn't handle schema migrations. For production use, consider a migration tool.
939
+ This library generates CREATE TABLE statements for initial schema definition. It does not:
940
+ - Track schema changes over time
941
+ - Generate ALTER TABLE migrations
942
+ - Handle data migrations
943
+ - Manage version history
944
+
945
+ ### SQLite-Specific Features
946
+
947
+ This tool is designed specifically for SQLite. Some features may not translate to other databases:
875
948
 
876
- ### SQLite-Specific
949
+ | Feature | SQLite Behavior | Other Databases |
950
+ |---------|----------------|-----------------|
951
+ | Type System | Dynamic type affinity | Strict typing (PostgreSQL, MySQL) |
952
+ | Boolean Storage | 0/1 integers | True BOOLEAN type |
953
+ | Date Storage | TEXT in ISO 8601 | Native DATE/TIMESTAMP types |
954
+ | CHECK Constraints | Fully supported | Varies by database |
955
+ | Foreign Keys | Optional (needs PRAGMA) | Usually enforced by default |
877
956
 
878
- This is designed specifically for SQLite. Features may not translate to other databases:
879
- - Type affinity rules are SQLite-specific
880
- - Some constraint syntax is SQLite-specific
881
- - Boolean storage as 0/1 is SQLite convention
957
+ **Portability:** If you need multi-database support, consider an ORM like Prisma or TypeORM instead.
882
958
 
883
959
  ### Foreign Key Enforcement
884
960
 
885
- SQLite doesn't enforce foreign keys by default. You must enable them:
961
+ **Critical:** SQLite does not enforce foreign key constraints by default. You must enable them:
886
962
 
887
- ```sql
888
- PRAGMA foreign_keys = ON;
963
+ ```typescript
964
+ // Example using db0
965
+ const db = createDatabase(sqlite({
966
+ name: './db.sqlite',
967
+ }))
968
+
969
+ // Enable for each database connection
970
+ db.exec('PRAGMA foreign_keys = ON')
889
971
  ```
890
972
 
891
- This must be set for each database connection.
973
+ Without this pragma:
974
+ - Foreign key constraints are ignored
975
+ - No referential integrity checks
976
+ - Data can become inconsistent
977
+
978
+ **Always enable this in production** to maintain data integrity.
892
979
 
893
980
  ---
894
981
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod-sqlite",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "1.0.0",
4
4
  "description": "Generate type-safe SQLite table schemas from Zod validation schemas.",
5
5
  "private": false,
6
6
  "author": {
@@ -57,6 +57,7 @@
57
57
  "@typescript-eslint/eslint-plugin": "^8.51.0",
58
58
  "@typescript-eslint/parser": "^8.51.0",
59
59
  "@vitest/ui": "^4.0.16",
60
+ "db0": "^0.3.4",
60
61
  "eslint": "^9.39.2",
61
62
  "tsup": "^8.5.1",
62
63
  "typescript": "^5.9.3",