mirror of
https://github.com/Kaelio/ktx.git
synced 2026-07-25 12:01:03 +02:00
refactor(mongo-query): extract shared runMongoQuery execution seam
This commit is contained in:
parent
f5d431a398
commit
9a2e215bdc
3 changed files with 60 additions and 17 deletions
|
|
@ -25,7 +25,7 @@ import { readLocalSlSource } from '../../context/sl/local-sl.js';
|
|||
import { assertSafeConnectionId } from '../../context/sl/source-files.js';
|
||||
import { assertConfiguredConnectionId } from '../../context/connections/configured-connections.js';
|
||||
import { readLocalKnowledgePage, searchLocalKnowledgePages } from '../wiki/local-knowledge.js';
|
||||
import type { KtxMongoDbScanConnector } from '../../connectors/mongodb/connector.js';
|
||||
import { runMongoQuery } from './mongo-query-runner.js';
|
||||
import type { KtxMcpContextPorts, KtxMcpProgressCallback, KtxMongoQueryResponse, KtxSqlExecutionResponse } from './types.js';
|
||||
|
||||
interface CreateLocalProjectMcpContextPortsOptions {
|
||||
|
|
@ -66,22 +66,7 @@ async function executeMongoQuery(
|
|||
createConnector: (connectionId: string) => Promise<KtxScanConnector> | KtxScanConnector,
|
||||
input: { connectionId: string; collection: string; database?: string; pipeline: Record<string, unknown>[]; limit: number },
|
||||
): Promise<KtxMongoQueryResponse> {
|
||||
const connectionId = assertSafeConnectionId(input.connectionId);
|
||||
let connector: KtxScanConnector | null = null;
|
||||
try {
|
||||
connector = await createConnector(connectionId);
|
||||
if (connector.driver !== 'mongodb') {
|
||||
throw new KtxExpectedError(
|
||||
`Connection "${connectionId}" driver "${connector.driver}" is not a MongoDB connection; mongo_query serves mongodb connections only.`,
|
||||
);
|
||||
}
|
||||
return (connector as unknown as KtxMongoDbScanConnector).executeQuery(
|
||||
{ connectionId, collection: input.collection, database: input.database, pipeline: input.pipeline, limit: input.limit },
|
||||
{ runId: 'mcp-mongo-query' },
|
||||
);
|
||||
} finally {
|
||||
await connector?.cleanup?.();
|
||||
}
|
||||
return runMongoQuery(createConnector, input);
|
||||
}
|
||||
|
||||
async function executeValidatedReadOnlySql(
|
||||
|
|
|
|||
35
packages/cli/src/context/mcp/mongo-query-runner.ts
Normal file
35
packages/cli/src/context/mcp/mongo-query-runner.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import type { KtxMongoDbScanConnector, KtxMongoQueryResult } from '../../connectors/mongodb/connector.js';
|
||||
import { KtxExpectedError } from '../../errors.js';
|
||||
import { assertSafeConnectionId } from '../sl/source-files.js';
|
||||
import type { KtxScanConnector } from '../scan/types.js';
|
||||
|
||||
export interface KtxMongoQueryRequest {
|
||||
connectionId: string;
|
||||
collection: string;
|
||||
database?: string;
|
||||
pipeline: Record<string, unknown>[];
|
||||
limit: number;
|
||||
}
|
||||
|
||||
/** Single Mongo-read execution seam: resolve the connector, guard the driver, run the pipeline. */
|
||||
export async function runMongoQuery(
|
||||
createConnector: (connectionId: string) => Promise<KtxScanConnector> | KtxScanConnector,
|
||||
input: KtxMongoQueryRequest,
|
||||
): Promise<KtxMongoQueryResult> {
|
||||
const connectionId = assertSafeConnectionId(input.connectionId);
|
||||
let connector: KtxScanConnector | null = null;
|
||||
try {
|
||||
connector = await createConnector(connectionId);
|
||||
if (connector.driver !== 'mongodb') {
|
||||
throw new KtxExpectedError(
|
||||
`Connection "${connectionId}" driver "${connector.driver}" is not a MongoDB connection; mongo_query serves mongodb connections only.`,
|
||||
);
|
||||
}
|
||||
return await (connector as unknown as KtxMongoDbScanConnector).executeQuery(
|
||||
{ connectionId, collection: input.collection, database: input.database, pipeline: input.pipeline, limit: input.limit },
|
||||
{ runId: 'mongo-query' },
|
||||
);
|
||||
} finally {
|
||||
await connector?.cleanup?.();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
|
|||
import { KtxExpectedError } from '../../src/errors.js';
|
||||
import { KtxMongoDbScanConnector } from '../../src/connectors/mongodb/connector.js';
|
||||
import { createLocalProjectMcpContextPorts } from '../../src/context/mcp/local-project-ports.js';
|
||||
import { runMongoQuery } from '../../src/context/mcp/mongo-query-runner.js';
|
||||
import type { KtxLocalProject } from '../../src/context/project/project.js';
|
||||
import type { KtxScanConnector } from '../../src/context/scan/types.js';
|
||||
|
||||
|
|
@ -80,3 +81,25 @@ describe('mongoQuery MCP port', () => {
|
|||
).rejects.toBeInstanceOf(KtxExpectedError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('runMongoQuery shared helper', () => {
|
||||
it('fetches rows from a mongodb connector', async () => {
|
||||
const result = await runMongoQuery(
|
||||
(id) => (id === 'mongo' ? mongoConnector() : warehouseConnector()),
|
||||
{ connectionId: 'mongo', collection: 'business', pipeline: [], limit: 100 },
|
||||
);
|
||||
expect(result.rowCount).toBe(2);
|
||||
expect(result.headers).toEqual(['_id', 'city']);
|
||||
});
|
||||
|
||||
it('throws an expected error naming the wrong driver for a non-mongodb connector', async () => {
|
||||
await expect(
|
||||
runMongoQuery((id) => (id === 'mongo' ? mongoConnector() : warehouseConnector()), {
|
||||
connectionId: 'warehouse',
|
||||
collection: 'x',
|
||||
pipeline: [],
|
||||
limit: 10,
|
||||
}),
|
||||
).rejects.toThrow(/is not a MongoDB connection/);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue