mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-28 08:49:38 +02:00
feat(sqlite): implement connector scope listing
This commit is contained in:
parent
8ec2acba40
commit
54dd9cc518
11 changed files with 82 additions and 1 deletions
|
|
@ -59,6 +59,8 @@ function nativeConnector(
|
|||
introspect: vi.fn(async () => {
|
||||
throw new Error('introspect should not be called from connection test');
|
||||
}),
|
||||
listSchemas: vi.fn(async () => []),
|
||||
listTables: vi.fn(async () => []),
|
||||
testConnection,
|
||||
cleanup,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -150,6 +150,20 @@ describe('KtxSqliteScanConnector', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('lists schemaless tables and views for setup discovery', async () => {
|
||||
const connector = new KtxSqliteScanConnector({
|
||||
connectionId: 'warehouse',
|
||||
connection: { driver: 'sqlite', path: dbPath },
|
||||
});
|
||||
|
||||
await expect(connector.listSchemas()).resolves.toEqual([]);
|
||||
await expect(connector.listTables(['ignored'])).resolves.toEqual([
|
||||
{ schema: '', name: 'customers', kind: 'table' },
|
||||
{ schema: '', name: 'orders', kind: 'table' },
|
||||
{ schema: '', name: 'recent_orders', kind: 'view' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('runs samples, distinct values, statistics, and read-only SQL', async () => {
|
||||
const connector = new KtxSqliteScanConnector({
|
||||
connectionId: 'warehouse',
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ describe('createLocalProjectMcpContextPorts', () => {
|
|||
driver: snapshot.driver,
|
||||
capabilities: createKtxConnectorCapabilities({ readOnlySql: queryResult !== undefined }),
|
||||
introspect: vi.fn(async () => snapshot),
|
||||
listSchemas: vi.fn(async () => []),
|
||||
listTables: vi.fn(async () => []),
|
||||
executeReadOnly: queryResult === undefined ? undefined : vi.fn(async () => queryResult),
|
||||
cleanup: vi.fn(async () => {}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ function createConnector(): KtxScanConnector {
|
|||
introspect: vi.fn(async () => {
|
||||
throw new Error('introspection is not used by description generation');
|
||||
}),
|
||||
listSchemas: vi.fn(async () => []),
|
||||
listTables: vi.fn(async () => []),
|
||||
sampleColumn: vi.fn(async () => ({
|
||||
values: ['paid', 'refunded', null],
|
||||
nullCount: 1,
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@ function connector(): KtxScanConnector {
|
|||
columnStats: true,
|
||||
}),
|
||||
introspect: vi.fn(async () => snapshot),
|
||||
listSchemas: vi.fn(async () => []),
|
||||
listTables: vi.fn(async () => []),
|
||||
sampleTable: vi.fn(async () => ({
|
||||
headers: ['id', 'customer_id'],
|
||||
rows: [[1, 10]],
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ import type {
|
|||
KtxSchemaSnapshot,
|
||||
} from '../../../src/context/scan/types.js';
|
||||
|
||||
const connectorScopeListing = {
|
||||
listSchemas: vi.fn(async () => []),
|
||||
listTables: vi.fn(async () => []),
|
||||
};
|
||||
|
||||
function relationshipSqlResult(
|
||||
input: KtxReadOnlyQueryInput,
|
||||
options: { throwOnCoverage?: boolean } = {},
|
||||
|
|
@ -254,6 +259,7 @@ function nativeScanConnector(options: { cleanup?: () => Promise<void> } = {}): K
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: false,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
introspect: vi.fn(async () => nativeScanSnapshot()),
|
||||
sampleTable: vi.fn(async () => ({ headers: ['id'], rows: [[1]], totalRows: 1 })),
|
||||
sampleColumn: vi.fn(async () => ({ values: ['1'], nullCount: 0, distinctCount: 1 })),
|
||||
|
|
@ -656,6 +662,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: false,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -741,6 +748,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: true,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -930,6 +938,14 @@ describe('local scan', () => {
|
|||
};
|
||||
}
|
||||
|
||||
async listSchemas(): Promise<string[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async listTables() {
|
||||
return [];
|
||||
}
|
||||
|
||||
async executeReadOnly(input: KtxReadOnlyQueryInput): Promise<KtxQueryResult> {
|
||||
return relationshipSqlResult(input);
|
||||
}
|
||||
|
|
@ -972,6 +988,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: true,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -1073,6 +1090,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: true,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -1200,6 +1218,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: true,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -1340,6 +1359,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: true,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -1455,6 +1475,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: false,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -1550,6 +1571,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: false,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -1666,6 +1688,7 @@ describe('local scan', () => {
|
|||
formalForeignKeys: false,
|
||||
estimatedRowCounts: false,
|
||||
},
|
||||
...connectorScopeListing,
|
||||
async introspect() {
|
||||
return {
|
||||
connectionId: 'warehouse',
|
||||
|
|
|
|||
|
|
@ -213,6 +213,8 @@ function connector(executor: InMemorySqliteExecutor | null): KtxScanConnector {
|
|||
columnSampling: false,
|
||||
}),
|
||||
introspect: async () => snapshot(),
|
||||
listSchemas: async () => [],
|
||||
listTables: async () => [],
|
||||
executeReadOnly: executor ? executor.executeReadOnly.bind(executor) : undefined,
|
||||
};
|
||||
}
|
||||
|
|
@ -645,6 +647,8 @@ describe('production relationship discovery', () => {
|
|||
columnSampling: false,
|
||||
}),
|
||||
introspect: async () => maskedSnapshot,
|
||||
listSchemas: async () => [],
|
||||
listTables: async () => [],
|
||||
executeReadOnly: async (input) => {
|
||||
const rows = database.prepare(input.sql).all() as Record<string, unknown>[];
|
||||
const headers = Object.keys(rows[0] ?? {});
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@ describe('KTX scan contract types', () => {
|
|||
expect(ctx.runId).toBe('scan-run-1');
|
||||
return snapshot;
|
||||
},
|
||||
listSchemas: async () => [],
|
||||
listTables: async () => [],
|
||||
};
|
||||
|
||||
await expect(
|
||||
|
|
@ -164,6 +166,8 @@ describe('KTX scan contract types', () => {
|
|||
tables: [],
|
||||
};
|
||||
},
|
||||
listSchemas: async () => [],
|
||||
listTables: async () => [],
|
||||
};
|
||||
|
||||
await expect(
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ function connector(overrides: Partial<KtxScanConnector> = {}): KtxScanConnector
|
|||
})),
|
||||
cleanup: vi.fn(async () => {}),
|
||||
...overrides,
|
||||
listSchemas: overrides.listSchemas ?? vi.fn(async () => []),
|
||||
listTables: overrides.listTables ?? vi.fn(async () => []),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ function makeConnector(overrides: Partial<KtxScanConnector> = {}): KtxScanConnec
|
|||
})),
|
||||
cleanup: vi.fn(async () => undefined),
|
||||
...overrides,
|
||||
listSchemas: overrides.listSchemas ?? vi.fn(async () => []),
|
||||
listTables: overrides.listTables ?? vi.fn(async () => []),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue