mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-19 08:28:06 +02:00
140 lines
4.4 KiB
TypeScript
140 lines
4.4 KiB
TypeScript
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { initKtxProject, loadKtxProject } from '@ktx/context/project';
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { createKtxCliScanConnector } from './local-scan-connectors.js';
|
|
|
|
const bigQueryMock = vi.hoisted(() => ({
|
|
constructorInputs: [] as Array<{
|
|
connectionId: string;
|
|
connection: unknown;
|
|
maxBytesBilled?: number | string;
|
|
}>,
|
|
}));
|
|
|
|
vi.mock('@ktx/connector-bigquery', () => ({
|
|
isKtxBigQueryConnectionConfig: (connection: { driver?: unknown } | undefined) =>
|
|
String(connection?.driver ?? '').toLowerCase() === 'bigquery',
|
|
KtxBigQueryScanConnector: class {
|
|
readonly id: string;
|
|
readonly driver = 'bigquery';
|
|
|
|
constructor(options: { connectionId: string; connection: unknown; maxBytesBilled?: number | string }) {
|
|
bigQueryMock.constructorInputs.push(options);
|
|
this.id = `bigquery:${options.connectionId}`;
|
|
}
|
|
},
|
|
}));
|
|
|
|
describe('createKtxCliScanConnector', () => {
|
|
let tempDir: string;
|
|
|
|
beforeEach(async () => {
|
|
bigQueryMock.constructorInputs.length = 0;
|
|
tempDir = await mkdtemp(join(tmpdir(), 'ktx-cli-scan-connector-'));
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await rm(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('creates a native sqlite connector from standalone config', async () => {
|
|
await initKtxProject({ projectDir: tempDir, projectName: 'warehouse' });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'project: warehouse',
|
|
'connections:',
|
|
' warehouse:',
|
|
' driver: sqlite',
|
|
' path: warehouse.db',
|
|
' readonly: true',
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
const project = await loadKtxProject({ projectDir: tempDir });
|
|
|
|
const connector = await createKtxCliScanConnector(project, 'warehouse');
|
|
|
|
expect(connector.id).toBe('sqlite:warehouse');
|
|
expect(connector.driver).toBe('sqlite');
|
|
});
|
|
|
|
it.each([
|
|
['maxBytesBilled', ' maxBytesBilled: 123456789', 123456789],
|
|
['max_bytes_billed', ' max_bytes_billed: "987654321"', '987654321'],
|
|
])('passes BigQuery %s from standalone config', async (_label, byteCapLine, expectedMaxBytesBilled) => {
|
|
await initKtxProject({ projectDir: tempDir, projectName: 'warehouse' });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'project: warehouse',
|
|
'connections:',
|
|
' warehouse:',
|
|
' driver: bigquery',
|
|
' dataset_id: analytics',
|
|
' readonly: true',
|
|
byteCapLine,
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
const project = await loadKtxProject({ projectDir: tempDir });
|
|
|
|
const connector = await createKtxCliScanConnector(project, 'warehouse');
|
|
|
|
expect(connector.id).toBe('bigquery:warehouse');
|
|
expect(connector.driver).toBe('bigquery');
|
|
expect(bigQueryMock.constructorInputs).toEqual([
|
|
expect.objectContaining({
|
|
connectionId: 'warehouse',
|
|
maxBytesBilled: expectedMaxBytesBilled,
|
|
}),
|
|
]);
|
|
});
|
|
|
|
it('throws for structural daemon-only fallback configs', async () => {
|
|
await initKtxProject({ projectDir: tempDir, projectName: 'warehouse' });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'project: warehouse',
|
|
'connections:',
|
|
' warehouse:',
|
|
' driver: duckdb',
|
|
' path: warehouse.duckdb',
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
const project = await loadKtxProject({ projectDir: tempDir });
|
|
|
|
await expect(createKtxCliScanConnector(project, 'warehouse')).rejects.toThrow(
|
|
'Connection "warehouse" uses driver "duckdb", which has no native standalone KTX scan connector',
|
|
);
|
|
});
|
|
|
|
it('throws a clear error when the connection block has no driver field', async () => {
|
|
await initKtxProject({ projectDir: tempDir, projectName: 'warehouse' });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'project: warehouse',
|
|
'connections:',
|
|
' warehouse:',
|
|
' type: postgres',
|
|
' url: postgresql://example/db',
|
|
' readonly: true',
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
const project = await loadKtxProject({ projectDir: tempDir });
|
|
|
|
await expect(createKtxCliScanConnector(project, 'warehouse')).rejects.toThrow(
|
|
'Connection "warehouse" has no `driver` field in ktx.yaml',
|
|
);
|
|
});
|
|
});
|