zod-sqlite 0.1.0-alpha.2 → 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.
- package/README.md +119 -32
- package/package.json +15 -12
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Zod
|
|
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
|
|
|
@@ -47,7 +47,7 @@ npm install zod-sqlite
|
|
|
47
47
|
Requires Zod v4 as a peer dependency:
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
npm install zod
|
|
50
|
+
npm install zod
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
## Quick Start
|
|
@@ -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
|
-
|
|
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
|
-
//
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
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
|
|
842
|
-
- Enums and literals
|
|
843
|
-
- Numeric min
|
|
844
|
-
- String length min
|
|
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
|
|
879
|
+
Custom refinements and complex validations work at the application level but don't generate SQL constraints:
|
|
847
880
|
|
|
848
881
|
```typescript
|
|
849
|
-
|
|
850
|
-
|
|
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
|
|
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
|
-
//
|
|
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
|
|
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
|
-
//
|
|
869
|
-
//
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
961
|
+
**Critical:** SQLite does not enforce foreign key constraints by default. You must enable them:
|
|
886
962
|
|
|
887
|
-
```
|
|
888
|
-
|
|
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
|
-
|
|
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": "
|
|
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": {
|
|
@@ -40,12 +40,24 @@
|
|
|
40
40
|
"LICENSE"
|
|
41
41
|
],
|
|
42
42
|
"sideEffects": false,
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "pnpm clean && tsup",
|
|
45
|
+
"dev": "tsup --watch",
|
|
46
|
+
"test": "vitest",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"lint": "eslint src --ext .ts --fix",
|
|
49
|
+
"clean": "rm -rf dist",
|
|
50
|
+
"prepublishOnly": "pnpm build && pnpm typecheck && pnpm vitest --watch=false",
|
|
51
|
+
"release": "pnpm build && pnpm dlx @changesets/cli publish"
|
|
52
|
+
},
|
|
53
|
+
"packageManager": "pnpm@10.26.1",
|
|
43
54
|
"devDependencies": {
|
|
44
55
|
"@changesets/cli": "^2.29.8",
|
|
45
56
|
"@stylistic/eslint-plugin": "^5.6.1",
|
|
46
57
|
"@typescript-eslint/eslint-plugin": "^8.51.0",
|
|
47
58
|
"@typescript-eslint/parser": "^8.51.0",
|
|
48
59
|
"@vitest/ui": "^4.0.16",
|
|
60
|
+
"db0": "^0.3.4",
|
|
49
61
|
"eslint": "^9.39.2",
|
|
50
62
|
"tsup": "^8.5.1",
|
|
51
63
|
"typescript": "^5.9.3",
|
|
@@ -67,14 +79,5 @@
|
|
|
67
79
|
"schema",
|
|
68
80
|
"validation",
|
|
69
81
|
"zod-to-sqlite"
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
"build": "pnpm clean && tsup",
|
|
73
|
-
"dev": "tsup --watch",
|
|
74
|
-
"test": "vitest",
|
|
75
|
-
"typecheck": "tsc --noEmit",
|
|
76
|
-
"lint": "eslint src --ext .ts --fix",
|
|
77
|
-
"clean": "rm -rf dist",
|
|
78
|
-
"release": "pnpm build && pnpm dlx @changesets/cli publish"
|
|
79
|
-
}
|
|
80
|
-
}
|
|
82
|
+
]
|
|
83
|
+
}
|