@onreza/sqlx-js 0.5.0 → 0.7.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 +99 -30
- package/ROADMAP.md +2 -2
- package/dist/bin/sqlx-js-diagnostics.d.ts +2 -0
- package/dist/bin/sqlx-js-diagnostics.js +96 -0
- package/dist/bin/sqlx-js.js +291 -92
- package/dist/src/cache.d.ts +1 -1
- package/dist/src/cache.js +1 -1
- package/dist/src/codegen.js +27 -14
- package/dist/src/commands/init.js +97 -3
- package/dist/src/commands/migrate.d.ts +2 -101
- package/dist/src/commands/migrate.js +6 -546
- package/dist/src/commands/prepare.d.ts +10 -2
- package/dist/src/commands/prepare.js +201 -33
- package/dist/src/commands/schema.js +1 -1
- package/dist/src/commands/watch.d.ts +14 -6
- package/dist/src/commands/watch.js +184 -21
- package/dist/src/config.d.ts +1 -0
- package/dist/src/config.js +8 -0
- package/dist/src/function-cache.d.ts +2 -0
- package/dist/src/function-cache.js +6 -3
- package/dist/src/index.d.ts +17 -1
- package/dist/src/index.js +3 -0
- package/dist/src/migration-core.d.ts +157 -0
- package/dist/src/migration-core.js +578 -0
- package/dist/src/pg/schema.d.ts +1 -0
- package/dist/src/pg/schema.js +42 -31
- package/dist/src/pg/wire.d.ts +1 -0
- package/dist/src/pg/wire.js +6 -0
- package/dist/src/postgres-runtime.d.ts +11 -1
- package/dist/src/postgres-runtime.js +22 -5
- package/dist/src/runtime.d.ts +5 -2
- package/dist/src/runtime.js +34 -13
- package/dist/src/scan/scanner.d.ts +1 -1
- package/dist/src/scan/scanner.js +84 -17
- package/dist/src/type-inspection.d.ts +1 -0
- package/dist/src/type-inspection.js +20 -0
- package/package.json +6 -2
package/dist/bin/sqlx-js.js
CHANGED
|
@@ -2,13 +2,7 @@
|
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import {
|
|
6
|
-
import { runWatch } from "../src/commands/watch.js";
|
|
7
|
-
import { migrateArchiveList, migrateArchiveRestore, migrateCheck, migrateDev, migrateRun, migrateInfo, migrateRevert, migrateAdd, migrateSquash, migrateVerify, } from "../src/commands/migrate.js";
|
|
8
|
-
import { applyShadowMigrations, runSchemaCheck, runSchemaDump } from "../src/commands/schema.js";
|
|
9
|
-
import { runInit } from "../src/commands/init.js";
|
|
10
|
-
import { runPgschemaCommand, runPgschemaInstall } from "../src/commands/pgschema.js";
|
|
11
|
-
import { runDoctor } from "../src/commands/doctor.js";
|
|
5
|
+
import { parseArgs } from "node:util";
|
|
12
6
|
import { assertSupportedRuntime, loadConfig, loadRootEnv } from "../src/config.js";
|
|
13
7
|
function packageVersion() {
|
|
14
8
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
@@ -22,33 +16,39 @@ function packageVersion() {
|
|
|
22
16
|
throw new Error("sqlx-js: cannot locate package.json for version");
|
|
23
17
|
}
|
|
24
18
|
const VERSION = packageVersion();
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
const HELP = {
|
|
20
|
+
root: `sqlx-js — compile-time-checked SQL for TypeScript + Postgres (v${VERSION})
|
|
27
21
|
|
|
28
22
|
usage:
|
|
29
23
|
sqlx-js init [--root <dir>] [--schema-provider builtin|pgschema]
|
|
30
|
-
sqlx-js doctor [--root <dir>] [--json]
|
|
31
|
-
sqlx-js db install | check
|
|
32
|
-
sqlx-js
|
|
33
|
-
sqlx-js
|
|
34
|
-
sqlx-js
|
|
24
|
+
sqlx-js doctor [--root <dir>] [--dts <path>] [--json]
|
|
25
|
+
sqlx-js db install | check [--root <dir>]
|
|
26
|
+
sqlx-js db plan | apply [--root <dir>] [-- <pgschema args>]
|
|
27
|
+
sqlx-js prepare [--check | --offline | --verify | --watch] [--json | --jsonl] [--strict-inference] [--root <dir>] [--dts <path>] [--no-prune] [--shadow-url <url>]
|
|
28
|
+
sqlx-js migrate dev [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] [--strict-inference] | verify [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] [--strict-inference] | 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]
|
|
29
|
+
sqlx-js schema dump [--schema <path>] [--manifest <path>] [--no-manifest] [--shadow-url <url>]
|
|
30
|
+
sqlx-js schema check [--schema <path>] [--shadow-url <url>]
|
|
35
31
|
sqlx-js --version
|
|
32
|
+
sqlx-js-diagnostics github|unix < prepare-diagnostics.json
|
|
36
33
|
|
|
37
34
|
env:
|
|
38
|
-
DATABASE_URL=postgres://... (supports sslmode, cert paths, application_name, connect_timeout, statement_timeout)
|
|
35
|
+
DATABASE_URL=postgres://... (supports sslmode, cert paths, application_name, options, connect_timeout, statement_timeout)
|
|
39
36
|
SHADOW_DATABASE_URL=postgres://... (optional pre-created disposable shadow DB)
|
|
40
37
|
SHADOW_ADMIN_DATABASE_URL=postgres://... (optional admin URL for auto-created shadow DBs)
|
|
41
38
|
|
|
42
39
|
flags:
|
|
43
40
|
--root <dir> scan root (default: cwd)
|
|
44
41
|
--dts <path> declarations output (default: <root>/sqlx-js-env.d.ts)
|
|
45
|
-
--check offline
|
|
42
|
+
--check read-only offline verification of cache and declarations
|
|
43
|
+
--offline regenerate declarations from committed cache, no DB
|
|
46
44
|
--verify prepare against DB/shadow and compare committed generated artifacts
|
|
47
45
|
--watch re-prepare on file change (persistent PG connection)
|
|
48
46
|
--no-prune keep orphaned cache entries (default: remove)
|
|
49
47
|
--migrations <dir> migrations directory (default: <root>/migrations)
|
|
50
48
|
--dry-run validate and print migrate run/revert plan without applying migrations
|
|
51
49
|
--json machine-readable output for prepare and migration inspection/dry-run commands
|
|
50
|
+
--jsonl streaming machine-readable output for prepare --watch
|
|
51
|
+
--strict-inference fail when query inference degrades or emits unknown types
|
|
52
52
|
--force allow archive restore to overwrite existing migration files
|
|
53
53
|
--lock-timeout <ms> advisory-lock acquisition timeout for migrate run/revert/dev/verify/squash
|
|
54
54
|
--shadow-url <url> use an existing disposable shadow DB instead of auto-creating one
|
|
@@ -59,38 +59,210 @@ flags:
|
|
|
59
59
|
--manifest <path> LLM schema manifest path (default: <root>/.sqlx-js/schema/schema.md)
|
|
60
60
|
--no-manifest skip writing the LLM schema manifest during schema dump
|
|
61
61
|
--schema-provider <name> init schema workflow: builtin (default) or pgschema
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
`,
|
|
63
|
+
init: `usage: sqlx-js init [--root <dir>] [--schema-provider builtin|pgschema]`,
|
|
64
|
+
doctor: `usage: sqlx-js doctor [--root <dir>] [--dts <path>] [--json]`,
|
|
65
|
+
db: `usage: sqlx-js db install | check [--root <dir>] | plan | apply [--root <dir>] [-- <pgschema args>]`,
|
|
66
|
+
prepare: `usage: sqlx-js prepare [--check | --offline | --verify | --watch] [--json | --jsonl] [--strict-inference] [--root <dir>] [--dts <path>] [--no-prune] [--shadow-url <url>]`,
|
|
67
|
+
migrate: `usage: sqlx-js migrate dev [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] [--strict-inference] | verify [--shadow-admin-url <url> | --shadow-url <url>] [--lock-timeout <ms>] [--strict-inference] | 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]`,
|
|
68
|
+
schema: `usage: sqlx-js schema dump [--schema <path>] [--manifest <path>] [--no-manifest] [--shadow-url <url>] | check [--schema <path>] [--shadow-url <url>]`,
|
|
69
|
+
};
|
|
70
|
+
function printHelp(scope, error = false) {
|
|
71
|
+
(error ? console.error : console.log)(HELP[scope]);
|
|
64
72
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
function arg(name, def) {
|
|
69
|
-
const eq = `${name}=`;
|
|
70
|
-
for (let i = 0; i < cliArgv.length; i++) {
|
|
71
|
-
const a = cliArgv[i];
|
|
72
|
-
if (a === name)
|
|
73
|
-
return cliArgv[i + 1] ?? def;
|
|
74
|
-
if (a.startsWith(eq))
|
|
75
|
-
return a.slice(eq.length);
|
|
76
|
-
}
|
|
77
|
-
return def;
|
|
73
|
+
function exitHelp(scope) {
|
|
74
|
+
printHelp(scope);
|
|
75
|
+
process.exit(0);
|
|
78
76
|
}
|
|
79
|
-
function
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
77
|
+
function usageError(message, scope = "root") {
|
|
78
|
+
console.error(`sqlx-js: ${message}`);
|
|
79
|
+
printHelp(scope, true);
|
|
80
|
+
process.exit(2);
|
|
85
81
|
}
|
|
86
|
-
const
|
|
82
|
+
const rawArgv = process.argv.slice(2);
|
|
83
|
+
const passthroughIndex = rawArgv.indexOf("--");
|
|
84
|
+
const cliArgv = passthroughIndex >= 0 ? rawArgv.slice(0, passthroughIndex) : rawArgv;
|
|
85
|
+
const passthroughArgs = passthroughIndex >= 0 ? rawArgv.slice(passthroughIndex + 1) : [];
|
|
86
|
+
const cmd = cliArgv[0];
|
|
87
|
+
const scopes = new Set(["init", "doctor", "db", "prepare", "migrate", "schema"]);
|
|
87
88
|
if (cmd === "--version" || cmd === "-v") {
|
|
88
89
|
console.log(VERSION);
|
|
89
90
|
process.exit(0);
|
|
90
91
|
}
|
|
91
|
-
if (cmd === "--help" || cmd === "-h"
|
|
92
|
-
|
|
92
|
+
if (!cmd || cmd === "--help" || cmd === "-h")
|
|
93
|
+
exitHelp("root");
|
|
94
|
+
if (!scopes.has(cmd))
|
|
95
|
+
usageError(`unknown command ${JSON.stringify(cmd)}`);
|
|
96
|
+
const scope = cmd;
|
|
97
|
+
if (cliArgv.includes("--help") || cliArgv.includes("-h"))
|
|
98
|
+
exitHelp(scope);
|
|
99
|
+
if (passthroughIndex >= 0 && cmd !== "db")
|
|
100
|
+
usageError("arguments after -- are only supported by sqlx-js db", scope);
|
|
101
|
+
const ROOT_OPTIONS = {
|
|
102
|
+
root: { type: "string" },
|
|
103
|
+
help: { type: "boolean", short: "h" },
|
|
104
|
+
};
|
|
105
|
+
function optionsFor(command, subcommand) {
|
|
106
|
+
if (command === "init")
|
|
107
|
+
return { ...ROOT_OPTIONS, "schema-provider": { type: "string" } };
|
|
108
|
+
if (command === "doctor")
|
|
109
|
+
return { ...ROOT_OPTIONS, dts: { type: "string" }, json: { type: "boolean" } };
|
|
110
|
+
if (command === "db")
|
|
111
|
+
return ROOT_OPTIONS;
|
|
112
|
+
if (command === "prepare") {
|
|
113
|
+
return {
|
|
114
|
+
...ROOT_OPTIONS,
|
|
115
|
+
dts: { type: "string" },
|
|
116
|
+
check: { type: "boolean" },
|
|
117
|
+
offline: { type: "boolean" },
|
|
118
|
+
verify: { type: "boolean" },
|
|
119
|
+
watch: { type: "boolean" },
|
|
120
|
+
json: { type: "boolean" },
|
|
121
|
+
jsonl: { type: "boolean" },
|
|
122
|
+
"no-prune": { type: "boolean" },
|
|
123
|
+
"shadow-url": { type: "string" },
|
|
124
|
+
migrations: { type: "string" },
|
|
125
|
+
"strict-inference": { type: "boolean" },
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (command === "schema") {
|
|
129
|
+
const common = {
|
|
130
|
+
...ROOT_OPTIONS,
|
|
131
|
+
schema: { type: "string" },
|
|
132
|
+
"shadow-url": { type: "string" },
|
|
133
|
+
migrations: { type: "string" },
|
|
134
|
+
};
|
|
135
|
+
return subcommand === "dump"
|
|
136
|
+
? { ...common, manifest: { type: "string" }, "no-manifest": { type: "boolean" } }
|
|
137
|
+
: common;
|
|
138
|
+
}
|
|
139
|
+
const common = { ...ROOT_OPTIONS, migrations: { type: "string" } };
|
|
140
|
+
if (subcommand === "run") {
|
|
141
|
+
return { ...common, "dry-run": { type: "boolean" }, json: { type: "boolean" }, "lock-timeout": { type: "string" } };
|
|
142
|
+
}
|
|
143
|
+
if (subcommand === "info" || subcommand === "check")
|
|
144
|
+
return { ...common, json: { type: "boolean" } };
|
|
145
|
+
if (subcommand === "dev") {
|
|
146
|
+
return {
|
|
147
|
+
...common,
|
|
148
|
+
"shadow-admin-url": { type: "string" },
|
|
149
|
+
"shadow-url": { type: "string" },
|
|
150
|
+
"lock-timeout": { type: "string" },
|
|
151
|
+
"no-prune": { type: "boolean" },
|
|
152
|
+
"strict-inference": { type: "boolean" },
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (subcommand === "verify") {
|
|
156
|
+
return {
|
|
157
|
+
...common,
|
|
158
|
+
"shadow-admin-url": { type: "string" },
|
|
159
|
+
"shadow-url": { type: "string" },
|
|
160
|
+
"lock-timeout": { type: "string" },
|
|
161
|
+
"strict-inference": { type: "boolean" },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (subcommand === "revert") {
|
|
165
|
+
return {
|
|
166
|
+
...common,
|
|
167
|
+
"dry-run": { type: "boolean" },
|
|
168
|
+
json: { type: "boolean" },
|
|
169
|
+
"shadow-admin-url": { type: "string" },
|
|
170
|
+
"shadow-url": { type: "string" },
|
|
171
|
+
"lock-timeout": { type: "string" },
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
if (subcommand === "squash") {
|
|
175
|
+
return {
|
|
176
|
+
...common,
|
|
177
|
+
"shadow-admin-url": { type: "string" },
|
|
178
|
+
"shadow-url": { type: "string" },
|
|
179
|
+
"lock-timeout": { type: "string" },
|
|
180
|
+
replace: { type: "boolean" },
|
|
181
|
+
"pg-dump": { type: "string" },
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (subcommand === "archive")
|
|
185
|
+
return { ...common, force: { type: "boolean" } };
|
|
186
|
+
return common;
|
|
187
|
+
}
|
|
188
|
+
const commandArgv = cliArgv.slice(1);
|
|
189
|
+
const subcommand = commandArgv[0]?.startsWith("-") ? undefined : commandArgv[0];
|
|
190
|
+
let parsed;
|
|
191
|
+
try {
|
|
192
|
+
parsed = parseArgs({
|
|
193
|
+
args: commandArgv,
|
|
194
|
+
options: optionsFor(cmd, subcommand),
|
|
195
|
+
strict: true,
|
|
196
|
+
allowPositionals: true,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
usageError(error.message, scope);
|
|
201
|
+
}
|
|
202
|
+
const values = parsed.values;
|
|
203
|
+
const positionals = parsed.positionals;
|
|
204
|
+
function arg(name, def) {
|
|
205
|
+
const value = values[name.replace(/^--/, "")];
|
|
206
|
+
return typeof value === "string" ? value : def;
|
|
207
|
+
}
|
|
208
|
+
function flag(name) {
|
|
209
|
+
return values[name.replace(/^--/, "")] === true;
|
|
210
|
+
}
|
|
211
|
+
function requirePositionals(min, max, label) {
|
|
212
|
+
if (positionals.length < min || positionals.length > max) {
|
|
213
|
+
usageError(`${label}: expected ${min === max ? min : `${min} to ${max}`} positional argument(s)`, scope);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function validateInvocation() {
|
|
217
|
+
if (cmd === "init" || cmd === "doctor" || cmd === "prepare") {
|
|
218
|
+
requirePositionals(0, 0, cmd);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (cmd === "db") {
|
|
222
|
+
requirePositionals(1, 1, "db");
|
|
223
|
+
const sub = positionals[0];
|
|
224
|
+
if (sub !== "install" && sub !== "check" && sub !== "plan" && sub !== "apply") {
|
|
225
|
+
usageError(`unknown db command ${JSON.stringify(sub)}`, "db");
|
|
226
|
+
}
|
|
227
|
+
if (passthroughArgs.length > 0 && sub !== "plan" && sub !== "apply") {
|
|
228
|
+
usageError(`db ${sub} does not accept arguments after --`, "db");
|
|
229
|
+
}
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (cmd === "schema") {
|
|
233
|
+
requirePositionals(1, 1, "schema");
|
|
234
|
+
const sub = positionals[0];
|
|
235
|
+
if (sub !== "dump" && sub !== "check")
|
|
236
|
+
usageError(`unknown schema command ${JSON.stringify(sub)}`, "schema");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const sub = positionals[0];
|
|
240
|
+
if (!sub)
|
|
241
|
+
usageError("migrate command is required", "migrate");
|
|
242
|
+
if (["dev", "verify", "run", "info", "check", "revert"].includes(sub)) {
|
|
243
|
+
requirePositionals(1, 1, `migrate ${sub}`);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (sub === "add" || sub === "squash") {
|
|
247
|
+
requirePositionals(2, 2, `migrate ${sub}`);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (sub === "archive") {
|
|
251
|
+
const action = positionals[1];
|
|
252
|
+
if (action === "list") {
|
|
253
|
+
requirePositionals(2, 2, "migrate archive list");
|
|
254
|
+
if (flag("--force"))
|
|
255
|
+
usageError("--force is only supported by migrate archive restore", "migrate");
|
|
256
|
+
}
|
|
257
|
+
else if (action === "restore")
|
|
258
|
+
requirePositionals(3, 3, "migrate archive restore");
|
|
259
|
+
else
|
|
260
|
+
usageError(`unknown migrate archive command ${JSON.stringify(action)}`, "migrate");
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
usageError(`unknown migrate command ${JSON.stringify(sub)}`, "migrate");
|
|
93
264
|
}
|
|
265
|
+
validateInvocation();
|
|
94
266
|
const root = resolve(arg("--root", process.cwd()));
|
|
95
267
|
if (cmd !== "doctor") {
|
|
96
268
|
try {
|
|
@@ -102,14 +274,21 @@ if (cmd !== "doctor") {
|
|
|
102
274
|
}
|
|
103
275
|
}
|
|
104
276
|
let envError;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
277
|
+
const needsEnvironment = cmd === "doctor" ||
|
|
278
|
+
cmd === "schema" ||
|
|
279
|
+
(cmd === "db" && (positionals[0] === "plan" || positionals[0] === "apply")) ||
|
|
280
|
+
(cmd === "prepare" && !flag("--check") && !flag("--offline")) ||
|
|
281
|
+
(cmd === "migrate" && !["add", "check", "archive"].includes(positionals[0]));
|
|
282
|
+
if (needsEnvironment) {
|
|
283
|
+
try {
|
|
284
|
+
loadRootEnv(root);
|
|
285
|
+
}
|
|
286
|
+
catch (e) {
|
|
287
|
+
envError = e.message;
|
|
288
|
+
if (cmd !== "doctor") {
|
|
289
|
+
console.error(envError);
|
|
290
|
+
process.exit(2);
|
|
291
|
+
}
|
|
113
292
|
}
|
|
114
293
|
}
|
|
115
294
|
const databaseUrl = process.env.DATABASE_URL ?? "";
|
|
@@ -118,13 +297,14 @@ const shadowUrl = shadowUrlArg ?? process.env.SHADOW_DATABASE_URL;
|
|
|
118
297
|
const shadowAdminUrl = arg("--shadow-admin-url") ?? process.env.SHADOW_ADMIN_DATABASE_URL;
|
|
119
298
|
const cacheDir = join(root, ".sqlx-js");
|
|
120
299
|
const dtsArg = arg("--dts");
|
|
121
|
-
const dtsPath = dtsArg ? resolve(dtsArg) : join(root, "sqlx-js-env.d.ts");
|
|
300
|
+
const dtsPath = dtsArg ? resolve(root, dtsArg) : join(root, "sqlx-js-env.d.ts");
|
|
122
301
|
const migrationsDir = join(root, arg("--migrations", "migrations"));
|
|
123
302
|
const schemaArg = arg("--schema");
|
|
124
|
-
const schemaPath = schemaArg ? resolve(schemaArg) : join(root, ".sqlx-js/schema/schema.json");
|
|
303
|
+
const schemaPath = schemaArg ? resolve(root, schemaArg) : join(root, ".sqlx-js/schema/schema.json");
|
|
125
304
|
const manifestArg = arg("--manifest");
|
|
126
|
-
const manifestPath = manifestArg ? resolve(manifestArg) : join(root, ".sqlx-js/schema/schema.md");
|
|
305
|
+
const manifestPath = manifestArg ? resolve(root, manifestArg) : join(root, ".sqlx-js/schema/schema.md");
|
|
127
306
|
if (cmd === "init") {
|
|
307
|
+
const { runInit } = await import("../src/commands/init.js");
|
|
128
308
|
const provider = arg("--schema-provider", "builtin");
|
|
129
309
|
if (provider !== "builtin" && provider !== "pgschema") {
|
|
130
310
|
console.error("--schema-provider must be builtin or pgschema");
|
|
@@ -133,10 +313,12 @@ if (cmd === "init") {
|
|
|
133
313
|
runInit({ root, schemaProvider: provider });
|
|
134
314
|
}
|
|
135
315
|
else if (cmd === "doctor") {
|
|
316
|
+
const { runDoctor } = await import("../src/commands/doctor.js");
|
|
136
317
|
await runDoctor({ root, databaseUrl, cacheDir, dtsPath, json: flag("--json"), envError });
|
|
137
318
|
}
|
|
138
319
|
else if (cmd === "db") {
|
|
139
|
-
const
|
|
320
|
+
const { runPgschemaCommand, runPgschemaInstall } = await import("../src/commands/pgschema.js");
|
|
321
|
+
const sub = positionals[0];
|
|
140
322
|
if (sub === "install") {
|
|
141
323
|
try {
|
|
142
324
|
await runPgschemaInstall({ root });
|
|
@@ -147,8 +329,6 @@ else if (cmd === "db") {
|
|
|
147
329
|
}
|
|
148
330
|
}
|
|
149
331
|
else {
|
|
150
|
-
if (sub !== "check" && sub !== "plan" && sub !== "apply")
|
|
151
|
-
help();
|
|
152
332
|
try {
|
|
153
333
|
runPgschemaCommand({
|
|
154
334
|
root,
|
|
@@ -165,13 +345,24 @@ else if (cmd === "db") {
|
|
|
165
345
|
}
|
|
166
346
|
}
|
|
167
347
|
else if (cmd === "prepare") {
|
|
348
|
+
const { PrepareFatalError, runPrepare } = await import("../src/commands/prepare.js");
|
|
168
349
|
const prepareCheck = flag("--check");
|
|
350
|
+
const prepareOffline = flag("--offline");
|
|
169
351
|
const prepareVerify = flag("--verify");
|
|
170
352
|
const prepareWatch = flag("--watch");
|
|
171
353
|
const prepareJson = flag("--json");
|
|
172
|
-
const
|
|
354
|
+
const prepareJsonl = flag("--jsonl");
|
|
355
|
+
const prepareMode = prepareVerify ? "verify" : prepareCheck ? "check" : prepareOffline ? "offline" : "prepare";
|
|
173
356
|
const failPrepare = (message, phase, exitCode = 2, location = {}) => {
|
|
174
|
-
if (
|
|
357
|
+
if (prepareJsonl) {
|
|
358
|
+
console.log(JSON.stringify({
|
|
359
|
+
formatVersion: 1,
|
|
360
|
+
event: "error",
|
|
361
|
+
timestamp: new Date().toISOString(),
|
|
362
|
+
diagnostic: { severity: "error", phase, message, ...location },
|
|
363
|
+
}));
|
|
364
|
+
}
|
|
365
|
+
else if (prepareJson) {
|
|
175
366
|
console.log(JSON.stringify({
|
|
176
367
|
formatVersion: 1,
|
|
177
368
|
ok: false,
|
|
@@ -189,19 +380,28 @@ else if (cmd === "prepare") {
|
|
|
189
380
|
}
|
|
190
381
|
process.exit(exitCode);
|
|
191
382
|
};
|
|
192
|
-
if ([prepareCheck, prepareVerify, prepareWatch].filter(Boolean).length > 1) {
|
|
193
|
-
failPrepare("--check, --verify, and --watch are mutually exclusive", "config");
|
|
383
|
+
if ([prepareCheck, prepareOffline, prepareVerify, prepareWatch].filter(Boolean).length > 1) {
|
|
384
|
+
failPrepare("--check, --offline, --verify, and --watch are mutually exclusive", "config");
|
|
194
385
|
}
|
|
195
|
-
if (prepareCheck && shadowUrlArg) {
|
|
196
|
-
failPrepare("--shadow-url cannot be used with prepare
|
|
386
|
+
if ((prepareCheck || prepareOffline) && shadowUrlArg) {
|
|
387
|
+
failPrepare("--shadow-url cannot be used with offline prepare modes; use live prepare or schema check --shadow-url", "config");
|
|
197
388
|
}
|
|
198
389
|
if (prepareWatch && prepareJson) {
|
|
199
390
|
failPrepare("--watch and --json are mutually exclusive", "config");
|
|
200
391
|
}
|
|
201
|
-
|
|
392
|
+
if (prepareJson && prepareJsonl) {
|
|
393
|
+
failPrepare("--json and --jsonl are mutually exclusive", "config");
|
|
394
|
+
}
|
|
395
|
+
if (prepareJsonl && !prepareWatch) {
|
|
396
|
+
failPrepare("--jsonl is only supported by prepare --watch", "config");
|
|
397
|
+
}
|
|
398
|
+
if ((prepareCheck || prepareOffline || prepareVerify) && flag("--no-prune")) {
|
|
399
|
+
failPrepare("--no-prune is only supported by live prepare and prepare --watch", "config");
|
|
400
|
+
}
|
|
401
|
+
const prepareShadowUrl = prepareCheck || prepareOffline ? undefined : shadowUrl;
|
|
202
402
|
const prepareDatabaseUrl = prepareShadowUrl ?? databaseUrl;
|
|
203
|
-
if (!prepareCheck && !prepareDatabaseUrl) {
|
|
204
|
-
failPrepare("DATABASE_URL is required for prepare (use --check
|
|
403
|
+
if (!prepareCheck && !prepareOffline && !prepareDatabaseUrl) {
|
|
404
|
+
failPrepare("DATABASE_URL is required for prepare (use --check or --offline without a database)", "connect");
|
|
205
405
|
}
|
|
206
406
|
const opts = {
|
|
207
407
|
root,
|
|
@@ -209,13 +409,20 @@ else if (cmd === "prepare") {
|
|
|
209
409
|
cacheDir,
|
|
210
410
|
dtsPath,
|
|
211
411
|
check: prepareCheck,
|
|
412
|
+
offline: prepareOffline,
|
|
212
413
|
verify: prepareVerify,
|
|
213
414
|
json: prepareJson,
|
|
214
415
|
prune: !flag("--no-prune"),
|
|
416
|
+
strictInference: flag("--strict-inference"),
|
|
215
417
|
};
|
|
418
|
+
const applyShadowMigrations = prepareShadowUrl
|
|
419
|
+
? (await import("../src/commands/schema.js")).applyShadowMigrations
|
|
420
|
+
: undefined;
|
|
216
421
|
if (prepareWatch) {
|
|
422
|
+
const { runWatch } = await import("../src/commands/watch.js");
|
|
217
423
|
await runWatch({
|
|
218
424
|
...opts,
|
|
425
|
+
jsonl: prepareJsonl,
|
|
219
426
|
...(prepareShadowUrl
|
|
220
427
|
? {
|
|
221
428
|
beforePrepare: async () => {
|
|
@@ -252,7 +459,8 @@ else if (cmd === "prepare") {
|
|
|
252
459
|
}
|
|
253
460
|
}
|
|
254
461
|
else if (cmd === "schema") {
|
|
255
|
-
const
|
|
462
|
+
const { runSchemaCheck, runSchemaDump } = await import("../src/commands/schema.js");
|
|
463
|
+
const sub = positionals[0];
|
|
256
464
|
const schemaDatabaseUrl = shadowUrl ?? databaseUrl;
|
|
257
465
|
if (!schemaDatabaseUrl) {
|
|
258
466
|
console.error("DATABASE_URL is required for schema commands (or pass --shadow-url)");
|
|
@@ -270,19 +478,21 @@ else if (cmd === "schema") {
|
|
|
270
478
|
await runSchemaDump(opts);
|
|
271
479
|
else if (sub === "check")
|
|
272
480
|
await runSchemaCheck(opts);
|
|
273
|
-
else
|
|
274
|
-
help();
|
|
275
481
|
}
|
|
276
482
|
else if (cmd === "migrate") {
|
|
277
|
-
const
|
|
483
|
+
const { migrateArchiveList, migrateArchiveRestore, migrateCheck, migrateDev, migrateRun, migrateInfo, migrateRevert, migrateAdd, migrateSquash, migrateVerify, } = await import("../src/commands/migrate.js");
|
|
484
|
+
const sub = positionals[0];
|
|
278
485
|
const revertDryRun = sub === "revert" && flag("--dry-run");
|
|
279
486
|
const workflowShadowOnly = ((sub === "dev" || sub === "verify" || sub === "squash") && !!shadowUrl) || (revertDryRun && !!shadowUrl);
|
|
280
|
-
if (!databaseUrl && sub !== "add" && sub !== "check" && sub !== "
|
|
487
|
+
if (!databaseUrl && sub !== "add" && sub !== "check" && sub !== "archive" && !workflowShadowOnly) {
|
|
281
488
|
console.error("DATABASE_URL is required");
|
|
282
489
|
process.exit(2);
|
|
283
490
|
}
|
|
284
491
|
const tRaw = arg("--lock-timeout");
|
|
285
492
|
const lockTimeoutMs = tRaw ? Number(tRaw) : undefined;
|
|
493
|
+
if (lockTimeoutMs !== undefined && !Number.isFinite(lockTimeoutMs)) {
|
|
494
|
+
usageError("--lock-timeout must be a finite number of milliseconds", "migrate");
|
|
495
|
+
}
|
|
286
496
|
if (sub === "dev") {
|
|
287
497
|
await migrateDev({
|
|
288
498
|
root,
|
|
@@ -294,6 +504,7 @@ else if (cmd === "migrate") {
|
|
|
294
504
|
shadowUrl,
|
|
295
505
|
shadowAdminUrl,
|
|
296
506
|
lockTimeoutMs,
|
|
507
|
+
strictInference: flag("--strict-inference"),
|
|
297
508
|
});
|
|
298
509
|
}
|
|
299
510
|
else if (sub === "verify") {
|
|
@@ -306,15 +517,18 @@ else if (cmd === "migrate") {
|
|
|
306
517
|
shadowUrl,
|
|
307
518
|
shadowAdminUrl,
|
|
308
519
|
lockTimeoutMs,
|
|
520
|
+
strictInference: flag("--strict-inference"),
|
|
309
521
|
});
|
|
310
522
|
}
|
|
311
523
|
else if (sub === "run") {
|
|
312
524
|
await migrateRun({ databaseUrl, migrationsDir, lockTimeoutMs, dryRun: flag("--dry-run"), json: flag("--json") });
|
|
313
525
|
}
|
|
314
|
-
else if (sub === "info")
|
|
526
|
+
else if (sub === "info") {
|
|
315
527
|
await migrateInfo({ databaseUrl, migrationsDir, json: flag("--json") });
|
|
316
|
-
|
|
528
|
+
}
|
|
529
|
+
else if (sub === "check") {
|
|
317
530
|
migrateCheck({ migrationsDir, json: flag("--json") });
|
|
531
|
+
}
|
|
318
532
|
else if (sub === "revert") {
|
|
319
533
|
await migrateRevert({
|
|
320
534
|
databaseUrl,
|
|
@@ -327,19 +541,11 @@ else if (cmd === "migrate") {
|
|
|
327
541
|
});
|
|
328
542
|
}
|
|
329
543
|
else if (sub === "add") {
|
|
330
|
-
const name =
|
|
331
|
-
if (!name) {
|
|
332
|
-
console.error("migrate add: name required");
|
|
333
|
-
process.exit(2);
|
|
334
|
-
}
|
|
544
|
+
const name = positionals[1];
|
|
335
545
|
migrateAdd({ databaseUrl, migrationsDir, name });
|
|
336
546
|
}
|
|
337
547
|
else if (sub === "squash") {
|
|
338
|
-
const name =
|
|
339
|
-
if (!name) {
|
|
340
|
-
console.error("migrate squash: name required");
|
|
341
|
-
process.exit(2);
|
|
342
|
-
}
|
|
548
|
+
const name = positionals[1];
|
|
343
549
|
await migrateSquash({
|
|
344
550
|
databaseUrl,
|
|
345
551
|
migrationsDir,
|
|
@@ -352,23 +558,16 @@ else if (cmd === "migrate") {
|
|
|
352
558
|
});
|
|
353
559
|
}
|
|
354
560
|
else if (sub === "archive") {
|
|
355
|
-
const action =
|
|
356
|
-
if (action === "list")
|
|
561
|
+
const action = positionals[1];
|
|
562
|
+
if (action === "list") {
|
|
357
563
|
migrateArchiveList({ migrationsDir });
|
|
564
|
+
}
|
|
358
565
|
else if (action === "restore") {
|
|
359
|
-
const name =
|
|
360
|
-
if (!name) {
|
|
361
|
-
console.error("migrate archive restore: name required");
|
|
362
|
-
process.exit(2);
|
|
363
|
-
}
|
|
566
|
+
const name = positionals[2];
|
|
364
567
|
migrateArchiveRestore({ migrationsDir, name, force: flag("--force") });
|
|
365
568
|
}
|
|
366
|
-
else
|
|
367
|
-
help();
|
|
368
569
|
}
|
|
369
|
-
else
|
|
370
|
-
help();
|
|
371
570
|
}
|
|
372
571
|
else {
|
|
373
|
-
|
|
572
|
+
usageError(`unknown command ${JSON.stringify(cmd)}`);
|
|
374
573
|
}
|
package/dist/src/cache.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const CACHE_FORMAT_VERSION = 2;
|
|
2
|
-
export declare const GENERATOR_REVISION =
|
|
2
|
+
export declare const GENERATOR_REVISION = 4;
|
|
3
3
|
export declare const CACHE_MANIFEST_FILE = "cache-manifest.json";
|
|
4
4
|
export type CacheManifest = {
|
|
5
5
|
cacheFormat: typeof CACHE_FORMAT_VERSION;
|
package/dist/src/cache.js
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlink
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { isBuiltinOid } from "./pg/oids.js";
|
|
5
5
|
export const CACHE_FORMAT_VERSION = 2;
|
|
6
|
-
export const GENERATOR_REVISION =
|
|
6
|
+
export const GENERATOR_REVISION = 4;
|
|
7
7
|
export const CACHE_MANIFEST_FILE = "cache-manifest.json";
|
|
8
8
|
export function portableCacheOid(oid) {
|
|
9
9
|
return isBuiltinOid(oid) ? oid : 0;
|
package/dist/src/codegen.js
CHANGED
|
@@ -23,7 +23,9 @@ export function emitDts(outPath, entries, functions = []) {
|
|
|
23
23
|
lines.push("// AUTO-GENERATED by sqlx-js. Do not edit.");
|
|
24
24
|
lines.push("// Run `sqlx-js prepare` to regenerate.");
|
|
25
25
|
lines.push("");
|
|
26
|
-
|
|
26
|
+
emitRegistry(lines, entries, functions);
|
|
27
|
+
lines.push("");
|
|
28
|
+
emitModuleAugmentation(lines, "@onreza/sqlx-js");
|
|
27
29
|
lines.push("");
|
|
28
30
|
lines.push("export {};");
|
|
29
31
|
const tmp = `${outPath}.tmp-${randomBytes(4).toString("hex")}`;
|
|
@@ -39,9 +41,8 @@ export function emitDts(outPath, entries, functions = []) {
|
|
|
39
41
|
throw err;
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
|
-
function
|
|
43
|
-
lines.push(
|
|
44
|
-
lines.push(" interface KnownQueries {");
|
|
44
|
+
function emitRegistry(lines, entries, functions) {
|
|
45
|
+
lines.push("export interface SqlxJsGeneratedQueries {");
|
|
45
46
|
const inlineSeen = new Set();
|
|
46
47
|
const inlinePairs = [];
|
|
47
48
|
for (const e of entries) {
|
|
@@ -58,12 +59,12 @@ function emitModule(lines, moduleName, entries, functions) {
|
|
|
58
59
|
inlineSeen.add(query);
|
|
59
60
|
const { params, row } = entrySignature(entry);
|
|
60
61
|
if (entry.degraded)
|
|
61
|
-
lines.push(`
|
|
62
|
-
lines.push(`
|
|
62
|
+
lines.push(` /** Nullability inference degraded: ${entry.degraded.reason}. All result columns conservatively typed as nullable. */`);
|
|
63
|
+
lines.push(` ${JSON.stringify(query)}: { params: ${params}; row: ${row} };`);
|
|
63
64
|
}
|
|
64
|
-
lines.push("
|
|
65
|
+
lines.push("}");
|
|
65
66
|
lines.push("");
|
|
66
|
-
lines.push("
|
|
67
|
+
lines.push("export interface SqlxJsGeneratedFileQueries {");
|
|
67
68
|
const filePairs = [];
|
|
68
69
|
for (const e of entries) {
|
|
69
70
|
if (!e.filePaths || e.filePaths.length === 0)
|
|
@@ -78,21 +79,33 @@ function emitModule(lines, moduleName, entries, functions) {
|
|
|
78
79
|
filePathsSeen.add(path);
|
|
79
80
|
const { params, row } = entrySignature(entry);
|
|
80
81
|
if (entry.degraded)
|
|
81
|
-
lines.push(`
|
|
82
|
-
lines.push(`
|
|
82
|
+
lines.push(` /** Nullability inference degraded: ${entry.degraded.reason}. */`);
|
|
83
|
+
lines.push(` ${JSON.stringify(path)}: { params: ${params}; row: ${row} };`);
|
|
83
84
|
}
|
|
84
|
-
lines.push("
|
|
85
|
+
lines.push("}");
|
|
85
86
|
lines.push("");
|
|
86
|
-
lines.push("
|
|
87
|
+
lines.push("export interface SqlxJsGeneratedFunctions {");
|
|
87
88
|
const functionSeen = new Set();
|
|
88
89
|
for (const fn of functions.slice().sort((a, b) => a.signature.localeCompare(b.signature))) {
|
|
89
90
|
if (functionSeen.has(fn.signature))
|
|
90
91
|
continue;
|
|
91
92
|
functionSeen.add(fn.signature);
|
|
92
93
|
const params = inputParams(fn);
|
|
93
|
-
lines.push(`
|
|
94
|
+
lines.push(` ${JSON.stringify(fn.signature)}: { kind: ${JSON.stringify(fn.kind)}; params: ${params}; returns: ${fn.returns}; returnsSet: ${fn.returnsSet} };`);
|
|
94
95
|
}
|
|
95
|
-
lines.push("
|
|
96
|
+
lines.push("}");
|
|
97
|
+
lines.push("");
|
|
98
|
+
lines.push("export interface SqlxJsGeneratedRegistry {");
|
|
99
|
+
lines.push(" queries: SqlxJsGeneratedQueries;");
|
|
100
|
+
lines.push(" fileQueries: SqlxJsGeneratedFileQueries;");
|
|
101
|
+
lines.push(" functions: SqlxJsGeneratedFunctions;");
|
|
102
|
+
lines.push("}");
|
|
103
|
+
}
|
|
104
|
+
function emitModuleAugmentation(lines, moduleName) {
|
|
105
|
+
lines.push(`declare module ${JSON.stringify(moduleName)} {`);
|
|
106
|
+
lines.push(" interface KnownQueries extends SqlxJsGeneratedQueries {}");
|
|
107
|
+
lines.push(" interface KnownFileQueries extends SqlxJsGeneratedFileQueries {}");
|
|
108
|
+
lines.push(" interface KnownFunctions extends SqlxJsGeneratedFunctions {}");
|
|
96
109
|
lines.push("}");
|
|
97
110
|
}
|
|
98
111
|
function inputParams(fn) {
|