@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
const CONFIG_TEMPLATE = `import { defineConfig } from "@onreza/sqlx-js";
|
|
4
4
|
|
|
@@ -33,10 +33,32 @@ const PGSCHEMA_TEMPLATE = `-- Desired PostgreSQL schema managed by pgschema.
|
|
|
33
33
|
-- sqlx-js db plan -- --output-json plan.json
|
|
34
34
|
-- sqlx-js db apply -- --auto-approve
|
|
35
35
|
`;
|
|
36
|
+
const DTS_TEMPLATE = `// AUTO-GENERATED by sqlx-js. Do not edit.
|
|
37
|
+
// Run \`sqlx-js prepare\` to regenerate.
|
|
38
|
+
|
|
39
|
+
export interface SqlxJsGeneratedQueries {}
|
|
40
|
+
export interface SqlxJsGeneratedFileQueries {}
|
|
41
|
+
export interface SqlxJsGeneratedFunctions {}
|
|
42
|
+
export interface SqlxJsGeneratedRegistry {
|
|
43
|
+
queries: SqlxJsGeneratedQueries;
|
|
44
|
+
fileQueries: SqlxJsGeneratedFileQueries;
|
|
45
|
+
functions: SqlxJsGeneratedFunctions;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare module "@onreza/sqlx-js" {
|
|
49
|
+
interface KnownQueries extends SqlxJsGeneratedQueries {}
|
|
50
|
+
interface KnownFileQueries extends SqlxJsGeneratedFileQueries {}
|
|
51
|
+
interface KnownFunctions extends SqlxJsGeneratedFunctions {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export {};
|
|
55
|
+
`;
|
|
36
56
|
export function runInit(opts) {
|
|
37
57
|
const log = opts.log ?? console.log;
|
|
38
58
|
const created = [];
|
|
59
|
+
const updated = [];
|
|
39
60
|
const skipped = [];
|
|
61
|
+
const notes = [];
|
|
40
62
|
const ensureFile = (rel, content) => {
|
|
41
63
|
const full = join(opts.root, rel);
|
|
42
64
|
if (existsSync(full)) {
|
|
@@ -63,10 +85,82 @@ export function runInit(opts) {
|
|
|
63
85
|
else
|
|
64
86
|
ensureDir("migrations");
|
|
65
87
|
ensureFile(".env.example", ENV_TEMPLATE);
|
|
88
|
+
ensureFile("sqlx-js-env.d.ts", DTS_TEMPLATE);
|
|
89
|
+
const updateJson = (rel, mutate) => {
|
|
90
|
+
const full = join(opts.root, rel);
|
|
91
|
+
if (!existsSync(full))
|
|
92
|
+
return;
|
|
93
|
+
const source = readFileSync(full, "utf8");
|
|
94
|
+
let value;
|
|
95
|
+
try {
|
|
96
|
+
value = JSON.parse(source);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
notes.push(`${rel}: manual update required because the file is not strict JSON`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
103
|
+
return;
|
|
104
|
+
if (!mutate(value))
|
|
105
|
+
return;
|
|
106
|
+
const indent = source.match(/\n([ \t]+)"/)?.[1] ?? " ";
|
|
107
|
+
writeFileSync(full, JSON.stringify(value, null, indent) + "\n");
|
|
108
|
+
updated.push(rel);
|
|
109
|
+
};
|
|
110
|
+
updateJson("tsconfig.json", (value) => {
|
|
111
|
+
const files = value.files;
|
|
112
|
+
if (files !== undefined && (!Array.isArray(files) || !files.every((item) => typeof item === "string"))) {
|
|
113
|
+
notes.push("tsconfig.json: manual update required because files is not an array of strings");
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
if (Array.isArray(files)) {
|
|
117
|
+
if (files.includes("sqlx-js-env.d.ts"))
|
|
118
|
+
return false;
|
|
119
|
+
files.push("sqlx-js-env.d.ts");
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
const include = value.include;
|
|
123
|
+
if (include !== undefined && (!Array.isArray(include) || !include.every((item) => typeof item === "string"))) {
|
|
124
|
+
notes.push("tsconfig.json: manual update required because include is not an array of strings");
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
if (Array.isArray(include)) {
|
|
128
|
+
if (include.includes("sqlx-js-env.d.ts"))
|
|
129
|
+
return false;
|
|
130
|
+
include.push("sqlx-js-env.d.ts");
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
});
|
|
135
|
+
updateJson("package.json", (value) => {
|
|
136
|
+
if (value.scripts !== undefined && (!value.scripts || typeof value.scripts !== "object" || Array.isArray(value.scripts))) {
|
|
137
|
+
notes.push("package.json: manual script update required because scripts is not an object");
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
const scripts = (value.scripts ??= {});
|
|
141
|
+
const defaults = {
|
|
142
|
+
"sqlx:prepare": "sqlx-js prepare",
|
|
143
|
+
"sqlx:check": "sqlx-js prepare --check",
|
|
144
|
+
"sqlx:offline": "sqlx-js prepare --offline",
|
|
145
|
+
"sqlx:verify": "sqlx-js prepare --verify --strict-inference",
|
|
146
|
+
};
|
|
147
|
+
let changed = false;
|
|
148
|
+
for (const [name, command] of Object.entries(defaults)) {
|
|
149
|
+
if (scripts[name] !== undefined)
|
|
150
|
+
continue;
|
|
151
|
+
scripts[name] = command;
|
|
152
|
+
changed = true;
|
|
153
|
+
}
|
|
154
|
+
return changed;
|
|
155
|
+
});
|
|
66
156
|
for (const f of created)
|
|
67
157
|
log(`created ${f}`);
|
|
158
|
+
for (const f of updated)
|
|
159
|
+
log(`updated ${f}`);
|
|
68
160
|
for (const f of skipped)
|
|
69
161
|
log(`exists ${f} (left unchanged)`);
|
|
162
|
+
for (const note of notes)
|
|
163
|
+
log(`manual ${note}`);
|
|
70
164
|
log("");
|
|
71
165
|
log("Next steps:");
|
|
72
166
|
log(" 1. Set DATABASE_URL (see .env.example).");
|
|
@@ -78,7 +172,7 @@ export function runInit(opts) {
|
|
|
78
172
|
}
|
|
79
173
|
else {
|
|
80
174
|
log(" 2. Add a migration: sqlx-js migrate add init");
|
|
81
|
-
log(" 3.
|
|
82
|
-
log(" 4. Develop locally: sqlx-js migrate dev");
|
|
175
|
+
log(" 3. Check the project setup: sqlx-js doctor");
|
|
176
|
+
log(" 4. Develop locally: sqlx-js migrate dev --strict-inference");
|
|
83
177
|
}
|
|
84
178
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PgClient } from "../pg/wire.js";
|
|
2
|
+
export * from "../migration-core.js";
|
|
2
3
|
export type MigrateOptions = {
|
|
3
4
|
databaseUrl: string;
|
|
4
5
|
migrationsDir: string;
|
|
@@ -12,91 +13,7 @@ export type MigrationWorkflowOptions = MigrateOptions & {
|
|
|
12
13
|
shadowAdminUrl?: string;
|
|
13
14
|
lockKey?: number | bigint;
|
|
14
15
|
lockTimeoutMs?: number;
|
|
15
|
-
|
|
16
|
-
export type MigrationStore = {
|
|
17
|
-
table: string;
|
|
18
|
-
};
|
|
19
|
-
export declare const DEFAULT_MIGRATE_LOCK_KEY = 18750938867203960n;
|
|
20
|
-
export declare function ensureTable(c: PgClient): Promise<MigrationStore>;
|
|
21
|
-
export declare function listApplied(c: PgClient, store?: MigrationStore): Promise<Map<number, {
|
|
22
|
-
name: string;
|
|
23
|
-
hash: string;
|
|
24
|
-
}>>;
|
|
25
|
-
export type ApplyOutcome = {
|
|
26
|
-
kind: "applied";
|
|
27
|
-
version: number;
|
|
28
|
-
name: string;
|
|
29
|
-
} | {
|
|
30
|
-
kind: "adopted";
|
|
31
|
-
version: number;
|
|
32
|
-
name: string;
|
|
33
|
-
replaced: number;
|
|
34
|
-
} | {
|
|
35
|
-
kind: "tampered";
|
|
36
|
-
version: number;
|
|
37
|
-
name: string;
|
|
38
|
-
applied: string;
|
|
39
|
-
current: string;
|
|
40
|
-
} | {
|
|
41
|
-
kind: "failed";
|
|
42
|
-
version: number;
|
|
43
|
-
name: string;
|
|
44
|
-
error: string;
|
|
45
|
-
};
|
|
46
|
-
export type PlanOutcome = {
|
|
47
|
-
kind: "pending";
|
|
48
|
-
version: number;
|
|
49
|
-
name: string;
|
|
50
|
-
} | {
|
|
51
|
-
kind: "adoptable";
|
|
52
|
-
version: number;
|
|
53
|
-
name: string;
|
|
54
|
-
replaced: number;
|
|
55
|
-
} | {
|
|
56
|
-
kind: "tampered";
|
|
57
|
-
version: number;
|
|
58
|
-
name: string;
|
|
59
|
-
applied: string;
|
|
60
|
-
current: string;
|
|
61
|
-
} | {
|
|
62
|
-
kind: "failed";
|
|
63
|
-
version: number;
|
|
64
|
-
name: string;
|
|
65
|
-
error: string;
|
|
66
|
-
};
|
|
67
|
-
export type MigrationPlanItem = {
|
|
68
|
-
kind: "apply";
|
|
69
|
-
version: number;
|
|
70
|
-
name: string;
|
|
71
|
-
} | {
|
|
72
|
-
kind: "adopt";
|
|
73
|
-
version: number;
|
|
74
|
-
name: string;
|
|
75
|
-
replaced: number;
|
|
76
|
-
};
|
|
77
|
-
export type MigrationPlanDiagnostic = Extract<PlanOutcome, {
|
|
78
|
-
kind: "tampered" | "failed";
|
|
79
|
-
}>;
|
|
80
|
-
export type MigrationPlanSnapshot = {
|
|
81
|
-
ok: boolean;
|
|
82
|
-
pending: number;
|
|
83
|
-
adoptable: number;
|
|
84
|
-
tampered: number;
|
|
85
|
-
failed: number;
|
|
86
|
-
steps: MigrationPlanItem[];
|
|
87
|
-
diagnostics: MigrationPlanDiagnostic[];
|
|
88
|
-
};
|
|
89
|
-
export type MigrationInfoStatus = "applied" | "pending" | "adoptable" | "superseded" | "tampered" | "failed";
|
|
90
|
-
export type MigrationInfoItem = {
|
|
91
|
-
version: number;
|
|
92
|
-
name: string;
|
|
93
|
-
status: MigrationInfoStatus;
|
|
94
|
-
detail?: string;
|
|
95
|
-
};
|
|
96
|
-
export type MigrationInfoSnapshot = {
|
|
97
|
-
historyTable: string | null;
|
|
98
|
-
summary: Record<MigrationInfoStatus, number>;
|
|
99
|
-
items: MigrationInfoItem[];
|
|
16
|
+
strictInference?: boolean;
|
|
100
17
|
};
|
|
101
18
|
export type MigrationArchive = {
|
|
102
19
|
name: string;
|
|
@@ -151,22 +68,6 @@ export type RevertDryRunOutcome = {
|
|
|
151
68
|
error: string;
|
|
152
69
|
};
|
|
153
70
|
export declare function checkMigrationFiles(migrationsDir: string): MigrationCheckReport;
|
|
154
|
-
export declare function planPending(c: PgClient, migrationsDir: string, onEvent?: (e: PlanOutcome) => void): Promise<{
|
|
155
|
-
pending: number;
|
|
156
|
-
adoptable: number;
|
|
157
|
-
tampered: number;
|
|
158
|
-
failed: number;
|
|
159
|
-
steps: MigrationPlanItem[];
|
|
160
|
-
}>;
|
|
161
|
-
export declare function inspectMigrationPlan(c: PgClient, migrationsDir: string): Promise<MigrationPlanSnapshot>;
|
|
162
|
-
export declare function inspectMigrations(c: PgClient, migrationsDir: string): Promise<MigrationInfoSnapshot>;
|
|
163
|
-
export declare function applyPending(c: PgClient, migrationsDir: string, onEvent?: (e: ApplyOutcome) => void): Promise<{
|
|
164
|
-
applied: number;
|
|
165
|
-
tampered: number;
|
|
166
|
-
failed: number;
|
|
167
|
-
}>;
|
|
168
|
-
export declare function acquireMigrateLock(c: PgClient, lockKey?: number | bigint, timeoutMs?: number): Promise<void>;
|
|
169
|
-
export declare function releaseMigrateLock(c: PgClient, lockKey?: number | bigint): Promise<void>;
|
|
170
71
|
export declare function sanitizePgDumpSchema(sql: string): string;
|
|
171
72
|
export declare function listMigrationArchives(migrationsDir: string): MigrationArchive[];
|
|
172
73
|
export declare function restoreMigrationArchive(migrationsDir: string, archiveName: string, opts?: {
|