@softure-ai/db 0.0.0-stage → 0.1.6
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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +383 -2
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +5 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/command.d.ts +8 -0
- package/dist/cli/command.d.ts.map +1 -0
- package/dist/cli/command.js +38 -0
- package/dist/cli/command.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/run.d.ts +27 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +205 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/client.d.ts +73 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +90 -0
- package/dist/client.js.map +1 -0
- package/dist/configured.d.ts +31 -0
- package/dist/configured.d.ts.map +1 -0
- package/dist/configured.js +74 -0
- package/dist/configured.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/adopt.d.ts +33 -0
- package/dist/migrations/adopt.d.ts.map +1 -0
- package/dist/migrations/adopt.js +97 -0
- package/dist/migrations/adopt.js.map +1 -0
- package/dist/migrations/apply.d.ts +35 -0
- package/dist/migrations/apply.d.ts.map +1 -0
- package/dist/migrations/apply.js +115 -0
- package/dist/migrations/apply.js.map +1 -0
- package/dist/migrations/export.d.ts +10 -0
- package/dist/migrations/export.d.ts.map +1 -0
- package/dist/migrations/export.js +58 -0
- package/dist/migrations/export.js.map +1 -0
- package/dist/migrations/exported.d.ts +20 -0
- package/dist/migrations/exported.d.ts.map +1 -0
- package/dist/migrations/exported.js +61 -0
- package/dist/migrations/exported.js.map +1 -0
- package/dist/migrations/files.d.ts +21 -0
- package/dist/migrations/files.d.ts.map +1 -0
- package/dist/migrations/files.js +112 -0
- package/dist/migrations/files.js.map +1 -0
- package/dist/migrations/introspect.d.ts +6 -0
- package/dist/migrations/introspect.d.ts.map +1 -0
- package/dist/migrations/introspect.js +117 -0
- package/dist/migrations/introspect.js.map +1 -0
- package/dist/migrations/ledger.d.ts +27 -0
- package/dist/migrations/ledger.d.ts.map +1 -0
- package/dist/migrations/ledger.js +45 -0
- package/dist/migrations/ledger.js.map +1 -0
- package/dist/migrations/migrator.d.ts +97 -0
- package/dist/migrations/migrator.d.ts.map +1 -0
- package/dist/migrations/migrator.js +301 -0
- package/dist/migrations/migrator.js.map +1 -0
- package/dist/migrations/problems.d.ts +93 -0
- package/dist/migrations/problems.d.ts.map +1 -0
- package/dist/migrations/problems.js +62 -0
- package/dist/migrations/problems.js.map +1 -0
- package/dist/migrations/reference.d.ts +23 -0
- package/dist/migrations/reference.d.ts.map +1 -0
- package/dist/migrations/reference.js +64 -0
- package/dist/migrations/reference.js.map +1 -0
- package/dist/migrations/session.d.ts +15 -0
- package/dist/migrations/session.d.ts.map +1 -0
- package/dist/migrations/session.js +56 -0
- package/dist/migrations/session.js.map +1 -0
- package/dist/migrations/stubs.d.ts +23 -0
- package/dist/migrations/stubs.d.ts.map +1 -0
- package/dist/migrations/stubs.js +99 -0
- package/dist/migrations/stubs.js.map +1 -0
- package/dist/shared.d.ts +9 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +32 -0
- package/dist/shared.js.map +1 -0
- package/dist/testing.d.ts +23 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +62 -0
- package/dist/testing.js.map +1 -0
- package/package.json +73 -4
- package/src/cli/bin.ts +5 -0
- package/src/cli/command.ts +47 -0
- package/src/cli/index.ts +3 -0
- package/src/cli/run.ts +250 -0
- package/src/client.ts +151 -0
- package/src/configured.ts +109 -0
- package/src/index.ts +46 -0
- package/src/migrations/adopt.ts +136 -0
- package/src/migrations/apply.ts +135 -0
- package/src/migrations/export.ts +66 -0
- package/src/migrations/exported.ts +82 -0
- package/src/migrations/files.ts +129 -0
- package/src/migrations/introspect.ts +165 -0
- package/src/migrations/ledger.ts +75 -0
- package/src/migrations/migrator.ts +403 -0
- package/src/migrations/problems.ts +99 -0
- package/src/migrations/reference.ts +78 -0
- package/src/migrations/session.ts +74 -0
- package/src/migrations/stubs.ts +139 -0
- package/src/shared.ts +36 -0
- package/src/testing.ts +80 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Newest first. Each version lists what changed for an app that uses `@softure-ai/db`. When an app has run a version in
|
|
4
|
+
production, the version gets a line `verified in: <app>@<commit>` ([docs/05](../../docs/05-adoption-playbook.md),
|
|
5
|
+
"Definition of done"). Versions before the first one below are described in their GitHub Releases (`db@x.y.z`).
|
|
6
|
+
|
|
7
|
+
## 0.1.6
|
|
8
|
+
|
|
9
|
+
- One database handle per process: `getConfiguredDatabase` opens the config's `database.handle` or URL once, and modules, health route and commands share it.
|
|
10
|
+
- App migrations run around module migrations (`before` and `after` hooks).
|
|
11
|
+
- Adoption: app baselines, `--adopt <module>@<version> --through <n>`, dependencies adopted first, and modules whose SQL references app tables (stub tables).
|
|
12
|
+
- **Breaking:** `pg` and `@electric-sql/pglite` are optional peer dependencies, no longer dependencies. An app installs
|
|
13
|
+
the driver its `DATABASE_URL` uses and lists `"@softure-ai/db"` and that driver in `serverExternalPackages`
|
|
14
|
+
([README §2](README.md#2-installation)); a URL whose driver is missing fails with a message naming the package.
|
|
15
|
+
- A migrate bundle keeps drizzle's driver adapters external (`--external:drizzle-orm/pglite`,
|
|
16
|
+
`--external:drizzle-orm/node-postgres`).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SOFTURE
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,384 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @softure-ai/db
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The database layer every SOFTURE module stands on. Standard:
|
|
4
|
+
[docs/02-module-standard.md](../../docs/02-module-standard.md) §4.
|
|
5
|
+
|
|
6
|
+
## 1. What it provides
|
|
7
|
+
|
|
8
|
+
A pg/PGlite client chosen by URL, a migrator that runs each module's SQL in the module's own
|
|
9
|
+
Postgres schema (with a ledger, checksums, a lock, a dry run and adoption of existing tables),
|
|
10
|
+
`createTestDatabase` for unit tests, and the `softure migrate` command.
|
|
11
|
+
|
|
12
|
+
## 2. Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @softure-ai/db drizzle-orm
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Node ≥ 22, **ESM only**: module packages locate their migrations through `import.meta.url`, which a
|
|
19
|
+
CJS bundle (esbuild `--format=cjs`) leaves empty, so `resolveMigrationsDir` throws naming the bundle
|
|
20
|
+
format; the app script below also uses top-level await. Bundle migrate scripts with `--format=esm`.
|
|
21
|
+
`drizzle-orm` (`^0.45.2`) is a peer dependency, so the app, the modules and
|
|
22
|
+
this package share one drizzle.
|
|
23
|
+
|
|
24
|
+
The drivers are optional peers: install the one the app's URL uses, and only that one goes into the
|
|
25
|
+
app image. Each loads only when a URL needs it.
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install pg # postgres:// and postgresql://
|
|
29
|
+
npm install @electric-sql/pglite # pglite:// (dev without a server)
|
|
30
|
+
npm install -D @electric-sql/pglite # a Postgres app's createTestDatabase, --adopt and baseline
|
|
31
|
+
npm install -D @types/pg # only with skipLibCheck: false
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Needs | `pg` (`^8.11.0`) | `@electric-sql/pglite` (`^0.5.0`) |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| `postgres://`, `postgresql://` | yes | no |
|
|
37
|
+
| `pglite://` | no | yes |
|
|
38
|
+
| `createTestDatabase` (`@softure-ai/db/testing`) | no | yes (dev) |
|
|
39
|
+
| `softure migrate --adopt`, an app `baseline` (compare against a scratch PGlite) | URL's driver | yes |
|
|
40
|
+
|
|
41
|
+
A URL whose driver is missing fails at the first connection: `createDatabase: postgres:// URLs need
|
|
42
|
+
the "pg" package, which is not installed; …`, with Node's error as `cause`.
|
|
43
|
+
|
|
44
|
+
**Next.js.** List this package and the driver in `serverExternalPackages`:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// next.config.ts
|
|
48
|
+
const nextConfig: NextConfig = {
|
|
49
|
+
serverExternalPackages: ["@softure-ai/db", "pg"], // or "@electric-sql/pglite" for pglite://
|
|
50
|
+
};
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Bundled, the package's `import()` of each driver and drizzle adapter is resolved at build time, so
|
|
54
|
+
`next build` fails with `Can't resolve '@electric-sql/pglite'` in an app without PGlite (drizzle's
|
|
55
|
+
adapter imports it statically). External, it loads from `node_modules` at run time, and standalone
|
|
56
|
+
output tracing follows the same imports, so `.next/standalone` carries the installed driver and
|
|
57
|
+
drizzle and nothing else (the example app installs `pg` only:
|
|
58
|
+
[`next.config.ts`](../../examples/next-app/next.config.ts)). The config and the shared handles live on `globalThis`, so this copy and the modules bundled next
|
|
59
|
+
to it share them. Hiding the imports from the bundler instead (`turbopackIgnore`) builds, but
|
|
60
|
+
tracing skips the driver and the image fails at the first query.
|
|
61
|
+
|
|
62
|
+
## 3. Configuration
|
|
63
|
+
|
|
64
|
+
The database URL comes from the app config (`database.url` in `defineSoftureConfig`), usually
|
|
65
|
+
`process.env.DATABASE_URL`:
|
|
66
|
+
|
|
67
|
+
| URL | Driver |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `postgres://…`, `postgresql://…` | node-postgres pool (production) |
|
|
70
|
+
| `pglite://<dir>` | PGlite, a real Postgres in-process, data in `<dir>` (dev without a server) |
|
|
71
|
+
| `pglite://` | PGlite in memory |
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { createDatabase, type Queryable } from "@softure-ai/db";
|
|
75
|
+
|
|
76
|
+
const handle = await createDatabase(config.database.url, { max: 10 }); // max: pg pool size
|
|
77
|
+
await handle.db.select().from(notes); // drizzle
|
|
78
|
+
await handle.close();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `DatabaseHandle` is `{ kind: "postgres", db, pool, close } | { kind: "pglite", db, client, close }`.
|
|
82
|
+
- `Database<TSchema>` is the drizzle database of either driver; `Queryable<TSchema>` is a `Database`
|
|
83
|
+
or an open transaction, so one helper serves both (`db.transaction(async (tx) => helper(tx))`).
|
|
84
|
+
Without a type argument both accept any schema, so an app database made with
|
|
85
|
+
`drizzle({ client, schema })`, and its transactions, pass to module functions as they are.
|
|
86
|
+
- An unsupported scheme throws, naming the scheme only; the URL (and its password) is never
|
|
87
|
+
printed.
|
|
88
|
+
|
|
89
|
+
### One handle per process
|
|
90
|
+
|
|
91
|
+
Modules open their database through the config, never on their own: the app's handle when
|
|
92
|
+
`database.handle` is set, otherwise one process-wide handle per URL (`getSharedDatabase(url)`). An
|
|
93
|
+
app that also has its own client must make sure both are the same handle. A second handle is a second
|
|
94
|
+
pool on Postgres; on `pglite://` it is a second PGlite instance on the same directory, which corrupts
|
|
95
|
+
it without an error (the next open fails with `could not locate a valid checkpoint record`).
|
|
96
|
+
|
|
97
|
+
**Either** hand the app's client to the config. The function is called on first use, never while the
|
|
98
|
+
config is defined (a build does not connect), and must return the app's one handle:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// db/client.ts: the app's own client, memoized: `next dev` re-evaluates modules on every change
|
|
102
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
103
|
+
import { createPgliteHandle, createPostgresHandle, type DatabaseHandle } from "@softure-ai/db";
|
|
104
|
+
import pg from "pg";
|
|
105
|
+
|
|
106
|
+
const cache = globalThis as typeof globalThis & { appDatabase?: Promise<DatabaseHandle> };
|
|
107
|
+
|
|
108
|
+
export function getAppDatabase(url: string): Promise<DatabaseHandle> {
|
|
109
|
+
cache.appDatabase ??= url.startsWith("pglite://")
|
|
110
|
+
? createPgliteHandle(new PGlite(url.slice("pglite://".length)))
|
|
111
|
+
: createPostgresHandle(new pg.Pool({ connectionString: url }).on("error", () => undefined));
|
|
112
|
+
return cache.appDatabase;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// softure.config.ts
|
|
116
|
+
const url = process.env.DATABASE_URL ?? "";
|
|
117
|
+
defineSoftureConfig({ database: { url, handle: () => getAppDatabase(url) }, /* … */ });
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Every module adapter, the ops health route, `softure migrate` (and the app's migration hooks it
|
|
121
|
+
runs), `softure-blog`, `softure-mail` and ops scripts then use that handle; a command closes it
|
|
122
|
+
when it is done, which writes a `pglite://` directory back.
|
|
123
|
+
|
|
124
|
+
**Or** build the app's typed drizzle instance over the shared handle, so there is nothing to hand
|
|
125
|
+
over:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { getSharedDatabase } from "@softure-ai/db";
|
|
129
|
+
import { drizzle as drizzlePg } from "drizzle-orm/node-postgres";
|
|
130
|
+
import { drizzle as drizzlePglite } from "drizzle-orm/pglite";
|
|
131
|
+
import * as schema from "./schema";
|
|
132
|
+
|
|
133
|
+
export async function getDb() {
|
|
134
|
+
const handle = await getSharedDatabase(config.database.url);
|
|
135
|
+
return handle.kind === "postgres" ? drizzlePg({ client: handle.pool, schema }) : drizzlePglite({ client: handle.client, schema });
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`getConfiguredDatabase(config.database)` is what modules call; app code that needs the database
|
|
140
|
+
the modules use can call it too. A migration run on a PGlite handle the app shares keeps the app's
|
|
141
|
+
session settings (`TimeZone`, `search_path`); only what the run changed is put back.
|
|
142
|
+
|
|
143
|
+
## 4. Mounting
|
|
144
|
+
|
|
145
|
+
Nothing to mount. Migrations run as a deploy step:
|
|
146
|
+
|
|
147
|
+
- **Dev:** `npx softure migrate` finds `softure.config.{ts,mts,js,mjs}` in the working directory
|
|
148
|
+
(or `--config <file>`). The file must be one Node can import: `.js`/`.mjs`, or `.ts` where Node
|
|
149
|
+
strips types (Node ≥ 22.18, relative imports written with `.ts`). Otherwise use the script below.
|
|
150
|
+
The lookup is `@softure-ai/core/cli`'s, shared with `softure-mail` and `softure-blog`.
|
|
151
|
+
- **App script and container image:** the app owns a three-line script, which esbuild bundles:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
// scripts/migrate.ts
|
|
155
|
+
import { runMigrateCli } from "@softure-ai/db/cli";
|
|
156
|
+
import config from "../softure.config";
|
|
157
|
+
|
|
158
|
+
process.exitCode = await runMigrateCli({ config, argv: process.argv.slice(2) });
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```dockerfile
|
|
162
|
+
# build stage: copy each module's SQL next to the bundle, then bundle the runner
|
|
163
|
+
RUN npx tsx scripts/migrate.ts --export-migrations ./softure-migrations
|
|
164
|
+
RUN npx esbuild scripts/migrate.ts --bundle --platform=node --format=esm --target=node22 \
|
|
165
|
+
--external:pg --external:@electric-sql/pglite \
|
|
166
|
+
--external:drizzle-orm/pglite --external:drizzle-orm/node-postgres --outfile=migrate.mjs
|
|
167
|
+
# run stage (needs the URL's driver, and @electric-sql/pglite for --adopt or an app baseline)
|
|
168
|
+
COPY --from=builder /app/migrate.mjs ./migrate.mjs
|
|
169
|
+
COPY --from=builder /app/softure-migrations ./softure-migrations
|
|
170
|
+
CMD ["node", "migrate.mjs", "--migrations-dir", "./softure-migrations"]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
A config that imports `server-only` throws under plain Node: run the export as
|
|
174
|
+
`npx tsx --conditions=react-server scripts/migrate.ts --export-migrations …` and bundle with
|
|
175
|
+
`--alias:server-only=./scripts/empty.mjs` (an empty file). Path aliases (`@/…`) need nothing extra: tsx and
|
|
176
|
+
esbuild both read `paths` from `tsconfig.json`. The [ops container recipe](../../modules/ops/README.md#container-recipe)
|
|
177
|
+
uses the same commands.
|
|
178
|
+
|
|
179
|
+
The drivers and drizzle's two driver adapters stay external: bundled, the adapter of a driver the app
|
|
180
|
+
does not install imports it at the top of `migrate.mjs`, which then fails at start. At run time they
|
|
181
|
+
come from the standalone output, which carries the installed driver and its adapter.
|
|
182
|
+
|
|
183
|
+
A bundle cannot find package folders (`import.meta.url` points at the bundle), hence
|
|
184
|
+
`--export-migrations` at build time and `--migrations-dir` at run time. The build stage needs no
|
|
185
|
+
`DATABASE_URL`: the config accepts an empty `database.url` (`DATABASE_URL ?? ""`) and only a command that
|
|
186
|
+
connects refuses it. The ledger's own migration
|
|
187
|
+
ships as code.
|
|
188
|
+
|
|
189
|
+
**The app's own migrations** run in the same step, through hooks. `before` runs ahead of the module
|
|
190
|
+
files (app tables a module references, normally the app's whole history), `after` behind them (app
|
|
191
|
+
migrations that reference a table a module creates). With drizzle, define them once and pass the same
|
|
192
|
+
object to the migrate script and to `createTestDatabase`:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
// db/app-migrations.ts
|
|
196
|
+
import type { AppMigrations, DatabaseHandle } from "@softure-ai/db";
|
|
197
|
+
|
|
198
|
+
async function runDrizzle(handle: DatabaseHandle, migrationsFolder: string): Promise<void> {
|
|
199
|
+
if (handle.kind === "postgres") {
|
|
200
|
+
const { migrate } = await import("drizzle-orm/node-postgres/migrator");
|
|
201
|
+
await migrate(handle.db, { migrationsFolder });
|
|
202
|
+
} else {
|
|
203
|
+
const { migrate } = await import("drizzle-orm/pglite/migrator");
|
|
204
|
+
await migrate(handle.db, { migrationsFolder });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export const appMigrations: AppMigrations = {
|
|
209
|
+
before: (handle) => runDrizzle(handle, "./drizzle"),
|
|
210
|
+
// only when an app migration needs a module table: a second drizzle folder
|
|
211
|
+
// after: (handle) => runDrizzle(handle, "./drizzle-after"),
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// scripts/migrate.ts
|
|
215
|
+
process.exitCode = await runMigrateCli({ config, argv: process.argv.slice(2), app: appMigrations });
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
- Order of a run: the ledger, `before`, the module files in dependency order, `after`. Everything
|
|
219
|
+
runs under the migration lock, after every module file passed its checks; nothing runs when a check
|
|
220
|
+
fails. The hooks run on every run, so they must skip what they already applied (drizzle does).
|
|
221
|
+
- A hook that throws is reported as `db.app_migration_failed` with the error and its causes (drizzle
|
|
222
|
+
puts the Postgres message in `cause`). A failing `before` stops the run before any module file; a
|
|
223
|
+
failing `after` leaves the module files applied.
|
|
224
|
+
- `--plan` runs no hook (it says so); `--adopt` without `--plan` runs `before` first, so the app
|
|
225
|
+
migration that moves a table into the module's schema and the adoption are one command.
|
|
226
|
+
|
|
227
|
+
**A baseline: fresh databases after an adoption.** The app keeps its old migrations, so every fresh
|
|
228
|
+
database (the unit-test template, an integration stack, a reset dev database) recreates the tables it
|
|
229
|
+
moved into a module's schema before the module files run. `baseline` names, per module, the last module
|
|
230
|
+
file the app's own history creates; `migrate` then adopts or migrates by itself, on every database:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
export const appMigrations: AppMigrations = {
|
|
234
|
+
before: (handle) => runDrizzle(handle, "./drizzle"),
|
|
235
|
+
// the app's history creates auth's 0001 (users, sessions); 0002.. are new to it
|
|
236
|
+
baseline: { auth: 1 },
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
- For a listed module the ledger has never seen, after `before` and after the modules it depends on:
|
|
241
|
+
an empty schema is migrated normally; otherwise the schema is compared with what files 1..n create
|
|
242
|
+
(as `--adopt` does), files 1..n are recorded as `adopted` and the later files are applied. A
|
|
243
|
+
difference stops the run (`db.schema_mismatch`, every difference printed); nothing of that module is
|
|
244
|
+
recorded and `after` does not run.
|
|
245
|
+
- Once the module is in the ledger the entry has no effect, so the same command serves every deploy.
|
|
246
|
+
Keep the number when the module ships new files: it describes the app's history, which no longer
|
|
247
|
+
changes.
|
|
248
|
+
- Only a prefix 1..n can be adopted (the ledger refuses a file numbered below an applied one): when the
|
|
249
|
+
app's tables already carry a later file's change, align them in the app's own migration or raise n.
|
|
250
|
+
- A module that is not enabled, has no schema, or an n outside 1..files refuses the run before anything
|
|
251
|
+
runs. `--plan` marks the files a baseline may adopt (`adopted if its schema already holds objects`).
|
|
252
|
+
- The comparison builds the reference on a scratch PGlite, only when a module is actually adopted,
|
|
253
|
+
with stubs of the app tables `before` created (section 5, adoption).
|
|
254
|
+
- Under node-postgres a hook queries through the pool while the migrator holds one connection, so the
|
|
255
|
+
pool needs at least two (`createDatabase`'s default is 10).
|
|
256
|
+
- The `softure` bin reads only the config; an app with its own migrations uses the script above.
|
|
257
|
+
- In a bundle, the drizzle folder must be copied next to the bundle, as the module files are.
|
|
258
|
+
|
|
259
|
+
**Options of `softure migrate`:**
|
|
260
|
+
|
|
261
|
+
| Option | Effect |
|
|
262
|
+
| --- | --- |
|
|
263
|
+
| (none) | apply every pending migration |
|
|
264
|
+
| `--plan` | print what would be applied (or adopted); change nothing |
|
|
265
|
+
| `--adopt <module>@<version>` | record an existing schema as migrated after comparing it, after applying the pending migrations of its dependencies (section 5) |
|
|
266
|
+
| `--through <n>` | with `--adopt`: adopt files 1..n only; the next migrate applies the rest |
|
|
267
|
+
| `--migrations-dir <dir>` | read module files from `<dir>/<module id>/` |
|
|
268
|
+
| `--export-migrations <dir>` | copy module files to `<dir>/<module id>/` and exit; needs no database; replaces older `.sql` copies and refuses a module folder holding anything else |
|
|
269
|
+
|
|
270
|
+
Exit codes: 0 done, 1 a problem or failure (each printed on stderr), 2 a usage error.
|
|
271
|
+
|
|
272
|
+
The same operations as functions: `migrate(handle, { modules, migrationsDir?, app?, onApplied?, onAdopted?, onAppMigrated? })`
|
|
273
|
+
(`runAppMigrations(handle, app, phase)` runs one hook alone under the lock),
|
|
274
|
+
`planMigrations(handle, { modules, app? })` (`pending`, and `baseline`: the pending files a baseline may adopt),
|
|
275
|
+
`adoptModule(handle, { modules, module, version, through?, dryRun? })`,
|
|
276
|
+
`exportMigrations(modules, dir)`. Each returns `{ ok: true, value } | { ok: false, error, problems }`;
|
|
277
|
+
`describeProblem(problem)` gives the English line.
|
|
278
|
+
|
|
279
|
+
For a deploy, `checkExportedMigrations(dir, journal)` runs the same comparison on an exported folder without the app
|
|
280
|
+
config: `journal` is `readJournal(session)` of the target database, and the result lists the pending files and the
|
|
281
|
+
ledger modules the folder does not hold, or every problem. `softure-deploy schema-guard` (`@softure-ai/deploy`) is
|
|
282
|
+
built on it.
|
|
283
|
+
|
|
284
|
+
## 5. Migrations and tables
|
|
285
|
+
|
|
286
|
+
**Owned:** schema `softure`, table `softure.migrations` (`id, module, version, name, checksum,
|
|
287
|
+
module_version, method ('applied' | 'adopted'), applied_at`, primary key `(module, version)`).
|
|
288
|
+
|
|
289
|
+
**Module files** (`migrations/NNNN_<lower_snake>.sql`, numbered 1..n without gaps):
|
|
290
|
+
- the file opens with a comment block that contains `Rollback:` and says how to undo it;
|
|
291
|
+
- no top-level statement may begin, end or abort a transaction (`BEGIN`, `COMMIT`, `ROLLBACK`,
|
|
292
|
+
`END`, `ABORT`, `START TRANSACTION`, `PREPARE TRANSACTION`); bodies in quotes or dollar quotes
|
|
293
|
+
(PL/pgSQL `BEGIN … END;`) are fine, SQL-standard `BEGIN ATOMIC` bodies are not. Each file runs in
|
|
294
|
+
its own transaction with its ledger row, and a file that still ended it is reported as such,
|
|
295
|
+
not as rolled back;
|
|
296
|
+
- unqualified names land in the module's schema: the runner runs `CREATE SCHEMA IF NOT EXISTS` and
|
|
297
|
+
`SET LOCAL search_path TO <schema>, public` first. Name other modules' tables with their schema
|
|
298
|
+
(`REFERENCES notes.notes (id)`), and create extensions `WITH SCHEMA public`.
|
|
299
|
+
|
|
300
|
+
**Each run:** the ledger, the app's `before` hook, modules in dependency order (`sortModulesByDependencies`), files in number order.
|
|
301
|
+
Before anything runs, every file of every module is checked: an applied file that was edited or
|
|
302
|
+
renamed (`db.migration_changed`), deleted (`db.migration_missing`), or a new file numbered below an
|
|
303
|
+
applied one (`db.migration_out_of_order`) refuses the whole run. The run holds a session-level
|
|
304
|
+
`pg_advisory_lock`, so a second runner waits, then finds nothing to do. A failing file is rolled
|
|
305
|
+
back completely and stops the run; the files before it stay applied. The migration connection is
|
|
306
|
+
closed after the run, never returned to the pool. The app's `after` hook runs last (section 4).
|
|
307
|
+
|
|
308
|
+
**Refused modules:** the id `softure`; the schemas `softure`, `public`, `information_schema`,
|
|
309
|
+
`drizzle` (drizzle's ledger in every app), `pg_*` and names over 63 bytes; migrations without a `dbSchema`.
|
|
310
|
+
|
|
311
|
+
**Adoption** ([docs/05](../../docs/05-adoption-playbook.md) step 3): after the app's own migration
|
|
312
|
+
moved its tables into the module's schema, `--adopt <module>@<version>` (with `--plan` first)
|
|
313
|
+
builds the schema the module's migrations create on a scratch PGlite and compares it with the live
|
|
314
|
+
one through `pg_catalog`: relations (and whether they are unlogged), columns (type, collation,
|
|
315
|
+
not null, default, identity, generated), sequences with their parameters, constraints and indexes
|
|
316
|
+
(names and definitions), triggers, functions, and enum, domain, range and composite types. Only an
|
|
317
|
+
exact match records the files as `adopted`; every difference is printed (`missing in database: …`,
|
|
318
|
+
`unexpected in database: …`). `--through <n>` compares with and adopts files 1..n only; the next
|
|
319
|
+
migrate applies the rest. The version must equal the enabled module's and the module must be new to
|
|
320
|
+
the ledger. The pending migrations of the modules it depends on are applied first (listed as
|
|
321
|
+
`apply` lines; a dry run applies nothing); when one fails because its tables exist too, adopt that
|
|
322
|
+
module first. Module SQL may reference the app's own tables (`REFERENCES public.app_users (id)`):
|
|
323
|
+
the scratch database first gets stubs of every table outside the ledger, the enabled modules'
|
|
324
|
+
schemas and `drizzle`, copied from the live database (columns with their types, primary keys,
|
|
325
|
+
unique constraints, plain unique indexes and the enum types they use; no defaults, NOT NULL, checks
|
|
326
|
+
or foreign keys). The tables must therefore exist when the comparison runs: `--adopt` and a baseline
|
|
327
|
+
run `before` first, a `--plan` dry run reads only what is already there. A stub that cannot be
|
|
328
|
+
created (a domain or extension type) is skipped, and named in the failure when the module needs it.
|
|
329
|
+
For fresh databases of an app that adopted a module, declare a baseline (section 4). Undo:
|
|
330
|
+
`DELETE FROM softure.migrations WHERE module = '<id>' AND method = 'adopted'`.
|
|
331
|
+
|
|
332
|
+
**Tests:** `createTestDatabase(modules)` from `@softure-ai/db/testing` returns `{ db, client, close }`:
|
|
333
|
+
an in-memory PGlite with the ledger and the listed modules migrated (list the module and the
|
|
334
|
+
modules it depends on). Each module set is migrated once per test worker and copied per call; a
|
|
335
|
+
broken migration throws naming the file. An app with its own migrations passes the same hooks,
|
|
336
|
+
`createTestDatabase(modules, { app: appMigrations })`, so module tables can reference app tables; the
|
|
337
|
+
template is cached per hook object, so import the shared object rather than writing hooks inline.
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
import { createTestDatabase } from "@softure-ai/db/testing";
|
|
341
|
+
|
|
342
|
+
const database = await createTestDatabase([notes()]);
|
|
343
|
+
afterEach(() => database.close());
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## 6. Environment variables
|
|
347
|
+
|
|
348
|
+
None read by the package. The app passes `DATABASE_URL` (or any variable) through
|
|
349
|
+
`database.url` in its config.
|
|
350
|
+
|
|
351
|
+
## 7. Switches
|
|
352
|
+
|
|
353
|
+
None.
|
|
354
|
+
|
|
355
|
+
## 8. Appearance
|
|
356
|
+
|
|
357
|
+
None.
|
|
358
|
+
|
|
359
|
+
## 9. Copy
|
|
360
|
+
|
|
361
|
+
None: no user-facing text. Command output and problem lines are English developer messages.
|
|
362
|
+
|
|
363
|
+
## 10. Hooks
|
|
364
|
+
|
|
365
|
+
`onApplied(step)` in `migrate` options, called after each committed file.
|
|
366
|
+
|
|
367
|
+
## 11. GDPR
|
|
368
|
+
|
|
369
|
+
No personal data. The ledger holds module ids, file names and checksums.
|
|
370
|
+
|
|
371
|
+
## 12. Limitations
|
|
372
|
+
|
|
373
|
+
- Forward only: there are no down migrations; each file states its rollback in its comment.
|
|
374
|
+
- A file cannot run outside a transaction (`CREATE INDEX CONCURRENTLY`, `ALTER TYPE … ADD VALUE`
|
|
375
|
+
before Postgres 12).
|
|
376
|
+
- No lock timeout: a stuck runner holds the lock until its connection ends (visible in `pg_locks`).
|
|
377
|
+
The session-level lock needs a direct connection or a session-mode pooler, not a
|
|
378
|
+
transaction-mode PgBouncer.
|
|
379
|
+
- Adoption does not compare grants, comments, column order, row-level security policies or view
|
|
380
|
+
bodies, and needs PGlite installed where it runs (also in an image that otherwise uses `pg`).
|
|
381
|
+
- The app table stubs of the reference carry no domains, extension types, views or functions: a
|
|
382
|
+
module whose SQL needs one of those from the app cannot be adopted (`db.adopt_reference_failed`
|
|
383
|
+
names the skipped stub objects).
|
|
384
|
+
- No cached connection for Next.js dev reloads yet; the Next adapter (identity ID-1, FD-7) adds it.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":""}
|
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `softure` executable. All logic lives in command.ts, which the tests call directly.
|
|
3
|
+
import { runSoftureCommand } from "./command.js";
|
|
4
|
+
process.exitCode = await runSoftureCommand({ argv: process.argv.slice(2), cwd: process.cwd() });
|
|
5
|
+
//# sourceMappingURL=bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA,0FAA0F;AAC1F,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,CAAC,QAAQ,GAAG,MAAM,iBAAiB,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type CliOutput } from "./run.js";
|
|
2
|
+
export interface RunSoftureCommandOptions {
|
|
3
|
+
readonly argv: readonly string[];
|
|
4
|
+
readonly cwd: string;
|
|
5
|
+
readonly output?: CliOutput;
|
|
6
|
+
}
|
|
7
|
+
export declare function runSoftureCommand(options: RunSoftureCommandOptions): Promise<number>;
|
|
8
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/cli/command.ts"],"names":[],"mappings":"AAKA,OAAO,EAAkE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1G,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B;AASD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B1F"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// The `softure` bin: `softure migrate [--config <file>] [options]`. It loads the app's config through
|
|
2
|
+
// `@softure-ai/core/cli`, so the file must be loadable by Node itself: `.js`/`.mjs`, or `.ts` where
|
|
3
|
+
// Node strips types (Node >= 22.18; relative imports then need `.ts` extensions). Anything else
|
|
4
|
+
// uses an app script with `runMigrateCli` instead (see run.ts).
|
|
5
|
+
import { loadAppConfig, takeConfigOption } from "@softure-ai/core/cli";
|
|
6
|
+
import { EXIT_FAILED, EXIT_OK, EXIT_USAGE, MIGRATE_USAGE, runMigrateCli } from "./run.js";
|
|
7
|
+
const APP_SCRIPT = { runner: "runMigrateCli", packageName: "@softure-ai/db" };
|
|
8
|
+
const consoleOutput = {
|
|
9
|
+
log: (line) => console.log(line),
|
|
10
|
+
error: (line) => console.error(line),
|
|
11
|
+
};
|
|
12
|
+
export async function runSoftureCommand(options) {
|
|
13
|
+
const output = options.output ?? consoleOutput;
|
|
14
|
+
const [command, ...rest] = options.argv;
|
|
15
|
+
if (command !== "migrate") {
|
|
16
|
+
output.error(command === undefined ? "softure: missing command" : `softure: unknown command "${command}"`);
|
|
17
|
+
output.error("Commands: migrate");
|
|
18
|
+
output.error(MIGRATE_USAGE);
|
|
19
|
+
return EXIT_USAGE;
|
|
20
|
+
}
|
|
21
|
+
if (rest.includes("--help")) {
|
|
22
|
+
output.log(MIGRATE_USAGE);
|
|
23
|
+
return EXIT_OK;
|
|
24
|
+
}
|
|
25
|
+
const taken = takeConfigOption(rest);
|
|
26
|
+
if (!taken.ok) {
|
|
27
|
+
output.error(`softure migrate: ${taken.problem}`);
|
|
28
|
+
output.error(MIGRATE_USAGE);
|
|
29
|
+
return EXIT_USAGE;
|
|
30
|
+
}
|
|
31
|
+
const loaded = await loadAppConfig({ cwd: options.cwd, configPath: taken.configPath, appScript: APP_SCRIPT });
|
|
32
|
+
if (!loaded.ok) {
|
|
33
|
+
output.error(`softure: ${loaded.problem}`);
|
|
34
|
+
return EXIT_FAILED;
|
|
35
|
+
}
|
|
36
|
+
return runMigrateCli({ config: loaded.config, argv: taken.argv, cwd: options.cwd, output });
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.js","sourceRoot":"","sources":["../../src/cli/command.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,oGAAoG;AACpG,gGAAgG;AAChG,gEAAgE;AAChE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAC;AAQ1G,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC;AAE9E,MAAM,aAAa,GAAc;IAC/B,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAiC;IACvE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC;IAC/C,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IACxC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,6BAA6B,OAAO,GAAG,CAAC,CAAC;QAC3G,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC5B,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACd,MAAM,CAAC,KAAK,CAAC,oBAAoB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC5B,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;IAC9G,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3C,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,OAAO,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// `@softure-ai/db/cli`: the `softure migrate` command for app scripts and container bundles.
|
|
2
|
+
export { runSoftureCommand } from "./command.js";
|
|
3
|
+
export { EXIT_FAILED, EXIT_OK, EXIT_USAGE, MIGRATE_USAGE, runMigrateCli } from "./run.js";
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,OAAO,EAAE,iBAAiB,EAAiC,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAA6C,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SoftureConfig } from "@softure-ai/core";
|
|
2
|
+
import { type AppMigrations } from "../migrations/migrator.js";
|
|
3
|
+
export interface CliOutput {
|
|
4
|
+
readonly log: (line: string) => void;
|
|
5
|
+
readonly error: (line: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export interface RunMigrateCliOptions {
|
|
8
|
+
readonly config: Pick<SoftureConfig, "database" | "modules">;
|
|
9
|
+
/** The arguments after the command name, e.g. `["--plan"]`. */
|
|
10
|
+
readonly argv: readonly string[];
|
|
11
|
+
/** Relative paths resolve against it. Default: `process.cwd()`. */
|
|
12
|
+
readonly cwd?: string;
|
|
13
|
+
readonly output?: CliOutput;
|
|
14
|
+
/**
|
|
15
|
+
* The app's own migrations: migrate runs `before`, the module files (adopting `baseline` where
|
|
16
|
+
* it applies), then `after`; `--adopt` (without `--plan`) runs `before` first; `--plan` runs no
|
|
17
|
+
* hook and marks the files a baseline may adopt.
|
|
18
|
+
*/
|
|
19
|
+
readonly app?: AppMigrations;
|
|
20
|
+
}
|
|
21
|
+
export declare const EXIT_OK = 0;
|
|
22
|
+
export declare const EXIT_FAILED = 1;
|
|
23
|
+
export declare const EXIT_USAGE = 2;
|
|
24
|
+
export declare const MIGRATE_USAGE = "Usage: softure migrate [options]\n\nApplies the SQL migrations of every enabled module, each in its own schema.\n\nOptions:\n --plan show what would be applied (or adopted) and change nothing\n --adopt <module>@<version> record an existing schema as migrated, after comparing it;\n applies the pending migrations of its dependencies first\n --through <n> with --adopt: adopt files 1..n only, leave the rest to migrate\n --migrations-dir <dir> read module files from <dir>/<module id>/ (bundled runners)\n --export-migrations <dir> copy module files to <dir>/<module id>/ and exit (build stage)\n --help show this help";
|
|
25
|
+
/** Runs the command and returns the process exit code: 0 done, 1 failed, 2 usage error. */
|
|
26
|
+
export declare function runMigrateCli(options: RunMigrateCliOptions): Promise<number>;
|
|
27
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKtD,OAAO,EAA6C,KAAK,aAAa,EAAsB,MAAM,2BAA2B,CAAC;AAG9H,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,SAAS,CAAC,CAAC;IAC7D,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,eAAO,MAAM,OAAO,IAAI,CAAC;AACzB,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,eAAO,MAAM,aAAa,+tBAWqB,CAAC;AAehD,2FAA2F;AAC3F,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4ClF"}
|