@shaferllc/keel 0.66.0 → 0.74.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/AGENTS.md +169 -0
- package/README.md +44 -6
- package/bin/keel-mcp.mjs +9 -0
- package/dist/api/api.config.stub +9 -0
- package/dist/api/config.d.ts +13 -0
- package/dist/api/config.js +14 -0
- package/dist/api/index.d.ts +16 -0
- package/dist/api/index.js +13 -0
- package/dist/api/provider.d.ts +10 -0
- package/dist/api/provider.js +17 -0
- package/dist/api/query.d.ts +35 -0
- package/dist/api/query.js +42 -0
- package/dist/api/resource.d.ts +91 -0
- package/dist/api/resource.js +188 -0
- package/dist/core/application.d.ts +5 -5
- package/dist/core/application.js +8 -2
- package/dist/core/cache.d.ts +81 -5
- package/dist/core/cache.js +188 -23
- package/dist/core/cli/stubs.d.ts +26 -0
- package/dist/core/cli/stubs.js +225 -0
- package/dist/core/console-prompt.d.ts +79 -0
- package/dist/core/console-prompt.js +239 -0
- package/dist/core/console-ui.d.ts +96 -0
- package/dist/core/console-ui.js +187 -0
- package/dist/core/console.d.ts +188 -0
- package/dist/core/console.js +395 -0
- package/dist/core/database.d.ts +70 -1
- package/dist/core/database.js +174 -15
- package/dist/core/env.d.ts +96 -0
- package/dist/core/env.js +140 -0
- package/dist/core/events.d.ts +129 -5
- package/dist/core/events.js +165 -7
- package/dist/core/health.d.ts +141 -0
- package/dist/core/health.js +226 -0
- package/dist/core/helpers.d.ts +9 -3
- package/dist/core/helpers.js +11 -3
- package/dist/core/http/kernel.d.ts +2 -0
- package/dist/core/http/kernel.js +48 -0
- package/dist/core/http/router.d.ts +5 -5
- package/dist/core/http/router.js +5 -5
- package/dist/core/i18n.d.ts +162 -0
- package/dist/core/i18n.js +472 -0
- package/dist/core/index.d.ts +39 -13
- package/dist/core/index.js +19 -6
- package/dist/core/instrumentation.d.ts +113 -0
- package/dist/core/instrumentation.js +52 -0
- package/dist/core/lock.d.ts +139 -0
- package/dist/core/lock.js +215 -0
- package/dist/core/logger.d.ts +89 -4
- package/dist/core/logger.js +167 -22
- package/dist/core/mail.d.ts +128 -7
- package/dist/core/mail.js +264 -16
- package/dist/core/notification.js +10 -1
- package/dist/core/package.d.ts +120 -0
- package/dist/core/package.js +169 -0
- package/dist/core/pages.d.ts +108 -0
- package/dist/core/pages.js +199 -0
- package/dist/core/queue.d.ts +134 -9
- package/dist/core/queue.js +325 -14
- package/dist/core/repl.d.ts +33 -0
- package/dist/core/repl.js +88 -0
- package/dist/core/scheduler.js +6 -0
- package/dist/core/social.d.ts +4 -4
- package/dist/core/social.js +4 -4
- package/dist/core/storage.d.ts +159 -6
- package/dist/core/storage.js +299 -7
- package/dist/core/telemetry.d.ts +208 -0
- package/dist/core/telemetry.js +383 -0
- package/dist/core/template.d.ts +2 -3
- package/dist/core/template.js +2 -3
- package/dist/core/testing.d.ts +170 -1
- package/dist/core/testing.js +504 -2
- package/dist/db/d1.js +13 -0
- package/dist/db/pg.d.ts +13 -0
- package/dist/db/pg.js +46 -4
- package/dist/mcp/server.d.ts +19 -0
- package/dist/mcp/server.js +355 -0
- package/dist/openapi/config.d.ts +28 -0
- package/dist/openapi/config.js +25 -0
- package/dist/openapi/doc.d.ts +40 -0
- package/dist/openapi/doc.js +20 -0
- package/dist/openapi/export.d.ts +8 -0
- package/dist/openapi/export.js +19 -0
- package/dist/openapi/gate.d.ts +15 -0
- package/dist/openapi/gate.js +27 -0
- package/dist/openapi/index.d.ts +19 -0
- package/dist/openapi/index.js +15 -0
- package/dist/openapi/openapi.config.stub +29 -0
- package/dist/openapi/provider.d.ts +18 -0
- package/dist/openapi/provider.js +35 -0
- package/dist/openapi/routes.d.ts +9 -0
- package/dist/openapi/routes.js +23 -0
- package/dist/openapi/spec.d.ts +23 -0
- package/dist/openapi/spec.js +132 -0
- package/dist/openapi/ui.d.ts +8 -0
- package/dist/openapi/ui.js +31 -0
- package/dist/openapi/zod.d.ts +12 -0
- package/dist/openapi/zod.js +46 -0
- package/dist/watch/config.d.ts +33 -0
- package/dist/watch/config.js +38 -0
- package/dist/watch/entry.d.ts +53 -0
- package/dist/watch/entry.js +105 -0
- package/dist/watch/gate.d.ts +20 -0
- package/dist/watch/gate.js +32 -0
- package/dist/watch/index.d.ts +21 -0
- package/dist/watch/index.js +17 -0
- package/dist/watch/migration.d.ts +7 -0
- package/dist/watch/migration.js +20 -0
- package/dist/watch/provider.d.ts +22 -0
- package/dist/watch/provider.js +58 -0
- package/dist/watch/prune.d.ts +11 -0
- package/dist/watch/prune.js +20 -0
- package/dist/watch/recorder.d.ts +24 -0
- package/dist/watch/recorder.js +39 -0
- package/dist/watch/routes.d.ts +13 -0
- package/dist/watch/routes.js +55 -0
- package/dist/watch/store.d.ts +54 -0
- package/dist/watch/store.js +158 -0
- package/dist/watch/ui/dist/watch.css +1 -0
- package/dist/watch/ui/dist/watch.js +555 -0
- package/dist/watch/ui-shell.d.ts +12 -0
- package/dist/watch/ui-shell.js +24 -0
- package/dist/watch/watch.config.stub +47 -0
- package/dist/watch/watchers.d.ts +12 -0
- package/dist/watch/watchers.js +156 -0
- package/docs/ai-manifest.json +3206 -0
- package/docs/ai.md +128 -0
- package/docs/api-resources.md +118 -0
- package/docs/architecture.md +331 -0
- package/docs/authentication.md +453 -0
- package/docs/authorization.md +167 -0
- package/docs/broadcasting.md +137 -0
- package/docs/broker.md +500 -0
- package/docs/cache.md +558 -0
- package/docs/configuration.md +385 -0
- package/docs/console.md +536 -0
- package/docs/container.md +467 -0
- package/docs/controllers.md +265 -0
- package/docs/cors.md +51 -0
- package/docs/database.md +631 -0
- package/docs/debugging.md +129 -0
- package/docs/decorators.md +127 -0
- package/docs/errors.md +395 -0
- package/docs/events.md +496 -0
- package/docs/examples/architecture-app.ts +27 -0
- package/docs/examples/authentication.ts +61 -0
- package/docs/examples/authorization.ts +79 -0
- package/docs/examples/broadcasting.ts +60 -0
- package/docs/examples/broker-cache-validate.ts +34 -0
- package/docs/examples/broker-fault-tolerance.ts +29 -0
- package/docs/examples/broker-middleware.ts +27 -0
- package/docs/examples/broker.ts +203 -0
- package/docs/examples/cache.ts +222 -0
- package/docs/examples/configuration.ts +121 -0
- package/docs/examples/console.ts +134 -0
- package/docs/examples/container.ts +134 -0
- package/docs/examples/controllers.ts +86 -0
- package/docs/examples/database.ts +208 -0
- package/docs/examples/debugging.ts +41 -0
- package/docs/examples/decorators.ts +40 -0
- package/docs/examples/errors.ts +121 -0
- package/docs/examples/events.ts +204 -0
- package/docs/examples/factories.ts +84 -0
- package/docs/examples/hashing.ts +71 -0
- package/docs/examples/health.ts +94 -0
- package/docs/examples/helpers.ts +171 -0
- package/docs/examples/hooks.ts +54 -0
- package/docs/examples/i18n.ts +117 -0
- package/docs/examples/inertia.ts +81 -0
- package/docs/examples/locks.ts +120 -0
- package/docs/examples/logger.ts +166 -0
- package/docs/examples/mail.ts +263 -0
- package/docs/examples/middleware.ts +119 -0
- package/docs/examples/migrations.ts +126 -0
- package/docs/examples/models.ts +239 -0
- package/docs/examples/notification.ts +124 -0
- package/docs/examples/pages.ts +82 -0
- package/docs/examples/providers.ts +123 -0
- package/docs/examples/queues.ts +254 -0
- package/docs/examples/rate-limiting.ts +42 -0
- package/docs/examples/redis.ts +99 -0
- package/docs/examples/request-response.ts +197 -0
- package/docs/examples/routing.ts +186 -0
- package/docs/examples/scheduling.ts +62 -0
- package/docs/examples/sessions.ts +102 -0
- package/docs/examples/static-files.ts +63 -0
- package/docs/examples/storage.ts +132 -0
- package/docs/examples/telemetry.ts +127 -0
- package/docs/examples/templates.ts +58 -0
- package/docs/examples/testing.ts +215 -0
- package/docs/examples/transformer.ts +141 -0
- package/docs/examples/transformers.ts +49 -0
- package/docs/examples/url-builder.ts +86 -0
- package/docs/examples/validation.ts +102 -0
- package/docs/examples/views.tsx +62 -0
- package/docs/examples/vite.ts +106 -0
- package/docs/factories.md +166 -0
- package/docs/getting-started.md +290 -0
- package/docs/hashing.md +259 -0
- package/docs/health.md +225 -0
- package/docs/helpers.md +347 -0
- package/docs/hono.md +186 -0
- package/docs/hooks.md +118 -0
- package/docs/i18n.md +302 -0
- package/docs/inertia.md +241 -0
- package/docs/locks.md +323 -0
- package/docs/logger.md +436 -0
- package/docs/mail.md +751 -0
- package/docs/middleware.md +425 -0
- package/docs/migrations.md +476 -0
- package/docs/models.md +810 -0
- package/docs/notifications.md +474 -0
- package/docs/openapi.md +111 -0
- package/docs/packages.md +118 -0
- package/docs/pages.md +217 -0
- package/docs/providers.md +363 -0
- package/docs/queues.md +679 -0
- package/docs/rate-limiting.md +155 -0
- package/docs/redis.md +178 -0
- package/docs/request-response.md +953 -0
- package/docs/routing.md +804 -0
- package/docs/scheduling.md +110 -0
- package/docs/security.md +85 -0
- package/docs/sessions.md +354 -0
- package/docs/social-auth.md +174 -0
- package/docs/static-files.md +211 -0
- package/docs/storage.md +452 -0
- package/docs/telemetry.md +263 -0
- package/docs/templates.md +314 -0
- package/docs/testing.md +376 -0
- package/docs/transformers.md +381 -0
- package/docs/url-builder.md +295 -0
- package/docs/validation.md +288 -0
- package/docs/views.md +267 -0
- package/docs/vite.md +434 -0
- package/docs/watch.md +118 -0
- package/llms-full.txt +19816 -0
- package/llms.txt +127 -0
- package/package.json +42 -7
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
# Migrations
|
|
2
|
+
|
|
3
|
+
Version your database schema. A migration is a `{ name, up, down }` object; a
|
|
4
|
+
fluent **schema builder** describes tables, and the **migrator** runs them
|
|
5
|
+
against your [connection](./database.md), tracking what's applied. The SQL is
|
|
6
|
+
dialect-aware (sqlite / mysql / postgres) and the core imports no driver.
|
|
7
|
+
|
|
8
|
+
## Define migrations
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import type { Migration } from "@shaferllc/keel/core";
|
|
12
|
+
|
|
13
|
+
export const migrations: Migration[] = [
|
|
14
|
+
{
|
|
15
|
+
name: "01_create_users",
|
|
16
|
+
up: (schema) =>
|
|
17
|
+
schema.createTable("users", (t) => {
|
|
18
|
+
t.id();
|
|
19
|
+
t.string("email").unique();
|
|
20
|
+
t.string("name");
|
|
21
|
+
t.boolean("active").default(true);
|
|
22
|
+
t.timestamps(); // created_at + updated_at
|
|
23
|
+
}),
|
|
24
|
+
down: (schema) => schema.dropTable("users"),
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A migration's `name` is its identity — the migrator records it verbatim in the
|
|
30
|
+
bookkeeping table and skips it on re-runs. Keep names stable and ordered (an
|
|
31
|
+
`NN_` prefix sorts them); the migrator runs the array in the order you give it.
|
|
32
|
+
`up`/`down` may be sync or async (`void | Promise<void>`) — return the
|
|
33
|
+
`schema.createTable(...)` promise, or `await` several statements.
|
|
34
|
+
|
|
35
|
+
### Column types
|
|
36
|
+
|
|
37
|
+
`t.id()` · `t.string(name, length?)` · `t.text(name)` · `t.integer(name)` ·
|
|
38
|
+
`t.bigInteger(name)` · `t.boolean(name)` · `t.timestamp(name)` · `t.json(name)` ·
|
|
39
|
+
`t.timestamps()`.
|
|
40
|
+
|
|
41
|
+
Every column method except `timestamps()` returns a [`Column`](#column) you can
|
|
42
|
+
chain modifiers on: `.nullable()`, `.unique()`, `.default(value)`. `timestamps()`
|
|
43
|
+
returns `void` — it adds nullable `created_at` and `updated_at` for you, so
|
|
44
|
+
there's nothing to chain.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
schema.createTable("posts", (t) => {
|
|
48
|
+
t.id();
|
|
49
|
+
t.integer("user_id");
|
|
50
|
+
t.string("slug", 120).unique();
|
|
51
|
+
t.text("body").nullable();
|
|
52
|
+
t.json("meta").nullable();
|
|
53
|
+
t.boolean("published").default(false);
|
|
54
|
+
t.timestamps();
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Columns are emitted in the order you declare them. `t.id()` is special: it maps
|
|
59
|
+
to the dialect's auto-increment primary key (`SERIAL PRIMARY KEY`,
|
|
60
|
+
`INT AUTO_INCREMENT PRIMARY KEY`, or `INTEGER PRIMARY KEY AUTOINCREMENT`) and is
|
|
61
|
+
never marked `NOT NULL` — modifiers on it are redundant.
|
|
62
|
+
|
|
63
|
+
### Defaults and nullability
|
|
64
|
+
|
|
65
|
+
By default every column is `NOT NULL`; `.nullable()` drops that. `.default(v)`
|
|
66
|
+
renders the literal inline: strings are single-quoted, booleans become `1`/`0`
|
|
67
|
+
on sqlite and `true`/`false` elsewhere, numbers pass through. Because the default
|
|
68
|
+
is inlined (not a binding), keep it to dev-authored constants.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
t.string("role").default("member"); // ... DEFAULT 'member'
|
|
72
|
+
t.boolean("active").default(true); // sqlite: DEFAULT 1, else DEFAULT true
|
|
73
|
+
t.integer("retries").default(0); // ... DEFAULT 0
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
For anything the builder doesn't cover — indexes, foreign keys, an `ALTER
|
|
77
|
+
TABLE` — `schema.raw(sql, bindings?)` runs arbitrary SQL:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
up: (schema) =>
|
|
81
|
+
schema.raw("CREATE INDEX idx_posts_user ON posts (user_id)"),
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> `raw()` writes through the connection **without** placeholder conversion, so
|
|
85
|
+
> its `?` markers are not rewritten to `$1, $2` on the `postgres` dialect
|
|
86
|
+
> (unlike the migrator's own bookkeeping writes). On Postgres, prefer `$n`
|
|
87
|
+
> placeholders — or no bindings — in `raw()`.
|
|
88
|
+
|
|
89
|
+
## Run and roll back
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { Migrator } from "@shaferllc/keel/core";
|
|
93
|
+
|
|
94
|
+
const migrator = new Migrator(connection, "postgres");
|
|
95
|
+
|
|
96
|
+
await migrator.up(migrations); // runs pending migrations (idempotent)
|
|
97
|
+
await migrator.down(migrations); // rolls back the last batch
|
|
98
|
+
await migrator.ran(); // names already applied
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`up()` records each applied migration in a `migrations` table
|
|
102
|
+
(`name` PRIMARY KEY, `batch`), so re-running only applies new ones. Every
|
|
103
|
+
migration applied in a single `up()` call shares one batch number — the previous
|
|
104
|
+
max plus one. `down()` reverses just the most recent batch, in reverse
|
|
105
|
+
declaration order, calling each migration's `down()`.
|
|
106
|
+
|
|
107
|
+
Both `up()` and `down()` return the list of names they touched, so you can report
|
|
108
|
+
progress:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const applied = await migrator.up(migrations); // ["02_add_posts"]
|
|
112
|
+
const rolled = await migrator.down(migrations); // ["02_add_posts"]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The bookkeeping table is created on demand — `up()`, `down()`, and `ran()` each
|
|
116
|
+
ensure `migrations` exists before touching it, so a fresh database Just Works.
|
|
117
|
+
|
|
118
|
+
### Edge cases
|
|
119
|
+
|
|
120
|
+
- **Nothing pending:** `up()` returns `[]` and writes nothing new.
|
|
121
|
+
- **Nothing to roll back:** `down()` returns `[]` when no batch exists.
|
|
122
|
+
- **A recorded migration missing from the array:** `down()` still deletes its
|
|
123
|
+
bookkeeping row but has no `down()` to call, so the schema change is *not*
|
|
124
|
+
reversed — keep old migrations in the array until they're fully retired.
|
|
125
|
+
- **Dialect default:** the `Migrator` constructor defaults to `"sqlite"` if you
|
|
126
|
+
omit the second argument.
|
|
127
|
+
|
|
128
|
+
## Wiring a console command
|
|
129
|
+
|
|
130
|
+
Migrations are usually driven from your app's console. Load your migration files
|
|
131
|
+
and call the migrator:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
// bin/console.ts
|
|
135
|
+
program.command("migrate").action(async () => {
|
|
136
|
+
const applied = await new Migrator(connection, dialect).up(migrations);
|
|
137
|
+
console.log(applied.length ? `Ran: ${applied.join(", ")}` : "Nothing to migrate.");
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Dialect notes
|
|
142
|
+
|
|
143
|
+
The builder emits the right primary-key syntax per dialect —
|
|
144
|
+
`SERIAL`/`INTEGER PRIMARY KEY AUTOINCREMENT`/`INT AUTO_INCREMENT` — and maps
|
|
145
|
+
`boolean`/`timestamp`/`json` to each dialect's types (`BOOLEAN` vs `INTEGER`,
|
|
146
|
+
`TIMESTAMP` vs `DATETIME`, `JSONB` vs `TEXT`). Pass the dialect that matches your
|
|
147
|
+
connection — it must be the same one you gave [`setConnection`](./database.md).
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## API reference
|
|
152
|
+
|
|
153
|
+
### `Migrator`
|
|
154
|
+
|
|
155
|
+
Runs migrations against a [`Connection`](./database.md#connection) and tracks
|
|
156
|
+
what's applied in a `migrations` table. You construct it directly.
|
|
157
|
+
|
|
158
|
+
#### `new Migrator(conn, dialect?)`
|
|
159
|
+
|
|
160
|
+
`new Migrator(conn: Connection, dialect?: Dialect)`
|
|
161
|
+
|
|
162
|
+
Creates a migrator bound to a connection and dialect (default `"sqlite"`).
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const migrator = new Migrator(connection, "postgres");
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Notes:** the dialect drives both the generated DDL and the `?`→`$n` rewrite of
|
|
169
|
+
the migrator's own bookkeeping writes. It should match the connection you
|
|
170
|
+
registered with `setConnection`.
|
|
171
|
+
|
|
172
|
+
#### `up(migrations)`
|
|
173
|
+
|
|
174
|
+
`up(migrations: Migration[]): Promise<string[]>`
|
|
175
|
+
|
|
176
|
+
Runs every migration not yet recorded, in array order, under one new batch;
|
|
177
|
+
returns the names applied.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
const applied = await migrator.up(migrations);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Notes:** idempotent — already-run migrations (matched by `name`) are skipped.
|
|
184
|
+
Ensures the `migrations` table exists first. Not wrapped in a transaction: if one
|
|
185
|
+
migration throws, earlier ones in the same call stay applied.
|
|
186
|
+
|
|
187
|
+
#### `down(migrations)`
|
|
188
|
+
|
|
189
|
+
`down(migrations: Migration[]): Promise<string[]>`
|
|
190
|
+
|
|
191
|
+
Rolls back the most recent batch, calling each migration's `down()` in reverse
|
|
192
|
+
order; returns the names rolled back.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const rolled = await migrator.down(migrations);
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Notes:** returns `[]` when there's no batch to reverse. A recorded name absent
|
|
199
|
+
from `migrations` has its bookkeeping row deleted but no `down()` invoked, so its
|
|
200
|
+
schema change is not undone.
|
|
201
|
+
|
|
202
|
+
#### `ran()`
|
|
203
|
+
|
|
204
|
+
`ran(): Promise<string[]>`
|
|
205
|
+
|
|
206
|
+
Returns the names of all migrations already applied.
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
const names = await migrator.ran();
|
|
210
|
+
const pending = migrations.filter((m) => !names.includes(m.name));
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Notes:** ensures the `migrations` table exists first, so it's safe to call on a
|
|
214
|
+
brand-new database (returns `[]`).
|
|
215
|
+
|
|
216
|
+
### `SchemaBuilder`
|
|
217
|
+
|
|
218
|
+
The object passed to a migration's `up`/`down`. **You don't construct it in
|
|
219
|
+
migrations** — the migrator creates one and hands it to your callbacks — though
|
|
220
|
+
it is exported and constructible (`new SchemaBuilder(conn, dialect)`) for
|
|
221
|
+
one-off scripts.
|
|
222
|
+
|
|
223
|
+
#### `createTable(name, build)`
|
|
224
|
+
|
|
225
|
+
`createTable(name: string, build: (table: TableBuilder) => void): Promise<void>`
|
|
226
|
+
|
|
227
|
+
Creates a table, using the `build` callback to describe its columns via a
|
|
228
|
+
[`TableBuilder`](#tablebuilder).
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
await schema.createTable("users", (t) => {
|
|
232
|
+
t.id();
|
|
233
|
+
t.string("email").unique();
|
|
234
|
+
t.timestamps();
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Notes:** emits a single `CREATE TABLE` — it does not add `IF NOT EXISTS`, so
|
|
239
|
+
re-creating an existing table errors at the driver. Columns appear in declaration
|
|
240
|
+
order.
|
|
241
|
+
|
|
242
|
+
#### `dropTable(name)`
|
|
243
|
+
|
|
244
|
+
`dropTable(name: string): Promise<void>`
|
|
245
|
+
|
|
246
|
+
Drops a table if it exists.
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
await schema.dropTable("users");
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Notes:** uses `DROP TABLE IF EXISTS`, so it's safe to run when the table is
|
|
253
|
+
already gone — the typical `down()` for a `createTable`.
|
|
254
|
+
|
|
255
|
+
#### `raw(sql, bindings?)`
|
|
256
|
+
|
|
257
|
+
`raw(sql: string, bindings?: unknown[]): Promise<void>`
|
|
258
|
+
|
|
259
|
+
Runs arbitrary SQL through the connection — the escape hatch for indexes, foreign
|
|
260
|
+
keys, and `ALTER TABLE`.
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
await schema.raw("CREATE INDEX idx_posts_user ON posts (user_id)");
|
|
264
|
+
await schema.raw("UPDATE users SET active = ? WHERE active IS NULL", [true]);
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Notes:** `bindings` defaults to `[]`. Unlike the migrator's bookkeeping writes,
|
|
268
|
+
`raw()` does **not** rewrite `?` to `$n`, so pass `$1, $2, …` yourself on the
|
|
269
|
+
`postgres` dialect.
|
|
270
|
+
|
|
271
|
+
### `TableBuilder`
|
|
272
|
+
|
|
273
|
+
Describes a table's columns. **You get one from the `createTable` callback** — it
|
|
274
|
+
is not constructed in migrations. Each column method (except `timestamps`) returns
|
|
275
|
+
a [`Column`](#column) for chaining modifiers.
|
|
276
|
+
|
|
277
|
+
#### `id(name?)`
|
|
278
|
+
|
|
279
|
+
`id(name?: string): Column`
|
|
280
|
+
|
|
281
|
+
Adds an auto-increment primary-key column (default name `"id"`).
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
t.id(); // "id"
|
|
285
|
+
t.id("uuid"); // custom name
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**Notes:** maps to `SERIAL PRIMARY KEY` (postgres), `INT AUTO_INCREMENT PRIMARY
|
|
289
|
+
KEY` (mysql), or `INTEGER PRIMARY KEY AUTOINCREMENT` (sqlite). Never emitted as
|
|
290
|
+
`NOT NULL`; chaining modifiers on it is redundant.
|
|
291
|
+
|
|
292
|
+
#### `string(name, length?)`
|
|
293
|
+
|
|
294
|
+
`string(name: string, length?: number): Column`
|
|
295
|
+
|
|
296
|
+
Adds a `VARCHAR(length)` column (default length `255`).
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
t.string("email");
|
|
300
|
+
t.string("slug", 120);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
#### `text(name)`
|
|
304
|
+
|
|
305
|
+
`text(name: string): Column`
|
|
306
|
+
|
|
307
|
+
Adds a `TEXT` column (unbounded string).
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
t.text("body");
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
#### `integer(name)` / `bigInteger(name)`
|
|
314
|
+
|
|
315
|
+
`integer(name: string): Column`
|
|
316
|
+
`bigInteger(name: string): Column`
|
|
317
|
+
|
|
318
|
+
Add an `INTEGER` / `BIGINT` column.
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
t.integer("user_id");
|
|
322
|
+
t.bigInteger("view_count");
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
#### `boolean(name)`
|
|
326
|
+
|
|
327
|
+
`boolean(name: string): Column`
|
|
328
|
+
|
|
329
|
+
Adds a boolean column — `BOOLEAN` on mysql/postgres, `INTEGER` on sqlite.
|
|
330
|
+
|
|
331
|
+
```ts
|
|
332
|
+
t.boolean("active").default(true);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
#### `timestamp(name)`
|
|
336
|
+
|
|
337
|
+
`timestamp(name: string): Column`
|
|
338
|
+
|
|
339
|
+
Adds a timestamp column — `TIMESTAMP` on mysql/postgres, `DATETIME` on sqlite.
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
t.timestamp("published_at").nullable();
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### `json(name)`
|
|
346
|
+
|
|
347
|
+
`json(name: string): Column`
|
|
348
|
+
|
|
349
|
+
Adds a JSON column — `JSONB` on postgres, `TEXT` elsewhere.
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
t.json("meta").nullable();
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Notes:** on sqlite/mysql the value is stored as text; serialize/deserialize in
|
|
356
|
+
your app or [`Model`](./models.md) layer.
|
|
357
|
+
|
|
358
|
+
#### `timestamps()`
|
|
359
|
+
|
|
360
|
+
`timestamps(): void`
|
|
361
|
+
|
|
362
|
+
Adds nullable `created_at` and `updated_at` timestamp columns.
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
t.timestamps();
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Notes:** returns `void`, not a `Column` — there's nothing to chain. Both
|
|
369
|
+
columns are `nullable()`.
|
|
370
|
+
|
|
371
|
+
#### `toCreateSql(table, dialect)`
|
|
372
|
+
|
|
373
|
+
`toCreateSql(table: string, dialect: Dialect): string`
|
|
374
|
+
|
|
375
|
+
Renders the accumulated columns into a `CREATE TABLE` statement. Called
|
|
376
|
+
internally by `SchemaBuilder.createTable`; useful directly only if you're
|
|
377
|
+
generating DDL by hand.
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
const t = new TableBuilder();
|
|
381
|
+
t.id();
|
|
382
|
+
t.string("email");
|
|
383
|
+
t.toCreateSql("users", "postgres");
|
|
384
|
+
// CREATE TABLE users (id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL)
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### `columns`
|
|
388
|
+
|
|
389
|
+
`readonly columns: Column[]`
|
|
390
|
+
|
|
391
|
+
The `Column` instances added so far, in declaration order. Read-only inspection
|
|
392
|
+
seam; you rarely touch it.
|
|
393
|
+
|
|
394
|
+
### `Column`
|
|
395
|
+
|
|
396
|
+
A single column definition. **You get one from a `TableBuilder` method** (`t.string(...)` etc.) — you don't construct it in migrations. Modifier methods
|
|
397
|
+
return `this`, so they chain.
|
|
398
|
+
|
|
399
|
+
#### `nullable()`
|
|
400
|
+
|
|
401
|
+
`nullable(): this`
|
|
402
|
+
|
|
403
|
+
Marks the column nullable (drops the default `NOT NULL`).
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
t.text("bio").nullable();
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
#### `unique()`
|
|
410
|
+
|
|
411
|
+
`unique(): this`
|
|
412
|
+
|
|
413
|
+
Adds a `UNIQUE` constraint.
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
t.string("email").unique();
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
#### `default(value)`
|
|
420
|
+
|
|
421
|
+
`default(value: unknown): this`
|
|
422
|
+
|
|
423
|
+
Sets a default, rendered inline into the DDL.
|
|
424
|
+
|
|
425
|
+
```ts
|
|
426
|
+
t.boolean("active").default(true);
|
|
427
|
+
t.string("role").default("member");
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Notes:** strings are single-quoted (with no escaping — keep them constant),
|
|
431
|
+
booleans render as `1`/`0` on sqlite and `true`/`false` elsewhere, numbers pass
|
|
432
|
+
through via `String(value)`.
|
|
433
|
+
|
|
434
|
+
#### `toSql(dialect)`
|
|
435
|
+
|
|
436
|
+
`toSql(dialect: Dialect): string`
|
|
437
|
+
|
|
438
|
+
Renders this one column's DDL fragment (`name TYPE [NOT NULL] [UNIQUE] [DEFAULT
|
|
439
|
+
…]`). Called internally by `TableBuilder.toCreateSql`.
|
|
440
|
+
|
|
441
|
+
```ts
|
|
442
|
+
new Column("email", "string").unique().toSql("sqlite");
|
|
443
|
+
// email VARCHAR(255) NOT NULL UNIQUE
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Interfaces & types
|
|
447
|
+
|
|
448
|
+
#### `Migration`
|
|
449
|
+
|
|
450
|
+
```ts
|
|
451
|
+
interface Migration {
|
|
452
|
+
name: string;
|
|
453
|
+
up(schema: SchemaBuilder): void | Promise<void>;
|
|
454
|
+
down(schema: SchemaBuilder): void | Promise<void>;
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
One schema change and its reversal. `name` is the identity recorded in the
|
|
459
|
+
`migrations` table (make it unique and sortable); `up` applies the change, `down`
|
|
460
|
+
reverses it. Both receive a [`SchemaBuilder`](#schemabuilder) and may be sync or
|
|
461
|
+
async. Implement it as a plain object literal:
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
const m: Migration = {
|
|
465
|
+
name: "03_add_index",
|
|
466
|
+
up: (s) => s.raw("CREATE INDEX idx_users_email ON users (email)"),
|
|
467
|
+
down: (s) => s.raw("DROP INDEX idx_users_email"),
|
|
468
|
+
};
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
#### `Connection` / `Dialect`
|
|
472
|
+
|
|
473
|
+
Re-used from the [database](./database.md) layer. `Migrator` and `SchemaBuilder`
|
|
474
|
+
take a `Connection` (the driver seam) and a `Dialect`
|
|
475
|
+
(`"sqlite" | "mysql" | "postgres"`). See
|
|
476
|
+
[Database → Interfaces & types](./database.md#interfaces--types).
|