@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,7 +1,9 @@
|
|
|
1
|
-
import { watch as fsWatch } from "node:fs";
|
|
2
|
-
import { basename } from "node:path";
|
|
3
|
-
import { openSession, prepareOnce } from "./prepare.js";
|
|
1
|
+
import { existsSync, watch as fsWatch } from "node:fs";
|
|
2
|
+
import { basename, relative, resolve } from "node:path";
|
|
3
|
+
import { openSession, prepareOnce, PrepareFatalError, } from "./prepare.js";
|
|
4
4
|
import { configHash, loadConfig } from "../config.js";
|
|
5
|
+
import { fingerprint } from "../cache.js";
|
|
6
|
+
import { findSourceFiles, scanFile, scanProject } from "../scan/scanner.js";
|
|
5
7
|
const EXT_RE = /\.(ts|tsx|mts|cts|sql)$/;
|
|
6
8
|
const SKIP_DIRS = ["node_modules", ".git", ".sqlx-js", "dist", "build", ".next"];
|
|
7
9
|
const DEBOUNCE_MS = 150;
|
|
@@ -23,7 +25,25 @@ export function shouldWatchFile(filename) {
|
|
|
23
25
|
return true;
|
|
24
26
|
return EXT_RE.test(file);
|
|
25
27
|
}
|
|
26
|
-
|
|
28
|
+
export function formatWatchEvent(name, data = {}, timestamp = new Date().toISOString()) {
|
|
29
|
+
return JSON.stringify({ formatVersion: 1, event: name, timestamp, ...data });
|
|
30
|
+
}
|
|
31
|
+
export function watchErrorData(error) {
|
|
32
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
+
if (!(error instanceof PrepareFatalError))
|
|
34
|
+
return { message };
|
|
35
|
+
return {
|
|
36
|
+
diagnostic: {
|
|
37
|
+
severity: "error",
|
|
38
|
+
phase: error.phase,
|
|
39
|
+
message,
|
|
40
|
+
...(error.file === undefined ? {} : { file: error.file }),
|
|
41
|
+
...(error.line === undefined ? {} : { line: error.line }),
|
|
42
|
+
...(error.column === undefined ? {} : { column: error.column }),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const DEFAULT_DEPS = { openSession, prepareOnce, loadConfig, scanProject, scanFile, findSourceFiles };
|
|
27
47
|
async function closeSession(session) {
|
|
28
48
|
if (!session)
|
|
29
49
|
return;
|
|
@@ -32,35 +52,164 @@ async function closeSession(session) {
|
|
|
32
52
|
}
|
|
33
53
|
catch { }
|
|
34
54
|
}
|
|
35
|
-
export async function prepareWatchedOnce(opts, state, log, err, deps =
|
|
55
|
+
export async function prepareWatchedOnce(opts, state, log, err, deps = {}, changedFiles = []) {
|
|
56
|
+
const active = { ...DEFAULT_DEPS, ...deps };
|
|
36
57
|
const hookResult = await opts.beforePrepare?.();
|
|
37
|
-
const currentConfig = await loadConfig(opts.root);
|
|
38
|
-
|
|
39
|
-
|
|
58
|
+
const currentConfig = await active.loadConfig(opts.root);
|
|
59
|
+
const configChanged = state.session !== null && configHash(state.session.userCfg) !== configHash(currentConfig);
|
|
60
|
+
const resetSession = hookResult?.resetSession === true || configChanged;
|
|
61
|
+
if (resetSession) {
|
|
40
62
|
await closeSession(state.session);
|
|
41
63
|
state.session = null;
|
|
42
64
|
}
|
|
43
65
|
if (!state.session)
|
|
44
|
-
state.session = await
|
|
45
|
-
|
|
66
|
+
state.session = await active.openSession(opts);
|
|
67
|
+
const full = resetSession || !state.sitesByFile || changedFiles.some(isProjectGraphFile);
|
|
68
|
+
let nextSites;
|
|
69
|
+
let changedFps = new Set();
|
|
70
|
+
if (full) {
|
|
71
|
+
const sites = active.scanProject(opts.root, currentConfig.scan);
|
|
72
|
+
nextSites = groupSites(sites);
|
|
73
|
+
changedFps = new Set(sites.map((site) => fingerprint(site.query)));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
const previousSites = state.sitesByFile;
|
|
77
|
+
const dirtyFiles = state.dirtyFiles ?? new Set();
|
|
78
|
+
const requested = new Set([...changedFiles, ...dirtyFiles].map((file) => projectPath(opts.root, file)));
|
|
79
|
+
const affectedSources = new Set();
|
|
80
|
+
for (const changed of requested) {
|
|
81
|
+
if (/\.(ts|tsx|mts|cts)$/.test(changed))
|
|
82
|
+
affectedSources.add(changed);
|
|
83
|
+
if (changed.endsWith(".sql")) {
|
|
84
|
+
for (const [source, sites] of previousSites) {
|
|
85
|
+
if (sites.some((site) => site.sqlFilePath && projectPath(opts.root, site.sqlFilePath) === changed)) {
|
|
86
|
+
affectedSources.add(source);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
nextSites = new Map(previousSites);
|
|
92
|
+
const allowed = new Set(active.findSourceFiles(opts.root, currentConfig.scan).map((file) => projectPath(opts.root, file)));
|
|
93
|
+
for (const source of nextSites.keys()) {
|
|
94
|
+
if (!allowed.has(source))
|
|
95
|
+
affectedSources.add(source);
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
for (const source of affectedSources) {
|
|
99
|
+
const previous = nextSites.get(source) ?? [];
|
|
100
|
+
for (const site of previous)
|
|
101
|
+
changedFps.add(fingerprint(site.query));
|
|
102
|
+
const absolute = resolve(opts.root, source);
|
|
103
|
+
if (!existsSync(absolute) || !allowed.has(source)) {
|
|
104
|
+
nextSites.delete(source);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const scanned = active.scanFile(absolute, opts.root, currentConfig.scan?.modules);
|
|
108
|
+
if (scanned.length > 0)
|
|
109
|
+
nextSites.set(source, scanned);
|
|
110
|
+
else
|
|
111
|
+
nextSites.delete(source);
|
|
112
|
+
for (const site of scanned)
|
|
113
|
+
changedFps.add(fingerprint(site.query));
|
|
114
|
+
}
|
|
115
|
+
for (const source of affectedSources)
|
|
116
|
+
dirtyFiles.delete(source);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
for (const source of affectedSources)
|
|
120
|
+
dirtyFiles.add(source);
|
|
121
|
+
state.dirtyFiles = dirtyFiles;
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
state.dirtyFiles = dirtyFiles;
|
|
125
|
+
}
|
|
126
|
+
const sites = [...nextSites.values()].flat();
|
|
127
|
+
const dirtyFps = state.dirtyFps ?? new Set();
|
|
128
|
+
const reuseCacheFps = new Set(sites
|
|
129
|
+
.map((site) => fingerprint(site.query))
|
|
130
|
+
.filter((fp) => !changedFps.has(fp) && !dirtyFps.has(fp)));
|
|
131
|
+
const result = await active.prepareOnce(opts, state.session, log, err, 1, {
|
|
132
|
+
sites,
|
|
133
|
+
reuseCacheFps,
|
|
134
|
+
reuseFunctions: !full,
|
|
135
|
+
});
|
|
136
|
+
state.sitesByFile = nextSites;
|
|
137
|
+
if (result.failures === 0) {
|
|
138
|
+
state.dirtyFps = new Set();
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
state.dirtyFps = new Set([...dirtyFps, ...changedFps]);
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
function normalizePath(path) {
|
|
146
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
147
|
+
}
|
|
148
|
+
function projectPath(root, path) {
|
|
149
|
+
return normalizePath(relative(resolve(root), resolve(root, path)));
|
|
150
|
+
}
|
|
151
|
+
function isProjectGraphFile(path) {
|
|
152
|
+
const base = basename(path);
|
|
153
|
+
return CONFIG_FILES.has(base) || /^tsconfig(?:\.[^.]+)*\.json$/.test(base);
|
|
154
|
+
}
|
|
155
|
+
function groupSites(sites) {
|
|
156
|
+
const grouped = new Map();
|
|
157
|
+
for (const site of sites) {
|
|
158
|
+
const file = normalizePath(site.file);
|
|
159
|
+
const current = grouped.get(file) ?? [];
|
|
160
|
+
current.push(site);
|
|
161
|
+
grouped.set(file, current);
|
|
162
|
+
}
|
|
163
|
+
return grouped;
|
|
46
164
|
}
|
|
47
165
|
export async function runWatch(opts) {
|
|
48
166
|
const stamp = () => new Date().toTimeString().slice(0, 8);
|
|
49
|
-
const
|
|
50
|
-
|
|
167
|
+
const event = (name, data = {}) => {
|
|
168
|
+
console.log(formatWatchEvent(name, data));
|
|
169
|
+
};
|
|
170
|
+
const log = opts.jsonl ? () => { } : (m) => console.log(`[${stamp()}] ${m}`);
|
|
171
|
+
const err = opts.jsonl ? () => { } : (m) => console.error(`[${stamp()}] ${m}`);
|
|
51
172
|
const state = { session: null };
|
|
52
|
-
|
|
173
|
+
const report = (result, durationMs) => {
|
|
174
|
+
if (!opts.jsonl)
|
|
175
|
+
return;
|
|
176
|
+
for (const diagnostic of result.diagnostics)
|
|
177
|
+
event("diagnostic", { diagnostic });
|
|
178
|
+
event("prepared", {
|
|
179
|
+
ok: result.failures === 0,
|
|
180
|
+
sites: result.sites,
|
|
181
|
+
entries: result.entries,
|
|
182
|
+
failures: result.failures,
|
|
183
|
+
pruned: result.pruned,
|
|
184
|
+
functions: result.functions,
|
|
185
|
+
...(durationMs === undefined ? {} : { durationMs }),
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
if (opts.jsonl)
|
|
189
|
+
event("start", { root: opts.root });
|
|
190
|
+
else
|
|
191
|
+
log("watch: initial prepare");
|
|
53
192
|
try {
|
|
54
193
|
const r = await prepareWatchedOnce(opts, state, log, err);
|
|
55
|
-
|
|
194
|
+
if (opts.jsonl)
|
|
195
|
+
report(r);
|
|
196
|
+
else
|
|
197
|
+
log(`watch: ready — ${r.entries} queries, ${r.failures} failures`);
|
|
56
198
|
}
|
|
57
199
|
catch (e) {
|
|
58
|
-
|
|
200
|
+
if (opts.jsonl)
|
|
201
|
+
event("error", watchErrorData(e));
|
|
202
|
+
else
|
|
203
|
+
err(`watch: initial prepare failed — ${e.message}`);
|
|
59
204
|
}
|
|
60
|
-
|
|
205
|
+
if (opts.jsonl)
|
|
206
|
+
event("watching", { root: opts.root });
|
|
207
|
+
else
|
|
208
|
+
log(`watch: monitoring ${opts.root}`);
|
|
61
209
|
let pending = false;
|
|
62
210
|
let running = null;
|
|
63
211
|
let timer = null;
|
|
212
|
+
const changedFiles = new Set();
|
|
64
213
|
const trigger = () => {
|
|
65
214
|
if (timer)
|
|
66
215
|
clearTimeout(timer);
|
|
@@ -71,13 +220,22 @@ export async function runWatch(opts) {
|
|
|
71
220
|
return;
|
|
72
221
|
}
|
|
73
222
|
const start = Date.now();
|
|
223
|
+
const batch = [...changedFiles];
|
|
224
|
+
changedFiles.clear();
|
|
74
225
|
running = (async () => {
|
|
75
226
|
try {
|
|
76
|
-
const r = await prepareWatchedOnce(opts, state, log, err);
|
|
77
|
-
|
|
227
|
+
const r = await prepareWatchedOnce(opts, state, log, err, {}, batch);
|
|
228
|
+
const durationMs = Date.now() - start;
|
|
229
|
+
if (opts.jsonl)
|
|
230
|
+
report(r, durationMs);
|
|
231
|
+
else
|
|
232
|
+
log(`watch: re-prepared in ${durationMs}ms (${r.entries} queries, ${r.failures} failures)`);
|
|
78
233
|
}
|
|
79
234
|
catch (e) {
|
|
80
|
-
|
|
235
|
+
if (opts.jsonl)
|
|
236
|
+
event("error", watchErrorData(e));
|
|
237
|
+
else
|
|
238
|
+
err(`watch: prepare error — ${e.message}`);
|
|
81
239
|
}
|
|
82
240
|
})();
|
|
83
241
|
await running;
|
|
@@ -93,11 +251,16 @@ export async function runWatch(opts) {
|
|
|
93
251
|
return;
|
|
94
252
|
if (!shouldWatchFile(filename.toString()))
|
|
95
253
|
return;
|
|
254
|
+
changedFiles.add(normalizePath(filename.toString()));
|
|
96
255
|
trigger();
|
|
97
256
|
});
|
|
98
257
|
const shutdown = async () => {
|
|
99
|
-
|
|
100
|
-
|
|
258
|
+
if (opts.jsonl)
|
|
259
|
+
event("stopping");
|
|
260
|
+
else {
|
|
261
|
+
console.log();
|
|
262
|
+
log("watch: stopping");
|
|
263
|
+
}
|
|
101
264
|
watcher.close();
|
|
102
265
|
await closeSession(state.session);
|
|
103
266
|
process.exit(0);
|
package/dist/src/config.d.ts
CHANGED
package/dist/src/config.js
CHANGED
|
@@ -52,6 +52,12 @@ function validateStringArray(value, name, path) {
|
|
|
52
52
|
throw new Error(`sqlx-js: ${path} ${name} must be an array of strings`);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
+
function validateModuleArray(value, path) {
|
|
56
|
+
validateStringArray(value, "scan.modules", path);
|
|
57
|
+
if (value.length === 0 || value.some((item) => item.trim() === "")) {
|
|
58
|
+
throw new Error(`sqlx-js: ${path} scan.modules must contain at least one non-empty module name`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
55
61
|
function validateConfig(value, path) {
|
|
56
62
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
57
63
|
throw new Error(`sqlx-js: ${path} must default-export a config object`);
|
|
@@ -70,6 +76,8 @@ function validateConfig(value, path) {
|
|
|
70
76
|
validateStringArray(scan.include, "scan.include", path);
|
|
71
77
|
if (scan.exclude !== undefined)
|
|
72
78
|
validateStringArray(scan.exclude, "scan.exclude", path);
|
|
79
|
+
if (scan.modules !== undefined)
|
|
80
|
+
validateModuleArray(scan.modules, path);
|
|
73
81
|
}
|
|
74
82
|
if (config.schema !== undefined) {
|
|
75
83
|
if (!config.schema || typeof config.schema !== "object" || Array.isArray(config.schema)) {
|
|
@@ -14,5 +14,7 @@ export type FunctionEntry = {
|
|
|
14
14
|
returns: string;
|
|
15
15
|
returnsSet: boolean;
|
|
16
16
|
};
|
|
17
|
+
export declare function functionCachePath(cacheDir: string): string;
|
|
18
|
+
export declare function functionCacheExists(cacheDir: string): boolean;
|
|
17
19
|
export declare function readFunctionCache(cacheDir: string): FunctionEntry[];
|
|
18
20
|
export declare function writeFunctionCache(cacheDir: string, functions: FunctionEntry[]): void;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { randomBytes } from "node:crypto";
|
|
4
|
-
function
|
|
4
|
+
export function functionCachePath(cacheDir) {
|
|
5
5
|
return join(cacheDir, "functions", "functions.json");
|
|
6
6
|
}
|
|
7
|
+
export function functionCacheExists(cacheDir) {
|
|
8
|
+
return existsSync(functionCachePath(cacheDir));
|
|
9
|
+
}
|
|
7
10
|
function parseFunctionCache(raw) {
|
|
8
11
|
if (!raw || typeof raw !== "object")
|
|
9
12
|
return [];
|
|
@@ -13,14 +16,14 @@ function parseFunctionCache(raw) {
|
|
|
13
16
|
return obj.functions;
|
|
14
17
|
}
|
|
15
18
|
export function readFunctionCache(cacheDir) {
|
|
16
|
-
const path =
|
|
19
|
+
const path = functionCachePath(cacheDir);
|
|
17
20
|
if (!existsSync(path))
|
|
18
21
|
return [];
|
|
19
22
|
const text = readFileSync(path, "utf8");
|
|
20
23
|
return parseFunctionCache(JSON.parse(text));
|
|
21
24
|
}
|
|
22
25
|
export function writeFunctionCache(cacheDir, functions) {
|
|
23
|
-
const path =
|
|
26
|
+
const path = functionCachePath(cacheDir);
|
|
24
27
|
mkdirSync(dirname(path), { recursive: true });
|
|
25
28
|
const payload = { version: 1, functions };
|
|
26
29
|
const tmp = `${path}.tmp-${randomBytes(4).toString("hex")}`;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -23,17 +23,33 @@ export type { ScanConfig, SqlxJsConfig } from "./config.js";
|
|
|
23
23
|
export type { SslMode, ConnConfig } from "./pg/wire.js";
|
|
24
24
|
export { PgError, ConnectionLostError } from "./pg/wire.js";
|
|
25
25
|
export { NoRowsError, TooManyRowsError } from "./runtime.js";
|
|
26
|
-
export type { TransactionOptions, MigrateOptions, OnQueryEvent, OnQueryHook } from "./runtime.js";
|
|
26
|
+
export type { TransactionOptions, MigrateOptions, OnQueryEvent, OnQueryHook, OnQueryHookError } from "./runtime.js";
|
|
27
27
|
export type { ExecuteResult, JsonParameter, PgArrayParameter } from "./runtime.js";
|
|
28
28
|
export type { PostgresClient, PostgresOptions, CreateClientOptions } from "./postgres-runtime.js";
|
|
29
29
|
export type TypedFile = TypedFileFor<KnownFileQueries>;
|
|
30
30
|
export type TypedSql = TypedSqlFor<KnownQueries, KnownFileQueries>;
|
|
31
31
|
export type Typed = TypedFor<KnownQueries, KnownFileQueries, import("./runtime.js").TransactionOptions>;
|
|
32
|
+
export type QueryRegistry = {
|
|
33
|
+
queries: object;
|
|
34
|
+
fileQueries: object;
|
|
35
|
+
};
|
|
36
|
+
export interface DefaultQueryRegistry {
|
|
37
|
+
queries: KnownQueries;
|
|
38
|
+
fileQueries: KnownFileQueries;
|
|
39
|
+
functions: KnownFunctions;
|
|
40
|
+
}
|
|
41
|
+
export type SqlClient<Registry extends QueryRegistry = DefaultQueryRegistry> = {
|
|
42
|
+
sql: TypedFor<Registry["queries"], Registry["fileQueries"], import("./runtime.js").TransactionOptions>;
|
|
43
|
+
unsafe: Unsafe;
|
|
44
|
+
client: import("./postgres-runtime.js").PostgresClient;
|
|
45
|
+
close: () => Promise<void>;
|
|
46
|
+
};
|
|
32
47
|
export declare const sql: Typed;
|
|
33
48
|
export type Unsafe = (query: string, ...params: unknown[]) => Promise<Record<string, unknown>[]>;
|
|
34
49
|
export declare const unsafe: Unsafe;
|
|
35
50
|
export declare const getClient: typeof rt.getClient;
|
|
36
51
|
export declare const setClient: typeof rt.setClient;
|
|
37
52
|
export declare const createClient: typeof rt.createClient;
|
|
53
|
+
export declare function createSqlClient<Registry extends QueryRegistry = DefaultQueryRegistry>(url?: string, options?: import("./postgres-runtime.js").CreateClientOptions): SqlClient<Registry>;
|
|
38
54
|
export declare const close: typeof rt.close;
|
|
39
55
|
export { migrate, clearSqlFileCache, encodePgArrayLiteral, id, json, array } from "./runtime.js";
|
package/dist/src/index.js
CHANGED
|
@@ -7,5 +7,8 @@ export const unsafe = rt.unsafe;
|
|
|
7
7
|
export const getClient = rt.getClient;
|
|
8
8
|
export const setClient = rt.setClient;
|
|
9
9
|
export const createClient = rt.createClient;
|
|
10
|
+
export function createSqlClient(url, options) {
|
|
11
|
+
return rt.createSqlClient(url, options);
|
|
12
|
+
}
|
|
10
13
|
export const close = rt.close;
|
|
11
14
|
export { migrate, clearSqlFileCache, encodePgArrayLiteral, id, json, array } from "./runtime.js";
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { PgClient } from "./pg/wire.js";
|
|
2
|
+
export type MigrationFile = {
|
|
3
|
+
version: number;
|
|
4
|
+
name: string;
|
|
5
|
+
upPath: string;
|
|
6
|
+
downPath: string | null;
|
|
7
|
+
upSql: string;
|
|
8
|
+
upHash: string;
|
|
9
|
+
squash: SquashMetadata | null;
|
|
10
|
+
};
|
|
11
|
+
export type SquashReplacement = {
|
|
12
|
+
version: number;
|
|
13
|
+
name: string;
|
|
14
|
+
upHash: string;
|
|
15
|
+
};
|
|
16
|
+
export type SquashMetadata = {
|
|
17
|
+
format: 1;
|
|
18
|
+
replaces: SquashReplacement[];
|
|
19
|
+
};
|
|
20
|
+
export type MigrationStore = {
|
|
21
|
+
table: string;
|
|
22
|
+
};
|
|
23
|
+
export declare const SQUASH_PREFIX = "-- sqlx-js-squash:";
|
|
24
|
+
export declare const DEFAULT_MIGRATE_LOCK_KEY = 18750938867203960n;
|
|
25
|
+
export declare function readMigrations(dir: string): MigrationFile[];
|
|
26
|
+
export declare function parseSquashMetadata(sql: string): SquashMetadata | null;
|
|
27
|
+
export declare function ensureTable(client: PgClient): Promise<MigrationStore>;
|
|
28
|
+
export declare function listApplied(client: PgClient, store?: MigrationStore): Promise<Map<number, {
|
|
29
|
+
name: string;
|
|
30
|
+
hash: string;
|
|
31
|
+
}>>;
|
|
32
|
+
export type ApplyOutcome = {
|
|
33
|
+
kind: "applied";
|
|
34
|
+
version: number;
|
|
35
|
+
name: string;
|
|
36
|
+
} | {
|
|
37
|
+
kind: "adopted";
|
|
38
|
+
version: number;
|
|
39
|
+
name: string;
|
|
40
|
+
replaced: number;
|
|
41
|
+
} | {
|
|
42
|
+
kind: "tampered";
|
|
43
|
+
version: number;
|
|
44
|
+
name: string;
|
|
45
|
+
applied: string;
|
|
46
|
+
current: string;
|
|
47
|
+
} | {
|
|
48
|
+
kind: "failed";
|
|
49
|
+
version: number;
|
|
50
|
+
name: string;
|
|
51
|
+
error: string;
|
|
52
|
+
};
|
|
53
|
+
export type PlanOutcome = {
|
|
54
|
+
kind: "pending";
|
|
55
|
+
version: number;
|
|
56
|
+
name: string;
|
|
57
|
+
} | {
|
|
58
|
+
kind: "adoptable";
|
|
59
|
+
version: number;
|
|
60
|
+
name: string;
|
|
61
|
+
replaced: number;
|
|
62
|
+
} | {
|
|
63
|
+
kind: "tampered";
|
|
64
|
+
version: number;
|
|
65
|
+
name: string;
|
|
66
|
+
applied: string;
|
|
67
|
+
current: string;
|
|
68
|
+
} | {
|
|
69
|
+
kind: "failed";
|
|
70
|
+
version: number;
|
|
71
|
+
name: string;
|
|
72
|
+
error: string;
|
|
73
|
+
};
|
|
74
|
+
export type MigrationPlanItem = {
|
|
75
|
+
kind: "apply";
|
|
76
|
+
version: number;
|
|
77
|
+
name: string;
|
|
78
|
+
} | {
|
|
79
|
+
kind: "adopt";
|
|
80
|
+
version: number;
|
|
81
|
+
name: string;
|
|
82
|
+
replaced: number;
|
|
83
|
+
};
|
|
84
|
+
export type MigrationPlanDiagnostic = Extract<PlanOutcome, {
|
|
85
|
+
kind: "tampered" | "failed";
|
|
86
|
+
}>;
|
|
87
|
+
export type MigrationPlanSnapshot = {
|
|
88
|
+
ok: boolean;
|
|
89
|
+
pending: number;
|
|
90
|
+
adoptable: number;
|
|
91
|
+
tampered: number;
|
|
92
|
+
failed: number;
|
|
93
|
+
steps: MigrationPlanItem[];
|
|
94
|
+
diagnostics: MigrationPlanDiagnostic[];
|
|
95
|
+
};
|
|
96
|
+
export type MigrationInfoStatus = "applied" | "pending" | "adoptable" | "superseded" | "tampered" | "failed";
|
|
97
|
+
export type MigrationInfoItem = {
|
|
98
|
+
version: number;
|
|
99
|
+
name: string;
|
|
100
|
+
status: MigrationInfoStatus;
|
|
101
|
+
detail?: string;
|
|
102
|
+
};
|
|
103
|
+
export type MigrationInfoSnapshot = {
|
|
104
|
+
historyTable: string | null;
|
|
105
|
+
summary: Record<MigrationInfoStatus, number>;
|
|
106
|
+
items: MigrationInfoItem[];
|
|
107
|
+
};
|
|
108
|
+
type InternalMigrationPlanItem = {
|
|
109
|
+
kind: "apply";
|
|
110
|
+
migration: MigrationFile;
|
|
111
|
+
} | {
|
|
112
|
+
kind: "adopt";
|
|
113
|
+
migration: MigrationFile;
|
|
114
|
+
replaced: number;
|
|
115
|
+
};
|
|
116
|
+
export type MigrationValidationOutcome = {
|
|
117
|
+
kind: "tampered";
|
|
118
|
+
version: number;
|
|
119
|
+
name: string;
|
|
120
|
+
applied: string;
|
|
121
|
+
current: string;
|
|
122
|
+
} | {
|
|
123
|
+
kind: "failed";
|
|
124
|
+
version: number;
|
|
125
|
+
name: string;
|
|
126
|
+
error: string;
|
|
127
|
+
};
|
|
128
|
+
export declare function effectiveSquashReplacements(all: MigrationFile[]): SquashReplacement[];
|
|
129
|
+
export declare function buildMigrationPlan(all: MigrationFile[], applied: Map<number, {
|
|
130
|
+
name: string;
|
|
131
|
+
hash: string;
|
|
132
|
+
}>, onEvent?: (event: MigrationValidationOutcome) => void): {
|
|
133
|
+
kind: "ok";
|
|
134
|
+
steps: InternalMigrationPlanItem[];
|
|
135
|
+
} | {
|
|
136
|
+
kind: "failed";
|
|
137
|
+
} | {
|
|
138
|
+
kind: "tampered";
|
|
139
|
+
};
|
|
140
|
+
export declare function resetMigrationSession(client: PgClient): Promise<void>;
|
|
141
|
+
export declare function planPending(client: PgClient, migrationsDir: string, onEvent?: (event: PlanOutcome) => void): Promise<{
|
|
142
|
+
pending: number;
|
|
143
|
+
adoptable: number;
|
|
144
|
+
tampered: number;
|
|
145
|
+
failed: number;
|
|
146
|
+
steps: MigrationPlanItem[];
|
|
147
|
+
}>;
|
|
148
|
+
export declare function inspectMigrationPlan(client: PgClient, migrationsDir: string): Promise<MigrationPlanSnapshot>;
|
|
149
|
+
export declare function inspectMigrations(client: PgClient, migrationsDir: string): Promise<MigrationInfoSnapshot>;
|
|
150
|
+
export declare function applyPending(client: PgClient, migrationsDir: string, onEvent?: (event: ApplyOutcome) => void): Promise<{
|
|
151
|
+
applied: number;
|
|
152
|
+
tampered: number;
|
|
153
|
+
failed: number;
|
|
154
|
+
}>;
|
|
155
|
+
export declare function acquireMigrateLock(client: PgClient, lockKey?: number | bigint, timeoutMs?: number): Promise<void>;
|
|
156
|
+
export declare function releaseMigrateLock(client: PgClient, lockKey?: number | bigint): Promise<void>;
|
|
157
|
+
export {};
|