@bockit/sequel 0.0.0-stage → 0.1.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/LICENSE +202 -0
- package/README.md +191 -2
- package/THIRD_PARTY_NOTICES.md +268 -0
- package/binaries.json +106 -0
- package/dist/binaries/cache.d.ts +6 -0
- package/dist/binaries/cache.js +36 -0
- package/dist/binaries/ensure-binary.d.ts +10 -0
- package/dist/binaries/ensure-binary.js +85 -0
- package/dist/binaries/manifest.d.ts +30 -0
- package/dist/binaries/manifest.js +112 -0
- package/dist/binaries/platform.d.ts +3 -0
- package/dist/binaries/platform.js +10 -0
- package/dist/binaries/unpack.d.ts +2 -0
- package/dist/binaries/unpack.js +35 -0
- package/dist/binaries/verify.d.ts +2 -0
- package/dist/binaries/verify.js +16 -0
- package/dist/check.d.ts +9 -0
- package/dist/check.js +166 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +324 -0
- package/dist/config/define-config.d.ts +23 -0
- package/dist/config/define-config.js +4 -0
- package/dist/config/load-config.d.ts +6 -0
- package/dist/config/load-config.js +34 -0
- package/dist/config/resolve-config.d.ts +34 -0
- package/dist/config/resolve-config.js +144 -0
- package/dist/db/connection.d.ts +6 -0
- package/dist/db/connection.js +38 -0
- package/dist/db/shadow.d.ts +11 -0
- package/dist/db/shadow.js +68 -0
- package/dist/engine/client.d.ts +24 -0
- package/dist/engine/client.js +123 -0
- package/dist/engine/diff.d.ts +12 -0
- package/dist/engine/diff.js +51 -0
- package/dist/errors.d.ts +3 -0
- package/dist/errors.js +5 -0
- package/dist/extras/snapshot.d.ts +3 -0
- package/dist/extras/snapshot.js +99 -0
- package/dist/files.d.ts +1 -0
- package/dist/files.js +15 -0
- package/dist/generate/generate-modules.d.ts +17 -0
- package/dist/generate/generate-modules.js +97 -0
- package/dist/generate/modules.d.ts +16 -0
- package/dist/generate/modules.js +118 -0
- package/dist/generate/pg-dump.d.ts +8 -0
- package/dist/generate/pg-dump.js +66 -0
- package/dist/generate/plugin-wrapper.d.ts +3 -0
- package/dist/generate/plugin-wrapper.js +20 -0
- package/dist/generate/sqlc.d.ts +27 -0
- package/dist/generate/sqlc.js +113 -0
- package/dist/generate/watch.d.ts +16 -0
- package/dist/generate/watch.js +73 -0
- package/dist/generator/generate.d.ts +21 -0
- package/dist/generator/generate.js +440 -0
- package/dist/generator/keys.d.ts +4 -0
- package/dist/generator/keys.js +24 -0
- package/dist/generator/lexer.d.ts +12 -0
- package/dist/generator/lexer.js +210 -0
- package/dist/generator/main.d.ts +1 -0
- package/dist/generator/main.js +12 -0
- package/dist/generator/pg-array-helper.d.ts +2 -0
- package/dist/generator/pg-array-helper.js +53 -0
- package/dist/generator/plugin.d.ts +6 -0
- package/dist/generator/plugin.js +26 -0
- package/dist/generator/request.d.ts +57 -0
- package/dist/generator/request.js +96 -0
- package/dist/generator/select-list.d.ts +27 -0
- package/dist/generator/select-list.js +580 -0
- package/dist/generator/strings.d.ts +2 -0
- package/dist/generator/strings.js +34 -0
- package/dist/generator/types.d.ts +23 -0
- package/dist/generator/types.js +216 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/migrate/adopt-prisma.d.ts +23 -0
- package/dist/migrate/adopt-prisma.js +119 -0
- package/dist/migrate/deploy.d.ts +7 -0
- package/dist/migrate/deploy.js +23 -0
- package/dist/migrate/drift.d.ts +10 -0
- package/dist/migrate/drift.js +36 -0
- package/dist/migrate/files.d.ts +19 -0
- package/dist/migrate/files.js +97 -0
- package/dist/migrate/history.d.ts +20 -0
- package/dist/migrate/history.js +54 -0
- package/dist/migrate/lint.d.ts +21 -0
- package/dist/migrate/lint.js +153 -0
- package/dist/migrate/new.d.ts +13 -0
- package/dist/migrate/new.js +41 -0
- package/dist/migrate/runner.d.ts +28 -0
- package/dist/migrate/runner.js +124 -0
- package/dist/migrate/sql-text.d.ts +33 -0
- package/dist/migrate/sql-text.js +233 -0
- package/dist/schema/schema.d.ts +16 -0
- package/dist/schema/schema.js +111 -0
- package/dist/schema/unsupported.d.ts +3 -0
- package/dist/schema/unsupported.js +36 -0
- package/dist/schema/wasm.d.ts +8 -0
- package/dist/schema/wasm.js +32 -0
- package/package.json +50 -4
- package/vendor/prisma-schema-wasm/LICENSE +201 -0
- package/vendor/prisma-schema-wasm/README.md +32 -0
- package/vendor/prisma-schema-wasm/package.json +3 -0
- package/vendor/prisma-schema-wasm/prisma_schema_build.js +539 -0
- package/vendor/prisma-schema-wasm/prisma_schema_build_bg.wasm +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function pgDumpMajor(versionOutput: string): number | null;
|
|
2
|
+
export declare function checkPgDump(serverMajor: number, pgDump?: string): Promise<void>;
|
|
3
|
+
export declare function serverMajor(databaseUrl: string): Promise<number>;
|
|
4
|
+
export declare function dumpSchema(databaseUrl: string, file: string, pgDump?: string): Promise<void>;
|
|
5
|
+
export declare function withoutPassword(databaseUrl: string): {
|
|
6
|
+
url: string;
|
|
7
|
+
password: string | undefined;
|
|
8
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import pg from 'pg';
|
|
4
|
+
import { SequelError } from '../errors.js';
|
|
5
|
+
const run = promisify(execFile);
|
|
6
|
+
// The major version in `pg_dump --version`, such as 18 from `pg_dump (PostgreSQL) 18.6`.
|
|
7
|
+
export function pgDumpMajor(versionOutput) {
|
|
8
|
+
const match = /\(PostgreSQL\)\s+(\d+)/.exec(versionOutput) ?? /\b(\d+)(?:\.\d+)?\b/.exec(versionOutput);
|
|
9
|
+
return match?.[1] === undefined ? null : Number(match[1]);
|
|
10
|
+
}
|
|
11
|
+
// TECH-SPEC §1: `pg_dump` must be on PATH, at the server's major version or newer.
|
|
12
|
+
export async function checkPgDump(serverMajor, pgDump = 'pg_dump') {
|
|
13
|
+
let stdout;
|
|
14
|
+
try {
|
|
15
|
+
;
|
|
16
|
+
({ stdout } = await run(pgDump, ['--version']));
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error.code === 'ENOENT') {
|
|
20
|
+
throw new SequelError(`pg_dump was not found on PATH. sequel needs it to read the test database's schema. Install the Postgres ${serverMajor} client tools, or newer, and put pg_dump on PATH.`);
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
const major = pgDumpMajor(stdout);
|
|
25
|
+
if (major === null) {
|
|
26
|
+
throw new SequelError(`Could not read pg_dump's version from "${stdout.trim()}". Check that pg_dump on PATH is Postgres's.`);
|
|
27
|
+
}
|
|
28
|
+
if (major < serverMajor) {
|
|
29
|
+
throw new SequelError(`pg_dump on PATH is version ${major}, but the test database's server is Postgres ${serverMajor}. Install pg_dump ${serverMajor} or newer and put it first on PATH.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export async function serverMajor(databaseUrl) {
|
|
33
|
+
const client = new pg.Client({ connectionString: databaseUrl });
|
|
34
|
+
await client.connect();
|
|
35
|
+
try {
|
|
36
|
+
const result = await client.query('SHOW server_version_num');
|
|
37
|
+
return Math.floor(Number(result.rows[0]?.server_version_num) / 10_000);
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
await client.end();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// TECH-SPEC §9: `pg_dump --schema-only --no-owner --no-privileges` of the test database into
|
|
44
|
+
// `file`. The password travels in `PGPASSWORD`, so `ps` never shows it.
|
|
45
|
+
export async function dumpSchema(databaseUrl, file, pgDump = 'pg_dump') {
|
|
46
|
+
await checkPgDump(await serverMajor(databaseUrl), pgDump);
|
|
47
|
+
const { url, password } = withoutPassword(databaseUrl);
|
|
48
|
+
const env = { ...process.env };
|
|
49
|
+
if (password !== undefined)
|
|
50
|
+
env.PGPASSWORD = password;
|
|
51
|
+
try {
|
|
52
|
+
await run(pgDump, ['--schema-only', '--no-owner', '--no-privileges', '--file', file, '--dbname', url], { env, maxBuffer: 64 * 1024 * 1024 });
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const stderr = String(error.stderr ?? '').trim();
|
|
56
|
+
throw new SequelError(`pg_dump could not dump the test database's schema: ${stderr || error.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function withoutPassword(databaseUrl) {
|
|
60
|
+
const parsed = new URL(databaseUrl);
|
|
61
|
+
if (parsed.password === '')
|
|
62
|
+
return { url: databaseUrl, password: undefined };
|
|
63
|
+
const password = decodeURIComponent(parsed.password);
|
|
64
|
+
parsed.password = '';
|
|
65
|
+
return { url: parsed.toString(), password };
|
|
66
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { chmod, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
// The generator's entry: `main.ts` from source, `main.js` from the published `dist/`.
|
|
5
|
+
export function generatorEntry() {
|
|
6
|
+
const here = fileURLToPath(import.meta.url);
|
|
7
|
+
return path.join(path.dirname(here), '..', 'generator', `main${path.extname(here)}`);
|
|
8
|
+
}
|
|
9
|
+
// sqlc runs a process plugin with no `PATH`, so `#!/usr/bin/env node` can't start. Each run
|
|
10
|
+
// writes a `#!/bin/sh` wrapper that `exec`s this Node on the generator's entry (TECH-SPEC §9,
|
|
11
|
+
// R1), and points the plugin's `cmd` at it.
|
|
12
|
+
export async function writePluginWrapper(dir, node = process.execPath, entry = generatorEntry()) {
|
|
13
|
+
const file = path.join(dir, 'sequel-generator.sh');
|
|
14
|
+
await writeFile(file, `#!/bin/sh\nexec ${shellQuote(node)} ${shellQuote(entry)} "$@"\n`);
|
|
15
|
+
await chmod(file, 0o755);
|
|
16
|
+
return file;
|
|
17
|
+
}
|
|
18
|
+
export function shellQuote(value) {
|
|
19
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
20
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { BigintMode } from '../config/define-config.ts';
|
|
2
|
+
export type Block = {
|
|
3
|
+
queries: string;
|
|
4
|
+
out: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const DATABASE_URL_VARIABLE = "SEQUEL_SQLC_DATABASE_URL";
|
|
7
|
+
export declare function pluginName(index: number): string;
|
|
8
|
+
export declare function sqlcConfig(options: {
|
|
9
|
+
configDir: string;
|
|
10
|
+
schema: string;
|
|
11
|
+
blocks: Block[];
|
|
12
|
+
wrapper: string;
|
|
13
|
+
bigint: BigintMode;
|
|
14
|
+
}): object;
|
|
15
|
+
export declare function writeSqlcConfig(file: string, config: object): Promise<void>;
|
|
16
|
+
export type SqlcRun = {
|
|
17
|
+
exitCode: number;
|
|
18
|
+
stdout: string;
|
|
19
|
+
stderr: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function runSqlc(sqlc: string, command: 'generate' | 'diff', configFile: string, databaseUrl: string): Promise<SqlcRun>;
|
|
22
|
+
export declare function readFailures(output: string, options: {
|
|
23
|
+
configDir: string;
|
|
24
|
+
blocks: Block[];
|
|
25
|
+
root: string;
|
|
26
|
+
}): string[];
|
|
27
|
+
export declare function nameLine(file: string, query: string): number | undefined;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
// sqlc reads the test database's URL from this variable, through `${…}` in `database.uri`,
|
|
6
|
+
// so the URL, and any password in it, is never written to disk.
|
|
7
|
+
export const DATABASE_URL_VARIABLE = 'SEQUEL_SQLC_DATABASE_URL';
|
|
8
|
+
// The plugin entry for block `i`. sqlc heads each block's failures with
|
|
9
|
+
// `# package <plugin>`, so a plugin per block tells failures apart by folder.
|
|
10
|
+
export function pluginName(index) {
|
|
11
|
+
return `sequel-${index}`;
|
|
12
|
+
}
|
|
13
|
+
// TECH-SPEC §9: sqlc's config, one `sql` block per folder of query files, typed by the
|
|
14
|
+
// database analyzer against the test database. sqlc joins every path onto the config's own
|
|
15
|
+
// folder, even an absolute one, so paths are written relative to `configDir`.
|
|
16
|
+
export function sqlcConfig(options) {
|
|
17
|
+
const relative = (to) => path.relative(options.configDir, to) || '.';
|
|
18
|
+
return {
|
|
19
|
+
version: '2',
|
|
20
|
+
plugins: options.blocks.map((_, i) => ({
|
|
21
|
+
name: pluginName(i),
|
|
22
|
+
process: { cmd: options.wrapper, format: 'json' },
|
|
23
|
+
})),
|
|
24
|
+
sql: options.blocks.map((block, i) => ({
|
|
25
|
+
engine: 'postgresql',
|
|
26
|
+
schema: relative(options.schema),
|
|
27
|
+
queries: relative(block.queries),
|
|
28
|
+
database: { uri: `\${${DATABASE_URL_VARIABLE}}` },
|
|
29
|
+
analyzer: { database: true },
|
|
30
|
+
codegen: [
|
|
31
|
+
{ plugin: pluginName(i), out: relative(block.out), options: { bigint: options.bigint } },
|
|
32
|
+
],
|
|
33
|
+
})),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export async function writeSqlcConfig(file, config) {
|
|
37
|
+
await writeFile(file, `${JSON.stringify(config, null, 2)}\n`);
|
|
38
|
+
}
|
|
39
|
+
// Runs `sqlc generate` or `sqlc diff` on a config, with the test database's URL in the
|
|
40
|
+
// environment.
|
|
41
|
+
export function runSqlc(sqlc, command, configFile, databaseUrl) {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
execFile(sqlc, [command, '-f', configFile], {
|
|
44
|
+
cwd: path.dirname(configFile),
|
|
45
|
+
env: { ...process.env, [DATABASE_URL_VARIABLE]: databaseUrl },
|
|
46
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
47
|
+
}, (error, stdout, stderr) => {
|
|
48
|
+
if (error !== null && typeof error.code !== 'number') {
|
|
49
|
+
reject(error);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
resolve({ exitCode: error === null ? 0 : error.code, stdout, stderr });
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const PLUGIN_PREFIX = 'error generating code: process: error running command ';
|
|
57
|
+
// Turns sqlc's failure output into one line per failure, each naming its file, relative to
|
|
58
|
+
// `root`, and line. sqlc's own errors carry `path:line:col`. The generator's carry only
|
|
59
|
+
// `<file>: <query>`, so the line is that of the query's `-- name:` comment (R57).
|
|
60
|
+
export function readFailures(output, options) {
|
|
61
|
+
const failures = [];
|
|
62
|
+
let block;
|
|
63
|
+
for (const raw of output.split('\n')) {
|
|
64
|
+
const header = /^# package (.*)$/.exec(raw);
|
|
65
|
+
if (header !== null) {
|
|
66
|
+
block = options.blocks.find((_, i) => pluginName(i) === header[1]);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const line = raw.startsWith(PLUGIN_PREFIX) ? raw.slice(PLUGIN_PREFIX.length) : raw;
|
|
70
|
+
if (line.trim() === '')
|
|
71
|
+
continue;
|
|
72
|
+
const own = /^(.+?\.sql):(\d+):(\d+): (.*)$/.exec(line);
|
|
73
|
+
if (own !== null) {
|
|
74
|
+
const [, file = '', row, column, message] = own;
|
|
75
|
+
const shown = path.relative(options.root, path.resolve(options.configDir, file));
|
|
76
|
+
failures.push(`${shown}:${row}:${column}: ${message}`);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const fileOnly = /^([^:]+): (query file name must end in \.sql)$/.exec(line);
|
|
80
|
+
if (fileOnly !== null && block !== undefined) {
|
|
81
|
+
const shown = path.relative(options.root, path.join(block.queries, fileOnly[1] ?? ''));
|
|
82
|
+
failures.push(`${shown}: ${fileOnly[2]}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const generator = /^([^:]+\.sql): ([^\s:]+): (.*)$/.exec(line);
|
|
86
|
+
if (generator !== null && block !== undefined) {
|
|
87
|
+
const [, file = '', query = '', message] = generator;
|
|
88
|
+
const full = path.join(block.queries, file);
|
|
89
|
+
const lineNumber = nameLine(full, query);
|
|
90
|
+
const shown = path.relative(options.root, full);
|
|
91
|
+
failures.push(`${shown}${lineNumber === undefined ? '' : `:${lineNumber}`}: ${query}: ${message}`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
failures.push(line);
|
|
95
|
+
}
|
|
96
|
+
return failures;
|
|
97
|
+
}
|
|
98
|
+
// The 1-based line of `-- name: <query>` in `file`.
|
|
99
|
+
export function nameLine(file, query) {
|
|
100
|
+
let text;
|
|
101
|
+
try {
|
|
102
|
+
text = readFileSync(file, 'utf8');
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
const pattern = new RegExp(`^\\s*--\\s*name:\\s*${escapeRegExp(query)}(\\s|$)`);
|
|
108
|
+
const index = text.split('\n').findIndex((line) => pattern.test(line));
|
|
109
|
+
return index === -1 ? undefined : index + 1;
|
|
110
|
+
}
|
|
111
|
+
function escapeRegExp(text) {
|
|
112
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
113
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function createRerunScheduler(options: {
|
|
2
|
+
run: () => Promise<void>;
|
|
3
|
+
onError: (error: unknown) => void;
|
|
4
|
+
debounceMs?: number;
|
|
5
|
+
}): {
|
|
6
|
+
trigger: () => void;
|
|
7
|
+
settled(): Promise<void>;
|
|
8
|
+
stop(): void;
|
|
9
|
+
};
|
|
10
|
+
export declare function watchAndRerun(options: {
|
|
11
|
+
folders: string[];
|
|
12
|
+
run: () => Promise<void>;
|
|
13
|
+
onError: (error: unknown) => void;
|
|
14
|
+
signal: AbortSignal;
|
|
15
|
+
debounceMs?: number;
|
|
16
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { existsSync, watch } from 'node:fs';
|
|
2
|
+
// TECH-SPEC §9's watch: reruns are debounced, and never overlap. A change during a run
|
|
3
|
+
// schedules one more run after it.
|
|
4
|
+
export function createRerunScheduler(options) {
|
|
5
|
+
const debounceMs = options.debounceMs ?? 200;
|
|
6
|
+
let timer;
|
|
7
|
+
let running;
|
|
8
|
+
let again = false;
|
|
9
|
+
const fire = async () => {
|
|
10
|
+
if (running !== undefined) {
|
|
11
|
+
again = true;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
running = (async () => {
|
|
15
|
+
try {
|
|
16
|
+
await options.run();
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
options.onError(error);
|
|
20
|
+
}
|
|
21
|
+
})();
|
|
22
|
+
await running;
|
|
23
|
+
running = undefined;
|
|
24
|
+
if (again) {
|
|
25
|
+
again = false;
|
|
26
|
+
trigger();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const trigger = () => {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
timer = setTimeout(() => void fire(), debounceMs);
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
trigger,
|
|
35
|
+
// Resolves once nothing is scheduled or running.
|
|
36
|
+
async settled() {
|
|
37
|
+
while (running !== undefined || again)
|
|
38
|
+
await (running ?? Promise.resolve());
|
|
39
|
+
},
|
|
40
|
+
stop() {
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Runs once, then again whenever a `.sql` file under the folders changes, until `signal`
|
|
46
|
+
// aborts. Only `.sql` changes count, so the modules a run writes don't trigger another.
|
|
47
|
+
export async function watchAndRerun(options) {
|
|
48
|
+
const scheduler = createRerunScheduler(options);
|
|
49
|
+
try {
|
|
50
|
+
await options.run();
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
options.onError(error);
|
|
54
|
+
}
|
|
55
|
+
const watchers = [];
|
|
56
|
+
for (const folder of options.folders) {
|
|
57
|
+
if (!existsSync(folder))
|
|
58
|
+
continue;
|
|
59
|
+
watchers.push(watch(folder, { recursive: true }, (_event, filename) => {
|
|
60
|
+
if (filename !== null && filename.endsWith('.sql'))
|
|
61
|
+
scheduler.trigger();
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
await new Promise((resolve) => {
|
|
65
|
+
if (options.signal.aborted)
|
|
66
|
+
resolve();
|
|
67
|
+
options.signal.addEventListener('abort', () => resolve(), { once: true });
|
|
68
|
+
});
|
|
69
|
+
scheduler.stop();
|
|
70
|
+
for (const watcher of watchers)
|
|
71
|
+
watcher.close();
|
|
72
|
+
await scheduler.settled();
|
|
73
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Catalog, GenerateRequest, Options, Query } from './request.ts';
|
|
2
|
+
export type OutputFile = {
|
|
3
|
+
name: string;
|
|
4
|
+
contents: string;
|
|
5
|
+
};
|
|
6
|
+
export type GenerateResult = {
|
|
7
|
+
ok: true;
|
|
8
|
+
files: OutputFile[];
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
failures: string[];
|
|
12
|
+
};
|
|
13
|
+
export declare function readOptions(encoded: string): {
|
|
14
|
+
options: Options;
|
|
15
|
+
failures: string[];
|
|
16
|
+
};
|
|
17
|
+
export declare function generate(request: GenerateRequest): GenerateResult;
|
|
18
|
+
export declare function correctNullability(query: Pick<Query, 'text' | 'columns'>, catalog: Catalog | null): {
|
|
19
|
+
notNull: boolean;
|
|
20
|
+
elementsNotNull: boolean;
|
|
21
|
+
}[];
|