driftsql 1.0.31 → 2.0.0-beta.1
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 +275 -95
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +57 -0
- package/dist/index.d.ts +360 -35
- package/dist/index.js +1 -48
- package/dist/postgres-9C7eE0wB.js +5 -0
- package/dist/postgres-DfhzvfQU.js +1 -0
- package/dist/src-B1L6LdRV.js +59 -0
- package/dist/type-generator-CpqI7vBb.js +7 -0
- package/dist/type-generator-DdCKALf8.js +1 -0
- package/package.json +38 -24
- package/.prettierrc +0 -5
- package/dist/drivers/bun.d.ts +0 -22
- package/dist/drivers/libsql.d.ts +0 -23
- package/dist/drivers/mysql.d.ts +0 -20
- package/dist/drivers/neon.d.ts +0 -19
- package/dist/drivers/postgres.d.ts +0 -26
- package/dist/drivers/poubelle/client.d.ts +0 -20
- package/dist/drivers/poubelle/poubelle.d.ts +0 -11
- package/dist/drivers/sqlitecloud.d.ts +0 -21
- package/dist/drivers/surreal.d.ts +0 -17
- package/dist/inspect.d.ts +0 -7
- package/dist/pull.d.ts +0 -7
- package/dist/types.d.ts +0 -49
- package/tsconfig.json +0 -34
package/README.md
CHANGED
|
@@ -1,148 +1,328 @@
|
|
|
1
1
|
# DriftSQL
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://npm.chart.dev/driftsql)
|
|
3
|
+
A modern, type-safe SQL client with built-in schema builder and migration system for TypeScript.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 **High-Performance SQL Client** with connection pooling and query caching
|
|
8
|
+
- 🎯 **Type-Safe Schema Builder** similar to Drizzle/Prisma
|
|
9
|
+
- 🔄 **Migration System** with automatic change detection
|
|
10
|
+
- 🛠️ **CLI Tools** for database management
|
|
11
|
+
- 📦 **Multiple Databases** - PostgreSQL, MySQL, SQLite support
|
|
12
|
+
- ⚡ **Helper Functions** for common CRUD operations
|
|
13
|
+
- 🔍 **Database Inspection** to generate TypeScript types
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Install
|
|
19
|
+
bun add driftsql
|
|
7
20
|
|
|
8
|
-
|
|
21
|
+
# Initialize with a basic notes schema
|
|
22
|
+
driftsql init
|
|
9
23
|
|
|
10
|
-
|
|
11
|
-
|
|
24
|
+
# Update .env with your DATABASE_URL
|
|
25
|
+
cp .env.example .env
|
|
26
|
+
|
|
27
|
+
# Generate migration from schema
|
|
28
|
+
driftsql migrate:generate initial
|
|
29
|
+
|
|
30
|
+
# Run migrations
|
|
31
|
+
driftsql migrate:up
|
|
32
|
+
|
|
33
|
+
# Edit schema.ts, then generate new migrations automatically
|
|
34
|
+
driftsql migrate:generate add_posts
|
|
12
35
|
```
|
|
13
36
|
|
|
14
|
-
##
|
|
37
|
+
## Automatic Workflow
|
|
15
38
|
|
|
16
|
-
|
|
17
|
-
- 🚀 **Modular** - Import only what you need
|
|
18
|
-
- 🛡️ **SQL injection protection** - Parameterized queries
|
|
19
|
-
- 🔄 **Unified API** - Same interface across all drivers
|
|
20
|
-
- ⚡ **Transactions** - When supported by the driver
|
|
39
|
+
DriftSQL automatically detects schema changes and generates migrations for you!
|
|
21
40
|
|
|
22
|
-
|
|
41
|
+
1. Define your schema in `schema.ts`:
|
|
23
42
|
|
|
24
43
|
```typescript
|
|
25
|
-
import {
|
|
44
|
+
import { createTable, serial, varchar, text } from 'driftsql'
|
|
26
45
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
connectionString: 'postgresql://user:password@localhost:5432/mydb',
|
|
46
|
+
const usersTable = createTable('users', (table) => {
|
|
47
|
+
table.column(serial('id').primaryKey()).column(varchar('email', 255).unique().notNull()).column(varchar('name', 255).notNull())
|
|
30
48
|
})
|
|
31
|
-
const client = new SQLClient({ driver })
|
|
32
49
|
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
const postsTable = createTable('posts', (table) => {
|
|
51
|
+
table.column(serial('id').primaryKey()).column(integer('user_id').references('users', 'id')).column(varchar('title', 255).notNull()).column(text('content'))
|
|
52
|
+
})
|
|
35
53
|
|
|
36
|
-
|
|
37
|
-
const user = await client.findFirst('users', { email: 'user@example.com' })
|
|
38
|
-
const newUser = await client.insert('users', { name: 'John', email: 'john@example.com' })
|
|
54
|
+
export default [usersTable.getDefinition(), postsTable.getDefinition()]
|
|
39
55
|
```
|
|
40
56
|
|
|
41
|
-
|
|
57
|
+
2. Generate migration:
|
|
42
58
|
|
|
43
|
-
```
|
|
44
|
-
|
|
59
|
+
```bash
|
|
60
|
+
driftsql migrate:generate
|
|
61
|
+
```
|
|
45
62
|
|
|
46
|
-
|
|
47
|
-
const pg = new PostgresDriver({ connectionString: 'postgresql://...' })
|
|
63
|
+
3. DriftSQL automatically:
|
|
48
64
|
|
|
49
|
-
|
|
50
|
-
|
|
65
|
+
- ✅ Compares with the last snapshot
|
|
66
|
+
- ✅ Detects all changes
|
|
67
|
+
- ✅ Generates migration file
|
|
68
|
+
- ✅ Generates TypeScript types (`db-types.ts`)
|
|
51
69
|
|
|
52
|
-
|
|
53
|
-
const libsql = new LibSQLDriver({ url: 'libsql://...', authToken: '...' })
|
|
54
|
-
// or for local SQLite: new LibSQLDriver({ url: 'file:./database.db' })
|
|
70
|
+
4. Apply migrations:
|
|
55
71
|
|
|
56
|
-
|
|
57
|
-
|
|
72
|
+
```bash
|
|
73
|
+
driftsql migrate:up
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
5. Use type-safe queries:
|
|
58
77
|
|
|
59
|
-
|
|
60
|
-
|
|
78
|
+
```typescript
|
|
79
|
+
import { Database } from './db-types'
|
|
80
|
+
const client = new SQLClient<Database>({
|
|
81
|
+
/* ... */
|
|
82
|
+
})
|
|
61
83
|
```
|
|
62
84
|
|
|
63
|
-
##
|
|
85
|
+
## Usage
|
|
64
86
|
|
|
65
|
-
|
|
87
|
+
### SQL Client with Type Safety
|
|
66
88
|
|
|
67
|
-
|
|
68
|
-
import type { DatabaseDriver, QueryResult } from 'driftsql'
|
|
69
|
-
|
|
70
|
-
class MyCustomDriver implements DatabaseDriver {
|
|
71
|
-
async query<T = any>(sql: string, params?: any[]): Promise<QueryResult<T>> {
|
|
72
|
-
// Your implementation here
|
|
73
|
-
return {
|
|
74
|
-
rows: [], // T[]
|
|
75
|
-
rowCount: 0,
|
|
76
|
-
command: 'SELECT',
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async close(): Promise<void> {
|
|
81
|
-
// Cleanup logic
|
|
82
|
-
}
|
|
83
|
-
}
|
|
89
|
+
TypeScript types are **automatically generated** when you run `migrate:generate`:
|
|
84
90
|
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
```bash
|
|
92
|
+
driftsql migrate:generate # Creates migration AND db-types.ts automatically
|
|
87
93
|
```
|
|
88
94
|
|
|
89
|
-
|
|
95
|
+
Or generate them manually:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
driftsql generate:types --schema ./schema.ts --output ./db-types.ts
|
|
99
|
+
```
|
|
90
100
|
|
|
91
|
-
|
|
101
|
+
Then use them for full type safety:
|
|
92
102
|
|
|
93
103
|
```typescript
|
|
94
|
-
import {
|
|
104
|
+
import { SQLClient, PostgresDriver } from 'driftsql'
|
|
105
|
+
import type { Database } from './db-types'
|
|
95
106
|
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
// Generic parameter makes client type-safe
|
|
108
|
+
const client = new SQLClient<Database>({
|
|
109
|
+
driver: new PostgresDriver({
|
|
110
|
+
connectionString: process.env.DATABASE_URL!,
|
|
111
|
+
max: 10, // Connection pool size
|
|
112
|
+
idle_timeout: 30, // Seconds
|
|
113
|
+
connect_timeout: 10, // Seconds
|
|
114
|
+
}),
|
|
115
|
+
cacheTTL: 5000, // Cache TTL in ms (default: 5000)
|
|
98
116
|
})
|
|
99
117
|
|
|
100
|
-
//
|
|
101
|
-
await
|
|
102
|
-
|
|
103
|
-
|
|
118
|
+
// Raw SQL queries (no type safety, but flexible)
|
|
119
|
+
const result = await client.query('SELECT * FROM users WHERE id = $1', [1])
|
|
120
|
+
|
|
121
|
+
// ✅ Type-safe helper methods (TypeScript validates everything!)
|
|
122
|
+
const user = await client.findFirst('users', { email: 'test@example.com' })
|
|
123
|
+
// ^^^^^ TypeScript ensures 'users' exists
|
|
124
|
+
// ^^^^^ TypeScript ensures 'email' is a valid column
|
|
125
|
+
|
|
126
|
+
const activeUsers = await client.findMany('users', {
|
|
127
|
+
where: { active: true }, // ✅ TypeScript validates field names and types
|
|
128
|
+
limit: 10,
|
|
129
|
+
offset: 0,
|
|
104
130
|
})
|
|
105
|
-
```
|
|
106
131
|
|
|
107
|
-
|
|
132
|
+
// ✅ Insert with type checking
|
|
133
|
+
const newUser = await client.insert('users', {
|
|
134
|
+
email: 'new@example.com', // ✅ Must be a string
|
|
135
|
+
name: 'New User', // ✅ Must be a string
|
|
136
|
+
active: true, // ✅ Must be a boolean
|
|
137
|
+
// invalid: 'field' // ❌ TypeScript error!
|
|
138
|
+
})
|
|
108
139
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
140
|
+
// ✅ Update with type checking
|
|
141
|
+
const updated = await client.update(
|
|
142
|
+
'users',
|
|
143
|
+
{ name: 'Updated Name' }, // ✅ Only valid columns
|
|
144
|
+
{ id: 1 } // ✅ Only valid columns in where clause
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
// ✅ Delete with type checking
|
|
148
|
+
const deletedCount = await client.delete('users', { id: 1 })
|
|
149
|
+
|
|
150
|
+
// Transactions - all operations succeed or all fail
|
|
151
|
+
await client.transaction(async (tx) => {
|
|
152
|
+
const user = await tx.insert('users', { email: 'user@example.com', name: 'User' })
|
|
153
|
+
await tx.insert('posts', { user_id: user.id, title: 'First Post' })
|
|
154
|
+
await tx.query('UPDATE users SET post_count = post_count + 1 WHERE id = $1', [user.id])
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
// Cache management
|
|
158
|
+
const stats = client.getCacheStats() // { size: 5, ttl: 5000 }
|
|
159
|
+
client.clearCache() // Clear all cached queries
|
|
118
160
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
published: boolean
|
|
161
|
+
// Check driver capabilities
|
|
162
|
+
if (client.supportsTransactions()) {
|
|
163
|
+
await client.transaction(async (tx) => {
|
|
164
|
+
/* ... */
|
|
165
|
+
})
|
|
125
166
|
}
|
|
126
167
|
|
|
127
|
-
|
|
128
|
-
users
|
|
129
|
-
|
|
168
|
+
if (client.supportsPreparedStatements()) {
|
|
169
|
+
const stmt = await client.prepare('SELECT * FROM users WHERE id = $1')
|
|
170
|
+
const result = await stmt.execute([1])
|
|
171
|
+
await stmt.finalize()
|
|
130
172
|
}
|
|
173
|
+
|
|
174
|
+
await client.close()
|
|
131
175
|
```
|
|
132
176
|
|
|
133
|
-
|
|
177
|
+
### Schema Builder
|
|
134
178
|
|
|
135
179
|
```typescript
|
|
136
|
-
import
|
|
137
|
-
|
|
180
|
+
import { createTable, createMigration, serial, varchar, text, timestamp } from 'driftsql'
|
|
181
|
+
|
|
182
|
+
// Define table
|
|
183
|
+
const usersTable = createTable('users', (table) => {
|
|
184
|
+
table
|
|
185
|
+
.column(serial('id').primaryKey())
|
|
186
|
+
.column(varchar('email', 255).unique().notNull())
|
|
187
|
+
.column(varchar('name', 255).notNull())
|
|
188
|
+
.column(text('bio'))
|
|
189
|
+
.column(timestamp('created_at').default('CURRENT_TIMESTAMP').notNull())
|
|
190
|
+
.index('idx_users_email', ['email'])
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
// Create migration
|
|
194
|
+
const migration = createMigration('postgres').createTable(usersTable).build('001', 'create_users_table')
|
|
195
|
+
|
|
196
|
+
// View generated SQL
|
|
197
|
+
console.log(migration.up) // CREATE TABLE statements
|
|
198
|
+
console.log(migration.down) // DROP TABLE statements
|
|
199
|
+
```
|
|
138
200
|
|
|
139
|
-
|
|
201
|
+
### Change Detection
|
|
140
202
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
203
|
+
```typescript
|
|
204
|
+
import { detectChanges, generateMigrationFromChanges } from 'driftsql'
|
|
205
|
+
|
|
206
|
+
const oldSchema = [
|
|
207
|
+
/* previous table definitions */
|
|
208
|
+
]
|
|
209
|
+
const newSchema = [
|
|
210
|
+
/* updated table definitions */
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
// Detect what changed
|
|
214
|
+
const changes = detectChanges(oldSchema, newSchema, 'postgres')
|
|
215
|
+
|
|
216
|
+
// Generate migration from changes
|
|
217
|
+
const migration = generateMigrationFromChanges(changes, '002', 'auto_migration')
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### CLI Commands
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Initialize project
|
|
224
|
+
driftsql init
|
|
225
|
+
|
|
226
|
+
# Create new migration
|
|
227
|
+
driftsql migrate:create add_users_table
|
|
228
|
+
|
|
229
|
+
# Run migrations
|
|
230
|
+
driftsql migrate:up
|
|
231
|
+
|
|
232
|
+
# Check migration status
|
|
233
|
+
driftsql migrate:status
|
|
234
|
+
|
|
235
|
+
# Rollback last migration
|
|
236
|
+
driftsql migrate:down
|
|
237
|
+
|
|
238
|
+
# Reset all migrations
|
|
239
|
+
driftsql migrate:reset
|
|
240
|
+
|
|
241
|
+
# Generate TypeScript types from database
|
|
242
|
+
driftsql db:inspect --output ./src/db-types.ts
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Performance Features
|
|
246
|
+
|
|
247
|
+
- **Connection Pooling**: Configurable pool size and timeouts
|
|
248
|
+
- **Query Caching**: Built-in LRU cache with TTL (default 5 seconds)
|
|
249
|
+
- **Smart Fallbacks**: Fast-path primary driver with automatic fallback support
|
|
250
|
+
- **Optimized Error Handling**: Reduced overhead in CRUD operations
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const client = new SQLClient({
|
|
254
|
+
driver: new PostgresDriver({
|
|
255
|
+
connectionString: process.env.DATABASE_URL!,
|
|
256
|
+
max: 10, // Pool size
|
|
257
|
+
idle_timeout: 30, // Seconds
|
|
258
|
+
connect_timeout: 10, // Seconds
|
|
259
|
+
}),
|
|
260
|
+
cacheTTL: 5000, // Cache TTL in ms
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
// Cache management
|
|
264
|
+
client.clearCache()
|
|
265
|
+
const stats = client.getCacheStats()
|
|
144
266
|
```
|
|
145
267
|
|
|
268
|
+
## Supported Databases
|
|
269
|
+
|
|
270
|
+
- ✅ **PostgreSQL** - Full feature support
|
|
271
|
+
- ✅ **MySQL** - Full feature support
|
|
272
|
+
- ✅ **SQLite** - Full feature support
|
|
273
|
+
- 🔄 More coming soon...
|
|
274
|
+
|
|
275
|
+
## Column Types
|
|
276
|
+
|
|
277
|
+
**Numeric**: `serial`, `bigserial`, `integer`, `bigint`, `smallint`, `decimal`, `numeric`, `real`, `doublePrecision`
|
|
278
|
+
|
|
279
|
+
**String**: `text`, `varchar`, `char`
|
|
280
|
+
|
|
281
|
+
**Date/Time**: `timestamp`, `timestamptz`, `date`, `time`
|
|
282
|
+
|
|
283
|
+
**Other**: `boolean`, `json`, `jsonb`, `uuid`, `bytea`
|
|
284
|
+
|
|
285
|
+
## Column Modifiers
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
column.primaryKey().notNull().unique().default(value).length(255).precision(10, 2).references('users', 'id').onDelete('CASCADE').check('age >= 18')
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Documentation
|
|
292
|
+
|
|
293
|
+
- [Schema Builder Guide](./SCHEMA.md) - Complete schema builder documentation
|
|
294
|
+
- [CLI Reference](./CLI.md) - All CLI commands and usage
|
|
295
|
+
|
|
296
|
+
## Examples
|
|
297
|
+
|
|
298
|
+
Check the `examples/` directory for:
|
|
299
|
+
|
|
300
|
+
- Basic schema creation
|
|
301
|
+
- Migration generation
|
|
302
|
+
- Change detection
|
|
303
|
+
- Multiple database dialects
|
|
304
|
+
|
|
305
|
+
## Contributing
|
|
306
|
+
|
|
307
|
+
Contributions are welcome! Please read our contributing guidelines.
|
|
308
|
+
|
|
146
309
|
## License
|
|
147
310
|
|
|
148
|
-
|
|
311
|
+
MIT
|
|
312
|
+
|
|
313
|
+
## Roadmap
|
|
314
|
+
|
|
315
|
+
- [x] PostgreSQL driver with helpers
|
|
316
|
+
- [x] Query caching
|
|
317
|
+
- [x] Schema builder
|
|
318
|
+
- [x] Migration system
|
|
319
|
+
- [x] Change detection
|
|
320
|
+
- [x] CLI tools
|
|
321
|
+
- [x] MySQL helpers
|
|
322
|
+
- [x] SQLite helpers
|
|
323
|
+
- [ ] MySQL driver implementation
|
|
324
|
+
- [ ] SQLite driver implementation
|
|
325
|
+
- [ ] More database drivers (SQL Server, Oracle, etc.)
|
|
326
|
+
- [ ] Schema diffing from live database
|
|
327
|
+
- [ ] Migration squashing
|
|
328
|
+
- [ ] Seeding system
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import"../postgres-9C7eE0wB.js";import{a as e,o as t,r as n,s as r}from"../src-B1L6LdRV.js";import"../type-generator-CpqI7vBb.js";import i from"consola";import a from"node:fs/promises";import o from"node:path";import{Command as s}from"commander";const c=new s;c.name(`driftsql`).description(`DriftSQL CLI - Database migrations and schema management`).version(`0.0.1`),c.command(`migrate:up`).description(`Run all pending migrations`).option(`-d, --dir <directory>`,`Migrations directory`,`./migrations`).option(`-c, --config <path>`,`Config file path`,`./driftsql.config.ts`).action(async e=>{try{let{client:t,migrations:n}=await u(e.dir,e.config);await new r(t).upAll(n),await t.close(),i.success(`All migrations applied successfully`)}catch(e){i.error(`Migration failed:`,e),process.exit(1)}}),c.command(`migrate:down`).description(`Rollback the last migration`).option(`-d, --dir <directory>`,`Migrations directory`,`./migrations`).option(`-c, --config <path>`,`Config file path`,`./driftsql.config.ts`).action(async e=>{try{let{client:t,migrations:n}=await u(e.dir,e.config),a=new r(t),o=await a.getAppliedMigrations(),s=n.find(e=>e.version===o[o.length-1]);s?await a.down(s):i.info(`No migrations to rollback`),await t.close()}catch(e){i.error(`Rollback failed:`,e),process.exit(1)}}),c.command(`migrate:reset`).description(`Reset all migrations (down then up)`).option(`-d, --dir <directory>`,`Migrations directory`,`./migrations`).option(`-c, --config <path>`,`Config file path`,`./driftsql.config.ts`).action(async e=>{try{let{client:t,migrations:n}=await u(e.dir,e.config);await new r(t).reset(n),await t.close(),i.success(`All migrations reset successfully`)}catch(e){i.error(`Reset failed:`,e),process.exit(1)}}),c.command(`migrate:status`).description(`Show migration status`).option(`-d, --dir <directory>`,`Migrations directory`,`./migrations`).option(`-c, --config <path>`,`Config file path`,`./driftsql.config.ts`).action(async e=>{try{let{client:t,migrations:n}=await u(e.dir,e.config),a=await new r(t).getAppliedMigrations();i.info(`Migration Status:
|
|
3
|
+
`);for(let e of n){let t=a.includes(e.version)?`✓ Applied`:`✗ Pending`;i.log(`${t} - ${e.version} (${e.name})`)}await t.close()}catch(e){i.error(`Failed to get status:`,e),process.exit(1)}}),c.command(`migrate:create <name>`).description(`Create a new migration file`).option(`-d, --dir <directory>`,`Migrations directory`,`./migrations`).action(async(e,t)=>{try{let n=new Date().toISOString().replace(/[-:T.]/g,``).slice(0,14),r=`${n}_${e}.ts`,s=o.join(t.dir,r);await a.mkdir(t.dir,{recursive:!0});let c=`import { createMigration } from 'driftsql'
|
|
4
|
+
|
|
5
|
+
export const migration = createMigration('postgres')
|
|
6
|
+
.raw('-- Add your migration SQL here')
|
|
7
|
+
.build('${n}', '${e}')
|
|
8
|
+
`;await a.writeFile(s,c,`utf8`),i.success(`Created migration: ${r}`)}catch(e){i.error(`Failed to create migration:`,e),process.exit(1)}}),c.command(`migrate:generate [name]`).description(`Automatically generate migration from schema changes`).option(`-s, --schema <path>`,`Schema file path`,`./schema.ts`).option(`-d, --dir <directory>`,`Migrations directory`,`./migrations`).action(async(r,s)=>{try{let c=new n,l=o.resolve(process.cwd(),s.schema);i.start(`Loading schema...`);let u=await import(l),d=u.default||u.schema;(!d||!Array.isArray(d))&&(i.error(`Schema file must export default or named "schema" as an array of table definitions`),i.info(`Example: export default [usersTable.getDefinition(), postsTable.getDefinition()]`),process.exit(1));let f=d,p=await c.load();if(!p){i.info(`No previous schema snapshot found, creating initial migration...`);let e=new Date().toISOString().replace(/[-:T.]/g,``).slice(0,14),t=r||`initial`,n=`${e}_${t}.ts`,l=o.join(s.dir,n);await a.mkdir(s.dir,{recursive:!0});let{PostgresGenerator:u}=await import(`../postgres-DfhzvfQU.js`),d=new u,p=f.map(e=>d.generateCreateTable(e)).map(e=>` .raw(\`${e.replace(/`/g,"\\`")}\`)`).join(`
|
|
9
|
+
`),m=`import { createMigration } from 'driftsql'
|
|
10
|
+
|
|
11
|
+
// Initial migration - automatically generated
|
|
12
|
+
// Generated at: ${new Date().toISOString()}
|
|
13
|
+
|
|
14
|
+
export const migration = createMigration('postgres')
|
|
15
|
+
${p}
|
|
16
|
+
.build('${e}', '${t}')
|
|
17
|
+
`;await a.writeFile(l,m,`utf8`),await c.save(f);let{generateTypesFromSchema:h}=await import(`../type-generator-DdCKALf8.js`);await h(f,o.join(process.cwd(),`db-types.ts`)),i.success(`\nCreated initial migration: ${n}`),i.success(`Generated TypeScript types: db-types.ts`),i.info(`Snapshot saved. Run "driftsql migrate:up" to apply changes.`);return}i.info(`Detecting changes...`);let m=e(p.tables,f,`postgres`);if(m.length===0){i.success(`No schema changes detected!`);return}i.info(`Found ${m.length} change(s):`),m.forEach((e,t)=>{i.log(` ${t+1}. ${e.type} - ${e.table}`)});let h=new Date().toISOString().replace(/[-:T.]/g,``).slice(0,14),g=r||`auto_migration`,_=`${h}_${g}.ts`,v=o.join(s.dir,_);await a.mkdir(s.dir,{recursive:!0});let y=t(m,h,g).build(h,g).up.map(e=>` .raw(\`${e.replace(/`/g,"\\`")}\``).join(`
|
|
18
|
+
`),b=`import { createMigration } from 'driftsql'
|
|
19
|
+
|
|
20
|
+
// This migration was automatically generated
|
|
21
|
+
// Generated at: ${new Date().toISOString()}
|
|
22
|
+
// Changes: ${m.length}
|
|
23
|
+
|
|
24
|
+
export const migration = createMigration('postgres')
|
|
25
|
+
${y}
|
|
26
|
+
.build('${h}', '${g}')
|
|
27
|
+
`;await a.writeFile(v,b,`utf8`),await c.save(f);let{generateTypesFromSchema:x}=await import(`../type-generator-DdCKALf8.js`);await x(f,o.join(process.cwd(),`db-types.ts`)),i.success(`\nGenerated migration: ${_}`),i.success(`Updated TypeScript types: db-types.ts`),i.info(`Snapshot updated. Run "driftsql migrate:up" to apply changes.`)}catch(e){i.error(`Failed to generate migration:`,e),process.exit(1)}}),c.command(`db:inspect`).description(`Inspect database and generate TypeScript types`).option(`-c, --config <path>`,`Config file path`,`./driftsql.config.ts`).option(`-o, --output <path>`,`Output file path`,`./db-types.ts`).action(async e=>{try{let t=await l(e.config);await t.inspectDB({driver:t.getDriver(),outputFile:e.output}),await t.close()}catch(e){i.error(`Inspection failed:`,e),process.exit(1)}}),c.command(`generate:types`).description(`Generate TypeScript types from schema file`).option(`-s, --schema <path>`,`Schema file path`,`./schema.ts`).option(`-o, --output <path>`,`Output file path`,`./db-types.ts`).action(async e=>{try{let t=o.resolve(process.cwd(),e.schema),n=o.resolve(process.cwd(),e.output);i.start(`Loading schema...`);let r=await import(t),a=r.default||r.schema;(!a||!Array.isArray(a))&&(i.error(`Schema file must export default or named "schema" as an array of table definitions`),process.exit(1));let{generateTypesFromSchema:s}=await import(`../type-generator-DdCKALf8.js`);await s(a,n),i.success(`TypeScript types generated: ${e.output}`)}catch(e){i.error(`Type generation failed:`,e),process.exit(1)}}),c.command(`init`).description(`Initialize DriftSQL with a basic notes schema`).option(`-d, --dir <directory>`,`Migrations directory`,`./migrations`).action(async e=>{try{await a.mkdir(e.dir,{recursive:!0});let t=`.driftsql/
|
|
28
|
+
.env
|
|
29
|
+
`,n=o.join(process.cwd(),`driftsql.config.ts`),r=o.join(process.cwd(),`schema.ts`),s=o.join(process.cwd(),`.env.example`),c=o.join(process.cwd(),`.gitignore`),l=[{path:n,content:`import { SQLClient, PostgresDriver } from 'driftsql'
|
|
30
|
+
|
|
31
|
+
export default new SQLClient({
|
|
32
|
+
driver: new PostgresDriver({
|
|
33
|
+
connectionString: process.env.DATABASE_URL!,
|
|
34
|
+
}),
|
|
35
|
+
})
|
|
36
|
+
`,name:`driftsql.config.ts`},{path:r,content:`import { createTable, serial, varchar, text, timestamp, boolean } from 'driftsql'
|
|
37
|
+
|
|
38
|
+
const notesTable = createTable('notes', (table) => {
|
|
39
|
+
table
|
|
40
|
+
.column(serial('id').primaryKey())
|
|
41
|
+
.column(varchar('title', 255).notNull())
|
|
42
|
+
.column(text('content'))
|
|
43
|
+
.column(boolean('is_archived').default(false).notNull())
|
|
44
|
+
.column(timestamp('created_at').default('CURRENT_TIMESTAMP').notNull())
|
|
45
|
+
.column(timestamp('updated_at').default('CURRENT_TIMESTAMP').notNull())
|
|
46
|
+
.index('idx_notes_archived', ['is_archived'])
|
|
47
|
+
.index('idx_notes_created_at', ['created_at'])
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// Export array of table definitions
|
|
51
|
+
export default [notesTable.getDefinition()]
|
|
52
|
+
`,name:`schema.ts`},{path:s,content:`DATABASE_URL=postgresql://user:password@localhost:5432/mydb
|
|
53
|
+
`,name:`.env.example`}];for(let e of l)try{await a.access(e.path),i.warn(`${e.name} already exists, skipping...`)}catch{await a.writeFile(e.path,e.content,`utf8`),i.success(`Created ${e.name}`)}try{(await a.readFile(c,`utf8`)).includes(`.driftsql/`)||(await a.appendFile(c,`
|
|
54
|
+
`+t),i.success(`Updated .gitignore`))}catch{await a.writeFile(c,t,`utf8`),i.success(`Created .gitignore`)}i.success(`
|
|
55
|
+
✨ DriftSQL initialized successfully!
|
|
56
|
+
`),i.info(`Next steps:`),i.info(`1. Copy .env.example to .env and update DATABASE_URL`),i.info(`2. Run: driftsql migrate:generate initial (generates migration + types)`),i.info(`3. Run: driftsql migrate:up`),i.info(`4. Import Database type from db-types.ts for type safety`),i.info(`5. Edit schema.ts and run migrate:generate to auto-detect changes!
|
|
57
|
+
`)}catch(e){i.error(`Initialization failed:`,e),process.exit(1)}});async function l(e){try{let t=await import(o.resolve(process.cwd(),e));return t.default||t.client}catch(t){throw i.error(`Failed to load config from ${e}`),t}}async function u(e,t){let n=await l(t),r=[];try{let t=o.resolve(process.cwd(),e),i=(await a.readdir(t)).filter(e=>e.endsWith(`.ts`)||e.endsWith(`.js`)).sort();for(let e of i){let n=await import(o.join(t,e)),i=n.migration||n.default;i&&r.push(i)}return{client:n,migrations:r}}catch(t){throw i.error(`Failed to load migrations from ${e}`),t}}c.parse();export{};
|