schema-navigator-mcp 0.2.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 +21 -0
- package/README.md +215 -0
- package/dist/db/pg-adapter.d.ts +17 -0
- package/dist/db/pg-adapter.js +74 -0
- package/dist/db/pg-adapter.js.map +1 -0
- package/dist/db/postgres.d.ts +19 -0
- package/dist/db/postgres.js +34 -0
- package/dist/db/postgres.js.map +1 -0
- package/dist/db/supabase-adapter.d.ts +45 -0
- package/dist/db/supabase-adapter.js +148 -0
- package/dist/db/supabase-adapter.js.map +1 -0
- package/dist/db/types.d.ts +25 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +129 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/constraints.d.ts +22 -0
- package/dist/tools/constraints.js +80 -0
- package/dist/tools/constraints.js.map +1 -0
- package/dist/tools/functions.d.ts +20 -0
- package/dist/tools/functions.js +118 -0
- package/dist/tools/functions.js.map +1 -0
- package/dist/tools/overview.d.ts +29 -0
- package/dist/tools/overview.js +142 -0
- package/dist/tools/overview.js.map +1 -0
- package/dist/tools/policies.d.ts +29 -0
- package/dist/tools/policies.js +96 -0
- package/dist/tools/policies.js.map +1 -0
- package/dist/tools/relations.d.ts +18 -0
- package/dist/tools/relations.js +72 -0
- package/dist/tools/relations.js.map +1 -0
- package/dist/tools/search.d.ts +13 -0
- package/dist/tools/search.js +77 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/table-profile.d.ts +68 -0
- package/dist/tools/table-profile.js +477 -0
- package/dist/tools/table-profile.js.map +1 -0
- package/dist/utils/check-parser.d.ts +17 -0
- package/dist/utils/check-parser.js +61 -0
- package/dist/utils/check-parser.js.map +1 -0
- package/dist/utils/pg-array.d.ts +6 -0
- package/dist/utils/pg-array.js +42 -0
- package/dist/utils/pg-array.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../../src/tools/overview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAgCtE,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc;IACjD,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAE7B,MAAM,OAAO,GAA+C,EAAE,CAAC;IAE/D,0CAA0C;IAC1C,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,IAAI,CAAC;YACX,GAAG,EAAE;;;;;;;;;;;;OAYJ;YACD,MAAM,EAAE,CAAC,MAAM,CAAC;SACjB,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC;YACX,GAAG,EAAE;;;0CAG+B;YACpC,MAAM,EAAE,CAAC,MAAM,CAAC;SACjB,CAAC,CAAC;IACL,CAAC;IAED,YAAY;IACZ,OAAO,CAAC,IAAI,CAAC;QACX,GAAG,EAAE,6FAA6F;QAClG,MAAM,EAAE,CAAC,MAAM,CAAC;KACjB,CAAC,CAAC;IAEH,0DAA0D;IAC1D,OAAO,CAAC,IAAI,CACV,IAAI;QACF,CAAC,CAAC,EAAE,GAAG,EAAE,gFAAgF,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE;QAC7G,CAAC,CAAC,EAAE,GAAG,EAAE,wCAAwC,EAAE,CACtD,CAAC;IAEF,4BAA4B;IAC5B,OAAO,CAAC,IAAI,CACV,IAAI;QACF,CAAC,CAAC;YACE,GAAG,EAAE;;;;;sDAKuC;YAC5C,MAAM,EAAE,CAAC,MAAM,CAAC;SACjB;QACH,CAAC,CAAC,EAAE,GAAG,EAAE,iDAAiD,EAAE,CAC/D,CAAC;IAEF,gDAAgD;IAChD,OAAO,CAAC,IAAI,CACV,IAAI;QACF,CAAC,CAAC,EAAE,GAAG,EAAE,mDAAmD,EAAE;QAC9D,CAAC,CAAC,EAAE,GAAG,EAAE,oCAAoC,EAAE,CAClD,CAAC;IAEF,qBAAqB;IACrB,OAAO,CAAC,IAAI,CAAC;QACX,GAAG,EAAE,0FAA0F;QAC/F,MAAM,EAAE,CAAC,MAAM,CAAC;KACjB,CAAC,CAAC;IAEH,wBAAwB;IACxB,OAAO,CAAC,IAAI,CAAC;QACX,GAAG,EAAE,oHAAoH;QACzH,MAAM,EAAE,CAAC,MAAM,CAAC;KACjB,CAAC,CAAC;IAEH,iDAAiD;IACjD,OAAO,CAAC,IAAI,CACV,IAAI;QACF,CAAC,CAAC;YACE,GAAG,EAAE;;;;mCAIoB;YACzB,MAAM,EAAE,CAAC,MAAM,CAAC;SACjB;QACH,CAAC,CAAC,EAAE,GAAG,EAAE,oCAAoC,EAAE,CAClD,CAAC;IAEF,kDAAkD;IAClD,OAAO,CAAC,IAAI,CACV,IAAI;QACF,CAAC,CAAC;YACE,GAAG,EAAE;;kFAEmE;YACxE,MAAM,EAAE,CAAC,MAAM,CAAC;SACjB;QACH,CAAC,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,CACjC,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAElD,gBAAgB;IAChB,MAAM,MAAM,GAAgB,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtD,IAAI,EAAE,CAAC,CAAC,IAAc;QACtB,IAAI,EAAE,CAAC,CAAC,IAAc;QACtB,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;QAC5C,IAAI,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;KACtE,CAAC,CAAC,CAAC;IAEJ,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAoB,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAqB,CAAC,CAAC;IACrE,MAAM,SAAS,GAAe,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxD,IAAI,EAAE,CAAC,CAAC,IAAc;QACtB,MAAM,EAAE,CAAC,CAAC,MAAkB;KAC7B,CAAC,CAAC,CAAC;IACJ,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAiB,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IAEnD,kBAAkB;IAClB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAiB,CAAC,CAAC;QACnE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,+BAA+B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;QAClD,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,QAAQ,CAAC,IAAI,CAAC,6BAA6B,UAAU,OAAO,WAAW,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM;QACN,MAAM;QACN,KAAK;QACL,kBAAkB,EAAE,QAAQ;QAC5B,UAAU,EAAE,SAAS;QACrB,UAAU;QACV,MAAM,EAAE;YACN,MAAM,EAAE,WAAW;YACnB,KAAK,EAAE,KAAK,CAAC,MAAM;YACnB,kBAAkB,EAAE,QAAQ,CAAC,MAAM;YACnC,SAAS,EAAE,OAAO;YAClB,UAAU,EAAE,SAAS,CAAC,MAAM;YAC5B,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClD;QACD,eAAe,EAAE,QAAQ;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7B,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnF,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
interface PolicyInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
command: string;
|
|
4
|
+
permissive: boolean;
|
|
5
|
+
roles: string[];
|
|
6
|
+
using: string | null;
|
|
7
|
+
with_check: string | null;
|
|
8
|
+
}
|
|
9
|
+
interface AccessMatrix {
|
|
10
|
+
[role: string]: {
|
|
11
|
+
select: boolean;
|
|
12
|
+
insert: boolean;
|
|
13
|
+
update: boolean;
|
|
14
|
+
delete: boolean;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
interface PoliciesResult {
|
|
18
|
+
table: string;
|
|
19
|
+
schema: string;
|
|
20
|
+
rls_enabled: boolean | null;
|
|
21
|
+
force_rls: boolean | null;
|
|
22
|
+
policies: PolicyInfo[];
|
|
23
|
+
matrix: AccessMatrix;
|
|
24
|
+
note?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function schemaPolicies(tableName: string, schema: string): Promise<PoliciesResult | {
|
|
27
|
+
error: string;
|
|
28
|
+
}>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readOnlyMultiQuery, getIsPostgres } from "../db/postgres.js";
|
|
2
|
+
import { parsePgArray } from "../utils/pg-array.js";
|
|
3
|
+
export async function schemaPolicies(tableName, schema) {
|
|
4
|
+
const isPg = getIsPostgres();
|
|
5
|
+
if (!isPg) {
|
|
6
|
+
return {
|
|
7
|
+
table: tableName,
|
|
8
|
+
schema,
|
|
9
|
+
rls_enabled: null,
|
|
10
|
+
force_rls: null,
|
|
11
|
+
policies: [],
|
|
12
|
+
matrix: {},
|
|
13
|
+
note: "RLS is PostgreSQL-specific. Not available on this database.",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const results = await readOnlyMultiQuery([
|
|
17
|
+
// Check existence + RLS status
|
|
18
|
+
{
|
|
19
|
+
sql: `
|
|
20
|
+
SELECT c.relrowsecurity AS rls_enabled, c.relforcerowsecurity AS force_rls
|
|
21
|
+
FROM pg_class c
|
|
22
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
23
|
+
WHERE n.nspname = $1 AND c.relname = $2 AND c.relkind IN ('r', 'p')
|
|
24
|
+
`,
|
|
25
|
+
params: [schema, tableName],
|
|
26
|
+
},
|
|
27
|
+
// Policies
|
|
28
|
+
{
|
|
29
|
+
sql: `
|
|
30
|
+
SELECT
|
|
31
|
+
pol.polname AS name,
|
|
32
|
+
CASE pol.polcmd
|
|
33
|
+
WHEN 'r' THEN 'SELECT'
|
|
34
|
+
WHEN 'a' THEN 'INSERT'
|
|
35
|
+
WHEN 'w' THEN 'UPDATE'
|
|
36
|
+
WHEN 'd' THEN 'DELETE'
|
|
37
|
+
WHEN '*' THEN 'ALL'
|
|
38
|
+
END AS command,
|
|
39
|
+
pol.polpermissive AS permissive,
|
|
40
|
+
CASE
|
|
41
|
+
WHEN pol.polroles = '{0}' THEN ARRAY['public']
|
|
42
|
+
ELSE ARRAY(SELECT rolname FROM pg_roles WHERE oid = ANY(pol.polroles))
|
|
43
|
+
END AS roles,
|
|
44
|
+
pg_get_expr(pol.polqual, pol.polrelid) AS using_expr,
|
|
45
|
+
pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check
|
|
46
|
+
FROM pg_policy pol
|
|
47
|
+
JOIN pg_class c ON c.oid = pol.polrelid
|
|
48
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
49
|
+
WHERE n.nspname = $1 AND c.relname = $2
|
|
50
|
+
ORDER BY pol.polname
|
|
51
|
+
`,
|
|
52
|
+
params: [schema, tableName],
|
|
53
|
+
},
|
|
54
|
+
]);
|
|
55
|
+
if (results[0].rows.length === 0) {
|
|
56
|
+
return { error: `Table '${tableName}' not found in schema '${schema}'` };
|
|
57
|
+
}
|
|
58
|
+
const meta = results[0].rows[0];
|
|
59
|
+
const rlsEnabled = meta.rls_enabled;
|
|
60
|
+
const forceRls = meta.force_rls;
|
|
61
|
+
const policies = results[1].rows.map((r) => ({
|
|
62
|
+
name: r.name,
|
|
63
|
+
command: r.command,
|
|
64
|
+
permissive: r.permissive,
|
|
65
|
+
roles: parsePgArray(r.roles),
|
|
66
|
+
using: r.using_expr ?? null,
|
|
67
|
+
with_check: r.with_check ?? null,
|
|
68
|
+
}));
|
|
69
|
+
// Build access matrix
|
|
70
|
+
const matrix = {};
|
|
71
|
+
for (const policy of policies) {
|
|
72
|
+
for (const role of policy.roles) {
|
|
73
|
+
if (!matrix[role]) {
|
|
74
|
+
matrix[role] = { select: false, insert: false, update: false, delete: false };
|
|
75
|
+
}
|
|
76
|
+
const cmd = policy.command;
|
|
77
|
+
if (cmd === "ALL" || cmd === "SELECT")
|
|
78
|
+
matrix[role].select = true;
|
|
79
|
+
if (cmd === "ALL" || cmd === "INSERT")
|
|
80
|
+
matrix[role].insert = true;
|
|
81
|
+
if (cmd === "ALL" || cmd === "UPDATE")
|
|
82
|
+
matrix[role].update = true;
|
|
83
|
+
if (cmd === "ALL" || cmd === "DELETE")
|
|
84
|
+
matrix[role].delete = true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
table: tableName,
|
|
89
|
+
schema,
|
|
90
|
+
rls_enabled: rlsEnabled,
|
|
91
|
+
force_rls: forceRls,
|
|
92
|
+
policies,
|
|
93
|
+
matrix,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=policies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies.js","sourceRoot":"","sources":["../../src/tools/policies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface FKRelation {
|
|
2
|
+
constraint_name: string;
|
|
3
|
+
column: string;
|
|
4
|
+
foreign_table: string;
|
|
5
|
+
foreign_column: string;
|
|
6
|
+
on_delete: string;
|
|
7
|
+
on_update: string;
|
|
8
|
+
}
|
|
9
|
+
interface RelationsResult {
|
|
10
|
+
table: string;
|
|
11
|
+
schema: string;
|
|
12
|
+
outbound: FKRelation[];
|
|
13
|
+
inbound: FKRelation[];
|
|
14
|
+
}
|
|
15
|
+
export declare function schemaRelations(tableName: string, schema: string): Promise<RelationsResult | {
|
|
16
|
+
error: string;
|
|
17
|
+
}>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { readOnlyMultiQuery } from "../db/postgres.js";
|
|
2
|
+
export async function schemaRelations(tableName, schema) {
|
|
3
|
+
// Check existence first
|
|
4
|
+
const results = await readOnlyMultiQuery([
|
|
5
|
+
{
|
|
6
|
+
sql: `SELECT 1 FROM information_schema.tables WHERE table_schema = $1 AND table_name = $2`,
|
|
7
|
+
params: [schema, tableName],
|
|
8
|
+
},
|
|
9
|
+
// Outbound FKs (this table references others)
|
|
10
|
+
{
|
|
11
|
+
sql: `
|
|
12
|
+
SELECT
|
|
13
|
+
tc.constraint_name,
|
|
14
|
+
kcu.column_name AS column,
|
|
15
|
+
ccu.table_name AS foreign_table,
|
|
16
|
+
ccu.column_name AS foreign_column,
|
|
17
|
+
rc.delete_rule AS on_delete,
|
|
18
|
+
rc.update_rule AS on_update
|
|
19
|
+
FROM information_schema.table_constraints tc
|
|
20
|
+
JOIN information_schema.key_column_usage kcu
|
|
21
|
+
ON kcu.constraint_name = tc.constraint_name AND kcu.constraint_schema = tc.constraint_schema
|
|
22
|
+
JOIN information_schema.constraint_column_usage ccu
|
|
23
|
+
ON ccu.constraint_name = tc.constraint_name AND ccu.constraint_schema = tc.constraint_schema
|
|
24
|
+
JOIN information_schema.referential_constraints rc
|
|
25
|
+
ON rc.constraint_name = tc.constraint_name AND rc.constraint_schema = tc.constraint_schema
|
|
26
|
+
WHERE tc.table_schema = $1 AND tc.table_name = $2 AND tc.constraint_type = 'FOREIGN KEY'
|
|
27
|
+
ORDER BY tc.constraint_name
|
|
28
|
+
`,
|
|
29
|
+
params: [schema, tableName],
|
|
30
|
+
},
|
|
31
|
+
// Inbound FKs (others reference this table)
|
|
32
|
+
{
|
|
33
|
+
sql: `
|
|
34
|
+
SELECT
|
|
35
|
+
tc.constraint_name,
|
|
36
|
+
ccu.column_name AS column,
|
|
37
|
+
kcu.table_name AS foreign_table,
|
|
38
|
+
kcu.column_name AS foreign_column,
|
|
39
|
+
rc.delete_rule AS on_delete,
|
|
40
|
+
rc.update_rule AS on_update
|
|
41
|
+
FROM information_schema.table_constraints tc
|
|
42
|
+
JOIN information_schema.key_column_usage kcu
|
|
43
|
+
ON kcu.constraint_name = tc.constraint_name AND kcu.constraint_schema = tc.constraint_schema
|
|
44
|
+
JOIN information_schema.constraint_column_usage ccu
|
|
45
|
+
ON ccu.constraint_name = tc.constraint_name AND ccu.constraint_schema = tc.constraint_schema
|
|
46
|
+
JOIN information_schema.referential_constraints rc
|
|
47
|
+
ON rc.constraint_name = tc.constraint_name AND rc.constraint_schema = tc.constraint_schema
|
|
48
|
+
WHERE ccu.table_schema = $1 AND ccu.table_name = $2 AND tc.constraint_type = 'FOREIGN KEY'
|
|
49
|
+
ORDER BY tc.constraint_name
|
|
50
|
+
`,
|
|
51
|
+
params: [schema, tableName],
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
if (results[0].rows.length === 0) {
|
|
55
|
+
return { error: `Table '${tableName}' not found in schema '${schema}'` };
|
|
56
|
+
}
|
|
57
|
+
const mapRow = (r) => ({
|
|
58
|
+
constraint_name: r.constraint_name,
|
|
59
|
+
column: r.column,
|
|
60
|
+
foreign_table: r.foreign_table,
|
|
61
|
+
foreign_column: r.foreign_column,
|
|
62
|
+
on_delete: r.on_delete,
|
|
63
|
+
on_update: r.on_update,
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
table: tableName,
|
|
67
|
+
schema,
|
|
68
|
+
outbound: results[1].rows.map(mapRow),
|
|
69
|
+
inbound: results[2].rows.map(mapRow),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=relations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.js","sourceRoot":"","sources":["../../src/tools/relations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAkBvD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAAiB,EACjB,MAAc;IAEd,wBAAwB;IACxB,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC;QACvC;YACE,GAAG,EAAE,qFAAqF;YAC1F,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;SAC5B;QACD,8CAA8C;QAC9C;YACE,GAAG,EAAE;;;;;;;;;;;;;;;;;OAiBJ;YACD,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;SAC5B;QACD,4CAA4C;QAC5C;YACE,GAAG,EAAE;;;;;;;;;;;;;;;;;OAiBJ;YACD,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;SAC5B;KACF,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,KAAK,EAAE,UAAU,SAAS,0BAA0B,MAAM,GAAG,EAAE,CAAC;IAC3E,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,CAA0B,EAAc,EAAE,CAAC,CAAC;QAC1D,eAAe,EAAE,CAAC,CAAC,eAAyB;QAC5C,MAAM,EAAE,CAAC,CAAC,MAAgB;QAC1B,aAAa,EAAE,CAAC,CAAC,aAAuB;QACxC,cAAc,EAAE,CAAC,CAAC,cAAwB;QAC1C,SAAS,EAAE,CAAC,CAAC,SAAmB;QAChC,SAAS,EAAE,CAAC,CAAC,SAAmB;KACjC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,SAAS;QAChB,MAAM;QACN,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;QACrC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;KACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface SearchMatch {
|
|
2
|
+
type: string;
|
|
3
|
+
name: string;
|
|
4
|
+
context: string;
|
|
5
|
+
}
|
|
6
|
+
interface SearchResult {
|
|
7
|
+
term: string;
|
|
8
|
+
schema: string;
|
|
9
|
+
matches: SearchMatch[];
|
|
10
|
+
truncated: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function schemaFind(term: string, schema: string): Promise<SearchResult>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readOnlyQuery, getIsPostgres } from "../db/postgres.js";
|
|
2
|
+
const MAX_RESULTS = 50;
|
|
3
|
+
export async function schemaFind(term, schema) {
|
|
4
|
+
const isPg = getIsPostgres();
|
|
5
|
+
// Escape ILIKE special characters so % and _ are treated as literals
|
|
6
|
+
const escaped = term.replace(/[%_\\]/g, "\\$&");
|
|
7
|
+
const pattern = `%${escaped}%`;
|
|
8
|
+
// Build UNION ALL search across object types
|
|
9
|
+
const parts = [];
|
|
10
|
+
const params = [schema, pattern];
|
|
11
|
+
// Tables
|
|
12
|
+
parts.push(`
|
|
13
|
+
SELECT 'table' AS type, table_name AS name, table_type AS context
|
|
14
|
+
FROM information_schema.tables
|
|
15
|
+
WHERE table_schema = $1 AND table_name ILIKE $2
|
|
16
|
+
`);
|
|
17
|
+
// Columns
|
|
18
|
+
parts.push(`
|
|
19
|
+
SELECT 'column' AS type, column_name AS name, table_name || '.' || column_name || ' (' || data_type || ')' AS context
|
|
20
|
+
FROM information_schema.columns
|
|
21
|
+
WHERE table_schema = $1 AND column_name ILIKE $2
|
|
22
|
+
`);
|
|
23
|
+
// Functions
|
|
24
|
+
parts.push(`
|
|
25
|
+
SELECT 'function' AS type, routine_name AS name, routine_type || ' → ' || COALESCE(data_type, 'void') AS context
|
|
26
|
+
FROM information_schema.routines
|
|
27
|
+
WHERE routine_schema = $1 AND routine_name ILIKE $2
|
|
28
|
+
`);
|
|
29
|
+
// Views
|
|
30
|
+
parts.push(`
|
|
31
|
+
SELECT 'view' AS type, table_name AS name, 'view' AS context
|
|
32
|
+
FROM information_schema.views
|
|
33
|
+
WHERE table_schema = $1 AND table_name ILIKE $2
|
|
34
|
+
`);
|
|
35
|
+
if (isPg) {
|
|
36
|
+
// Materialized views
|
|
37
|
+
parts.push(`
|
|
38
|
+
SELECT 'materialized_view' AS type, matviewname AS name, 'materialized view' AS context
|
|
39
|
+
FROM pg_matviews
|
|
40
|
+
WHERE schemaname = $1 AND matviewname ILIKE $2
|
|
41
|
+
`);
|
|
42
|
+
// RLS Policies
|
|
43
|
+
parts.push(`
|
|
44
|
+
SELECT 'policy' AS type, policyname AS name, 'on ' || tablename || ' (' || cmd || ')' AS context
|
|
45
|
+
FROM pg_policies
|
|
46
|
+
WHERE schemaname = $1 AND policyname ILIKE $2
|
|
47
|
+
`);
|
|
48
|
+
// ENUMs
|
|
49
|
+
parts.push(`
|
|
50
|
+
SELECT 'enum' AS type, t.typname AS name, 'enum type' AS context
|
|
51
|
+
FROM pg_type t
|
|
52
|
+
JOIN pg_namespace n ON n.oid = t.typnamespace
|
|
53
|
+
WHERE n.nspname = $1 AND t.typname ILIKE $2 AND t.typtype = 'e'
|
|
54
|
+
`);
|
|
55
|
+
// Column comments
|
|
56
|
+
parts.push(`
|
|
57
|
+
SELECT 'comment' AS type, a.attname AS name,
|
|
58
|
+
c.relname || '.' || a.attname || ': ' || d.description AS context
|
|
59
|
+
FROM pg_description d
|
|
60
|
+
JOIN pg_class c ON c.oid = d.objoid
|
|
61
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
62
|
+
JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = d.objsubid
|
|
63
|
+
WHERE n.nspname = $1 AND d.description ILIKE $2 AND d.objsubid > 0
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
const sql = parts.join("\nUNION ALL\n") + "\nLIMIT $3";
|
|
67
|
+
params.push(MAX_RESULTS + 1);
|
|
68
|
+
const result = await readOnlyQuery(sql, params);
|
|
69
|
+
const truncated = result.rows.length > MAX_RESULTS;
|
|
70
|
+
const matches = result.rows.slice(0, MAX_RESULTS).map((r) => ({
|
|
71
|
+
type: r.type,
|
|
72
|
+
name: r.name,
|
|
73
|
+
context: r.context,
|
|
74
|
+
}));
|
|
75
|
+
return { term, schema, matches, truncated };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAejE,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,MAAc;IAEd,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,qEAAqE;IACrE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,OAAO,GAAG,CAAC;IAE/B,6CAA6C;IAC7C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE5C,SAAS;IACT,KAAK,CAAC,IAAI,CAAC;;;;GAIV,CAAC,CAAC;IAEH,UAAU;IACV,KAAK,CAAC,IAAI,CAAC;;;;GAIV,CAAC,CAAC;IAEH,YAAY;IACZ,KAAK,CAAC,IAAI,CAAC;;;;GAIV,CAAC,CAAC;IAEH,QAAQ;IACR,KAAK,CAAC,IAAI,CAAC;;;;GAIV,CAAC,CAAC;IAEH,IAAI,IAAI,EAAE,CAAC;QACT,qBAAqB;QACrB,KAAK,CAAC,IAAI,CAAC;;;;KAIV,CAAC,CAAC;QAEH,eAAe;QACf,KAAK,CAAC,IAAI,CAAC;;;;KAIV,CAAC,CAAC;QAEH,QAAQ;QACR,KAAK,CAAC,IAAI,CAAC;;;;;KAKV,CAAC,CAAC;QAEH,kBAAkB;QAClB,KAAK,CAAC,IAAI,CAAC;;;;;;;;KAQV,CAAC,CAAC;IACL,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,YAAY,CAAC;IACvD,MAAM,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAEhD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;IACnD,MAAM,OAAO,GAAkB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3E,IAAI,EAAE,CAAC,CAAC,IAAc;QACtB,IAAI,EAAE,CAAC,CAAC,IAAc;QACtB,OAAO,EAAE,CAAC,CAAC,OAAiB;KAC7B,CAAC,CAAC,CAAC;IAEJ,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
interface ColumnInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
nullable: boolean;
|
|
5
|
+
default: string | null;
|
|
6
|
+
comment: string | null;
|
|
7
|
+
}
|
|
8
|
+
interface ConstraintInfo {
|
|
9
|
+
name: string;
|
|
10
|
+
type: string;
|
|
11
|
+
columns: string[];
|
|
12
|
+
definition?: string;
|
|
13
|
+
allowed_values?: string[];
|
|
14
|
+
}
|
|
15
|
+
interface ForeignKey {
|
|
16
|
+
constraint_name: string;
|
|
17
|
+
column: string;
|
|
18
|
+
foreign_table: string;
|
|
19
|
+
foreign_column: string;
|
|
20
|
+
on_delete: string;
|
|
21
|
+
on_update: string;
|
|
22
|
+
}
|
|
23
|
+
interface IndexInfo {
|
|
24
|
+
name: string;
|
|
25
|
+
columns: string;
|
|
26
|
+
unique: boolean;
|
|
27
|
+
definition: string;
|
|
28
|
+
}
|
|
29
|
+
interface TriggerInfo {
|
|
30
|
+
name: string;
|
|
31
|
+
event: string;
|
|
32
|
+
timing: string;
|
|
33
|
+
function: string;
|
|
34
|
+
}
|
|
35
|
+
interface PolicyInfo {
|
|
36
|
+
name: string;
|
|
37
|
+
command: string;
|
|
38
|
+
roles: string[];
|
|
39
|
+
using: string | null;
|
|
40
|
+
with_check: string | null;
|
|
41
|
+
}
|
|
42
|
+
interface GrantInfo {
|
|
43
|
+
grantee: string;
|
|
44
|
+
privileges: string[];
|
|
45
|
+
}
|
|
46
|
+
interface TableProfileResult {
|
|
47
|
+
object_type: string;
|
|
48
|
+
schema: string;
|
|
49
|
+
name: string;
|
|
50
|
+
columns: ColumnInfo[];
|
|
51
|
+
constraints: ConstraintInfo[];
|
|
52
|
+
fks_out: ForeignKey[];
|
|
53
|
+
fks_in: ForeignKey[];
|
|
54
|
+
indexes: IndexInfo[];
|
|
55
|
+
triggers: TriggerInfo[];
|
|
56
|
+
policies: PolicyInfo[];
|
|
57
|
+
rls_enabled: boolean | null;
|
|
58
|
+
grants: GrantInfo[];
|
|
59
|
+
size: string | null;
|
|
60
|
+
row_count: number | null;
|
|
61
|
+
view_definition?: string;
|
|
62
|
+
is_updatable?: boolean;
|
|
63
|
+
is_populated?: boolean;
|
|
64
|
+
}
|
|
65
|
+
export declare function schemaTable(tableName: string, schema: string): Promise<TableProfileResult | {
|
|
66
|
+
error: string;
|
|
67
|
+
}>;
|
|
68
|
+
export {};
|