@pilat/mcp-datalink 1.1.0 → 1.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/README.md +19 -97
- package/dist/adapters/factory.d.ts +0 -4
- package/dist/adapters/factory.d.ts.map +1 -1
- package/dist/adapters/factory.js +3 -8
- package/dist/adapters/factory.js.map +1 -1
- package/dist/adapters/mysql/adapter.d.ts +2 -31
- package/dist/adapters/mysql/adapter.d.ts.map +1 -1
- package/dist/adapters/mysql/adapter.js +27 -283
- package/dist/adapters/mysql/adapter.js.map +1 -1
- package/dist/adapters/postgresql/adapter.d.ts +2 -22
- package/dist/adapters/postgresql/adapter.d.ts.map +1 -1
- package/dist/adapters/postgresql/adapter.js +18 -175
- package/dist/adapters/postgresql/adapter.js.map +1 -1
- package/dist/adapters/sqlite/adapter.d.ts +3 -25
- package/dist/adapters/sqlite/adapter.d.ts.map +1 -1
- package/dist/adapters/sqlite/adapter.js +65 -364
- package/dist/adapters/sqlite/adapter.js.map +1 -1
- package/dist/adapters/sqlite/pragma-check.d.ts +19 -0
- package/dist/adapters/sqlite/pragma-check.d.ts.map +1 -0
- package/dist/adapters/sqlite/pragma-check.js +25 -0
- package/dist/adapters/sqlite/pragma-check.js.map +1 -0
- package/dist/adapters/sqlite/url-parser.d.ts +34 -0
- package/dist/adapters/sqlite/url-parser.d.ts.map +1 -0
- package/dist/adapters/sqlite/url-parser.js +73 -0
- package/dist/adapters/sqlite/url-parser.js.map +1 -0
- package/dist/adapters/types.d.ts +10 -113
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +31 -20
- package/dist/server.js.map +1 -1
- package/dist/tools/describe-table.d.ts +5 -6
- package/dist/tools/describe-table.d.ts.map +1 -1
- package/dist/tools/describe-table.js +65 -9
- package/dist/tools/describe-table.js.map +1 -1
- package/dist/tools/execute.d.ts +5 -6
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/execute.js +13 -11
- package/dist/tools/execute.js.map +1 -1
- package/dist/tools/explain.d.ts +5 -10
- package/dist/tools/explain.d.ts.map +1 -1
- package/dist/tools/explain.js +25 -26
- package/dist/tools/explain.js.map +1 -1
- package/dist/tools/list-databases.d.ts +5 -7
- package/dist/tools/list-databases.d.ts.map +1 -1
- package/dist/tools/list-databases.js +31 -0
- package/dist/tools/list-databases.js.map +1 -1
- package/dist/tools/list-tables.d.ts +5 -10
- package/dist/tools/list-tables.d.ts.map +1 -1
- package/dist/tools/list-tables.js +27 -9
- package/dist/tools/list-tables.js.map +1 -1
- package/dist/tools/query.d.ts +1 -6
- package/dist/tools/query.d.ts.map +1 -1
- package/dist/tools/query.js +7 -27
- package/dist/tools/query.js.map +1 -1
- package/dist/types.d.ts +39 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/formatter.d.ts +7 -4
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +20 -10
- package/dist/utils/formatter.js.map +1 -1
- package/dist/utils/sql-parser.d.ts +51 -0
- package/dist/utils/sql-parser.d.ts.map +1 -0
- package/dist/utils/sql-parser.js +310 -0
- package/dist/utils/sql-parser.js.map +1 -0
- package/dist/utils/truncate.d.ts +4 -13
- package/dist/utils/truncate.d.ts.map +1 -1
- package/dist/utils/truncate.js +38 -18
- package/dist/utils/truncate.js.map +1 -1
- package/dist/utils/validation.d.ts +35 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +89 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +10 -11
package/dist/tools/execute.js
CHANGED
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
* Execute tool for INSERT/UPDATE/DELETE statements
|
|
3
3
|
*/
|
|
4
4
|
import { createAdapter } from '../adapters/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Format ExecuteResult as Markdown
|
|
7
|
+
*/
|
|
8
|
+
export function formatExecuteResultAsMarkdown(result) {
|
|
9
|
+
const parts = [];
|
|
10
|
+
parts.push(`**Command:** ${result.command}`);
|
|
11
|
+
parts.push(`**Rows affected:** ${result.rowsAffected}`);
|
|
12
|
+
parts.push(`**Execution time:** ${result.executionTime}ms`);
|
|
13
|
+
return parts.join('\n');
|
|
14
|
+
}
|
|
5
15
|
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
16
|
+
import { getValidatedDatabase, validateParamCount } from '../utils/validation.js';
|
|
6
17
|
/**
|
|
7
18
|
* Execute an INSERT/UPDATE/DELETE statement
|
|
8
19
|
*
|
|
@@ -16,24 +27,15 @@ import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
|
16
27
|
*/
|
|
17
28
|
export async function execute(params, config) {
|
|
18
29
|
const startTime = Date.now();
|
|
19
|
-
|
|
20
|
-
const dbConfig = config.databases[params.database];
|
|
21
|
-
if (!dbConfig) {
|
|
22
|
-
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
23
|
-
}
|
|
24
|
-
// Step 1: Check if database is readonly
|
|
30
|
+
const dbConfig = getValidatedDatabase(params.database, config);
|
|
25
31
|
if (dbConfig.readonly) {
|
|
26
32
|
throw new DbMcpError(ErrorCode.READONLY_VIOLATION, `Database "${params.database}" is configured as readonly. INSERT/UPDATE/DELETE operations are not allowed.`, { database: params.database });
|
|
27
33
|
}
|
|
28
|
-
// Create adapter for this database
|
|
29
34
|
const adapter = createAdapter(dbConfig, config.defaults);
|
|
30
|
-
// Step 2: Validate query type - blocks SELECT and dangerous DDL
|
|
31
35
|
adapter.validateQueryForTool(params.sql, 'execute');
|
|
32
|
-
|
|
36
|
+
validateParamCount(params.sql, params.params ?? []);
|
|
33
37
|
const parsed = adapter.parseQuery(params.sql);
|
|
34
38
|
const command = parsed.type.toUpperCase();
|
|
35
|
-
// Step 4: Convert placeholders for non-PostgreSQL dialects
|
|
36
|
-
// PostgreSQL uses $1, $2; MySQL/SQLite use ?
|
|
37
39
|
const sql = adapter.convertPlaceholders(params.sql);
|
|
38
40
|
const result = await adapter.withConnection(async (conn) => {
|
|
39
41
|
return conn.query(sql, params.params ?? []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAqB;IACjE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7C,KAAK,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IACxD,KAAK,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;IAE5D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AACD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAElF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAqB,EACrB,MAAc;IAEd,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAE/D,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAClB,SAAS,CAAC,kBAAkB,EAC5B,aAAa,MAAM,CAAC,QAAQ,+EAA+E,EAC3G,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAC9B,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzD,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACpD,kBAAkB,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAEpD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAEpD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACzD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAE7C,OAAO;QACL,OAAO;QACP,YAAY,EAAE,MAAM,CAAC,QAAQ;QAC7B,aAAa;KACd,CAAC;AACJ,CAAC"}
|
package/dist/tools/explain.d.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Explain tool for showing query execution plans
|
|
3
3
|
*/
|
|
4
|
-
import type { Config } from '../types.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
export interface ExplainResult {
|
|
11
|
-
plan: string;
|
|
12
|
-
executionTime: number;
|
|
13
|
-
}
|
|
4
|
+
import type { Config, ExplainParams, ExplainResult } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Format ExplainResult as Markdown
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatExplainResultAsMarkdown(result: ExplainResult): string;
|
|
14
9
|
/**
|
|
15
10
|
* Get the execution plan for a SQL query
|
|
16
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../src/tools/explain.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../src/tools/explain.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIxE;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAU3E;AAID;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CA+DxB"}
|
package/dist/tools/explain.js
CHANGED
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
* Explain tool for showing query execution plans
|
|
3
3
|
*/
|
|
4
4
|
import { createAdapter } from '../adapters/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Format ExplainResult as Markdown
|
|
7
|
+
*/
|
|
8
|
+
export function formatExplainResultAsMarkdown(result) {
|
|
9
|
+
const parts = [];
|
|
10
|
+
parts.push('```');
|
|
11
|
+
parts.push(result.plan);
|
|
12
|
+
parts.push('```');
|
|
13
|
+
parts.push('');
|
|
14
|
+
parts.push(`**Execution time:** ${result.executionTime}ms`);
|
|
15
|
+
return parts.join('\n');
|
|
16
|
+
}
|
|
5
17
|
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
18
|
+
import { getValidatedDatabase } from '../utils/validation.js';
|
|
6
19
|
/**
|
|
7
20
|
* Get the execution plan for a SQL query
|
|
8
21
|
*
|
|
@@ -15,34 +28,19 @@ import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
|
15
28
|
*/
|
|
16
29
|
export async function explain(params, config) {
|
|
17
30
|
const startTime = Date.now();
|
|
18
|
-
|
|
19
|
-
const dbConfig = config.databases[params.database];
|
|
20
|
-
if (!dbConfig) {
|
|
21
|
-
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
22
|
-
}
|
|
23
|
-
// Create adapter for this database
|
|
31
|
+
const dbConfig = getValidatedDatabase(params.database, config);
|
|
24
32
|
const adapter = createAdapter(dbConfig, config.defaults);
|
|
25
|
-
// Step 1: Parse query and check for dangerous operations
|
|
26
33
|
const parsed = adapter.parseQuery(params.sql);
|
|
27
34
|
if (parsed.isDangerous) {
|
|
28
35
|
throw new DbMcpError(ErrorCode.QUERY_BLOCKED, parsed.dangerousReason ?? 'This operation is not allowed', { sql: params.sql, queryType: parsed.type });
|
|
29
36
|
}
|
|
30
37
|
const result = await adapter.withConnection(async (conn) => {
|
|
31
|
-
// Build EXPLAIN query using adapter-specific prefix
|
|
32
38
|
const explainPrefix = adapter.getExplainPrefix(params.analyze ?? false);
|
|
33
|
-
// SQLite
|
|
34
|
-
//
|
|
35
|
-
// - MySQL: EXPLAIN doesn't execute the query, and READ ONLY tx blocks
|
|
36
|
-
// EXPLAIN on UPDATE/DELETE even though they're safe
|
|
37
|
-
//
|
|
38
|
-
// Defense in depth is still provided by:
|
|
39
|
-
// 1. SQL parser blocking dangerous operations (DROP, TRUNCATE, etc.)
|
|
40
|
-
// 2. EXPLAIN not executing the query (MySQL) / EXPLAIN QUERY PLAN (SQLite)
|
|
41
|
-
// 3. Database adapter opening in readonly mode when configured
|
|
39
|
+
// SQLite/MySQL: EXPLAIN doesn't execute the query, no transaction needed
|
|
40
|
+
// PostgreSQL: EXPLAIN ANALYZE runs the query, wrap in READ ONLY transaction
|
|
42
41
|
if (adapter.type === 'sqlite' || adapter.type === 'mysql') {
|
|
43
42
|
return await conn.query(explainPrefix + params.sql);
|
|
44
43
|
}
|
|
45
|
-
// PostgreSQL: Use READ ONLY transaction since EXPLAIN ANALYZE executes the query
|
|
46
44
|
await conn.execute('BEGIN TRANSACTION READ ONLY');
|
|
47
45
|
try {
|
|
48
46
|
const queryResult = await conn.query(explainPrefix + params.sql);
|
|
@@ -51,18 +49,19 @@ export async function explain(params, config) {
|
|
|
51
49
|
}
|
|
52
50
|
catch (error) {
|
|
53
51
|
await conn.execute('ROLLBACK');
|
|
54
|
-
|
|
52
|
+
if (error instanceof Error) {
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(String(error));
|
|
55
56
|
}
|
|
56
57
|
});
|
|
57
|
-
// Step 3: Format plan as text (join rows with newlines)
|
|
58
|
-
// Different databases have different EXPLAIN output formats:
|
|
59
|
-
// - PostgreSQL: Single column with plan text
|
|
60
|
-
// - MySQL: Multiple columns (id, select_type, table, type, key, rows, Extra, etc.)
|
|
61
|
-
// - SQLite: 4 columns (id, parent, notused, detail)
|
|
62
58
|
const planLines = result.rows.map((row) => {
|
|
59
|
+
if (row.length === 0) {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
63
62
|
if (adapter.type === 'sqlite' && row.length >= 4) {
|
|
64
63
|
// SQLite: extract the 'detail' column (4th column, index 3)
|
|
65
|
-
return String(row[3]);
|
|
64
|
+
return String(row[3] ?? '');
|
|
66
65
|
}
|
|
67
66
|
if (adapter.type === 'mysql' && row.length > 1) {
|
|
68
67
|
// MySQL: Join all columns with tabs for tabular output
|
|
@@ -70,7 +69,7 @@ export async function explain(params, config) {
|
|
|
70
69
|
return row.map((col) => (col === null ? 'NULL' : String(col))).join('\t');
|
|
71
70
|
}
|
|
72
71
|
// PostgreSQL: first column is the plan line
|
|
73
|
-
return row[0];
|
|
72
|
+
return String(row[0] ?? '');
|
|
74
73
|
});
|
|
75
74
|
const executionTime = Date.now() - startTime;
|
|
76
75
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/tools/explain.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/tools/explain.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* list_databases tool - returns configured databases from config
|
|
3
3
|
*/
|
|
4
|
-
import type { Config } from '../types.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}>;
|
|
10
|
-
}
|
|
4
|
+
import type { Config, ListDatabasesResult } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Format ListDatabasesResult as Markdown table
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatListDatabasesResultAsMarkdown(result: ListDatabasesResult, config: Config): string;
|
|
11
9
|
/**
|
|
12
10
|
* Returns all configured databases with their readonly flags.
|
|
13
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-databases.d.ts","sourceRoot":"","sources":["../../src/tools/list-databases.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"list-databases.d.ts","sourceRoot":"","sources":["../../src/tools/list-databases.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAoB/D;;GAEG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,MAAM,GACb,MAAM,CAaR;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAOjE"}
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* list_databases tool - returns configured databases from config
|
|
3
3
|
*/
|
|
4
|
+
import { formatAsMarkdownTable } from '../utils/formatter.js';
|
|
5
|
+
/**
|
|
6
|
+
* Extract database type from URL
|
|
7
|
+
*/
|
|
8
|
+
function getDatabaseType(url) {
|
|
9
|
+
if (url.startsWith('postgresql://') || url.startsWith('postgres://')) {
|
|
10
|
+
return 'postgresql';
|
|
11
|
+
}
|
|
12
|
+
if (url.startsWith('mysql://')) {
|
|
13
|
+
return 'mysql';
|
|
14
|
+
}
|
|
15
|
+
if (url.startsWith('sqlite://') || url.startsWith('sqlite:')) {
|
|
16
|
+
return 'sqlite';
|
|
17
|
+
}
|
|
18
|
+
return 'unknown';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Format ListDatabasesResult as Markdown table
|
|
22
|
+
*/
|
|
23
|
+
export function formatListDatabasesResultAsMarkdown(result, config) {
|
|
24
|
+
if (result.databases.length === 0) {
|
|
25
|
+
return '_No databases configured_';
|
|
26
|
+
}
|
|
27
|
+
const headers = ['name', 'type', 'readonly'];
|
|
28
|
+
const rows = result.databases.map((db) => {
|
|
29
|
+
const dbConfig = config.databases[db.name];
|
|
30
|
+
const type = dbConfig ? getDatabaseType(dbConfig.url) : 'unknown';
|
|
31
|
+
return [db.name, type, db.readonly ? 'YES' : 'NO'];
|
|
32
|
+
});
|
|
33
|
+
return formatAsMarkdownTable(headers, rows);
|
|
34
|
+
}
|
|
4
35
|
/**
|
|
5
36
|
* Returns all configured databases with their readonly flags.
|
|
6
37
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-databases.js","sourceRoot":"","sources":["../../src/tools/list-databases.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"list-databases.js","sourceRoot":"","sources":["../../src/tools/list-databases.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACrE,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,IAAI,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7D,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mCAAmC,CACjD,MAA2B,EAC3B,MAAc;IAEd,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,2BAA2B,CAAC;IACrC,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;QACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5E,IAAI;QACJ,QAAQ,EAAE,QAAQ,CAAC,QAAQ;KAC5B,CAAC,CAAC,CAAC;IAEJ,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* list_tables tool - lists tables in a database schema
|
|
3
3
|
*/
|
|
4
|
-
import type { Config,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export interface ListTablesResult {
|
|
10
|
-
tables: TableInfo[];
|
|
11
|
-
truncated: boolean;
|
|
12
|
-
totalAvailable?: number;
|
|
13
|
-
}
|
|
4
|
+
import type { Config, ListTablesParams, ListTablesResult } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Format ListTablesResult as Markdown table
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatListTablesResultAsMarkdown(result: ListTablesResult): string;
|
|
14
9
|
/**
|
|
15
10
|
* Lists tables and views in a database schema.
|
|
16
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-tables.d.ts","sourceRoot":"","sources":["../../src/tools/list-tables.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"list-tables.d.ts","sourceRoot":"","sources":["../../src/tools/list-tables.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAK9E;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAsBjF;AAGD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CAyB3B"}
|
|
@@ -2,7 +2,32 @@
|
|
|
2
2
|
* list_tables tool - lists tables in a database schema
|
|
3
3
|
*/
|
|
4
4
|
import { createAdapter } from '../adapters/index.js';
|
|
5
|
-
import {
|
|
5
|
+
import { formatAsMarkdownTable } from '../utils/formatter.js';
|
|
6
|
+
/**
|
|
7
|
+
* Format ListTablesResult as Markdown table
|
|
8
|
+
*/
|
|
9
|
+
export function formatListTablesResultAsMarkdown(result) {
|
|
10
|
+
const parts = [];
|
|
11
|
+
if (result.tables.length > 0) {
|
|
12
|
+
const headers = ['name', 'schema', 'type', 'rows_estimate'];
|
|
13
|
+
const rows = result.tables.map((table) => [
|
|
14
|
+
table.name,
|
|
15
|
+
table.schema,
|
|
16
|
+
table.type,
|
|
17
|
+
table.rows_estimate !== null ? String(table.rows_estimate) : 'NULL',
|
|
18
|
+
]);
|
|
19
|
+
parts.push(formatAsMarkdownTable(headers, rows));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
parts.push('_No tables found_');
|
|
23
|
+
}
|
|
24
|
+
if (result.truncated && result.totalAvailable !== undefined) {
|
|
25
|
+
parts.push('');
|
|
26
|
+
parts.push(`**Note:** Showing ${result.tables.length} of ${result.totalAvailable} tables`);
|
|
27
|
+
}
|
|
28
|
+
return parts.join('\n');
|
|
29
|
+
}
|
|
30
|
+
import { getValidatedDatabase } from '../utils/validation.js';
|
|
6
31
|
/**
|
|
7
32
|
* Lists tables and views in a database schema.
|
|
8
33
|
*
|
|
@@ -12,15 +37,8 @@ import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
|
12
37
|
*/
|
|
13
38
|
export async function listTables(params, config) {
|
|
14
39
|
const maxTables = config.defaults.maxTables;
|
|
15
|
-
|
|
16
|
-
const dbConfig = config.databases[params.database];
|
|
17
|
-
if (!dbConfig) {
|
|
18
|
-
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
19
|
-
}
|
|
20
|
-
// Create adapter for this database
|
|
40
|
+
const dbConfig = getValidatedDatabase(params.database, config);
|
|
21
41
|
const adapter = createAdapter(dbConfig, config.defaults);
|
|
22
|
-
// Use provided schema or adapter's default schema
|
|
23
|
-
// PostgreSQL: "public", MySQL: database name, SQLite: "main"
|
|
24
42
|
const schema = params.schema ?? adapter.getDefaultSchema();
|
|
25
43
|
return adapter.withConnection(async (conn) => {
|
|
26
44
|
const result = await conn.listTables(schema, maxTables);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-tables.js","sourceRoot":"","sources":["../../src/tools/list-tables.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"list-tables.js","sourceRoot":"","sources":["../../src/tools/list-tables.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;GAEG;AACH,MAAM,UAAU,gCAAgC,CAAC,MAAwB;IACvE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;QAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;YACxC,KAAK,CAAC,IAAI;YACV,KAAK,CAAC,MAAM;YACZ,KAAK,CAAC,IAAI;YACV,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM;SACpE,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IACnD,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,MAAM,CAAC,MAAM,OAAO,MAAM,CAAC,cAAc,SAAS,CAAC,CAAC;IAC7F,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AACD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAwB,EACxB,MAAc;IAEd,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;IAC5C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAE3D,OAAO,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;QAChC,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC7C,MAAM,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC;QAE7C,IAAI,SAAS,EAAE,CAAC;YACd,OAAO;gBACL,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC;gBACrC,SAAS,EAAE,IAAI;gBACf,cAAc;aACf,CAAC;QACJ,CAAC;QAED,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/tools/query.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Query tool for executing SELECT statements
|
|
3
3
|
*/
|
|
4
|
-
import type { Config, QueryResult } from '../types.js';
|
|
5
|
-
export interface QueryParams {
|
|
6
|
-
database: string;
|
|
7
|
-
sql: string;
|
|
8
|
-
params?: unknown[];
|
|
9
|
-
}
|
|
4
|
+
import type { Config, QueryParams, QueryResult } from '../types.js';
|
|
10
5
|
/**
|
|
11
6
|
* Format QueryResult as Markdown table followed by metadata
|
|
12
7
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAOpE;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAqBvE;AAED;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CACzB,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,CAmEtB"}
|
package/dist/tools/query.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Query tool for executing SELECT statements
|
|
3
3
|
*/
|
|
4
4
|
import { createAdapter } from '../adapters/index.js';
|
|
5
|
-
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
6
|
-
import { truncateRows, truncateCell, checkTotalSize } from '../utils/truncate.js';
|
|
7
5
|
import { formatAsMarkdownTable, formatValue } from '../utils/formatter.js';
|
|
6
|
+
import { truncateCell, truncateRows } from '../utils/truncate.js';
|
|
7
|
+
import { getValidatedDatabase, validateParamCount } from '../utils/validation.js';
|
|
8
8
|
/**
|
|
9
9
|
* Format QueryResult as Markdown table followed by metadata
|
|
10
10
|
*/
|
|
@@ -39,34 +39,23 @@ export function formatQueryResultAsMarkdown(result) {
|
|
|
39
39
|
*/
|
|
40
40
|
export async function query(params, config) {
|
|
41
41
|
const startTime = Date.now();
|
|
42
|
-
|
|
43
|
-
const dbConfig = config.databases[params.database];
|
|
44
|
-
if (!dbConfig) {
|
|
45
|
-
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
46
|
-
}
|
|
47
|
-
// Create adapter for this database
|
|
42
|
+
const dbConfig = getValidatedDatabase(params.database, config);
|
|
48
43
|
const adapter = createAdapter(dbConfig, config.defaults);
|
|
49
|
-
// Step 1: Validate that this is a SELECT query
|
|
50
44
|
adapter.validateQueryForTool(params.sql, 'query');
|
|
51
|
-
|
|
45
|
+
validateParamCount(params.sql, params.params ?? []);
|
|
52
46
|
const parsed = adapter.parseQuery(params.sql);
|
|
53
47
|
let sql = params.sql;
|
|
54
48
|
if (!parsed.hasLimit) {
|
|
55
|
-
// Get maxRows from database config or defaults
|
|
56
49
|
const maxRows = dbConfig?.maxRows ?? config.defaults.maxRows;
|
|
57
50
|
sql = adapter.injectLimit(params.sql, maxRows);
|
|
58
51
|
}
|
|
59
|
-
// Step 3: Convert placeholders for non-PostgreSQL dialects
|
|
60
|
-
// PostgreSQL uses $1, $2; MySQL/SQLite use ?
|
|
61
52
|
sql = adapter.convertPlaceholders(sql);
|
|
62
53
|
const result = await adapter.withConnection(async (conn) => {
|
|
63
54
|
return conn.query(sql, params.params ?? []);
|
|
64
55
|
});
|
|
65
56
|
const columns = result.fields.map((field) => field.name);
|
|
66
57
|
const rawRows = result.rows;
|
|
67
|
-
// Step 4: Format each cell value
|
|
68
58
|
let formattedRows = rawRows.map((row) => row.map((cell) => formatValue(cell)));
|
|
69
|
-
// Step 5: Truncate individual cells if over maxCellLength
|
|
70
59
|
let anyCellTruncated = false;
|
|
71
60
|
formattedRows = formattedRows.map((row) => row.map((cell) => {
|
|
72
61
|
const truncated = truncateCell(cell, config.defaults.maxCellLength);
|
|
@@ -75,19 +64,10 @@ export async function query(params, config) {
|
|
|
75
64
|
}
|
|
76
65
|
return truncated.value;
|
|
77
66
|
}));
|
|
78
|
-
// Step 6: Truncate rows if over maxRows
|
|
79
67
|
const { rows: truncatedRows, info: rowTruncationInfo } = truncateRows(formattedRows, config.defaults.maxRows);
|
|
80
|
-
|
|
81
|
-
const tableOutput = formatAsMarkdownTable(columns, truncatedRows);
|
|
82
|
-
const sizeInfo = checkTotalSize(tableOutput, config.defaults.maxTotalSize);
|
|
83
|
-
// Determine final truncation state
|
|
84
|
-
const truncated = rowTruncationInfo.truncated || anyCellTruncated || sizeInfo.truncated;
|
|
85
|
-
// Determine truncation reason (priority: maxTotalSize > maxRows > maxCellLength)
|
|
68
|
+
const truncated = rowTruncationInfo.truncated || anyCellTruncated;
|
|
86
69
|
let truncationReason;
|
|
87
|
-
if (
|
|
88
|
-
truncationReason = sizeInfo.truncationReason;
|
|
89
|
-
}
|
|
90
|
-
else if (rowTruncationInfo.truncated) {
|
|
70
|
+
if (rowTruncationInfo.truncated) {
|
|
91
71
|
truncationReason = rowTruncationInfo.truncationReason;
|
|
92
72
|
}
|
|
93
73
|
else if (anyCellTruncated) {
|
|
@@ -102,7 +82,7 @@ export async function query(params, config) {
|
|
|
102
82
|
truncationReason,
|
|
103
83
|
totalAvailable: rowTruncationInfo.totalAvailable,
|
|
104
84
|
returned: rowTruncationInfo.returned,
|
|
105
|
-
hint: rowTruncationInfo.hint
|
|
85
|
+
hint: rowTruncationInfo.hint,
|
|
106
86
|
executionTime,
|
|
107
87
|
};
|
|
108
88
|
}
|
package/dist/tools/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,15 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export type QueryType = 'select' | 'insert' | 'update' | 'delete' | 'other';
|
|
5
5
|
export interface ParsedQuery {
|
|
6
|
-
/** The type of SQL query */
|
|
7
6
|
type: QueryType;
|
|
8
|
-
/** Whether the query has a LIMIT clause (for SELECT queries) */
|
|
9
7
|
hasLimit: boolean;
|
|
10
|
-
/** Whether the query is dangerous (DROP, TRUNCATE, ALTER, etc.) */
|
|
11
8
|
isDangerous: boolean;
|
|
12
|
-
/** Reason why query is considered dangerous */
|
|
13
9
|
dangerousReason?: string;
|
|
14
|
-
/** The original SQL string */
|
|
15
10
|
sql: string;
|
|
16
11
|
}
|
|
17
12
|
export interface DatabaseConfig {
|
|
@@ -83,4 +78,43 @@ export interface TableInfo {
|
|
|
83
78
|
type: 'table' | 'view';
|
|
84
79
|
rows_estimate: number | null;
|
|
85
80
|
}
|
|
81
|
+
export interface ListDatabasesResult {
|
|
82
|
+
databases: Array<{
|
|
83
|
+
name: string;
|
|
84
|
+
readonly: boolean;
|
|
85
|
+
}>;
|
|
86
|
+
}
|
|
87
|
+
export interface ListTablesParams {
|
|
88
|
+
database: string;
|
|
89
|
+
schema?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface ListTablesResult {
|
|
92
|
+
tables: TableInfo[];
|
|
93
|
+
truncated: boolean;
|
|
94
|
+
totalAvailable?: number;
|
|
95
|
+
}
|
|
96
|
+
export interface DescribeTableParams {
|
|
97
|
+
database: string;
|
|
98
|
+
table: string;
|
|
99
|
+
schema?: string;
|
|
100
|
+
}
|
|
101
|
+
export interface QueryParams {
|
|
102
|
+
database: string;
|
|
103
|
+
sql: string;
|
|
104
|
+
params?: unknown[];
|
|
105
|
+
}
|
|
106
|
+
export interface ExecuteParams {
|
|
107
|
+
database: string;
|
|
108
|
+
sql: string;
|
|
109
|
+
params?: unknown[];
|
|
110
|
+
}
|
|
111
|
+
export interface ExplainParams {
|
|
112
|
+
database: string;
|
|
113
|
+
sql: string;
|
|
114
|
+
analyze?: boolean;
|
|
115
|
+
}
|
|
116
|
+
export interface ExplainResult {
|
|
117
|
+
plan: string;
|
|
118
|
+
executionTime: number;
|
|
119
|
+
}
|
|
86
120
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5E,MAAM,WAAW,WAAW;IAC1B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE5E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE;QACV,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAID,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB"}
|
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
* Formatting utilities for query results
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* JSON replacer function that handles BigInt values by converting them to strings.
|
|
6
|
+
* This prevents "TypeError: Do not know how to serialize a BigInt" when using JSON.stringify.
|
|
7
7
|
*/
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function bigIntReplacer(_key: string, value: unknown): unknown;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Safely stringify a value to JSON, handling BigInt values.
|
|
11
11
|
*/
|
|
12
|
+
export declare function safeJsonStringify(value: unknown): string;
|
|
13
|
+
/** Format a value for display (handles null, dates, objects, primitives) */
|
|
14
|
+
export declare function formatValue(value: unknown): string;
|
|
12
15
|
export declare function formatAsMarkdownTable(columns: string[], rows: (string | null)[][]): string;
|
|
13
16
|
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/utils/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/utils/formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAKpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAExD;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAsBlD;AASD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,GACxB,MAAM,CAyBR"}
|