@onreza/sqlx-js 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -37
- package/ROADMAP.md +2 -3
- package/dist/bin/sqlx-js.js +97 -14
- package/dist/src/cache.d.ts +1 -0
- package/dist/src/cache.js +128 -1
- package/dist/src/codegen.js +16 -16
- package/dist/src/commands/init.d.ts +5 -0
- package/dist/src/commands/init.js +57 -0
- package/dist/src/commands/migrate.d.ts +190 -3
- package/dist/src/commands/migrate.js +1383 -46
- package/dist/src/commands/prepare.d.ts +16 -2
- package/dist/src/commands/prepare.js +116 -33
- package/dist/src/commands/schema.js +4 -0
- package/dist/src/commands/watch.js +1 -1
- package/dist/src/index.d.ts +14 -2
- package/dist/src/pg/narrow.js +8 -0
- package/dist/src/pg/oids.js +3 -2
- package/dist/src/pg/param-map.d.ts +2 -1
- package/dist/src/pg/param-map.js +181 -40
- package/dist/src/pg/schema.d.ts +17 -1
- package/dist/src/pg/schema.js +48 -2
- package/dist/src/pg/wire.d.ts +14 -1
- package/dist/src/pg/wire.js +81 -3
- package/dist/src/postgres-runtime.d.ts +9 -2
- package/dist/src/postgres-runtime.js +20 -5
- package/dist/src/runtime.d.ts +12 -0
- package/dist/src/runtime.js +83 -3
- package/dist/src/scan/scanner.js +1 -1
- package/package.json +5 -8
- package/dist/src/bun-runtime.d.ts +0 -7
- package/dist/src/bun-runtime.js +0 -45
- package/dist/src/bun.d.ts +0 -22
- package/dist/src/bun.js +0 -9
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Compile-time-checked raw SQL for TypeScript + PostgreSQL. Inspired by Rust's [sqlx](https://github.com/launchbadge/sqlx).
|
|
4
4
|
|
|
5
|
-
You write plain SQL strings. A `prepare` step validates them against your database via the PostgreSQL wire protocol and generates a TypeScript declaration file. Wrong column names
|
|
5
|
+
You write plain SQL strings. A `prepare` step validates them against your database via the PostgreSQL wire protocol and generates a TypeScript declaration file. Wrong column names and stale queries fail during `prepare`; mismatched parameter types and row usage become TypeScript errors.
|
|
6
6
|
|
|
7
|
-
The
|
|
7
|
+
The runtime uses [Postgres.js](https://github.com/porsager/postgres) through a single adapter instead of a Bun-specific client. The published CLI is a **Node ≥ 18** binary (`#!/usr/bin/env node`) and can also be run through Bun's npm tooling.
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
10
|
import { sql } from "@onreza/sqlx-js";
|
|
@@ -24,23 +24,24 @@ const rows = await sql(
|
|
|
24
24
|
- **Precise nullability inference** through `libpg-query`: `JOIN` direction (LEFT/RIGHT/FULL), inner `JOIN ... ON` predicates, DML `RETURNING`, `COALESCE`, `CASE`, `COUNT`, expression propagation. Parameters become `T | null` when wrapped in `COALESCE`/`NULLIF`/`IS [NOT] NULL`/`IS [NOT] DISTINCT FROM`, or when bound to a nullable column in `INSERT`/`UPDATE`.
|
|
25
25
|
- **WHERE narrowing**: `IS NOT NULL`, equality chains, `IN`, `LIKE`, `BETWEEN` make columns non-null. Tracks `AND`/`OR` semantics.
|
|
26
26
|
- **PostgreSQL enums** generated as TypeScript literal unions (read + write side).
|
|
27
|
-
- **Schema-aware `jsonb`** via a `SqlxJsJson` global namespace and a config-driven column → type mapping. Works for both result columns and `INSERT`/`UPDATE`/`WHERE` parameters.
|
|
27
|
+
- **Schema-aware `jsonb`** via a `SqlxJsJson` global namespace and a config-driven column → type mapping. Works for both result columns and `INSERT`/`UPDATE`/`WHERE` parameters. Unmapped `json`/`jsonb` falls back to `JsonValue` for rows and `JsonInput` for parameters instead of `unknown`.
|
|
28
28
|
- **Extension types out of the box**: `pgvector` (`vector`, `halfvec`, `sparsevec`), `hstore`, `citext`, `ltree`/`lquery`/`ltxtquery`. Add your own through `customTypes` config.
|
|
29
29
|
- **Domains** resolve to their base TypeScript type (`CREATE DOMAIN email AS text` → `string`), including domains over extension types or other domains.
|
|
30
30
|
- **Wide built-in type coverage**: numeric, text, date/time, UUID, json/jsonb, network (inet/cidr/macaddr/macaddr8), bit strings, ranges/multiranges, geometric, money, tsvector/tsquery, xml — and the matching array variants.
|
|
31
|
-
- **External SQL files** via `sql.file("queries/foo.sql", ...)` —
|
|
31
|
+
- **External SQL files** via `sql.file("queries/foo.sql", ...)` — prepared and typed through `KnownFileQueries`. Watch mode re-prepares on `.sql` edits too.
|
|
32
32
|
- **One-row helpers**: `sql.one(...)`, `sql.optional(...)`, `sql.file.one(...)`, `sql.file.optional(...)`, and the same chain on the `tx` callback — friendly with `noUncheckedIndexedAccess: true`. The scanner walks all of them.
|
|
33
33
|
- **Array params** for `text[]`, `int[]`, etc. are auto-serialised to PostgreSQL array literals (`{a,b,c}`) at runtime — no more `string_to_array` workaround.
|
|
34
34
|
- **Typed transactions** via `sql.transaction(async tx => …)` — the `tx` callback parameter is recognized by the scanner, so queries inside the block keep full type checking.
|
|
35
35
|
- **Sourcemap-accurate error reporting**: every prepare failure points to `file:line:column` of the originating `sql(...)` call site, with PG error code, position, and hint.
|
|
36
36
|
- **Linear migrations** with hash tampering detection.
|
|
37
|
+
- **Migration squash baselines** via `migrate squash`: generate a schema-only baseline from a shadow database, then hash-adopt it on already-migrated databases.
|
|
37
38
|
- **Runtime `migrate()`** with PostgreSQL advisory lock, safe for multi-replica startup.
|
|
38
39
|
- **Offline cache** committed to your repo. CI verifies via `prepare --check` without a database.
|
|
39
40
|
- **Schema snapshot + LLM manifest** via `schema dump` / `schema check`: tables, columns, constraints, indexes, types, and function/procedure metadata are introspected from PostgreSQL.
|
|
40
|
-
- **Shadow database validation** via
|
|
41
|
+
- **Shadow database validation** via `migrate dev` / `migrate verify`: auto-create a disposable shadow DB, apply migrations, validate SQL, and drop it afterwards.
|
|
41
42
|
- **Safe identifier quoting** via `sql.id(...)`, backed by the committed schema snapshot whitelist.
|
|
42
|
-
- **
|
|
43
|
-
- **Watch mode**:
|
|
43
|
+
- **Single runtime adapter**: Postgres.js backs the runtime on Node/Bun-compatible environments — no Bun.SQL-specific adapter to choose.
|
|
44
|
+
- **Watch mode**: debounced re-prepare with a warm `PgClient` + `SchemaCache` on `.ts` / `.tsx` / `.mts` / `.cts` / `.sql` changes.
|
|
44
45
|
- **Cache pruning** removes orphaned entries automatically (toggleable with `--no-prune`).
|
|
45
46
|
|
|
46
47
|
## Install
|
|
@@ -55,6 +56,14 @@ The package installs a `sqlx-js` binary. The CLI examples below use `npx @onreza
|
|
|
55
56
|
|
|
56
57
|
## Setup
|
|
57
58
|
|
|
59
|
+
### 0. Scaffold a project (optional)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx @onreza/sqlx-js init
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Creates `sqlx-js.config.ts`, a `migrations/` directory, and `.env.example` if they don't already exist (it never overwrites existing files), then prints the next steps. Skip it if you prefer to wire things up manually.
|
|
66
|
+
|
|
58
67
|
### 1. Configure the database URL
|
|
59
68
|
|
|
60
69
|
```bash
|
|
@@ -64,7 +73,7 @@ DATABASE_URL=postgres://user:password@localhost:5432/your_db
|
|
|
64
73
|
# DATABASE_URL=postgres://user:password@db.example.com:5432/your_db?sslmode=require
|
|
65
74
|
```
|
|
66
75
|
|
|
67
|
-
Supported `sslmode` values: `disable`, `prefer` (default — try TLS, fall back to plaintext), `require` (TLS or fail), `verify-ca`, `verify-full`. `
|
|
76
|
+
Supported `sslmode` values: `disable`, `prefer` (default — try TLS, fall back to plaintext), `require` (TLS or fail), `verify-ca`, `verify-full`. For a private/self-signed CA, point `sslrootcert` (and optionally `sslcert` / `sslkey` for client certs) at PEM files: `?sslmode=verify-full&sslrootcert=/etc/ssl/ca.pem`. `application_name`, `connect_timeout` (seconds), and `statement_timeout` (milliseconds) are also honored when provided as URL parameters.
|
|
68
77
|
|
|
69
78
|
### 2. Create a migration
|
|
70
79
|
|
|
@@ -72,7 +81,7 @@ Supported `sslmode` values: `disable`, `prefer` (default — try TLS, fall back
|
|
|
72
81
|
npx @onreza/sqlx-js migrate add init
|
|
73
82
|
```
|
|
74
83
|
|
|
75
|
-
Edit the
|
|
84
|
+
The command creates matching `.up.sql` and `.down.sql` stubs. Edit the `.up.sql` file (`migrations/0001_init.up.sql`):
|
|
76
85
|
|
|
77
86
|
```sql
|
|
78
87
|
CREATE TABLE users (
|
|
@@ -84,12 +93,22 @@ CREATE TABLE users (
|
|
|
84
93
|
);
|
|
85
94
|
```
|
|
86
95
|
|
|
87
|
-
|
|
96
|
+
During local development, validate the migration and regenerate query artifacts against a disposable shadow database:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx @onreza/sqlx-js migrate dev
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`migrate dev` does not touch your application database. It creates a temporary shadow database using `DATABASE_URL` credentials, applies migrations from scratch, validates that the latest migration's `.down.sql` restores the previous schema (squash baselines may omit `.down.sql`), prepares SQL queries against the resulting schema, writes `.sqlx-js/` and `sqlx-js-env.d.ts`, then drops the shadow database.
|
|
103
|
+
|
|
104
|
+
When you want to update your local application database, run:
|
|
88
105
|
|
|
89
106
|
```bash
|
|
90
107
|
npx @onreza/sqlx-js migrate run
|
|
91
108
|
```
|
|
92
109
|
|
|
110
|
+
If you need to change the latest migration after applying it locally, run `migrate revert`, edit the migration, then run `migrate run` again. Once a migration has been shared or merged, treat it as immutable and add a new migration instead.
|
|
111
|
+
|
|
93
112
|
### 3. Write your first query
|
|
94
113
|
|
|
95
114
|
```ts
|
|
@@ -133,7 +152,7 @@ Unknown queries, wrong parameter types, and dynamic strings are compile errors.
|
|
|
133
152
|
|
|
134
153
|
### `sql.file(path, ...params)`
|
|
135
154
|
|
|
136
|
-
Load SQL from an external file.
|
|
155
|
+
Load SQL from an external file. At prepare time the scanner reads the path relative to the source file. The generated `KnownFileQueries` key is the resolved SQL file path relative to `--root`; at runtime `sql.file(...)` reads the string argument relative to `process.cwd()`.
|
|
137
156
|
|
|
138
157
|
```ts
|
|
139
158
|
// queries/top_admins.sql
|
|
@@ -146,7 +165,7 @@ const admins = await sql.file("queries/top_admins.sql", "admin", 5);
|
|
|
146
165
|
// admins: { id: bigint; name: string }[]
|
|
147
166
|
```
|
|
148
167
|
|
|
149
|
-
File-backed queries are emitted into a separate `KnownFileQueries` interface
|
|
168
|
+
File-backed queries are emitted into a separate `KnownFileQueries` interface. Because the type key is the root-relative resolved SQL file path, keep file-backed call sites under a convention where that key matches the runtime string literal; the example keeps those call sites at the project root. Nested source-relative file paths are a current limitation.
|
|
150
169
|
|
|
151
170
|
### `sql.one(query, ...params)` and `sql.optional(query, ...params)`
|
|
152
171
|
|
|
@@ -221,7 +240,7 @@ const orderBy = sql.id("users", "created_at");
|
|
|
221
240
|
await unsafe(`SELECT id, email FROM ${sql.id("users")} ORDER BY ${orderBy} DESC`);
|
|
222
241
|
```
|
|
223
242
|
|
|
224
|
-
The default snapshot path is `.sqlx-js/schema/schema.json`. Override it at runtime with `SQLX_JS_SCHEMA_PATH`. Pass schema-qualified identifiers as separate segments: `sql.id("public", "users")`, not `sql.id("public.users")`.
|
|
243
|
+
The default snapshot path is `.sqlx-js/schema/schema.json`. Override it at runtime with `SQLX_JS_SCHEMA_PATH`. `sql.id(...)` accepts one to three identifier segments. Pass schema-qualified identifiers as separate segments: `sql.id("public", "users")`, not `sql.id("public.users")`.
|
|
225
244
|
|
|
226
245
|
### `migrate(options)`
|
|
227
246
|
|
|
@@ -258,15 +277,23 @@ import { createClient, setClient } from "@onreza/sqlx-js";
|
|
|
258
277
|
setClient(createClient(process.env.DATABASE_URL));
|
|
259
278
|
```
|
|
260
279
|
|
|
261
|
-
|
|
280
|
+
`createClient(url, options)` accepts every Postgres.js option plus two sqlx-js extras for observability and reliability:
|
|
262
281
|
|
|
263
282
|
```ts
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
283
|
+
setClient(createClient(process.env.DATABASE_URL, {
|
|
284
|
+
// Server-side per-connection statement timeout (ms). Also settable via
|
|
285
|
+
// ?statement_timeout=5000 in DATABASE_URL.
|
|
286
|
+
statementTimeoutMs: 5000,
|
|
287
|
+
// Fires after every query/transaction statement, success or failure.
|
|
288
|
+
onQuery: ({ query, params, durationMs, rowCount, error }) => {
|
|
289
|
+
if (error) logger.error({ query, error }); // database errors are PgError
|
|
290
|
+
else if (durationMs > 200) logger.warn({ slow: query, durationMs, rowCount });
|
|
291
|
+
},
|
|
292
|
+
}));
|
|
268
293
|
```
|
|
269
294
|
|
|
295
|
+
The `onQuery` hook is the integration point for metrics, tracing, and slow-query logging — sqlx-js does not log queries itself. The event carries the raw `params`, which may contain personal or sensitive data — don't log them blindly; redact or omit `params` in shared sinks. Database errors are normalized to `PgError`; transport and non-database errors pass through unchanged.
|
|
296
|
+
|
|
270
297
|
### `clearSqlFileCache()`
|
|
271
298
|
|
|
272
299
|
Drops the in-memory cache used by `sql.file(...)`. The cache invalidates automatically on file mtime change, so this is rarely needed manually.
|
|
@@ -286,7 +313,7 @@ try {
|
|
|
286
313
|
}
|
|
287
314
|
```
|
|
288
315
|
|
|
289
|
-
`sql.one` throws `NoRowsError` on 0 rows and `TooManyRowsError` (with `.actual`) on >1. `PgError` exposes `.code`, `.position`, `.hint`, `.detail`, `.severity`.
|
|
316
|
+
`sql.one` throws `NoRowsError` on 0 rows and `TooManyRowsError` (with `.actual`) on >1. Any database error raised by the default runtime is normalized into a `PgError`, so `e instanceof PgError` works the same in `prepare`, `migrate`, and ordinary `sql(...)` calls. `PgError` exposes `.code`, `.position`, `.hint`, `.detail`, `.severity`, `.schema`, `.table`, `.column`, `.constraint`, and the original driver error on `.cause`. Non-database failures (e.g. a dropped connection) are rethrown unchanged.
|
|
290
317
|
|
|
291
318
|
### Transactions with options
|
|
292
319
|
|
|
@@ -302,34 +329,97 @@ Options: `{ isolation?: "read uncommitted" | "read committed" | "repeatable read
|
|
|
302
329
|
|
|
303
330
|
### Namespace imports
|
|
304
331
|
|
|
305
|
-
In addition to `import { sql } from "@onreza/sqlx-js"`, the scanner recognises `import * as ns from "@onreza/sqlx-js"
|
|
332
|
+
In addition to `import { sql } from "@onreza/sqlx-js"`, the scanner recognises `import * as ns from "@onreza/sqlx-js"`. It validates `ns.sql(...)`, `ns.sql.one(...)`, `ns.sql.file(...)`, and `ns.sql.transaction(...)` exactly like the named-import form. Local re-declarations (`const sql = ...`, `const { sql } = ...`) correctly shadow the alias inside their scope.
|
|
306
333
|
|
|
307
334
|
## CLI
|
|
308
335
|
|
|
309
336
|
```
|
|
337
|
+
sqlx-js init [--root <dir>]
|
|
310
338
|
sqlx-js prepare [--check | --watch] [--root <dir>] [--dts <path>] [--no-prune] [--shadow-url <url>]
|
|
311
|
-
sqlx-js migrate run [--lock-timeout <ms>] | info | revert | add <name> [--
|
|
339
|
+
sqlx-js migrate dev [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] | verify [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] | run [--dry-run] [--json] [--lock-timeout <ms>] | info [--json] | check [--json] | revert [--dry-run] [--json] [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] | add <name> | squash <name> [--shadow-admin-url <url> | --shadow-url <url>] [--replace] [--pg-dump <path>] [--lock-timeout <ms>] | archive list | archive restore <name> [--force]
|
|
312
340
|
sqlx-js schema dump | check [--schema <path>] [--manifest <path>] [--no-manifest] [--shadow-url <url>]
|
|
313
341
|
sqlx-js --version | --help
|
|
314
342
|
```
|
|
315
343
|
|
|
344
|
+
Regular `prepare` describes queries across a small connection pool (default 8, override with `SQLX_JS_PREPARE_CONCURRENCY`) for faster cold runs on large projects. Watch mode keeps one session warm and reuses it between debounced changes.
|
|
345
|
+
|
|
316
346
|
| Flag | Meaning |
|
|
317
347
|
|-----------------------|--------------------------------------------------------------------------------------|
|
|
318
|
-
| `--check` | Offline: verify
|
|
348
|
+
| `--check` | Offline: verify every scanned query is present in cache, no database required. |
|
|
319
349
|
| `--watch` | Persistent connection, re-prepare on file change. |
|
|
320
350
|
| `--root <dir>` | Source/cache/migrations root (default: cwd). |
|
|
321
351
|
| `--dts <path>` | Declarations output (default: `<root>/sqlx-js-env.d.ts`). |
|
|
322
352
|
| `--no-prune` | Keep orphaned cache entries instead of removing them. |
|
|
323
353
|
| `--migrations <dir>` | Migrations directory (default: `<root>/migrations`). |
|
|
324
|
-
| `--
|
|
325
|
-
| `--
|
|
354
|
+
| `--dry-run` | For `migrate run` / `migrate revert`: validate without applying to the target DB. |
|
|
355
|
+
| `--json` | Machine-readable output for `migrate info/check` and migration dry-runs. |
|
|
356
|
+
| `--force` | For `migrate archive restore`: allow overwriting existing migration files. |
|
|
357
|
+
| `--lock-timeout <ms>` | Advisory-lock acquisition timeout for `migrate run` / `revert` / `dev` / `verify` / `squash`. |
|
|
358
|
+
| `--shadow-url <url>` | Use an existing disposable shadow DB instead of auto-creating one. |
|
|
359
|
+
| `--shadow-admin-url <url>` | Admin/maintenance DB URL used to auto-create shadow DBs. |
|
|
360
|
+
| `--replace` | For `migrate squash`: archive replaced migration files after writing the baseline. |
|
|
361
|
+
| `--pg-dump <path>` | For `migrate squash`: `pg_dump` executable path (default: `pg_dump`). |
|
|
326
362
|
| `--schema <path>` | Schema snapshot path (default: `<root>/.sqlx-js/schema/schema.json`). |
|
|
327
363
|
| `--manifest <path>` | LLM schema manifest path (default: `<root>/.sqlx-js/schema/schema.md`). |
|
|
328
364
|
| `--no-manifest` | Skip writing the LLM schema manifest during `schema dump`. |
|
|
329
365
|
|
|
330
|
-
|
|
366
|
+
Flags that take a value accept both `--flag value` and `--flag=value` forms.
|
|
367
|
+
|
|
368
|
+
`DATABASE_URL` must be set for any command that touches the application database or auto-creates a shadow database. `SHADOW_ADMIN_DATABASE_URL` can point at a maintenance/admin database when the application user cannot `CREATE DATABASE`; `SHADOW_DATABASE_URL` can point at a pre-created disposable shadow database. The internal wire client understands `sslmode`, `sslrootcert`, `sslcert`, `sslkey`, `application_name`, `connect_timeout` (seconds), and `statement_timeout` (milliseconds).
|
|
369
|
+
|
|
370
|
+
### Development and deployment flows
|
|
371
|
+
|
|
372
|
+
Use `migrate dev` while developing migrations and SQL:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
sqlx-js migrate add add_users
|
|
376
|
+
# edit migrations/000N_add_users.up.sql and .down.sql
|
|
377
|
+
sqlx-js migrate dev
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
`migrate dev` creates a disposable shadow database, applies all migrations from scratch, validates that the latest migration's `.down.sql` restores the previous schema (squash baselines may omit `.down.sql`), prepares project SQL against the shadow schema, writes `.sqlx-js/` plus `sqlx-js-env.d.ts`, and drops the shadow database. This means you can keep editing a local WIP migration before it is merged. You do not need to drop your application database or create a new migration for every local edit.
|
|
381
|
+
|
|
382
|
+
Use `migrate verify` in PR/CI before merge:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
sqlx-js migrate verify
|
|
386
|
+
sqlx-js prepare --check
|
|
387
|
+
tsc --noEmit
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
`migrate verify` runs the same shadow-database migration/down/SQL validation as `migrate dev`, but writes prepare output to temporary files instead of modifying `.sqlx-js/` or `sqlx-js-env.d.ts`.
|
|
391
|
+
|
|
392
|
+
Use `migrate run` in production/staging:
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
sqlx-js migrate run --dry-run --json
|
|
396
|
+
sqlx-js migrate run --lock-timeout 30000
|
|
397
|
+
sqlx-js migrate info --json
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Production migration users do not need `CREATEDB`; they only need permissions to apply migrations to the target database. Shadow databases are for development and CI validation before deployment.
|
|
401
|
+
|
|
402
|
+
By default, `migrate dev`, `migrate verify`, `migrate revert --dry-run`, and `migrate squash` derive a temporary database name from `DATABASE_URL`, connect to the `postgres` maintenance database with the same credentials, run `CREATE DATABASE ... OWNER <database-url-user>`, then `DROP DATABASE` after validation. If the application user cannot create databases, pass `--shadow-admin-url postgres://admin:.../postgres`; the generated shadow database is still owned by the application user from `DATABASE_URL`. In managed environments where databases must be pre-created, pass `--shadow-url` or set `SHADOW_DATABASE_URL`; that database is treated as disposable and its user schemas are cleared before development/verify/squash validation.
|
|
403
|
+
|
|
404
|
+
### Migration squash baselines
|
|
405
|
+
|
|
406
|
+
`migrate squash <name>` applies all migrations to a disposable shadow database, dumps the resulting schema with `pg_dump --schema-only`, and writes one baseline migration containing `sqlx-js` replacement metadata.
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
sqlx-js migrate squash baseline --replace
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
On an empty database, the baseline runs as ordinary schema SQL. On an already-migrated database, `migrate run` verifies that every replaced migration row exists in `_sqlx_js_migrations` with the exact recorded hash, then atomically replaces those rows with the baseline row without executing the baseline DDL. Partial or hash-mismatched history fails closed before any pending replaced migration is applied.
|
|
413
|
+
|
|
414
|
+
`--replace` moves the old `.up.sql` / `.down.sql` files into `migrations/.archive/<version>_<name>/` after the baseline is written. Omit it if you want to review the generated baseline first; while old files remain, a fresh database replays them and then adopts the baseline row. Repeated squash baselines replace the effective history, so migrations already covered by an earlier squash are not listed again. Squash baselines intentionally do not generate a `.down.sql`; automatic reversal of a full schema baseline is not safe enough to guess.
|
|
415
|
+
|
|
416
|
+
`migrate check` is filesystem-only: it validates migration filenames, duplicate versions, orphan `.down.sql` files, squash metadata, and replacement hashes where the replaced files are still present. It does not need `DATABASE_URL`.
|
|
417
|
+
|
|
418
|
+
`migrate info` is read-only: it reports the resolved history table, status summary, and per-file state without creating `_sqlx_js_migrations` on databases that have not been migrated yet. Use `migrate check --json`, `migrate info --json`, or `migrate run --dry-run --json` for CI/operator tooling that needs stable structured output.
|
|
419
|
+
|
|
420
|
+
`migrate revert --dry-run` validates the latest migration's `.down.sql` in a transaction on a shadow database. It applies all earlier `.up.sql` files, snapshots the schema, applies the latest `.up.sql`, applies its `.down.sql`, then fails if the final schema differs from the pre-`up` snapshot. The transaction is rolled back, so an explicit `--shadow-url` database is not changed by a successful or failed dry-run. Add `--json` for structured output.
|
|
331
421
|
|
|
332
|
-
`
|
|
422
|
+
`migrate archive list` shows archives created by `migrate squash --replace`. `migrate archive restore <name>` moves archived `.up.sql` / `.down.sql` files back into `migrations/` and refuses to overwrite current files unless `--force` is passed.
|
|
333
423
|
|
|
334
424
|
### Schema snapshot and manifest
|
|
335
425
|
|
|
@@ -338,7 +428,7 @@ All flags accept both `--flag value` and `--flag=value` forms.
|
|
|
338
428
|
- `.sqlx-js/schema/schema.json` — machine-readable contract for runtime identifier whitelisting and CI drift checks.
|
|
339
429
|
- `.sqlx-js/schema/schema.md` — compact LLM-facing manifest with tables, columns, constraints, indexes, types, and functions.
|
|
340
430
|
|
|
341
|
-
`schema check` re-introspects the database and fails if the committed snapshot is stale. With `--shadow-url`, both `prepare` and `schema dump/check` first apply pending migrations to the shadow database, then use that database as the source of truth. In watch mode, pending shadow migrations are checked before every re-prepare; when a migration is applied, the prepare session is reopened so schema metadata is not reused across DDL changes.
|
|
431
|
+
`schema check` re-introspects the database and fails if the committed snapshot is stale. With `--shadow-url`, both `prepare` and `schema dump/check` first apply pending migrations to the shadow database, then use that database as the source of truth. Unlike `migrate dev` / `verify` / `squash`, these commands do not clear an explicit shadow database first. In watch mode, pending shadow migrations are checked before every re-prepare; when a migration is applied, the prepare session is reopened so schema metadata is not reused across DDL changes.
|
|
342
432
|
|
|
343
433
|
### Error output
|
|
344
434
|
|
|
@@ -387,7 +477,7 @@ declare global {
|
|
|
387
477
|
export {};
|
|
388
478
|
```
|
|
389
479
|
|
|
390
|
-
After re-running `prepare`, every `jsonb` column or parameter declared in `jsonbTypes` is checked against the corresponding TypeScript type.
|
|
480
|
+
After re-running `prepare`, every `jsonb` column or parameter declared in `jsonbTypes` is checked against the corresponding TypeScript type. Columns without a custom mapping use `JsonValue` for result rows and `JsonInput` for parameters, both exported by `@onreza/sqlx-js`, so non-JSON inputs such as `Date`, functions, and `bigint` are rejected by TypeScript while plain JSON objects, arrays, strings, numbers, booleans, and nested JSON `null` values are accepted. Top-level SQL `null` is added separately as `| null` only when the mapped database parameter is nullable.
|
|
391
481
|
|
|
392
482
|
### Extension types and `customTypes`
|
|
393
483
|
|
|
@@ -404,7 +494,7 @@ sqlx-js ships with a built-in registry that resolves popular PostgreSQL extensio
|
|
|
404
494
|
| `lquery` | `string` | ltree |
|
|
405
495
|
| `ltxtquery` | `string` | ltree |
|
|
406
496
|
|
|
407
|
-
Add or override mappings via `customTypes` in `sqlx-js.config.ts`. Keys are `pg_type.typname` values (the bare type name
|
|
497
|
+
Add or override mappings via `customTypes` in `sqlx-js.config.ts`. Keys are `pg_type.typname` values (the bare type name). The registry is global by type name, so two schemas with the same `typname` cannot be mapped differently:
|
|
408
498
|
|
|
409
499
|
```ts
|
|
410
500
|
import type { SqlxJsConfig } from "@onreza/sqlx-js";
|
|
@@ -421,7 +511,7 @@ export default config;
|
|
|
421
511
|
|
|
422
512
|
Domains resolve to their base type through `pg_type.typbasetype`. `CREATE DOMAIN positive_int AS integer CHECK (VALUE > 0)` → `number`, `CREATE DOMAIN tagged AS hstore` → `Record<string, string | null>`. Array variants of any registered scalar are also wired up automatically — `vector[]` → `(number[])[]`.
|
|
423
513
|
|
|
424
|
-
Composite types (`CREATE TYPE foo AS (a int, b text)`)
|
|
514
|
+
Composite types (`CREATE TYPE foo AS (a int, b text)`) resolve to a struct literal — `{ a: number | null; b: string | null }` — with each attribute typed (enums, domains, and nested composites included) and nullable unless the attribute is `NOT NULL`. Array variants (`foo[]`) resolve too.
|
|
425
515
|
|
|
426
516
|
## How nullability is inferred
|
|
427
517
|
|
|
@@ -445,14 +535,15 @@ Commit the generated `sqlx-js-env.d.ts` and the `.sqlx-js/` cache directory to y
|
|
|
445
535
|
|
|
446
536
|
```yaml
|
|
447
537
|
- run: bun install
|
|
448
|
-
- run: sqlx-js
|
|
538
|
+
- run: sqlx-js migrate verify # builds schema from migrations in a disposable shadow DB
|
|
539
|
+
- run: sqlx-js prepare --check # fails if any query is missing from the committed cache
|
|
449
540
|
- run: sqlx-js schema check # fails if the committed schema snapshot is stale
|
|
450
541
|
- run: tsc --noEmit # fails if types are stale
|
|
451
542
|
- run: bun test
|
|
452
543
|
- run: bun run build # emits publishable JS + declarations under dist/
|
|
453
544
|
```
|
|
454
545
|
|
|
455
|
-
The `prepare --check` step runs without a database
|
|
546
|
+
The `migrate verify` step needs `DATABASE_URL` credentials that can either create a temporary database or use `--shadow-admin-url` / `--shadow-url`. It does not write `.sqlx-js/` or `sqlx-js-env.d.ts`. The `prepare --check` step then runs without a database; your committed offline cache is the source of truth. `schema check` intentionally uses a live database because it verifies the committed schema contract against PostgreSQL.
|
|
456
547
|
|
|
457
548
|
## Contributing
|
|
458
549
|
|
|
@@ -470,16 +561,16 @@ Releases are automated via `release-please`: pushes to `main` accumulate into a
|
|
|
470
561
|
`sqlx-js` is a young library. Known gaps:
|
|
471
562
|
|
|
472
563
|
- PostgreSQL only (no MySQL or SQLite).
|
|
564
|
+
- The scanner only follows direct named imports and namespace imports from `@onreza/sqlx-js`; it does not follow re-exports, dynamic aliases, or tagged-template calls.
|
|
473
565
|
- `INSERT INTO t VALUES (...)` without an explicit column list isn't parameter-mapped.
|
|
474
566
|
- `SELECT *` falls back to conservative nullability.
|
|
567
|
+
- Statements without a row description, such as `UPDATE ...` without `RETURNING`, are emitted with `row: never`, so the public return type is `Promise<never[]>`.
|
|
475
568
|
- Nested CTE references (CTE-`b` referencing CTE-`a` in the same `WITH`) and `WITH RECURSIVE` are not analysed transitively — at worst this produces extra `T | null`. Use `AS "id!"` overrides if needed.
|
|
476
|
-
- Composite types resolve to `unknown`. Domains and array types of registered types resolve correctly.
|
|
477
569
|
- Column names whose **real** name (not an alias) ends with `!` or `?` are not supported — the runtime strips those suffixes assuming an override. Use `AS "alias"` if you have such a column.
|
|
478
570
|
- Migrations run inside `BEGIN/COMMIT`. DDL that disallows transactions (`CREATE INDEX CONCURRENTLY`, `VACUUM`, `REINDEX CONCURRENTLY`, …) will fail; split such operations into separate migrations executed outside the runner.
|
|
479
|
-
-
|
|
480
|
-
-
|
|
481
|
-
- `
|
|
482
|
-
- `sql.file(path)` path is matched literally between scan time and runtime — they must agree on the working directory. Document a convention for your team (e.g. always run from the repo root).
|
|
571
|
+
- The **internal** wire client (used by `migrate run`, `prepare`, and the runtime `migrate()` helper) reads `sslmode`, `sslrootcert`/`sslcert`/`sslkey`, `application_name`, `connect_timeout`, and `statement_timeout` from `DATABASE_URL`. The default runtime `sql()` path delegates connection handling to Postgres.js; configure TLS, pooling, and timeouts through the `DATABASE_URL` and `createClient(...)` options it understands (`statementTimeoutMs` is a convenience that maps to a per-connection `statement_timeout`).
|
|
572
|
+
- `connect_timeout` bounds the entire internal-client connect, including the TLS handshake and SCRAM authentication.
|
|
573
|
+
- `sql.file(path)` has a path-key mismatch to be aware of: prepare resolves the file relative to the source file, codegen keys it by root-relative resolved path, and runtime reads the literal path relative to `process.cwd()`. Keep a project convention and verify with `tsc` after `prepare`.
|
|
483
574
|
|
|
484
575
|
See [ROADMAP.md](./ROADMAP.md) for what's planned.
|
|
485
576
|
|
package/ROADMAP.md
CHANGED
|
@@ -6,7 +6,8 @@ Items already shipped live in the [README](./README.md) feature list; this file
|
|
|
6
6
|
|
|
7
7
|
| Feature | ROI | Notes |
|
|
8
8
|
|---------|-----|-------|
|
|
9
|
-
|
|
|
9
|
+
| Migration lifecycle improvements | 8 | Squash baseline MVP, `migrate run --dry-run`, read-only `migrate info`, archive/restore helpers, JSON operator output, filesystem-only `migrate check`, and shadow-based `migrate revert --dry-run` exist; continue with safer migration lifecycle guardrails. This is the foundation for reliable external migration import. |
|
|
10
|
+
| Prisma migration assistant | 7 | Import Prisma Migrate SQL history and Prisma TypedSQL/raw SQL into `sqlx-js`; classify Prisma Client CRUD/nested-write sites as assisted/manual instead of promising a fully automatic ORM rewrite. |
|
|
10
11
|
| Self-join precision (unqualified ColumnRef) | 4 | `SELECT name FROM users u1 JOIN users u2 ON ...` with unqualified `name` can't be attributed to a specific alias. PG would reject ambiguous unqualified refs anyway, but explicit aliasing currently has no narrowing benefit in self-joins. |
|
|
11
12
|
| `INSERT INTO t VALUES (...)` without column list | 3 | Map params by `pg_attribute attnum` ordering. Rare in practice — most teams use explicit column lists. |
|
|
12
13
|
| Tagged-template literal API (`` sql`SELECT ${x}` ``) | 8 | Restoring sqlx's inline-SQL aesthetic requires either a TS compiler plugin (`ts-patch`) or a Bun preload-time AST rewriter. TS itself hardcodes the first tag argument as `TemplateStringsArray` and refuses to narrow to literal tuples. Significant effort, large UX win. |
|
|
@@ -15,9 +16,7 @@ Items already shipped live in the [README](./README.md) feature list; this file
|
|
|
15
16
|
| MySQL backend | 5 | Some runtime clients support it, but MySQL has no `Describe Statement` equivalent. Would need a real SQL parser pass + `INFORMATION_SCHEMA` introspection. |
|
|
16
17
|
| SQLite backend | 4 | SQLite's column types are dynamic. Would require running `EXPLAIN` and a heuristic mapper, or schema-driven inference per-statement. |
|
|
17
18
|
| `EXPLAIN`-based performance hints | 6 | `prepare` could optionally run `EXPLAIN` per query and surface seq-scan / missing-index warnings. Independent feature; pairs well with CI. |
|
|
18
|
-
| `NOT (col IS NULL)` narrowing | 2 | Symmetric inversion in WHERE walker. Niche pattern. |
|
|
19
19
|
| Multi-statement queries | 2 | One SQL string with multiple statements separated by `;`. PG's `Parse` is single-statement; this would require client-side splitting. |
|
|
20
|
-
| Migration `down` reversal dry-run | 3 | Apply `down`, diff schema, compare to pre-`up` snapshot. Useful for catching irreversible migrations. |
|
|
21
20
|
| Stored procedure / function typing | 3 | `CALL proc(...)` and `SELECT func(...)` with parameter and return-type binding from `pg_proc`. |
|
|
22
21
|
| Streaming / cursor / COPY typing | 3 | Surface Postgres.js cursor / COPY APIs with proper row types. |
|
|
23
22
|
|
package/dist/bin/sqlx-js.js
CHANGED
|
@@ -4,8 +4,9 @@ import { dirname, join, resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { runPrepare } from "../src/commands/prepare.js";
|
|
6
6
|
import { runWatch } from "../src/commands/watch.js";
|
|
7
|
-
import { migrateRun, migrateInfo, migrateRevert, migrateAdd } from "../src/commands/migrate.js";
|
|
7
|
+
import { migrateArchiveList, migrateArchiveRestore, migrateCheck, migrateDev, migrateRun, migrateInfo, migrateRevert, migrateAdd, migrateSquash, migrateVerify, } from "../src/commands/migrate.js";
|
|
8
8
|
import { applyShadowMigrations, runSchemaCheck, runSchemaDump } from "../src/commands/schema.js";
|
|
9
|
+
import { runInit } from "../src/commands/init.js";
|
|
9
10
|
function packageVersion() {
|
|
10
11
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
11
12
|
for (const path of [join(here, "../package.json"), join(here, "../../package.json")]) {
|
|
@@ -22,24 +23,32 @@ function help() {
|
|
|
22
23
|
console.error(`sqlx-js — compile-time-checked SQL for TypeScript + Postgres (v${VERSION})
|
|
23
24
|
|
|
24
25
|
usage:
|
|
26
|
+
sqlx-js init [--root <dir>]
|
|
25
27
|
sqlx-js prepare [--check | --watch] [--root <dir>] [--dts <path>] [--no-prune] [--shadow-url <url>]
|
|
26
|
-
sqlx-js migrate run [--lock-timeout <ms>] | info | revert [--lock-timeout <ms>] | add <name>
|
|
28
|
+
sqlx-js migrate dev [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] | verify [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] | run [--dry-run] [--json] [--lock-timeout <ms>] | info [--json] | check [--json] | revert [--dry-run] [--json] [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] | add <name> | squash <name> [--shadow-admin-url <url> | --shadow-url <url>] [--replace] [--pg-dump <path>] [--lock-timeout <ms>] | archive list | archive restore <name> [--force]
|
|
27
29
|
sqlx-js schema dump | check [--schema <path>] [--manifest <path>] [--no-manifest] [--shadow-url <url>]
|
|
28
30
|
sqlx-js --version
|
|
29
31
|
|
|
30
32
|
env:
|
|
31
|
-
DATABASE_URL=postgres://... (supports
|
|
32
|
-
SHADOW_DATABASE_URL=postgres://... (optional
|
|
33
|
+
DATABASE_URL=postgres://... (supports sslmode, cert paths, application_name, connect_timeout, statement_timeout)
|
|
34
|
+
SHADOW_DATABASE_URL=postgres://... (optional pre-created disposable shadow DB)
|
|
35
|
+
SHADOW_ADMIN_DATABASE_URL=postgres://... (optional admin URL for auto-created shadow DBs)
|
|
33
36
|
|
|
34
37
|
flags:
|
|
35
38
|
--root <dir> scan root (default: cwd)
|
|
36
39
|
--dts <path> declarations output (default: <root>/sqlx-js-env.d.ts)
|
|
37
|
-
--check offline mode:
|
|
40
|
+
--check offline mode: verify scanned queries exist in cache, no DB
|
|
38
41
|
--watch re-prepare on file change (persistent PG connection)
|
|
39
42
|
--no-prune keep orphaned cache entries (default: remove)
|
|
40
43
|
--migrations <dir> migrations directory (default: <root>/migrations)
|
|
41
|
-
--
|
|
42
|
-
--
|
|
44
|
+
--dry-run validate and print migrate run/revert plan without applying migrations
|
|
45
|
+
--json machine-readable output for migrate info/check and migrate run/revert --dry-run
|
|
46
|
+
--force allow archive restore to overwrite existing migration files
|
|
47
|
+
--lock-timeout <ms> advisory-lock acquisition timeout for migrate run/revert/dev/verify/squash
|
|
48
|
+
--shadow-url <url> use an existing disposable shadow DB instead of auto-creating one
|
|
49
|
+
--shadow-admin-url <url> admin/maintenance DB URL used to auto-create shadow DBs
|
|
50
|
+
--replace archive replaced migrations after migrate squash writes the baseline
|
|
51
|
+
--pg-dump <path> pg_dump executable for migrate squash (default: pg_dump)
|
|
43
52
|
--schema <path> schema snapshot path (default: <root>/.sqlx-js/schema/schema.json)
|
|
44
53
|
--manifest <path> LLM schema manifest path (default: <root>/.sqlx-js/schema/schema.md)
|
|
45
54
|
--no-manifest skip writing the LLM schema manifest during schema dump
|
|
@@ -77,6 +86,7 @@ const root = resolve(arg("--root", process.cwd()));
|
|
|
77
86
|
const databaseUrl = process.env.DATABASE_URL ?? "";
|
|
78
87
|
const shadowUrlArg = arg("--shadow-url");
|
|
79
88
|
const shadowUrl = shadowUrlArg ?? process.env.SHADOW_DATABASE_URL;
|
|
89
|
+
const shadowAdminUrl = arg("--shadow-admin-url") ?? process.env.SHADOW_ADMIN_DATABASE_URL;
|
|
80
90
|
const cacheDir = join(root, ".sqlx-js");
|
|
81
91
|
const dtsArg = arg("--dts");
|
|
82
92
|
const dtsPath = dtsArg ? resolve(dtsArg) : join(root, "sqlx-js-env.d.ts");
|
|
@@ -85,7 +95,10 @@ const schemaArg = arg("--schema");
|
|
|
85
95
|
const schemaPath = schemaArg ? resolve(schemaArg) : join(root, ".sqlx-js/schema/schema.json");
|
|
86
96
|
const manifestArg = arg("--manifest");
|
|
87
97
|
const manifestPath = manifestArg ? resolve(manifestArg) : join(root, ".sqlx-js/schema/schema.md");
|
|
88
|
-
if (cmd === "
|
|
98
|
+
if (cmd === "init") {
|
|
99
|
+
runInit({ root });
|
|
100
|
+
}
|
|
101
|
+
else if (cmd === "prepare") {
|
|
89
102
|
if (flag("--check") && shadowUrlArg) {
|
|
90
103
|
console.error("--shadow-url cannot be used with prepare --check; use live prepare or schema check --shadow-url");
|
|
91
104
|
process.exit(2);
|
|
@@ -151,19 +164,57 @@ else if (cmd === "schema") {
|
|
|
151
164
|
}
|
|
152
165
|
else if (cmd === "migrate") {
|
|
153
166
|
const sub = process.argv[3];
|
|
154
|
-
|
|
167
|
+
const revertDryRun = sub === "revert" && flag("--dry-run");
|
|
168
|
+
const workflowShadowOnly = ((sub === "dev" || sub === "verify" || sub === "squash") && !!shadowUrl) || (revertDryRun && !!shadowUrl);
|
|
169
|
+
if (!databaseUrl && sub !== "add" && sub !== "check" && sub !== "squash" && sub !== "archive" && !workflowShadowOnly) {
|
|
155
170
|
console.error("DATABASE_URL is required");
|
|
156
171
|
process.exit(2);
|
|
157
172
|
}
|
|
158
173
|
const tRaw = arg("--lock-timeout");
|
|
159
174
|
const lockTimeoutMs = tRaw ? Number(tRaw) : undefined;
|
|
160
|
-
if (sub === "
|
|
161
|
-
await
|
|
175
|
+
if (sub === "dev") {
|
|
176
|
+
await migrateDev({
|
|
177
|
+
root,
|
|
178
|
+
databaseUrl,
|
|
179
|
+
migrationsDir,
|
|
180
|
+
cacheDir,
|
|
181
|
+
dtsPath,
|
|
182
|
+
prune: !flag("--no-prune"),
|
|
183
|
+
shadowUrl,
|
|
184
|
+
shadowAdminUrl,
|
|
185
|
+
lockTimeoutMs,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else if (sub === "verify") {
|
|
189
|
+
await migrateVerify({
|
|
190
|
+
root,
|
|
191
|
+
databaseUrl,
|
|
192
|
+
migrationsDir,
|
|
193
|
+
cacheDir,
|
|
194
|
+
dtsPath,
|
|
195
|
+
shadowUrl,
|
|
196
|
+
shadowAdminUrl,
|
|
197
|
+
lockTimeoutMs,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
else if (sub === "run") {
|
|
201
|
+
await migrateRun({ databaseUrl, migrationsDir, lockTimeoutMs, dryRun: flag("--dry-run"), json: flag("--json") });
|
|
162
202
|
}
|
|
163
203
|
else if (sub === "info")
|
|
164
|
-
await migrateInfo({ databaseUrl, migrationsDir });
|
|
165
|
-
else if (sub === "
|
|
166
|
-
|
|
204
|
+
await migrateInfo({ databaseUrl, migrationsDir, json: flag("--json") });
|
|
205
|
+
else if (sub === "check")
|
|
206
|
+
migrateCheck({ migrationsDir, json: flag("--json") });
|
|
207
|
+
else if (sub === "revert") {
|
|
208
|
+
await migrateRevert({
|
|
209
|
+
databaseUrl,
|
|
210
|
+
migrationsDir,
|
|
211
|
+
lockTimeoutMs,
|
|
212
|
+
dryRun: flag("--dry-run"),
|
|
213
|
+
shadowUrl,
|
|
214
|
+
shadowAdminUrl,
|
|
215
|
+
json: flag("--json"),
|
|
216
|
+
});
|
|
217
|
+
}
|
|
167
218
|
else if (sub === "add") {
|
|
168
219
|
const name = process.argv[4];
|
|
169
220
|
if (!name) {
|
|
@@ -172,6 +223,38 @@ else if (cmd === "migrate") {
|
|
|
172
223
|
}
|
|
173
224
|
migrateAdd({ databaseUrl, migrationsDir, name });
|
|
174
225
|
}
|
|
226
|
+
else if (sub === "squash") {
|
|
227
|
+
const name = process.argv[4];
|
|
228
|
+
if (!name) {
|
|
229
|
+
console.error("migrate squash: name required");
|
|
230
|
+
process.exit(2);
|
|
231
|
+
}
|
|
232
|
+
await migrateSquash({
|
|
233
|
+
databaseUrl,
|
|
234
|
+
migrationsDir,
|
|
235
|
+
name,
|
|
236
|
+
shadowUrl,
|
|
237
|
+
shadowAdminUrl,
|
|
238
|
+
replace: flag("--replace"),
|
|
239
|
+
pgDumpPath: arg("--pg-dump"),
|
|
240
|
+
lockTimeoutMs,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
else if (sub === "archive") {
|
|
244
|
+
const action = process.argv[4];
|
|
245
|
+
if (action === "list")
|
|
246
|
+
migrateArchiveList({ migrationsDir });
|
|
247
|
+
else if (action === "restore") {
|
|
248
|
+
const name = process.argv[5];
|
|
249
|
+
if (!name) {
|
|
250
|
+
console.error("migrate archive restore: name required");
|
|
251
|
+
process.exit(2);
|
|
252
|
+
}
|
|
253
|
+
migrateArchiveRestore({ migrationsDir, name, force: flag("--force") });
|
|
254
|
+
}
|
|
255
|
+
else
|
|
256
|
+
help();
|
|
257
|
+
}
|
|
175
258
|
else
|
|
176
259
|
help();
|
|
177
260
|
}
|