flint-orm 0.6.0 → 0.7.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 +2 -0
- package/dist/drivers/better-sqlite3.d.ts +6 -2
- package/dist/drivers/bun-sqlite.d.ts +6 -2
- package/dist/drivers/lazy-executor.d.ts +3 -1
- package/dist/drivers/libsql-web.d.ts +6 -2
- package/dist/drivers/libsql.d.ts +6 -2
- package/dist/drivers/turso-sync.d.ts +6 -2
- package/dist/drivers/turso.d.ts +6 -2
- package/dist/executor.d.ts +4 -2
- package/dist/flint.d.ts +3 -1
- package/dist/query/builder.d.ts +9 -3
- package/dist/src/cli.js +15 -14
- package/dist/src/entries/better-sqlite3.js +5 -8
- package/dist/src/entries/bun-sqlite.js +5 -8
- package/dist/src/entries/expressions.js +3 -6
- package/dist/src/entries/libsql-web.js +5 -7
- package/dist/src/entries/libsql.js +5 -7
- package/dist/src/entries/turso-sync.js +5 -7
- package/dist/src/entries/turso.js +5 -7
- package/dist/src/index.js +3 -6
- package/package.json +15 -3
- package/skills/batch-transactions/SKILL.md +120 -0
- package/skills/define-schema/SKILL.md +212 -0
- package/skills/define-schema/references/column-modifiers.md +176 -0
- package/skills/driver-selection/SKILL.md +180 -0
- package/skills/driver-selection/references/driver-comparison.md +141 -0
- package/skills/run-migrations/SKILL.md +163 -0
- package/skills/setup-client/SKILL.md +142 -0
- package/skills/update-schema/SKILL.md +186 -0
- package/skills/write-queries/SKILL.md +267 -0
- package/skills/write-queries/references/condition-operators.md +220 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Driver Comparison Reference
|
|
2
|
+
|
|
3
|
+
Detailed comparison of all flint-orm drivers.
|
|
4
|
+
|
|
5
|
+
## bun:sqlite
|
|
6
|
+
|
|
7
|
+
**Runtime:** Bun only
|
|
8
|
+
**Type:** Sync (Promise-wrapped for uniform API)
|
|
9
|
+
**Install:** Built into Bun — no separate install needed
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { flint } from 'flint-orm/bun-sqlite';
|
|
13
|
+
const db = flint({ url: './app.db' });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Options:**
|
|
17
|
+
- `url: string` — Path to SQLite file or `:memory:`
|
|
18
|
+
|
|
19
|
+
**Limitations:**
|
|
20
|
+
- Only works in Bun runtime
|
|
21
|
+
- No remote database support
|
|
22
|
+
- No authentication support
|
|
23
|
+
|
|
24
|
+
## better-sqlite3
|
|
25
|
+
|
|
26
|
+
**Runtime:** Node.js
|
|
27
|
+
**Type:** Sync (Promise-wrapped for uniform API)
|
|
28
|
+
**Install:** `npm install better-sqlite3`
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { flint } from 'flint-orm/better-sqlite3';
|
|
32
|
+
const db = flint({ url: './app.db' });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Options:**
|
|
36
|
+
- `url: string` — Path to SQLite file or `:memory:`
|
|
37
|
+
|
|
38
|
+
**Limitations:**
|
|
39
|
+
- No remote database support
|
|
40
|
+
- No authentication support
|
|
41
|
+
|
|
42
|
+
## @libsql/client
|
|
43
|
+
|
|
44
|
+
**Runtime:** Bun/Node.js
|
|
45
|
+
**Type:** Async
|
|
46
|
+
**Install:** `npm install @libsql/client`
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { flint } from 'flint-orm/libsql';
|
|
50
|
+
const db = flint({
|
|
51
|
+
url: 'libsql://your-db.turso.io',
|
|
52
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Options:**
|
|
57
|
+
- `url: string` — Local file (`file:./app.db`), remote (`libsql://...`), or in-memory (`:memory:`)
|
|
58
|
+
- `authToken: string` — Required for remote databases
|
|
59
|
+
|
|
60
|
+
**Capabilities:**
|
|
61
|
+
- Local file access
|
|
62
|
+
- Remote database access
|
|
63
|
+
- Serverless compatible
|
|
64
|
+
- Authentication support
|
|
65
|
+
|
|
66
|
+
## @libsql/client/web
|
|
67
|
+
|
|
68
|
+
**Runtime:** Any (browser, edge, serverless)
|
|
69
|
+
**Type:** Async
|
|
70
|
+
**Install:** `npm install @libsql/client`
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { flint } from 'flint-orm/libsql-web';
|
|
74
|
+
const db = flint({
|
|
75
|
+
url: 'libsql://your-db.turso.io',
|
|
76
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Options:**
|
|
81
|
+
- `url: string` — Remote only (`ws://`, `wss://`, `http://`, `https://`)
|
|
82
|
+
- `authToken: string` — Required for remote databases
|
|
83
|
+
|
|
84
|
+
**Capabilities:**
|
|
85
|
+
- No native binary — works in any JavaScript runtime
|
|
86
|
+
- Serverless/edge optimized
|
|
87
|
+
- Authentication support
|
|
88
|
+
|
|
89
|
+
**Limitations:**
|
|
90
|
+
- No local file access (`file:` URLs not supported)
|
|
91
|
+
- No in-memory database support
|
|
92
|
+
|
|
93
|
+
## @tursodatabase/database
|
|
94
|
+
|
|
95
|
+
**Runtime:** Bun/Node.js
|
|
96
|
+
**Type:** Async
|
|
97
|
+
**Install:** `npm install @tursodatabase/database`
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { flint } from 'flint-orm/turso';
|
|
101
|
+
const db = flint({
|
|
102
|
+
url: 'libsql://your-db.turso.io',
|
|
103
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Options:**
|
|
108
|
+
- `url: string` — Local file or remote Turso database
|
|
109
|
+
- `authToken: string` — Required for remote databases
|
|
110
|
+
|
|
111
|
+
## @tursodatabase/sync
|
|
112
|
+
|
|
113
|
+
**Runtime:** Bun/Node.js
|
|
114
|
+
**Type:** Async
|
|
115
|
+
**Install:** `npm install @tursodatabase/sync`
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { flint } from 'flint-orm/turso-sync';
|
|
119
|
+
const db = flint({
|
|
120
|
+
url: 'libsql://your-db.turso.io',
|
|
121
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Options:**
|
|
126
|
+
- `url: string` — Local file or remote Turso database
|
|
127
|
+
- `authToken: string` — Required for remote databases
|
|
128
|
+
|
|
129
|
+
**Capabilities:**
|
|
130
|
+
- Includes sync support for offline-first applications
|
|
131
|
+
|
|
132
|
+
## Decision Guide
|
|
133
|
+
|
|
134
|
+
| Use Case | Recommended Driver |
|
|
135
|
+
|----------|-------------------|
|
|
136
|
+
| Bun runtime, local file | bun:sqlite |
|
|
137
|
+
| Node.js, local file | better-sqlite3 |
|
|
138
|
+
| Remote Turso database | libsql |
|
|
139
|
+
| Serverless/edge | libsql-web |
|
|
140
|
+
| Turso with sync | turso-sync |
|
|
141
|
+
| Testing/prototyping | Any with `:memory:` |
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-migrations
|
|
3
|
+
description: >
|
|
4
|
+
Generate and apply schema migrations safely using the CLI or programmatic
|
|
5
|
+
API. Covers flint generate, flint migrate, flint.config.ts, and the
|
|
6
|
+
migration pipeline (serialize → diff → generateSQL). Load when creating
|
|
7
|
+
or applying migrations, or when troubleshooting migration issues.
|
|
8
|
+
metadata:
|
|
9
|
+
type: core
|
|
10
|
+
library: flint-orm
|
|
11
|
+
library_version: 0.7.0
|
|
12
|
+
sources:
|
|
13
|
+
- 'kavenlabs/flint-orm:src/migration/generate.ts'
|
|
14
|
+
- 'kavenlabs/flint-orm:src/migration/migrate.ts'
|
|
15
|
+
- 'kavenlabs/flint-orm:src/migration/sql.ts'
|
|
16
|
+
- 'kavenlabs/flint-orm:src/cli.ts'
|
|
17
|
+
- 'kavenlabs/flint-orm:README.md'
|
|
18
|
+
- 'kavenlabs/flint-orm:API.md'
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# flint-orm — Migrations
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
### flint.config.ts
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { defineConfig } from 'flint-orm/config';
|
|
29
|
+
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
driver: 'bun-sqlite', // Must match the driver you import in your app
|
|
32
|
+
database: {
|
|
33
|
+
url: './app.db',
|
|
34
|
+
},
|
|
35
|
+
schema: './src/schema',
|
|
36
|
+
migrations: './flint',
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### CLI commands
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Generate a migration from schema changes
|
|
44
|
+
flint generate
|
|
45
|
+
flint generate --name add_users_table
|
|
46
|
+
flint generate --preview # Show SQL without writing
|
|
47
|
+
|
|
48
|
+
# Apply pending migrations
|
|
49
|
+
flint migrate
|
|
50
|
+
flint migrate --dry-run # Show what would run
|
|
51
|
+
flint migrate --status # Show applied vs pending
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Core Patterns
|
|
55
|
+
|
|
56
|
+
### Generate initial migration
|
|
57
|
+
|
|
58
|
+
After defining your schema, generate the first migration:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
flint generate --name init_schema
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This creates a folder in `./flint/` with:
|
|
65
|
+
- `migration.ts` — The operations to apply
|
|
66
|
+
- `state.json` — Snapshot of the schema
|
|
67
|
+
|
|
68
|
+
### Apply migrations
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
flint migrate
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This:
|
|
75
|
+
1. Reads pending migrations from the migrations directory
|
|
76
|
+
2. Applies them in order within transactions
|
|
77
|
+
3. Records applied migrations in `__flint_migrations` table
|
|
78
|
+
|
|
79
|
+
### Preview before applying
|
|
80
|
+
|
|
81
|
+
Always preview before applying in production:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
flint generate --preview # Review the SQL
|
|
85
|
+
flint migrate --dry-run # Verify what would run
|
|
86
|
+
flint migrate # Apply with confidence
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Programmatic API
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { flint } from 'flint-orm/bun-sqlite';
|
|
93
|
+
import { generate, migrate, getMigrationStatus } from 'flint-orm/migration';
|
|
94
|
+
|
|
95
|
+
const db = flint({ url: './app.db' });
|
|
96
|
+
|
|
97
|
+
// Generate a migration
|
|
98
|
+
await generate([users, posts], './flint', {
|
|
99
|
+
name: 'add_posts',
|
|
100
|
+
interactive: true,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// Apply pending migrations
|
|
104
|
+
const result = await migrate(db.$executor, { migrationsDir: './flint' });
|
|
105
|
+
console.log(`Applied: ${result.applied.join(', ')}`);
|
|
106
|
+
|
|
107
|
+
// Check status
|
|
108
|
+
const status = await getMigrationStatus(db.$executor, './flint');
|
|
109
|
+
console.log(`Pending: ${status.pending.length}`);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## How It Works
|
|
113
|
+
|
|
114
|
+
1. `flint generate` serializes your `table()` definitions to JSON
|
|
115
|
+
2. Diffs against the last migration's `state.json`
|
|
116
|
+
3. Detects adds, drops, renames, and safe modifications
|
|
117
|
+
4. Prompts to confirm potential renames (interactive mode)
|
|
118
|
+
5. Writes a migration folder with `migration.ts` + `state.json`
|
|
119
|
+
6. `flint migrate` reads pending migrations and executes them in order
|
|
120
|
+
|
|
121
|
+
## Common Mistakes
|
|
122
|
+
|
|
123
|
+
### HIGH Running migrate without generate first
|
|
124
|
+
|
|
125
|
+
Wrong:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
// Modifying schema, then:
|
|
129
|
+
flint migrate // No migration files exist yet!
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Correct:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
// After schema changes:
|
|
136
|
+
flint generate --name add_users_table
|
|
137
|
+
flint migrate
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`migrate` applies existing migration files — you must generate them first from schema changes.
|
|
141
|
+
|
|
142
|
+
Source: README.md
|
|
143
|
+
|
|
144
|
+
### HIGH Not using --preview or --dry-run before applying
|
|
145
|
+
|
|
146
|
+
Wrong:
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
flint generate
|
|
150
|
+
flint migrate // Applies without preview
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Correct:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
flint generate --preview // Review the SQL
|
|
157
|
+
flint migrate --dry-run // Verify what would run
|
|
158
|
+
flint migrate // Apply with confidence
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Migrations can be destructive (dropping columns, rebuilding tables). Always preview first.
|
|
162
|
+
|
|
163
|
+
Source: README.md
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup-client
|
|
3
|
+
description: >
|
|
4
|
+
Install flint-orm, choose a driver, and connect to a database. Covers
|
|
5
|
+
flint() factory, driver entry points (bun-sqlite, better-sqlite3, libsql,
|
|
6
|
+
libsql-web, turso, turso-sync), and flint.config.ts configuration. Load
|
|
7
|
+
when setting up a new project or switching drivers.
|
|
8
|
+
metadata:
|
|
9
|
+
type: core
|
|
10
|
+
library: flint-orm
|
|
11
|
+
library_version: 0.7.0
|
|
12
|
+
sources:
|
|
13
|
+
- 'kavenlabs/flint-orm:src/entries/bun-sqlite.ts'
|
|
14
|
+
- 'kavenlabs/flint-orm:src/entries/libsql.ts'
|
|
15
|
+
- 'kavenlabs/flint-orm:src/entries/libsql-web.ts'
|
|
16
|
+
- 'kavenlabs/flint-orm:src/entries/better-sqlite3.ts'
|
|
17
|
+
- 'kavenlabs/flint-orm:README.md'
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# flint-orm — Client Setup
|
|
21
|
+
|
|
22
|
+
flint-orm is a type-safe, driver-agnostic SQLite ORM for JavaScript. One schema, any driver.
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
### Install with a driver
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Choose ONE driver (bun:sqlite is built into Bun, no install needed):
|
|
30
|
+
bun add flint-orm # bun:sqlite (sync, Promise-wrapped) — Bun only
|
|
31
|
+
bun add flint-orm better-sqlite3 # better-sqlite3 (sync, Promise-wrapped)
|
|
32
|
+
bun add flint-orm @libsql/client # libsql (async, local or remote)
|
|
33
|
+
bun add flint-orm @libsql/client # libsql-web (async, serverless, no file: support)
|
|
34
|
+
bun add flint-orm @tursodatabase/database # turso (async)
|
|
35
|
+
bun add flint-orm @tursodatabase/sync # turso-sync (async, authToken)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Initialize the client
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { flint } from 'flint-orm/bun-sqlite';
|
|
42
|
+
|
|
43
|
+
const db = flint({ url: './app.db' });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Create flint.config.ts
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { defineConfig } from 'flint-orm/config';
|
|
50
|
+
|
|
51
|
+
export default defineConfig({
|
|
52
|
+
driver: 'bun-sqlite', // Must match the driver you import in your app
|
|
53
|
+
database: {
|
|
54
|
+
url: './app.db',
|
|
55
|
+
},
|
|
56
|
+
schema: './src/schema',
|
|
57
|
+
migrations: './flint',
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Core Patterns
|
|
62
|
+
|
|
63
|
+
### Connect to a local file
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { flint } from 'flint-orm/bun-sqlite';
|
|
67
|
+
|
|
68
|
+
const db = flint({ url: './app.db' });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Connect to a remote database
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { flint } from 'flint-orm/libsql';
|
|
75
|
+
|
|
76
|
+
const db = flint({
|
|
77
|
+
url: 'libsql://your-db.turso.io',
|
|
78
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Connect in a serverless environment
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { flint } from 'flint-orm/libsql-web';
|
|
86
|
+
|
|
87
|
+
// libsql-web only supports ws://, wss://, http://, https:// URLs
|
|
88
|
+
const db = flint({
|
|
89
|
+
url: 'libsql://your-db.turso.io',
|
|
90
|
+
authToken: process.env.TURSO_AUTH_TOKEN,
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Common Mistakes
|
|
95
|
+
|
|
96
|
+
### CRITICAL Driver mismatch between config and app
|
|
97
|
+
|
|
98
|
+
Wrong:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// flint.config.ts
|
|
102
|
+
export default defineConfig({ driver: 'bun-sqlite', ... });
|
|
103
|
+
|
|
104
|
+
// app.ts
|
|
105
|
+
import { flint } from 'flint-orm/libsql'; // MISMATCH
|
|
106
|
+
const db = flint({ url: '...' });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Correct:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
// flint.config.ts
|
|
113
|
+
export default defineConfig({ driver: 'libsql', ... });
|
|
114
|
+
|
|
115
|
+
// app.ts
|
|
116
|
+
import { flint } from 'flint-orm/libsql'; // MATCHES
|
|
117
|
+
const db = flint({ url: '...' });
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The CLI uses flint.config.ts to determine which driver to use for migrations, but the app uses whichever driver you import — these must match.
|
|
121
|
+
|
|
122
|
+
Source: maintainer interview
|
|
123
|
+
|
|
124
|
+
### HIGH Using libsql-web for local file databases
|
|
125
|
+
|
|
126
|
+
Wrong:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { flint } from 'flint-orm/libsql-web';
|
|
130
|
+
const db = flint({ url: './app.db' }); // ERROR: file: not supported
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Correct:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import { flint } from 'flint-orm/libsql';
|
|
137
|
+
const db = flint({ url: './app.db' });
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
libsql-web only supports ws:, wss:, http:, https: URLs — it has no native binary and cannot access local files. Use the regular libsql driver for local files.
|
|
141
|
+
|
|
142
|
+
Source: src/entries/libsql-web.ts
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: update-schema
|
|
3
|
+
description: >
|
|
4
|
+
Add columns and tables without data loss. Covers safe vs unsafe migrations,
|
|
5
|
+
rebuildTable operation, additive migration patterns, and which changes
|
|
6
|
+
trigger table rebuilds. Load when modifying schema after initial migration
|
|
7
|
+
or when planning schema evolution.
|
|
8
|
+
metadata:
|
|
9
|
+
type: core
|
|
10
|
+
library: flint-orm
|
|
11
|
+
library_version: 0.7.0
|
|
12
|
+
sources:
|
|
13
|
+
- 'kavenlabs/flint-orm:src/migration/diff.ts'
|
|
14
|
+
- 'kavenlabs/flint-orm:src/migration/sql.ts'
|
|
15
|
+
- 'kavenlabs/flint-orm:src/migration/migrate.ts'
|
|
16
|
+
- 'kavenlabs/flint-orm:README.md'
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# flint-orm — Schema Updates
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
After defining your initial schema, you'll need to evolve it over time. flint-orm detects changes and generates appropriate migrations.
|
|
24
|
+
|
|
25
|
+
## Core Patterns
|
|
26
|
+
|
|
27
|
+
### Safe migration: Adding a column with default
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// Add a new column with a default value — safe, no data loss
|
|
31
|
+
const users = snakeCase.table('users', {
|
|
32
|
+
id: integer().autoIncrement().primaryKey(),
|
|
33
|
+
name: text().notNull(),
|
|
34
|
+
status: text().notNull().default('active'), // NEW: safe to add
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Safe migration: Adding a new table
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// Add a new table — always safe
|
|
42
|
+
const posts = snakeCase.table('posts', {
|
|
43
|
+
id: integer().autoIncrement().primaryKey(),
|
|
44
|
+
userId: integer().notNull().references(users.id),
|
|
45
|
+
title: text().notNull(),
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Unsafe migration: Changing column type
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// Changing a column type triggers a table rebuild
|
|
53
|
+
// The old column was: age: text('age')
|
|
54
|
+
// The new column is: age: integer('age')
|
|
55
|
+
const users = snakeCase.table('users', {
|
|
56
|
+
id: integer().autoIncrement().primaryKey(),
|
|
57
|
+
name: text().notNull(),
|
|
58
|
+
age: integer('age').notNull().default(0), // TYPE CHANGE: triggers rebuild
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Unsafe migration: Adding NOT NULL without default
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// Adding NOT NULL without a default triggers a table rebuild
|
|
66
|
+
const users = snakeCase.table('users', {
|
|
67
|
+
id: integer().autoIncrement().primaryKey(),
|
|
68
|
+
name: text().notNull(),
|
|
69
|
+
status: text().notNull(), // NO DEFAULT: triggers rebuild
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Migration Safety Reference
|
|
74
|
+
|
|
75
|
+
### Safe changes (no rebuild)
|
|
76
|
+
|
|
77
|
+
| Change | Example |
|
|
78
|
+
|--------|---------|
|
|
79
|
+
| Add column with default | `status: text().default('active')` |
|
|
80
|
+
| Add new table | `snakeCase.table('new_table', {...})` |
|
|
81
|
+
| Add index | `index('idx_name').on(t.name)` |
|
|
82
|
+
| Drop index | Remove from index callback |
|
|
83
|
+
| Change default value | `status: text().default('inactive')` |
|
|
84
|
+
|
|
85
|
+
### Unsafe changes (triggers rebuild)
|
|
86
|
+
|
|
87
|
+
| Change | Example |
|
|
88
|
+
|--------|---------|
|
|
89
|
+
| Change column type | `text()` → `integer()` |
|
|
90
|
+
| Add NOT NULL without default | `text().notNull()` (no `.default()`) |
|
|
91
|
+
| Remove NOT NULL | `text().notNull()` → `text()` |
|
|
92
|
+
| Add/remove UNIQUE | `text().unique()` → `text()` |
|
|
93
|
+
| Remove default | `text().default('x')` → `text()` |
|
|
94
|
+
| Add/change/remove foreign key | `.references(col)` changes |
|
|
95
|
+
| Change FK actions | `.onDelete('cascade')` changes |
|
|
96
|
+
| Change autoincrement | `.autoIncrement()` changes |
|
|
97
|
+
|
|
98
|
+
### What is rebuildTable?
|
|
99
|
+
|
|
100
|
+
When an unsafe change is detected, flint-orm generates a `rebuildTable` operation that:
|
|
101
|
+
|
|
102
|
+
1. Creates a temporary table with the new schema
|
|
103
|
+
2. Copies data from the old table
|
|
104
|
+
3. Drops the old table
|
|
105
|
+
4. Renames the temporary table to the original name
|
|
106
|
+
5. Recreates indexes
|
|
107
|
+
|
|
108
|
+
This happens within a transaction — if anything fails, the original table is preserved.
|
|
109
|
+
|
|
110
|
+
## Common Mistakes
|
|
111
|
+
|
|
112
|
+
### HIGH Adding NOT NULL column without a default
|
|
113
|
+
|
|
114
|
+
Wrong:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// After initial migration, adding:
|
|
118
|
+
const users = snakeCase.table('users', {
|
|
119
|
+
id: integer().autoIncrement().primaryKey(),
|
|
120
|
+
name: text().notNull(),
|
|
121
|
+
status: text().notNull(), // No default — triggers rebuild
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Correct:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const users = snakeCase.table('users', {
|
|
129
|
+
id: integer().autoIncrement().primaryKey(),
|
|
130
|
+
name: text().notNull(),
|
|
131
|
+
status: text().notNull().default('active'), // Safe: has default
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
SQLite cannot add NOT NULL columns to existing tables without a default — this triggers a table rebuild.
|
|
136
|
+
|
|
137
|
+
Source: src/migration/diff.ts
|
|
138
|
+
|
|
139
|
+
### HIGH Changing a column type
|
|
140
|
+
|
|
141
|
+
Wrong:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
// Changing after initial migration:
|
|
145
|
+
const users = snakeCase.table('users', {
|
|
146
|
+
id: integer().autoIncrement().primaryKey(),
|
|
147
|
+
name: text().notNull(),
|
|
148
|
+
age: integer('age'), // Was: age: text('age')
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Correct:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// Plan for the type from the start, or accept the rebuild
|
|
156
|
+
const users = snakeCase.table('users', {
|
|
157
|
+
id: integer().autoIncrement().primaryKey(),
|
|
158
|
+
name: text().notNull(),
|
|
159
|
+
age: integer('age').notNull().default(0), // Correct type from start
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
SQLite has no `ALTER COLUMN TYPE` — this always triggers a table rebuild.
|
|
164
|
+
|
|
165
|
+
Source: src/migration/diff.ts
|
|
166
|
+
|
|
167
|
+
### HIGH Dropping a column referenced by foreign keys
|
|
168
|
+
|
|
169
|
+
Wrong:
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
// Dropping users.id when orders.userId references it
|
|
173
|
+
// Migration fails with: Cannot rebuild "users" — referenced by: orders
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Correct:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Migrate dependent tables first, then rebuild the parent
|
|
180
|
+
flint migrate # Apply orders migration first
|
|
181
|
+
flint generate # Then rebuild users
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The migration runner checks for incoming foreign keys before rebuild — it will refuse if other tables reference the table being rebuilt.
|
|
185
|
+
|
|
186
|
+
Source: src/migration/migrate.ts
|