dbctx 1.0.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/.prettierrc.cjs +7 -0
- package/.turbo/turbo-build.log +5 -0
- package/dist/App.d.ts +23 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/App.js +9 -0
- package/dist/components/Error.d.ts +7 -0
- package/dist/components/Error.d.ts.map +1 -0
- package/dist/components/Error.js +6 -0
- package/dist/db/analyze.d.mts +3 -0
- package/dist/db/analyze.d.mts.map +1 -0
- package/dist/db/analyze.mjs +16 -0
- package/dist/db/attributes.d.mts +16 -0
- package/dist/db/attributes.d.mts.map +1 -0
- package/dist/db/attributes.mjs +37 -0
- package/dist/db/enums.d.mts +8 -0
- package/dist/db/enums.d.mts.map +1 -0
- package/dist/db/enums.mjs +24 -0
- package/dist/db/file-stats.d.mts +11 -0
- package/dist/db/file-stats.d.mts.map +1 -0
- package/dist/db/file-stats.mjs +43 -0
- package/dist/db/foreign-keys.d.mts +14 -0
- package/dist/db/foreign-keys.d.mts.map +1 -0
- package/dist/db/foreign-keys.mjs +44 -0
- package/dist/db/index.d.mts +10 -0
- package/dist/db/index.d.mts.map +1 -0
- package/dist/db/index.mjs +10 -0
- package/dist/db/indexes.d.mts +16 -0
- package/dist/db/indexes.d.mts.map +1 -0
- package/dist/db/indexes.mjs +38 -0
- package/dist/db/relations.d.mts +10 -0
- package/dist/db/relations.d.mts.map +1 -0
- package/dist/db/relations.mjs +23 -0
- package/dist/db/stats.d.mts +12 -0
- package/dist/db/stats.d.mts.map +1 -0
- package/dist/db/stats.mjs +34 -0
- package/dist/db/version.d.mts +13 -0
- package/dist/db/version.d.mts.map +1 -0
- package/dist/db/version.mjs +19 -0
- package/dist/index.d.mts +17 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +75 -0
- package/dist/logger.d.mts +3 -0
- package/dist/logger.d.mts.map +1 -0
- package/dist/logger.mjs +7 -0
- package/dist/schemas/index.d.mts +2 -0
- package/dist/schemas/index.d.mts.map +1 -0
- package/dist/schemas/index.mjs +91 -0
- package/dist/validatePaths.d.mts +12 -0
- package/dist/validatePaths.d.mts.map +1 -0
- package/dist/validatePaths.mjs +48 -0
- package/package.json +43 -0
- package/src/App.tsx +44 -0
- package/src/components/Error.tsx +16 -0
- package/src/db/analyze.mts +22 -0
- package/src/db/attributes.mts +58 -0
- package/src/db/enums.mts +43 -0
- package/src/db/file-stats.mts +57 -0
- package/src/db/foreign-keys.mts +61 -0
- package/src/db/index.mts +9 -0
- package/src/db/indexes.mts +57 -0
- package/src/db/relations.mts +35 -0
- package/src/db/stats.mts +51 -0
- package/src/db/version.mts +34 -0
- package/src/index.mts +116 -0
- package/src/logger.mts +10 -0
- package/src/schemas/index.mts +102 -0
- package/src/validatePaths.mts +77 -0
- package/tsconfig.json +104 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export type TSSLMode = "disable" | "allow" | "prefer" | "require" | "verify-ca" | "verify-full";
|
|
3
|
+
export interface ConnectionOptions {
|
|
4
|
+
hostname?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
database?: string;
|
|
7
|
+
username?: string;
|
|
8
|
+
sslmode?: TSSLMode;
|
|
9
|
+
sslcert?: string;
|
|
10
|
+
sslkey?: string;
|
|
11
|
+
sslrootcert?: string;
|
|
12
|
+
sshHost?: string;
|
|
13
|
+
sshPort?: number;
|
|
14
|
+
sshUsername?: string;
|
|
15
|
+
sshPrivateKey?: string;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"./src/","sources":["index.mts"],"names":[],"mappings":";AAOA,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,aAAa,CAAC;AAEhG,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { render } from "ink";
|
|
4
|
+
import { Error } from "./components/Error.js";
|
|
5
|
+
import { App } from "./App.js";
|
|
6
|
+
import { validatePathOptions } from "./validatePaths.mjs";
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("dbctx")
|
|
10
|
+
.description("AI generated docs from your application database")
|
|
11
|
+
.version("1.0.0")
|
|
12
|
+
.argument("[connection-string]", "PostgreSQL connection string (env: DATABASE_URL)")
|
|
13
|
+
.option("-h, --hostname <host>", "database hostname (env: PGHOST, default: localhost)")
|
|
14
|
+
.option("-p, --port <port>", "database port (env: PGPORT, default: 5432)", parseInt)
|
|
15
|
+
.option("-d, --database <name>", "database name (env: PGDATABASE, default: postgres)")
|
|
16
|
+
.option("-U, --username <user>", "database username (env: PGUSER, default: postgres)")
|
|
17
|
+
.option("--sslmode <mode>", "SSL mode: disable|allow|prefer|require|verify-ca|verify-full (env: PGSSLMODE, default: prefer)")
|
|
18
|
+
.option("--sslcert <path>", "path to client certificate (env: PGSSLCERT)")
|
|
19
|
+
.option("--sslkey <path>", "path to client private key (env: PGSSLKEY)")
|
|
20
|
+
.option("--sslrootcert <path>", "path to root CA certificate (env: PGSSLROOTCERT)")
|
|
21
|
+
.option("--ssh-host <host>", "SSH tunnel host (bastion/jump server)")
|
|
22
|
+
.option("--ssh-port <port>", "SSH tunnel port (default: 22)", parseInt)
|
|
23
|
+
.option("--ssh-username <user>", "SSH tunnel username (default: $USER)")
|
|
24
|
+
.option("--ssh-private-key <path>", "path to SSH private key (default: ~/.ssh/id_rsa)")
|
|
25
|
+
.action((connectionString, options) => {
|
|
26
|
+
const hasConnectionString = Boolean(connectionString);
|
|
27
|
+
const hasIndividualOptions = Boolean(options.hostname || options.port || options.database || options.username);
|
|
28
|
+
if (hasConnectionString && hasIndividualOptions) {
|
|
29
|
+
render(Error({
|
|
30
|
+
message: "Cannot use both connection string and individual options (-h, -p, -d, -U). Use one or the other.",
|
|
31
|
+
}));
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
// Validate path options exist on filesystem
|
|
35
|
+
const { errors: pathErrors, expandedPaths } = validatePathOptions(options);
|
|
36
|
+
if (pathErrors.length > 0) {
|
|
37
|
+
const errorMessages = pathErrors
|
|
38
|
+
.map(({ option, path }) => ` ${option}: ${path}`)
|
|
39
|
+
.join("\n");
|
|
40
|
+
render(Error({
|
|
41
|
+
message: `The following paths do not exist:\n${errorMessages}`,
|
|
42
|
+
}));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
// Replace original paths with expanded paths (~ resolved to home directory)
|
|
46
|
+
const validatedOptions = {
|
|
47
|
+
...options,
|
|
48
|
+
...expandedPaths,
|
|
49
|
+
};
|
|
50
|
+
if (hasIndividualOptions) {
|
|
51
|
+
const requiredOptions = [
|
|
52
|
+
{ key: "hostname", flag: "-h/--hostname" },
|
|
53
|
+
{ key: "port", flag: "-p/--port" },
|
|
54
|
+
{ key: "database", flag: "-d/--database" },
|
|
55
|
+
{ key: "username", flag: "-U/--username" },
|
|
56
|
+
];
|
|
57
|
+
const missing = requiredOptions
|
|
58
|
+
.filter(({ key }) => !validatedOptions[key])
|
|
59
|
+
.map(({ flag }) => flag);
|
|
60
|
+
if (missing.length > 0) {
|
|
61
|
+
render(Error({
|
|
62
|
+
message: `Missing required options: ${missing.join(", ")}`,
|
|
63
|
+
}));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// All validations passed - build config and render the app
|
|
68
|
+
const config = {
|
|
69
|
+
connectionString,
|
|
70
|
+
...validatedOptions,
|
|
71
|
+
};
|
|
72
|
+
render(App({ config }));
|
|
73
|
+
});
|
|
74
|
+
program.parse();
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgubWpzIiwic291cmNlUm9vdCI6Ii4vc3JjLyIsInNvdXJjZXMiOlsiaW5kZXgubXRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDN0IsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzlDLE9BQU8sRUFBRSxHQUFHLEVBQTBCLE1BQU0sVUFBVSxDQUFDO0FBQ3ZELE9BQU8sRUFBRSxtQkFBbUIsRUFBNkIsTUFBTSxxQkFBcUIsQ0FBQztBQW1CckYsTUFBTSxPQUFPLEdBQUcsSUFBSSxPQUFPLEVBQUUsQ0FBQztBQUU5QixPQUFPO0tBQ0YsSUFBSSxDQUFDLE9BQU8sQ0FBQztLQUNiLFdBQVcsQ0FBQyxrREFBa0QsQ0FBQztLQUMvRCxPQUFPLENBQUMsT0FBTyxDQUFDO0tBQ2hCLFFBQVEsQ0FBQyxxQkFBcUIsRUFBRSxrREFBa0QsQ0FBQztLQUNuRixNQUFNLENBQUMsdUJBQXVCLEVBQUUscURBQXFELENBQUM7S0FDdEYsTUFBTSxDQUFDLG1CQUFtQixFQUFFLDRDQUE0QyxFQUFFLFFBQVEsQ0FBQztLQUNuRixNQUFNLENBQUMsdUJBQXVCLEVBQUUsb0RBQW9ELENBQUM7S0FDckYsTUFBTSxDQUFDLHVCQUF1QixFQUFFLG9EQUFvRCxDQUFDO0tBQ3JGLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxnR0FBZ0csQ0FBQztLQUM1SCxNQUFNLENBQUMsa0JBQWtCLEVBQUUsNkNBQTZDLENBQUM7S0FDekUsTUFBTSxDQUFDLGlCQUFpQixFQUFFLDRDQUE0QyxDQUFDO0tBQ3ZFLE1BQU0sQ0FBQyxzQkFBc0IsRUFBRSxrREFBa0QsQ0FBQztLQUNsRixNQUFNLENBQUMsbUJBQW1CLEVBQUUsdUNBQXVDLENBQUM7S0FDcEUsTUFBTSxDQUFDLG1CQUFtQixFQUFFLCtCQUErQixFQUFFLFFBQVEs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ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tIFwiY29tbWFuZGVyXCI7XG5pbXBvcnQgeyByZW5kZXIgfSBmcm9tIFwiaW5rXCI7XG5pbXBvcnQgeyBFcnJvciB9IGZyb20gXCIuL2NvbXBvbmVudHMvRXJyb3IuanNcIjtcbmltcG9ydCB7IEFwcCwgdHlwZSBUQ29ubmVjdGlvbkNvbmZpZyB9IGZyb20gXCIuL0FwcC5qc1wiO1xuaW1wb3J0IHsgdmFsaWRhdGVQYXRoT3B0aW9ucywgdHlwZSBUUGF0aFZhbGlkYXRpb25FcnJvciB9IGZyb20gXCIuL3ZhbGlkYXRlUGF0aHMubWpzXCI7XG5cbmV4cG9ydCB0eXBlIFRTU0xNb2RlID0gXCJkaXNhYmxlXCIgfCBcImFsbG93XCIgfCBcInByZWZlclwiIHwgXCJyZXF1aXJlXCIgfCBcInZlcmlmeS1jYVwiIHwgXCJ2ZXJpZnktZnVsbFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIENvbm5lY3Rpb25PcHRpb25zIHtcbiAgICBob3N0bmFtZT86IHN0cmluZztcbiAgICBwb3J0PzogbnVtYmVyO1xuICAgIGRhdGFiYXNlPzogc3RyaW5nO1xuICAgIHVzZXJuYW1lPzogc3RyaW5nO1xuICAgIHNzbG1vZGU/OiBUU1NMTW9kZTtcbiAgICBzc2xjZXJ0Pzogc3RyaW5nO1xuICAgIHNzbGtleT86IHN0cmluZztcbiAgICBzc2xyb290Y2VydD86IHN0cmluZztcbiAgICBzc2hIb3N0Pzogc3RyaW5nO1xuICAgIHNzaFBvcnQ/OiBudW1iZXI7XG4gICAgc3NoVXNlcm5hbWU/OiBzdHJpbmc7XG4gICAgc3NoUHJpdmF0ZUtleT86IHN0cmluZztcbn1cblxuY29uc3QgcHJvZ3JhbSA9IG5ldyBDb21tYW5kKCk7XG5cbnByb2dyYW1cbiAgICAubmFtZShcImRiY3R4XCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiQUkgZ2VuZXJhdGVkIGRvY3MgZnJvbSB5b3VyIGFwcGxpY2F0aW9uIGRhdGFiYXNlXCIpXG4gICAgLnZlcnNpb24oXCIxLjAuMFwiKVxuICAgIC5hcmd1bWVudChcIltjb25uZWN0aW9uLXN0cmluZ11cIiwgXCJQb3N0Z3JlU1FMIGNvbm5lY3Rpb24gc3RyaW5nIChlbnY6IERBVEFCQVNFX1VSTClcIilcbiAgICAub3B0aW9uKFwiLWgsIC0taG9zdG5hbWUgPGhvc3Q+XCIsIFwiZGF0YWJhc2UgaG9zdG5hbWUgKGVudjogUEdIT1NULCBkZWZhdWx0OiBsb2NhbGhvc3QpXCIpXG4gICAgLm9wdGlvbihcIi1wLCAtLXBvcnQgPHBvcnQ+XCIsIFwiZGF0YWJhc2UgcG9ydCAoZW52OiBQR1BPUlQsIGRlZmF1bHQ6IDU0MzIpXCIsIHBhcnNlSW50KVxuICAgIC5vcHRpb24oXCItZCwgLS1kYXRhYmFzZSA8bmFtZT5cIiwgXCJkYXRhYmFzZSBuYW1lIChlbnY6IFBHREFUQUJBU0UsIGRlZmF1bHQ6IHBvc3RncmVzKVwiKVxuICAgIC5vcHRpb24oXCItVSwgLS11c2VybmFtZSA8dXNlcj5cIiwgXCJkYXRhYmFzZSB1c2VybmFtZSAoZW52OiBQR1VTRVIsIGRlZmF1bHQ6IHBvc3RncmVzKVwiKVxuICAgIC5vcHRpb24oXCItLXNzbG1vZGUgPG1vZGU+XCIsIFwiU1NMIG1vZGU6IGRpc2FibGV8YWxsb3d8cHJlZmVyfHJlcXVpcmV8dmVyaWZ5LWNhfHZlcmlmeS1mdWxsIChlbnY6IFBHU1NMTU9ERSwgZGVmYXVsdDogcHJlZmVyKVwiKVxuICAgIC5vcHRpb24oXCItLXNzbGNlcnQgPHBhdGg+XCIsIFwicGF0aCB0byBjbGllbnQgY2VydGlmaWNhdGUgKGVudjogUEdTU0xDRVJUKVwiKVxuICAgIC5vcHRpb24oXCItLXNzbGtleSA8cGF0aD5cIiwgXCJwYXRoIHRvIGNsaWVudCBwcml2YXRlIGtleSAoZW52OiBQR1NTTEtFWSlcIilcbiAgICAub3B0aW9uKFwiLS1zc2xyb290Y2VydCA8cGF0aD5cIiwgXCJwYXRoIHRvIHJvb3QgQ0EgY2VydGlmaWNhdGUgKGVudjogUEdTU0xST09UQ0VSVClcIilcbiAgICAub3B0aW9uKFwiLS1zc2gtaG9zdCA8aG9zdD5cIiwgXCJTU0ggdHVubmVsIGhvc3QgKGJhc3Rpb24vanVtcCBzZXJ2ZXIpXCIpXG4gICAgLm9wdGlvbihcIi0tc3NoLXBvcnQgPHBvcnQ+XCIsIFwiU1NIIHR1bm5lbCBwb3J0IChkZWZhdWx0OiAyMilcIiwgcGFyc2VJbnQpXG4gICAgLm9wdGlvbihcIi0tc3NoLXVzZXJuYW1lIDx1c2VyPlwiLCBcIlNTSCB0dW5uZWwgdXNlcm5hbWUgKGRlZmF1bHQ6ICRVU0VSKVwiKVxuICAgIC5vcHRpb24oXCItLXNzaC1wcml2YXRlLWtleSA8cGF0aD5cIiwgXCJwYXRoIHRvIFNTSCBwcml2YXRlIGtleSAoZGVmYXVsdDogfi8uc3NoL2lkX3JzYSlcIilcbiAgICAuYWN0aW9uKChjb25uZWN0aW9uU3RyaW5nOiBzdHJpbmcgfCB1bmRlZmluZWQsIG9wdGlvbnM6IENvbm5lY3Rpb25PcHRpb25zKSA9PiB7XG4gICAgICAgIGNvbnN0IGhhc0Nvbm5lY3Rpb25TdHJpbmcgPSBCb29sZWFuKGNvbm5lY3Rpb25TdHJpbmcpO1xuICAgICAgICBjb25zdCBoYXNJbmRpdmlkdWFsT3B0aW9ucyA9IEJvb2xlYW4oXG4gICAgICAgICAgICBvcHRpb25zLmhvc3RuYW1lIHx8IG9wdGlvbnMucG9ydCB8fCBvcHRpb25zLmRhdGFiYXNlIHx8IG9wdGlvbnMudXNlcm5hbWVcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoaGFzQ29ubmVjdGlvblN0cmluZyAmJiBoYXNJbmRpdmlkdWFsT3B0aW9ucykge1xuICAgICAgICAgICAgcmVuZGVyKFxuICAgICAgICAgICAgICAgIEVycm9yKHtcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiQ2Fubm90IHVzZSBib3RoIGNvbm5lY3Rpb24gc3RyaW5nIGFuZCBpbmRpdmlkdWFsIG9wdGlvbnMgKC1oLCAtcCwgLWQsIC1VKS4gVXNlIG9uZSBvciB0aGUgb3RoZXIuXCIsXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFZhbGlkYXRlIHBhdGggb3B0aW9ucyBleGlzdCBvbiBmaWxlc3lzdGVtXG4gICAgICAgIGNvbnN0IHsgZXJyb3JzOiBwYXRoRXJyb3JzLCBleHBhbmRlZFBhdGhzIH0gPSB2YWxpZGF0ZVBhdGhPcHRpb25zKG9wdGlvbnMpO1xuXG4gICAgICAgIGlmIChwYXRoRXJyb3JzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZXMgPSBwYXRoRXJyb3JzXG4gICAgICAgICAgICAgICAgLm1hcCgoeyBvcHRpb24sIHBhdGggfTogVFBhdGhWYWxpZGF0aW9uRXJyb3IpID0+IGAgICR7b3B0aW9ufTogJHtwYXRofWApXG4gICAgICAgICAgICAgICAgLmpvaW4oXCJcXG5cIik7XG5cbiAgICAgICAgICAgIHJlbmRlcihcbiAgICAgICAgICAgICAgICBFcnJvcih7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgZm9sbG93aW5nIHBhdGhzIGRvIG5vdCBleGlzdDpcXG4ke2Vycm9yTWVzc2FnZXN9YCxcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gUmVwbGFjZSBvcmlnaW5hbCBwYXRocyB3aXRoIGV4cGFuZGVkIHBhdGhzICh+IHJlc29sdmVkIHRvIGhvbWUgZGlyZWN0b3J5KVxuICAgICAgICBjb25zdCB2YWxpZGF0ZWRPcHRpb25zOiBDb25uZWN0aW9uT3B0aW9ucyA9IHtcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgICAuLi5leHBhbmRlZFBhdGhzLFxuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChoYXNJbmRpdmlkdWFsT3B0aW9ucykge1xuICAgICAgICAgICAgY29uc3QgcmVxdWlyZWRPcHRpb25zID0gW1xuICAgICAgICAgICAgICAgIHsga2V5OiBcImhvc3RuYW1lXCIsIGZsYWc6IFwiLWgvLS1ob3N0bmFtZVwiIH0sXG4gICAgICAgICAgICAgICAgeyBrZXk6IFwicG9ydFwiLCBmbGFnOiBcIi1wLy0tcG9ydFwiIH0sXG4gICAgICAgICAgICAgICAgeyBrZXk6IFwiZGF0YWJhc2VcIiwgZmxhZzogXCItZC8tLWRhdGFiYXNlXCIgfSxcbiAgICAgICAgICAgICAgICB7IGtleTogXCJ1c2VybmFtZVwiLCBmbGFnOiBcIi1VLy0tdXNlcm5hbWVcIiB9LFxuICAgICAgICAgICAgXSBhcyBjb25zdDtcblxuICAgICAgICAgICAgY29uc3QgbWlzc2luZyA9IHJlcXVpcmVkT3B0aW9uc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKHsga2V5IH0pID0+ICF2YWxpZGF0ZWRPcHRpb25zW2tleV0pXG4gICAgICAgICAgICAgICAgLm1hcCgoeyBmbGFnIH0pID0+IGZsYWcpO1xuXG4gICAgICAgICAgICBpZiAobWlzc2luZy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgcmVuZGVyKFxuICAgICAgICAgICAgICAgICAgICBFcnJvcih7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlOiBgTWlzc2luZyByZXF1aXJlZCBvcHRpb25zOiAke21pc3Npbmcuam9pbihcIiwgXCIpfWAsXG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEFsbCB2YWxpZGF0aW9ucyBwYXNzZWQgLSBidWlsZCBjb25maWcgYW5kIHJlbmRlciB0aGUgYXBwXG4gICAgICAgIGNvbnN0IGNvbmZpZzogVENvbm5lY3Rpb25Db25maWcgPSB7XG4gICAgICAgICAgICBjb25uZWN0aW9uU3RyaW5nLFxuICAgICAgICAgICAgLi4udmFsaWRhdGVkT3B0aW9ucyxcbiAgICAgICAgfTtcblxuICAgICAgICByZW5kZXIoQXBwKHsgY29uZmlnIH0pKTtcbiAgICB9KTtcblxucHJvZ3JhbS5wYXJzZSgpO1xuIl19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.mts","sourceRoot":"./src/","sources":["logger.mts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,eAAO,MAAM,MAAM,gBAOjB,CAAC"}
|
package/dist/logger.mjs
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import winston from 'winston';
|
|
2
|
+
export const logger = winston.createLogger({
|
|
3
|
+
level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
|
|
4
|
+
format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
|
|
5
|
+
transports: [new winston.transports.Console()],
|
|
6
|
+
});
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLm1qcyIsInNvdXJjZVJvb3QiOiIuL3NyYy8iLCJzb3VyY2VzIjpbImxvZ2dlci5tdHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxPQUFPLE1BQU0sU0FBUyxDQUFDO0FBRTlCLE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDO0lBQ3ZDLEtBQUssRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxhQUFhLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTTtJQUNoRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQzFCLE9BQU8sQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLEVBQzFCLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQ3hCO0lBQ0QsVUFBVSxFQUFFLENBQUMsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO0NBQ2pELENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB3aW5zdG9uIGZyb20gJ3dpbnN0b24nO1xuXG5leHBvcnQgY29uc3QgbG9nZ2VyID0gd2luc3Rvbi5jcmVhdGVMb2dnZXIoe1xuICAgIGxldmVsOiBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50JyA/ICdkZWJ1ZycgOiAnaW5mbycsXG4gICAgZm9ybWF0OiB3aW5zdG9uLmZvcm1hdC5jb21iaW5lKFxuICAgICAgICB3aW5zdG9uLmZvcm1hdC50aW1lc3RhbXAoKSxcbiAgICAgICAgd2luc3Rvbi5mb3JtYXQuanNvbigpLFxuICAgICksXG4gICAgdHJhbnNwb3J0czogW25ldyB3aW5zdG9uLnRyYW5zcG9ydHMuQ29uc29sZSgpXSxcbn0pO1xuIl19
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"./src/","sources":["schemas/index.mts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const relationAttribute = z
|
|
3
|
+
.object({
|
|
4
|
+
name: z.string(),
|
|
5
|
+
data_type: z.string(),
|
|
6
|
+
is_nullable: z.boolean(),
|
|
7
|
+
comment: z.string().nullable(),
|
|
8
|
+
})
|
|
9
|
+
.and(z.discriminatedUnion('kind', [
|
|
10
|
+
z.discriminatedUnion('has_default', [
|
|
11
|
+
z.object({
|
|
12
|
+
kind: z.literal('regular'),
|
|
13
|
+
has_default: z.literal(false),
|
|
14
|
+
}),
|
|
15
|
+
z.object({
|
|
16
|
+
kind: z.literal('regular'),
|
|
17
|
+
has_default: z.literal(true),
|
|
18
|
+
default_expression: z.string(),
|
|
19
|
+
}),
|
|
20
|
+
]),
|
|
21
|
+
z.object({
|
|
22
|
+
kind: z.literal('generated'),
|
|
23
|
+
generated_storage: z.enum(['stored', 'virtual']),
|
|
24
|
+
generated_expression: z.string(),
|
|
25
|
+
}),
|
|
26
|
+
]));
|
|
27
|
+
const indexInfo = z
|
|
28
|
+
.object({
|
|
29
|
+
index_name: z.string(),
|
|
30
|
+
relation_name: z.string(),
|
|
31
|
+
attributes: z.array(z.string()),
|
|
32
|
+
definition: z.string(),
|
|
33
|
+
comment: z.string().nullable(),
|
|
34
|
+
})
|
|
35
|
+
.and(z.discriminatedUnion('index_kind', [
|
|
36
|
+
z.object({ index_kind: z.literal('primary') }),
|
|
37
|
+
z.object({ index_kind: z.literal('unique') }),
|
|
38
|
+
z.object({
|
|
39
|
+
index_kind: z.literal('exclusion'),
|
|
40
|
+
exclusion_operators: z.array(z.string()),
|
|
41
|
+
}),
|
|
42
|
+
z.object({ index_kind: z.literal('plain') }),
|
|
43
|
+
]))
|
|
44
|
+
.and(z.discriminatedUnion('is_partial', [
|
|
45
|
+
z.object({ is_partial: z.literal(false) }),
|
|
46
|
+
z.object({
|
|
47
|
+
is_partial: z.literal(true),
|
|
48
|
+
partial_predicate: z.string(),
|
|
49
|
+
}),
|
|
50
|
+
]));
|
|
51
|
+
const reference = z.object({
|
|
52
|
+
constraint_name: z.string(),
|
|
53
|
+
attributes: z.array(z.string()),
|
|
54
|
+
referenced_relation: z.string(),
|
|
55
|
+
referenced_attributes: z.array(z.string()),
|
|
56
|
+
on_update: z.enum([
|
|
57
|
+
'NO ACTION',
|
|
58
|
+
'RESTRICT',
|
|
59
|
+
'CASCADE',
|
|
60
|
+
'SET NULL',
|
|
61
|
+
'SET DEFAULT',
|
|
62
|
+
]),
|
|
63
|
+
on_delete: z.enum([
|
|
64
|
+
'NO ACTION',
|
|
65
|
+
'RESTRICT',
|
|
66
|
+
'CASCADE',
|
|
67
|
+
'SET NULL',
|
|
68
|
+
'SET DEFAULT',
|
|
69
|
+
]),
|
|
70
|
+
comment: z.string().nullable(),
|
|
71
|
+
});
|
|
72
|
+
const relation = z.object({
|
|
73
|
+
name: z.string(),
|
|
74
|
+
comment: z.string().nullable(),
|
|
75
|
+
kind: z.enum(['partitioned_table', 'table', 'view', 'materialized_view']),
|
|
76
|
+
summary: z.string().optional(),
|
|
77
|
+
details: z.string().optional(),
|
|
78
|
+
attributes: z.record(z.string(), relationAttribute),
|
|
79
|
+
references: z.record(z.string(), reference),
|
|
80
|
+
indexes: z.record(z.string(), indexInfo),
|
|
81
|
+
});
|
|
82
|
+
const relations = z.record(z.string(), relation);
|
|
83
|
+
const database = z.object({
|
|
84
|
+
type: z.enum(['postgresql']),
|
|
85
|
+
name: z.string(),
|
|
86
|
+
comment: z.string().nullable(),
|
|
87
|
+
summary: z.string().optional(),
|
|
88
|
+
details: z.string().optional(),
|
|
89
|
+
relations: relations,
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXgubWpzIiwic291cmNlUm9vdCI6Ii4vc3JjLyIsInNvdXJjZXMiOlsic2NoZW1hcy9pbmRleC5tdHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLENBQUMsRUFBQyxNQUFNLEtBQUssQ0FBQztBQUV0QixNQUFNLGlCQUFpQixHQUFHLENBQUM7S0FDdEIsTUFBTSxDQUFDO0lBQ0osSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDaEIsU0FBUyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDckIsV0FBVyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUU7SUFDeEIsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDakMsQ0FBQztLQUNELEdBQUcsQ0FDQSxDQUFDLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFO0lBQ3pCLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLEVBQUU7UUFDaEMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztZQUNMLElBQUksRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztZQUMxQixXQUFXLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7U0FDaEMsQ0FBQztRQUNGLENBQUMsQ0FBQyxNQUFNLENBQUM7WUFDTCxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUM7WUFDMUIsV0FBVyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDO1lBQzVCLGtCQUFrQixFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7U0FDakMsQ0FBQztLQUNMLENBQUM7SUFDRixDQUFDLENBQUMsTUFBTSxDQUFDO1FBQ0wsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDO1FBQzVCLGlCQUFpQixFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDaEQsb0JBQW9C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UUFBUSxFQUFFO0lBQzlCLE9BQU8sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQzlCLFVBQVUsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxpQkFBaUIsQ0FBQztJQUNuRCxVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsU0FBUyxDQUFDO0lBQzNDLE9BQU8sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxTQUFTLENBQUM7Q0FDM0MsQ0FBQyxDQUFDO0FBRUgsTUFBTSxTQUFTLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFFakQsTUFBTSxRQUFRLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUN0QixJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzVCLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0lBQ2hCLE9BQU8sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQzlCLE9BQU8sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQzlCLE9BQU8sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQzlCLFNBQVMsRUFBRSxTQUFTO0NBQ3ZCLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7en0gZnJvbSAnem9kJztcblxuY29uc3QgcmVsYXRpb25BdHRyaWJ1dGUgPSB6XG4gICAgLm9iamVjdCh7XG4gICAgICAgIG5hbWU6IHouc3RyaW5nKCksXG4gICAgICAgIGRhdGFfdHlwZTogei5zdHJpbmcoKSxcbiAgICAgICAgaXNfbnVsbGFibGU6IHouYm9vbGVhbigpLFxuICAgICAgICBjb21tZW50OiB6LnN0cmluZygpLm51bGxhYmxlKCksXG4gICAgfSlcbiAgICAuYW5kKFxuICAgICAgICB6LmRpc2NyaW1pbmF0ZWRVbmlvbigna2luZCcsIFtcbiAgICAgICAgICAgIHouZGlzY3JpbWluYXRlZFVuaW9uKCdoYXNfZGVmYXVsdCcsIFtcbiAgICAgICAgICAgICAgICB6Lm9iamVjdCh7XG4gICAgICAgICAgICAgICAgICAgIGtpbmQ6IHoubGl0ZXJhbCgncmVndWxhcicpLFxuICAgICAgICAgICAgICAgICAgICBoYXNfZGVmYXVsdDogei5saXRlcmFsKGZhbHNlKSxcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICB6Lm9iamVjdCh7XG4gICAgICAgICAgICAgICAgICAgIGtpbmQ6IHoubGl0ZXJhbCgncmVndWxhcicpLFxuICAgICAgICAgICAgICAgICAgICBoYXNfZGVmYXVsdDogei5saXRlcmFsKHRydWUpLFxuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0X2V4cHJlc3Npb246IHouc3RyaW5nKCksXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBdKSxcbiAgICAgICAgICAgIHoub2JqZWN0KHtcbiAgICAgICAgICAgICAgICBraW5kOiB6LmxpdGVyYWwoJ2dlbmVyYXRlZCcpLFxuICAgICAgICAgICAgICAgIGdlbmVyYXRlZF9zdG9yYWdlOiB6LmVudW0oWydzdG9yZWQnLCAndmlydHVhbCddKSxcbiAgICAgICAgICAgICAgICBnZW5lcmF0ZWRfZXhwcmVzc2lvbjogei5zdHJpbmcoKSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICBdKSxcbiAgICApO1xuXG5jb25zdCBpbmRleEluZm8gPSB6XG4gICAgLm9iamVjdCh7XG4gICAgICAgIGluZGV4X25hbWU6IHouc3RyaW5nKCksXG4gICAgICAgIHJlbGF0aW9uX25hbWU6IHouc3RyaW5nKCksXG4gICAgICAgIGF0dHJpYnV0ZXM6IHouYXJyYXkoei5zdHJpbmcoKSksXG4gICAgICAgIGRlZmluaXRpb246IHouc3RyaW5nKCksXG4gICAgICAgIGNvbW1lbnQ6IHouc3RyaW5nKCkubnVsbGFibGUoKSxcbiAgICB9KVxuICAgIC5hbmQoXG4gICAgICAgIHouZGlzY3JpbWluYXRlZFVuaW9uKCdpbmRleF9raW5kJywgW1xuICAgICAgICAgICAgei5vYmplY3QoeyBpbmRleF9raW5kOiB6LmxpdGVyYWwoJ3ByaW1hcnknKSB9KSxcbiAgICAgICAgICAgIHoub2JqZWN0KHsgaW5kZXhfa2luZDogei5saXRlcmFsKCd1bmlxdWUnKSB9KSxcbiAgICAgICAgICAgIHoub2JqZWN0KHtcbiAgICAgICAgICAgICAgICBpbmRleF9raW5kOiB6LmxpdGVyYWwoJ2V4Y2x1c2lvbicpLFxuICAgICAgICAgICAgICAgIGV4Y2x1c2lvbl9vcGVyYXRvcnM6IHouYXJyYXkoei5zdHJpbmcoKSksXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHoub2JqZWN0KHsgaW5kZXhfa2luZDogei5saXRlcmFsKCdwbGFpbicpIH0pLFxuICAgICAgICBdKSxcbiAgICApXG4gICAgLmFuZChcbiAgICAgICAgei5kaXNjcmltaW5hdGVkVW5pb24oJ2lzX3BhcnRpYWwnLCBbXG4gICAgICAgICAgICB6Lm9iamVjdCh7IGlzX3BhcnRpYWw6IHoubGl0ZXJhbChmYWxzZSkgfSksXG4gICAgICAgICAgICB6Lm9iamVjdCh7XG4gICAgICAgICAgICAgICAgaXNfcGFydGlhbDogei5saXRlcmFsKHRydWUpLFxuICAgICAgICAgICAgICAgIHBhcnRpYWxfcHJlZGljYXRlOiB6LnN0cmluZygpLFxuICAgICAgICAgICAgfSksXG4gICAgICAgIF0pLFxuICAgICk7XG5cbmNvbnN0IHJlZmVyZW5jZSA9IHoub2JqZWN0KHtcbiAgICBjb25zdHJhaW50X25hbWU6IHouc3RyaW5nKCksXG4gICAgYXR0cmlidXRlczogei5hcnJheSh6LnN0cmluZygpKSxcbiAgICByZWZlcmVuY2VkX3JlbGF0aW9uOiB6LnN0cmluZygpLFxuICAgIHJlZmVyZW5jZWRfYXR0cmlidXRlczogei5hcnJheSh6LnN0cmluZygpKSxcbiAgICBvbl91cGRhdGU6IHouZW51bShbXG4gICAgICAgICdOTyBBQ1RJT04nLFxuICAgICAgICAnUkVTVFJJQ1QnLFxuICAgICAgICAnQ0FTQ0FERScsXG4gICAgICAgICdTRVQgTlVMTCcsXG4gICAgICAgICdTRVQgREVGQVVMVCcsXG4gICAgXSksXG4gICAgb25fZGVsZXRlOiB6LmVudW0oW1xuICAgICAgICAnTk8gQUNUSU9OJyxcbiAgICAgICAgJ1JFU1RSSUNUJyxcbiAgICAgICAgJ0NBU0NBREUnLFxuICAgICAgICAnU0VUIE5VTEwnLFxuICAgICAgICAnU0VUIERFRkFVTFQnLFxuICAgIF0pLFxuICAgIGNvbW1lbnQ6IHouc3RyaW5nKCkubnVsbGFibGUoKSxcbn0pO1xuXG5jb25zdCByZWxhdGlvbiA9IHoub2JqZWN0KHtcbiAgICBuYW1lOiB6LnN0cmluZygpLFxuICAgIGNvbW1lbnQ6IHouc3RyaW5nKCkubnVsbGFibGUoKSxcbiAgICBraW5kOiB6LmVudW0oWydwYXJ0aXRpb25lZF90YWJsZScsICd0YWJsZScsICd2aWV3JywgJ21hdGVyaWFsaXplZF92aWV3J10pLFxuICAgIHN1bW1hcnk6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgICBkZXRhaWxzOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG4gICAgYXR0cmlidXRlczogei5yZWNvcmQoei5zdHJpbmcoKSwgcmVsYXRpb25BdHRyaWJ1dGUpLFxuICAgIHJlZmVyZW5jZXM6IHoucmVjb3JkKHouc3RyaW5nKCksIHJlZmVyZW5jZSksXG4gICAgaW5kZXhlczogei5yZWNvcmQoei5zdHJpbmcoKSwgaW5kZXhJbmZvKSxcbn0pO1xuXG5jb25zdCByZWxhdGlvbnMgPSB6LnJlY29yZCh6LnN0cmluZygpLCByZWxhdGlvbik7XG5cbmNvbnN0IGRhdGFiYXNlID0gei5vYmplY3Qoe1xuICAgIHR5cGU6IHouZW51bShbJ3Bvc3RncmVzcWwnXSksXG4gICAgbmFtZTogei5zdHJpbmcoKSxcbiAgICBjb21tZW50OiB6LnN0cmluZygpLm51bGxhYmxlKCksXG4gICAgc3VtbWFyeTogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICAgIGRldGFpbHM6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgICByZWxhdGlvbnM6IHJlbGF0aW9ucyxcbn0pO1xuIl19
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type TPathOptionKey = "sslcert" | "sslkey" | "sslrootcert" | "sshPrivateKey";
|
|
2
|
+
export type TPathValidationError = {
|
|
3
|
+
option: string;
|
|
4
|
+
path: string;
|
|
5
|
+
error: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const validatePathOptions: <T extends Partial<Record<TPathOptionKey, string>>>(options: T) => {
|
|
8
|
+
errors: TPathValidationError[];
|
|
9
|
+
expandedPaths: Partial<Record<TPathOptionKey, string>>;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=validatePaths.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validatePaths.d.mts","sourceRoot":"./src/","sources":["validatePaths.mts"],"names":[],"mappings":"AAQA,KAAK,cAAc,GAAG,SAAS,GAAG,QAAQ,GAAG,aAAa,GAAG,eAAe,CAAC;AAE7E,MAAM,MAAM,oBAAoB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACjB,CAAC;AAyBF,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,EACjF,SAAS,CAAC,KACX;IAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAA;CAmC1F,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
const expandTilde = (path) => path.startsWith("~/") || path === "~"
|
|
5
|
+
? path.replace(/^~/, homedir())
|
|
6
|
+
: path;
|
|
7
|
+
const normalizePath = (path) => resolve(expandTilde(path));
|
|
8
|
+
const validatePathExists = (path) => {
|
|
9
|
+
const expandedPath = normalizePath(path);
|
|
10
|
+
return existsSync(expandedPath)
|
|
11
|
+
? { valid: true, expandedPath }
|
|
12
|
+
: { valid: false, error: `Path does not exist: ${path}` };
|
|
13
|
+
};
|
|
14
|
+
const PATH_OPTION_LABELS = {
|
|
15
|
+
sslcert: "--sslcert",
|
|
16
|
+
sslkey: "--sslkey",
|
|
17
|
+
sslrootcert: "--sslrootcert",
|
|
18
|
+
sshPrivateKey: "--ssh-private-key",
|
|
19
|
+
};
|
|
20
|
+
export const validatePathOptions = (options) => {
|
|
21
|
+
const pathKeys = ["sslcert", "sslkey", "sslrootcert", "sshPrivateKey"];
|
|
22
|
+
const results = pathKeys
|
|
23
|
+
.filter((key) => options[key] !== undefined)
|
|
24
|
+
.map((key) => {
|
|
25
|
+
const path = options[key];
|
|
26
|
+
const result = validatePathExists(path);
|
|
27
|
+
return {
|
|
28
|
+
key,
|
|
29
|
+
path,
|
|
30
|
+
result,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
const errors = results
|
|
34
|
+
.filter((r) => !r.result.valid)
|
|
35
|
+
.map((r) => ({
|
|
36
|
+
option: PATH_OPTION_LABELS[r.key],
|
|
37
|
+
path: r.path,
|
|
38
|
+
error: r.result.error,
|
|
39
|
+
}));
|
|
40
|
+
const expandedPaths = results
|
|
41
|
+
.filter((r) => r.result.valid)
|
|
42
|
+
.reduce((acc, r) => ({
|
|
43
|
+
...acc,
|
|
44
|
+
[r.key]: r.result.expandedPath,
|
|
45
|
+
}), {});
|
|
46
|
+
return { errors, expandedPaths };
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGVQYXRocy5tanMiLCJzb3VyY2VSb290IjoiLi9zcmMvIiwic291cmNlcyI6WyJ2YWxpZGF0ZVBhdGhzLm10cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQWNwQyxNQUFNLFdBQVcsR0FBRyxDQUFDLElBQVksRUFBVSxFQUFFLENBQ3pDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxLQUFLLEdBQUc7SUFDakMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFDO0lBQy9CLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFFZixNQUFNLGFBQWEsR0FBRyxDQUFDLElBQVksRUFBVSxFQUFFLENBQzNDLE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztBQUUvQixNQUFNLGtCQUFrQixHQUFHLENBQUMsSUFBWSxFQUF5QixFQUFFO0lBQy9ELE1BQU0sWUFBWSxHQUFHLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUV6QyxPQUFPLFVBQVUsQ0FBQyxZQUFZLENBQUM7UUFDM0IsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUU7UUFDL0IsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsd0JBQXdCLElBQUksRUFBRSxFQUFFLENBQUM7QUFDbEUsQ0FBQyxDQUFDO0FBRUYsTUFBTSxrQkFBa0IsR0FBbUM7SUFDdkQsT0FBTyxFQUFFLFdBQVc7SUFDcEIsTUFBTSxFQUFFLFVBQVU7SUFDbEIsV0FBVyxFQUFFLGVBQWU7SUFDNUIsYUFBYSxFQUFFLG1CQUFtQjtDQUNyQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsQ0FDL0IsT0FBVSxFQUNnRixFQUFFO0lBQzVGLE1BQU0sUUFBUSxHQUFxQixDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsYUFBYSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBRXpGLE1BQU0sT0FBTyxHQUFHLFFBQVE7U0FDbkIsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssU0FBUyxDQUFDO1NBQzNDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1FBQ1QsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBVyxDQUFDO1FBQ3BDLE1BQU0sTUFBTSxHQUFHLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXhDLE9BQU87WUFDSCxHQUFHO1lBQ0gsSUFBSTtZQUNKLE1BQU07U0FDVCxDQUFDO0lBQ04sQ0FBQyxDQUFDLENBQUM7SUFFUCxNQUFNLE1BQU0sR0FBRyxPQUFPO1NBQ2pCLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztTQUM5QixHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDVCxNQUFNLEVBQUUsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztRQUNqQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUk7UUFDWixLQUFLLEVBQUcsQ0FBQyxDQUFDLE1BQTBDLENBQUMsS0FBSztLQUM3RCxDQUFDLENBQUMsQ0FBQztJQUVSLE1BQU0sYUFBYSxHQUFHLE9BQU87U0FDeEIsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztTQUM3QixNQUFNLENBQ0gsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ1QsR0FBRyxHQUFHO1FBQ04sQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUcsQ0FBQyxDQUFDLE1BQWdELENBQUMsWUFBWTtLQUM1RSxDQUFDLEVBQ0YsRUFBNkMsQ0FDaEQsQ0FBQztJQUVOLE9BQU8sRUFBRSxNQUFNLEVBQUUsYUFBYSxFQUFFLENBQUM7QUFDckMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhpc3RzU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBob21lZGlyIH0gZnJvbSBcIm5vZGU6b3NcIjtcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5cbnR5cGUgVFBhdGhWYWxpZGF0aW9uUmVzdWx0ID1cbiAgICB8IHsgdmFsaWQ6IHRydWU7IGV4cGFuZGVkUGF0aDogc3RyaW5nIH1cbiAgICB8IHsgdmFsaWQ6IGZhbHNlOyBlcnJvcjogc3RyaW5nIH07XG5cbnR5cGUgVFBhdGhPcHRpb25LZXkgPSBcInNzbGNlcnRcIiB8IFwic3Nsa2V5XCIgfCBcInNzbHJvb3RjZXJ0XCIgfCBcInNzaFByaXZhdGVLZXlcIjtcblxuZXhwb3J0IHR5cGUgVFBhdGhWYWxpZGF0aW9uRXJyb3IgPSB7XG4gICAgb3B0aW9uOiBzdHJpbmc7XG4gICAgcGF0aDogc3RyaW5nO1xuICAgIGVycm9yOiBzdHJpbmc7XG59O1xuXG5jb25zdCBleHBhbmRUaWxkZSA9IChwYXRoOiBzdHJpbmcpOiBzdHJpbmcgPT5cbiAgICBwYXRoLnN0YXJ0c1dpdGgoXCJ+L1wiKSB8fCBwYXRoID09PSBcIn5cIlxuICAgICAgICA/IHBhdGgucmVwbGFjZSgvXn4vLCBob21lZGlyKCkpXG4gICAgICAgIDogcGF0aDtcblxuY29uc3Qgbm9ybWFsaXplUGF0aCA9IChwYXRoOiBzdHJpbmcpOiBzdHJpbmcgPT5cbiAgICByZXNvbHZlKGV4cGFuZFRpbGRlKHBhdGgpKTtcblxuY29uc3QgdmFsaWRhdGVQYXRoRXhpc3RzID0gKHBhdGg6IHN0cmluZyk6IFRQYXRoVmFsaWRhdGlvblJlc3VsdCA9PiB7XG4gICAgY29uc3QgZXhwYW5kZWRQYXRoID0gbm9ybWFsaXplUGF0aChwYXRoKTtcblxuICAgIHJldHVybiBleGlzdHNTeW5jKGV4cGFuZGVkUGF0aClcbiAgICAgICAgPyB7IHZhbGlkOiB0cnVlLCBleHBhbmRlZFBhdGggfVxuICAgICAgICA6IHsgdmFsaWQ6IGZhbHNlLCBlcnJvcjogYFBhdGggZG9lcyBub3QgZXhpc3Q6ICR7cGF0aH1gIH07XG59O1xuXG5jb25zdCBQQVRIX09QVElPTl9MQUJFTFM6IFJlY29yZDxUUGF0aE9wdGlvbktleSwgc3RyaW5nPiA9IHtcbiAgICBzc2xjZXJ0OiBcIi0tc3NsY2VydFwiLFxuICAgIHNzbGtleTogXCItLXNzbGtleVwiLFxuICAgIHNzbHJvb3RjZXJ0OiBcIi0tc3Nscm9vdGNlcnRcIixcbiAgICBzc2hQcml2YXRlS2V5OiBcIi0tc3NoLXByaXZhdGUta2V5XCIsXG59O1xuXG5leHBvcnQgY29uc3QgdmFsaWRhdGVQYXRoT3B0aW9ucyA9IDxUIGV4dGVuZHMgUGFydGlhbDxSZWNvcmQ8VFBhdGhPcHRpb25LZXksIHN0cmluZz4+PihcbiAgICBvcHRpb25zOiBUXG4pOiB7IGVycm9yczogVFBhdGhWYWxpZGF0aW9uRXJyb3JbXTsgZXhwYW5kZWRQYXRoczogUGFydGlhbDxSZWNvcmQ8VFBhdGhPcHRpb25LZXksIHN0cmluZz4+IH0gPT4ge1xuICAgIGNvbnN0IHBhdGhLZXlzOiBUUGF0aE9wdGlvbktleVtdID0gW1wic3NsY2VydFwiLCBcInNzbGtleVwiLCBcInNzbHJvb3RjZXJ0XCIsIFwic3NoUHJpdmF0ZUtleVwiXTtcblxuICAgIGNvbnN0IHJlc3VsdHMgPSBwYXRoS2V5c1xuICAgICAgICAuZmlsdGVyKChrZXkpID0+IG9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkKVxuICAgICAgICAubWFwKChrZXkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBhdGggPSBvcHRpb25zW2tleV0gYXMgc3RyaW5nO1xuICAgICAgICAgICAgY29uc3QgcmVzdWx0ID0gdmFsaWRhdGVQYXRoRXhpc3RzKHBhdGgpO1xuXG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGtleSxcbiAgICAgICAgICAgICAgICBwYXRoLFxuICAgICAgICAgICAgICAgIHJlc3VsdCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgY29uc3QgZXJyb3JzID0gcmVzdWx0c1xuICAgICAgICAuZmlsdGVyKChyKSA9PiAhci5yZXN1bHQudmFsaWQpXG4gICAgICAgIC5tYXAoKHIpID0+ICh7XG4gICAgICAgICAgICBvcHRpb246IFBBVEhfT1BUSU9OX0xBQkVMU1tyLmtleV0sXG4gICAgICAgICAgICBwYXRoOiByLnBhdGgsXG4gICAgICAgICAgICBlcnJvcjogKHIucmVzdWx0IGFzIHsgdmFsaWQ6IGZhbHNlOyBlcnJvcjogc3RyaW5nIH0pLmVycm9yLFxuICAgICAgICB9KSk7XG5cbiAgICBjb25zdCBleHBhbmRlZFBhdGhzID0gcmVzdWx0c1xuICAgICAgICAuZmlsdGVyKChyKSA9PiByLnJlc3VsdC52YWxpZClcbiAgICAgICAgLnJlZHVjZShcbiAgICAgICAgICAgIChhY2MsIHIpID0+ICh7XG4gICAgICAgICAgICAgICAgLi4uYWNjLFxuICAgICAgICAgICAgICAgIFtyLmtleV06IChyLnJlc3VsdCBhcyB7IHZhbGlkOiB0cnVlOyBleHBhbmRlZFBhdGg6IHN0cmluZyB9KS5leHBhbmRlZFBhdGgsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHt9IGFzIFBhcnRpYWw8UmVjb3JkPFRQYXRoT3B0aW9uS2V5LCBzdHJpbmc+PlxuICAgICAgICApO1xuXG4gICAgcmV0dXJuIHsgZXJyb3JzLCBleHBhbmRlZFBhdGhzIH07XG59O1xuIl19
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dbctx",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "dbctx CLI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.mjs",
|
|
7
|
+
"bin": {
|
|
8
|
+
"dbctx": "./dist/index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "tsc && node ./dist/index.mjs",
|
|
12
|
+
"dev": "tsc --watch --preserveWatchOutput",
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"build:ts:watch": "tsc --watch --preserveWatchOutput"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "AirState",
|
|
19
|
+
"email": "hello@airstate.dev",
|
|
20
|
+
"url": "https://airstate.dev"
|
|
21
|
+
},
|
|
22
|
+
"license": "UNLICENSED",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"commander": "14.0.3",
|
|
25
|
+
"es-toolkit": "1.44.0",
|
|
26
|
+
"ink": "6.6.0",
|
|
27
|
+
"pg": "8.18.0",
|
|
28
|
+
"react": "19.2.4",
|
|
29
|
+
"winston": "3.19.0",
|
|
30
|
+
"zod": "4.3.6"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "24.0.0",
|
|
34
|
+
"@types/pg": "8.16.0",
|
|
35
|
+
"@types/react": "19.2.10",
|
|
36
|
+
"concurrently": "9.2.1",
|
|
37
|
+
"cross-env": "7.0.3",
|
|
38
|
+
"typescript": "5.9.3"
|
|
39
|
+
},
|
|
40
|
+
"volta": {
|
|
41
|
+
"node": "24.0.0"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/App.tsx
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Text, Box } from "ink";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import type { TSSLMode } from "./index.mjs";
|
|
4
|
+
|
|
5
|
+
export type TConnectionConfig = {
|
|
6
|
+
connectionString?: string;
|
|
7
|
+
hostname?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
database?: string;
|
|
10
|
+
username?: string;
|
|
11
|
+
sslmode?: TSSLMode;
|
|
12
|
+
sslcert?: string;
|
|
13
|
+
sslkey?: string;
|
|
14
|
+
sslrootcert?: string;
|
|
15
|
+
sshHost?: string;
|
|
16
|
+
sshPort?: number;
|
|
17
|
+
sshUsername?: string;
|
|
18
|
+
sshPrivateKey?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type TAppProps = {
|
|
22
|
+
config: TConnectionConfig;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function App({ config }: TAppProps): ReactNode {
|
|
26
|
+
const connectionTarget = config.connectionString
|
|
27
|
+
? config.connectionString.replace(/:[^:@]+@/, ":***@") // mask password
|
|
28
|
+
: `${config.hostname}:${config.port}/${config.database}`;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Box flexDirection="column" padding={1}>
|
|
32
|
+
<Box marginBottom={1}>
|
|
33
|
+
<Text color="cyan" bold>
|
|
34
|
+
dbctx
|
|
35
|
+
</Text>
|
|
36
|
+
<Text dimColor> - AI generated docs from your application database</Text>
|
|
37
|
+
</Box>
|
|
38
|
+
<Box>
|
|
39
|
+
<Text dimColor>Connecting to: </Text>
|
|
40
|
+
<Text color="yellow">{connectionTarget}</Text>
|
|
41
|
+
</Box>
|
|
42
|
+
</Box>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Text, Box } from "ink";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
interface ErrorProps {
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function Error({ message }: ErrorProps): ReactNode {
|
|
9
|
+
return (
|
|
10
|
+
<Box>
|
|
11
|
+
<Text color="red" bold>
|
|
12
|
+
Error: {message}
|
|
13
|
+
</Text>
|
|
14
|
+
</Box>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
|
|
3
|
+
export const analyzeRelation = async (pool: Pool, relationName: string): Promise<void> => {
|
|
4
|
+
// Validate relation exists and get properly quoted name to prevent SQL injection
|
|
5
|
+
const validation = await pool.query<{ quoted_name: string }>(
|
|
6
|
+
`
|
|
7
|
+
SELECT format('%I', c.relname) AS quoted_name
|
|
8
|
+
FROM pg_catalog.pg_class c
|
|
9
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
10
|
+
WHERE n.nspname = 'public'
|
|
11
|
+
AND c.relname = $1
|
|
12
|
+
AND c.relkind IN ('r', 'p', 'm')
|
|
13
|
+
`,
|
|
14
|
+
[relationName]
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
if (validation.rows.length === 0) {
|
|
18
|
+
throw new Error(`Relation "${relationName}" not found in public schema`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
await pool.query(`ANALYZE public.${validation.rows[0].quoted_name}`);
|
|
22
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
|
|
3
|
+
export type TAttributeKind = "regular" | "generated";
|
|
4
|
+
|
|
5
|
+
export type TGeneratedStorage = "stored" | "virtual";
|
|
6
|
+
|
|
7
|
+
export type TAttributeInfo = {
|
|
8
|
+
attribute_name: string;
|
|
9
|
+
data_type: string;
|
|
10
|
+
is_nullable: boolean;
|
|
11
|
+
has_default: boolean;
|
|
12
|
+
default_expression: string | null;
|
|
13
|
+
kind: TAttributeKind;
|
|
14
|
+
generated_storage: TGeneratedStorage | null;
|
|
15
|
+
generated_expression: string | null;
|
|
16
|
+
comment: string | null;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const fetchRelationAttributes = async (pool: Pool, relationName: string): Promise<TAttributeInfo[]> => {
|
|
20
|
+
const result = await pool.query<TAttributeInfo>(
|
|
21
|
+
`
|
|
22
|
+
SELECT
|
|
23
|
+
a.attname AS attribute_name,
|
|
24
|
+
format_type(a.atttypid, a.atttypemod) AS data_type,
|
|
25
|
+
NOT a.attnotnull AS is_nullable,
|
|
26
|
+
ad.adbin IS NOT NULL AS has_default,
|
|
27
|
+
CASE
|
|
28
|
+
WHEN a.attgenerated = '' AND ad.adbin IS NOT NULL THEN pg_get_expr(ad.adbin, ad.adrelid)
|
|
29
|
+
ELSE NULL
|
|
30
|
+
END AS default_expression,
|
|
31
|
+
CASE a.attgenerated
|
|
32
|
+
WHEN '' THEN 'regular'
|
|
33
|
+
ELSE 'generated'
|
|
34
|
+
END AS kind,
|
|
35
|
+
CASE a.attgenerated
|
|
36
|
+
WHEN 's' THEN 'stored'
|
|
37
|
+
WHEN 'v' THEN 'virtual'
|
|
38
|
+
ELSE NULL
|
|
39
|
+
END AS generated_storage,
|
|
40
|
+
CASE
|
|
41
|
+
WHEN a.attgenerated != '' THEN pg_get_expr(ad.adbin, ad.adrelid)
|
|
42
|
+
ELSE NULL
|
|
43
|
+
END AS generated_expression,
|
|
44
|
+
col_description(c.oid, a.attnum) AS comment
|
|
45
|
+
FROM pg_catalog.pg_class c
|
|
46
|
+
JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid
|
|
47
|
+
LEFT JOIN pg_catalog.pg_attrdef ad ON ad.adrelid = a.attrelid AND ad.adnum = a.attnum
|
|
48
|
+
WHERE c.relname = $1
|
|
49
|
+
AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'public')
|
|
50
|
+
AND a.attnum > 0
|
|
51
|
+
AND NOT a.attisdropped
|
|
52
|
+
ORDER BY a.attnum
|
|
53
|
+
`,
|
|
54
|
+
[relationName]
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return result.rows;
|
|
58
|
+
};
|
package/src/db/enums.mts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
import { groupBy } from "es-toolkit";
|
|
3
|
+
|
|
4
|
+
type TEnumValueRow = {
|
|
5
|
+
enum_name: string;
|
|
6
|
+
value: string;
|
|
7
|
+
sort_order: number;
|
|
8
|
+
comment: string | null;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type TEnumInfo = {
|
|
12
|
+
values: string[];
|
|
13
|
+
comment: string | null;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type TGroupedEnums = Record<string, TEnumInfo>;
|
|
17
|
+
|
|
18
|
+
export const fetchPublicEnums = async (pool: Pool): Promise<TGroupedEnums> => {
|
|
19
|
+
const result = await pool.query<TEnumValueRow>(`
|
|
20
|
+
SELECT
|
|
21
|
+
t.typname AS enum_name,
|
|
22
|
+
e.enumlabel AS value,
|
|
23
|
+
e.enumsortorder AS sort_order,
|
|
24
|
+
obj_description(t.oid, 'pg_type') AS comment
|
|
25
|
+
FROM pg_catalog.pg_type t
|
|
26
|
+
JOIN pg_catalog.pg_enum e ON t.oid = e.enumtypid
|
|
27
|
+
JOIN pg_catalog.pg_namespace n ON t.typnamespace = n.oid
|
|
28
|
+
WHERE n.nspname = 'public'
|
|
29
|
+
ORDER BY enum_name, sort_order
|
|
30
|
+
`);
|
|
31
|
+
|
|
32
|
+
const grouped = groupBy(result.rows, (row) => row.enum_name);
|
|
33
|
+
|
|
34
|
+
return Object.fromEntries(
|
|
35
|
+
Object.entries(grouped).map(([name, rows]) => [
|
|
36
|
+
name,
|
|
37
|
+
{
|
|
38
|
+
values: rows.map((r) => r.value),
|
|
39
|
+
comment: rows[0]?.comment ?? null,
|
|
40
|
+
},
|
|
41
|
+
])
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
|
|
3
|
+
export type TRelationFileStats = {
|
|
4
|
+
relation_name: string;
|
|
5
|
+
file_path: string | null;
|
|
6
|
+
modification_time: Date;
|
|
7
|
+
size_bytes: number;
|
|
8
|
+
is_partitioned: boolean;
|
|
9
|
+
partition_count: number | null;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const fetchRelationFileStats = async (pool: Pool, relationName: string): Promise<TRelationFileStats> => {
|
|
13
|
+
const result = await pool.query<TRelationFileStats>(
|
|
14
|
+
`
|
|
15
|
+
WITH target AS (
|
|
16
|
+
SELECT c.oid, c.relname, c.relkind
|
|
17
|
+
FROM pg_catalog.pg_class c
|
|
18
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
19
|
+
WHERE n.nspname = 'public'
|
|
20
|
+
AND c.relname = $1
|
|
21
|
+
AND c.relkind IN ('r', 'p', 'm')
|
|
22
|
+
),
|
|
23
|
+
partition_stats AS (
|
|
24
|
+
SELECT
|
|
25
|
+
(pg_stat_file(pg_relation_filepath(child.oid))).modification AS modification_time,
|
|
26
|
+
(pg_stat_file(pg_relation_filepath(child.oid))).size AS size_bytes
|
|
27
|
+
FROM target t
|
|
28
|
+
JOIN pg_catalog.pg_inherits i ON i.inhparent = t.oid
|
|
29
|
+
JOIN pg_catalog.pg_class child ON child.oid = i.inhrelid
|
|
30
|
+
WHERE t.relkind = 'p'
|
|
31
|
+
)
|
|
32
|
+
SELECT
|
|
33
|
+
t.relname AS relation_name,
|
|
34
|
+
CASE
|
|
35
|
+
WHEN t.relkind = 'p' THEN NULL
|
|
36
|
+
ELSE pg_relation_filepath(t.oid)
|
|
37
|
+
END AS file_path,
|
|
38
|
+
CASE
|
|
39
|
+
WHEN t.relkind = 'p' THEN (SELECT MAX(modification_time) FROM partition_stats)
|
|
40
|
+
ELSE (pg_stat_file(pg_relation_filepath(t.oid))).modification
|
|
41
|
+
END AS modification_time,
|
|
42
|
+
CASE
|
|
43
|
+
WHEN t.relkind = 'p' THEN (SELECT COALESCE(SUM(size_bytes), 0) FROM partition_stats)
|
|
44
|
+
ELSE (pg_stat_file(pg_relation_filepath(t.oid))).size
|
|
45
|
+
END AS size_bytes,
|
|
46
|
+
t.relkind = 'p' AS is_partitioned,
|
|
47
|
+
CASE
|
|
48
|
+
WHEN t.relkind = 'p' THEN (SELECT COUNT(*) FROM partition_stats)
|
|
49
|
+
ELSE NULL
|
|
50
|
+
END AS partition_count
|
|
51
|
+
FROM target t
|
|
52
|
+
`,
|
|
53
|
+
[relationName]
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return result.rows[0];
|
|
57
|
+
};
|