mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-16 08:25:14 +02:00
rename klo to ktx
This commit is contained in:
parent
1a42152e6f
commit
3ce510b55b
704 changed files with 10205 additions and 10255 deletions
|
|
@ -1,11 +1,11 @@
|
|||
import { describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
createSqlServerLiveDatabaseIntrospection,
|
||||
isKloSqlServerConnectionConfig,
|
||||
KloSqlServerScanConnector,
|
||||
isKtxSqlServerConnectionConfig,
|
||||
KtxSqlServerScanConnector,
|
||||
sqlServerConnectionPoolConfigFromConfig,
|
||||
type KloSqlServerPoolFactory,
|
||||
type KloSqlServerQueryResult,
|
||||
type KtxSqlServerPoolFactory,
|
||||
type KtxSqlServerQueryResult,
|
||||
} from './index.js';
|
||||
|
||||
function recordset<T extends Record<string, unknown>>(
|
||||
|
|
@ -17,12 +17,12 @@ function recordset<T extends Record<string, unknown>>(
|
|||
return withColumns;
|
||||
}
|
||||
|
||||
function result<T extends Record<string, unknown>>(rows: T[], columnNames: string[]): KloSqlServerQueryResult {
|
||||
function result<T extends Record<string, unknown>>(rows: T[], columnNames: string[]): KtxSqlServerQueryResult {
|
||||
return { recordset: recordset(rows, columnNames) };
|
||||
}
|
||||
|
||||
function fakePoolFactory(): KloSqlServerPoolFactory {
|
||||
const query = vi.fn(async (sql: string): Promise<KloSqlServerQueryResult> => {
|
||||
function fakePoolFactory(): KtxSqlServerPoolFactory {
|
||||
const query = vi.fn(async (sql: string): Promise<KtxSqlServerQueryResult> => {
|
||||
if (sql.includes('INFORMATION_SCHEMA.TABLES')) {
|
||||
return result(
|
||||
[
|
||||
|
|
@ -102,7 +102,7 @@ function fakePoolFactory(): KloSqlServerPoolFactory {
|
|||
if (sql.includes('SELECT TOP 1 [id], [status] FROM [dbo].[orders]')) {
|
||||
return result([{ id: 10, status: 'paid' }], ['id', 'status']);
|
||||
}
|
||||
if (sql.includes('SELECT TOP 1 * FROM (select id, status from dbo.orders) AS klo_query_result')) {
|
||||
if (sql.includes('SELECT TOP 1 * FROM (select id, status from dbo.orders) AS ktx_query_result')) {
|
||||
return result([{ id: 10, status: 'paid' }], ['id', 'status']);
|
||||
}
|
||||
if (sql.includes('SELECT TOP 5 [status] FROM [dbo].[orders]')) {
|
||||
|
|
@ -138,17 +138,17 @@ function fakePoolFactory(): KloSqlServerPoolFactory {
|
|||
};
|
||||
}
|
||||
|
||||
describe('KloSqlServerScanConnector', () => {
|
||||
describe('KtxSqlServerScanConnector', () => {
|
||||
it('resolves SQL Server connection configuration safely', () => {
|
||||
expect(
|
||||
isKloSqlServerConnectionConfig({
|
||||
isKtxSqlServerConnectionConfig({
|
||||
driver: 'sqlserver',
|
||||
host: 'localhost',
|
||||
database: 'analytics',
|
||||
readonly: true,
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(isKloSqlServerConnectionConfig({ driver: 'mysql', host: 'localhost', database: 'analytics' })).toBe(false);
|
||||
expect(isKtxSqlServerConnectionConfig({ driver: 'mysql', host: 'localhost', database: 'analytics' })).toBe(false);
|
||||
expect(
|
||||
sqlServerConnectionPoolConfigFromConfig({
|
||||
connectionId: 'warehouse',
|
||||
|
|
@ -178,7 +178,7 @@ describe('KloSqlServerScanConnector', () => {
|
|||
});
|
||||
|
||||
it('introspects schema, primary keys, comments, row counts, views, and foreign keys', async () => {
|
||||
const connector = new KloSqlServerScanConnector({
|
||||
const connector = new KtxSqlServerScanConnector({
|
||||
connectionId: 'warehouse',
|
||||
connection: {
|
||||
driver: 'sqlserver',
|
||||
|
|
@ -238,7 +238,7 @@ describe('KloSqlServerScanConnector', () => {
|
|||
|
||||
it('runs samples, distinct values, read-only SQL, row count, schema list, and cleanup', async () => {
|
||||
const poolFactory = fakePoolFactory();
|
||||
const connector = new KloSqlServerScanConnector({
|
||||
const connector = new KtxSqlServerScanConnector({
|
||||
connectionId: 'warehouse',
|
||||
connection: {
|
||||
driver: 'sqlserver',
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
import { assertReadOnlySql } from '@klo/context/connections';
|
||||
import { assertReadOnlySql } from '@ktx/context/connections';
|
||||
import {
|
||||
createKloConnectorCapabilities,
|
||||
type KloColumnSampleInput,
|
||||
type KloColumnSampleResult,
|
||||
type KloColumnStatsInput,
|
||||
type KloColumnStatsResult,
|
||||
type KloQueryResult,
|
||||
type KloReadOnlyQueryInput,
|
||||
type KloScanConnector,
|
||||
type KloScanContext,
|
||||
type KloScanInput,
|
||||
type KloSchemaColumn,
|
||||
type KloSchemaForeignKey,
|
||||
type KloSchemaSnapshot,
|
||||
type KloSchemaTable,
|
||||
type KloTableRef,
|
||||
type KloTableSampleInput,
|
||||
type KloTableSampleResult,
|
||||
} from '@klo/context/scan';
|
||||
createKtxConnectorCapabilities,
|
||||
type KtxColumnSampleInput,
|
||||
type KtxColumnSampleResult,
|
||||
type KtxColumnStatsInput,
|
||||
type KtxColumnStatsResult,
|
||||
type KtxQueryResult,
|
||||
type KtxReadOnlyQueryInput,
|
||||
type KtxScanConnector,
|
||||
type KtxScanContext,
|
||||
type KtxScanInput,
|
||||
type KtxSchemaColumn,
|
||||
type KtxSchemaForeignKey,
|
||||
type KtxSchemaSnapshot,
|
||||
type KtxSchemaTable,
|
||||
type KtxTableRef,
|
||||
type KtxTableSampleInput,
|
||||
type KtxTableSampleResult,
|
||||
} from '@ktx/context/scan';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { homedir } from 'node:os';
|
||||
import { resolve } from 'node:path';
|
||||
import sql from 'mssql';
|
||||
import { KloSqlServerDialect } from './dialect.js';
|
||||
import { KtxSqlServerDialect } from './dialect.js';
|
||||
|
||||
export interface KloSqlServerConnectionConfig {
|
||||
export interface KtxSqlServerConnectionConfig {
|
||||
driver?: string;
|
||||
host?: string;
|
||||
port?: number;
|
||||
|
|
@ -40,7 +40,7 @@ export interface KloSqlServerConnectionConfig {
|
|||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface KloSqlServerPoolConfig {
|
||||
export interface KtxSqlServerPoolConfig {
|
||||
server: string;
|
||||
port: number;
|
||||
database: string;
|
||||
|
|
@ -50,63 +50,63 @@ export interface KloSqlServerPoolConfig {
|
|||
pool: { max: number; min: number; idleTimeoutMillis: number };
|
||||
}
|
||||
|
||||
export interface KloSqlServerQueryResult {
|
||||
export interface KtxSqlServerQueryResult {
|
||||
recordset?: Array<Record<string, unknown>> & { columns?: Record<string, { type?: { declaration?: string } }> };
|
||||
}
|
||||
|
||||
interface KloSqlServerRequest {
|
||||
input(name: string, value: unknown): KloSqlServerRequest;
|
||||
query(query: string): Promise<KloSqlServerQueryResult>;
|
||||
interface KtxSqlServerRequest {
|
||||
input(name: string, value: unknown): KtxSqlServerRequest;
|
||||
query(query: string): Promise<KtxSqlServerQueryResult>;
|
||||
}
|
||||
|
||||
export interface KloSqlServerPool {
|
||||
request(): KloSqlServerRequest;
|
||||
export interface KtxSqlServerPool {
|
||||
request(): KtxSqlServerRequest;
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface KloSqlServerPoolFactory {
|
||||
createPool(config: KloSqlServerPoolConfig): Promise<KloSqlServerPool>;
|
||||
export interface KtxSqlServerPoolFactory {
|
||||
createPool(config: KtxSqlServerPoolConfig): Promise<KtxSqlServerPool>;
|
||||
}
|
||||
|
||||
interface KloSqlServerResolvedEndpoint {
|
||||
interface KtxSqlServerResolvedEndpoint {
|
||||
host: string;
|
||||
port: number;
|
||||
close?: () => Promise<void>;
|
||||
}
|
||||
|
||||
export interface KloSqlServerEndpointResolver {
|
||||
export interface KtxSqlServerEndpointResolver {
|
||||
resolve(input: {
|
||||
host: string;
|
||||
port: number;
|
||||
connection: KloSqlServerConnectionConfig;
|
||||
}): Promise<KloSqlServerResolvedEndpoint>;
|
||||
connection: KtxSqlServerConnectionConfig;
|
||||
}): Promise<KtxSqlServerResolvedEndpoint>;
|
||||
}
|
||||
|
||||
export interface KloSqlServerScanConnectorOptions {
|
||||
export interface KtxSqlServerScanConnectorOptions {
|
||||
connectionId: string;
|
||||
connection: KloSqlServerConnectionConfig | undefined;
|
||||
poolFactory?: KloSqlServerPoolFactory;
|
||||
endpointResolver?: KloSqlServerEndpointResolver;
|
||||
connection: KtxSqlServerConnectionConfig | undefined;
|
||||
poolFactory?: KtxSqlServerPoolFactory;
|
||||
endpointResolver?: KtxSqlServerEndpointResolver;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
now?: () => Date;
|
||||
}
|
||||
|
||||
export interface KloSqlServerReadOnlyQueryInput extends KloReadOnlyQueryInput {
|
||||
export interface KtxSqlServerReadOnlyQueryInput extends KtxReadOnlyQueryInput {
|
||||
params?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface KloSqlServerColumnDistinctValuesOptions {
|
||||
export interface KtxSqlServerColumnDistinctValuesOptions {
|
||||
maxCardinality: number;
|
||||
limit: number;
|
||||
sampleSize?: number;
|
||||
}
|
||||
|
||||
export interface KloSqlServerColumnDistinctValuesResult {
|
||||
export interface KtxSqlServerColumnDistinctValuesResult {
|
||||
values: string[] | null;
|
||||
cardinality: number;
|
||||
}
|
||||
|
||||
interface KloSqlServerTableSampleResult extends KloTableSampleResult {
|
||||
interface KtxSqlServerTableSampleResult extends KtxTableSampleResult {
|
||||
headerTypes?: string[];
|
||||
}
|
||||
|
||||
|
|
@ -128,8 +128,8 @@ function sqlTypeDeclaration(type: unknown): string {
|
|||
function sqlRecordset(
|
||||
rows: Array<Record<string, unknown>> | undefined,
|
||||
columns: Record<string, { type?: unknown }> | undefined,
|
||||
): NonNullable<KloSqlServerQueryResult['recordset']> {
|
||||
const recordset = [...(rows ?? [])] as NonNullable<KloSqlServerQueryResult['recordset']>;
|
||||
): NonNullable<KtxSqlServerQueryResult['recordset']> {
|
||||
const recordset = [...(rows ?? [])] as NonNullable<KtxSqlServerQueryResult['recordset']>;
|
||||
recordset.columns = Object.fromEntries(
|
||||
Object.entries(columns ?? {}).map(([name, metadata]) => [
|
||||
name,
|
||||
|
|
@ -139,8 +139,8 @@ function sqlRecordset(
|
|||
return recordset;
|
||||
}
|
||||
|
||||
class DefaultSqlServerPoolFactory implements KloSqlServerPoolFactory {
|
||||
async createPool(config: KloSqlServerPoolConfig): Promise<KloSqlServerPool> {
|
||||
class DefaultSqlServerPoolFactory implements KtxSqlServerPoolFactory {
|
||||
async createPool(config: KtxSqlServerPoolConfig): Promise<KtxSqlServerPool> {
|
||||
const pool = await new sql.ConnectionPool(config as sql.config).connect();
|
||||
return {
|
||||
request() {
|
||||
|
|
@ -164,8 +164,8 @@ class DefaultSqlServerPoolFactory implements KloSqlServerPoolFactory {
|
|||
}
|
||||
|
||||
function stringConfigValue(
|
||||
connection: KloSqlServerConnectionConfig | undefined,
|
||||
key: keyof KloSqlServerConnectionConfig,
|
||||
connection: KtxSqlServerConnectionConfig | undefined,
|
||||
key: keyof KtxSqlServerConnectionConfig,
|
||||
env: NodeJS.ProcessEnv,
|
||||
): string | undefined {
|
||||
const value = connection?.[key];
|
||||
|
|
@ -184,7 +184,7 @@ function resolveStringReference(value: string, env: NodeJS.ProcessEnv): string {
|
|||
return value;
|
||||
}
|
||||
|
||||
function parseSqlServerUrl(url: string): Partial<KloSqlServerConnectionConfig> {
|
||||
function parseSqlServerUrl(url: string): Partial<KtxSqlServerConnectionConfig> {
|
||||
const parsed = new URL(url);
|
||||
return {
|
||||
host: parsed.hostname,
|
||||
|
|
@ -200,7 +200,7 @@ function maybeNumber(value: unknown): number | undefined {
|
|||
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
||||
}
|
||||
|
||||
function schemaNames(connection: KloSqlServerConnectionConfig, env: NodeJS.ProcessEnv): string[] {
|
||||
function schemaNames(connection: KtxSqlServerConnectionConfig, env: NodeJS.ProcessEnv): string[] {
|
||||
if (Array.isArray(connection.schemas) && connection.schemas.length > 0) {
|
||||
return connection.schemas.filter((schema) => schema.trim().length > 0).map((schema) => resolveStringReference(schema, env));
|
||||
}
|
||||
|
|
@ -230,19 +230,19 @@ function limitSqlForSqlServerExecution(sqlText: string, maxRows: number | undefi
|
|||
if (!Number.isInteger(maxRows) || maxRows <= 0) {
|
||||
throw new Error('maxRows must be a positive integer.');
|
||||
}
|
||||
return `SELECT TOP ${maxRows} * FROM (${trimmed}) AS klo_query_result`;
|
||||
return `SELECT TOP ${maxRows} * FROM (${trimmed}) AS ktx_query_result`;
|
||||
}
|
||||
|
||||
export function isKloSqlServerConnectionConfig(connection: KloSqlServerConnectionConfig | undefined): boolean {
|
||||
export function isKtxSqlServerConnectionConfig(connection: KtxSqlServerConnectionConfig | undefined): boolean {
|
||||
return String(connection?.driver ?? '').toLowerCase() === 'sqlserver';
|
||||
}
|
||||
|
||||
export function sqlServerConnectionPoolConfigFromConfig(input: {
|
||||
connectionId: string;
|
||||
connection: KloSqlServerConnectionConfig | undefined;
|
||||
connection: KtxSqlServerConnectionConfig | undefined;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): KloSqlServerPoolConfig {
|
||||
if (!isKloSqlServerConnectionConfig(input.connection)) {
|
||||
}): KtxSqlServerPoolConfig {
|
||||
if (!isKtxSqlServerConnectionConfig(input.connection)) {
|
||||
throw new Error(`Native SQL Server connector cannot run driver "${input.connection?.driver ?? 'unknown'}"`);
|
||||
}
|
||||
if (input.connection?.readonly !== true) {
|
||||
|
|
@ -252,7 +252,7 @@ export function sqlServerConnectionPoolConfigFromConfig(input: {
|
|||
const env = input.env ?? process.env;
|
||||
const referencedUrl = stringConfigValue(input.connection, 'url', env);
|
||||
const urlConfig = referencedUrl ? parseSqlServerUrl(referencedUrl) : {};
|
||||
const merged: KloSqlServerConnectionConfig = { ...urlConfig, ...input.connection };
|
||||
const merged: KtxSqlServerConnectionConfig = { ...urlConfig, ...input.connection };
|
||||
const server = stringConfigValue(merged, 'host', env);
|
||||
const database = stringConfigValue(merged, 'database', env);
|
||||
const user = stringConfigValue(merged, 'username', env) ?? stringConfigValue(merged, 'user', env);
|
||||
|
|
@ -278,10 +278,10 @@ export function sqlServerConnectionPoolConfigFromConfig(input: {
|
|||
};
|
||||
}
|
||||
|
||||
export class KloSqlServerScanConnector implements KloScanConnector {
|
||||
export class KtxSqlServerScanConnector implements KtxScanConnector {
|
||||
readonly id: string;
|
||||
readonly driver = 'sqlserver' as const;
|
||||
readonly capabilities = createKloConnectorCapabilities({
|
||||
readonly capabilities = createKtxConnectorCapabilities({
|
||||
tableSampling: true,
|
||||
columnSampling: true,
|
||||
columnStats: false,
|
||||
|
|
@ -292,17 +292,17 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
});
|
||||
|
||||
private readonly connectionId: string;
|
||||
private readonly connection: KloSqlServerConnectionConfig;
|
||||
private readonly poolConfig: KloSqlServerPoolConfig;
|
||||
private readonly connection: KtxSqlServerConnectionConfig;
|
||||
private readonly poolConfig: KtxSqlServerPoolConfig;
|
||||
private readonly schemas: string[];
|
||||
private readonly poolFactory: KloSqlServerPoolFactory;
|
||||
private readonly endpointResolver?: KloSqlServerEndpointResolver;
|
||||
private readonly poolFactory: KtxSqlServerPoolFactory;
|
||||
private readonly endpointResolver?: KtxSqlServerEndpointResolver;
|
||||
private readonly now: () => Date;
|
||||
private readonly dialect = new KloSqlServerDialect();
|
||||
private pool: KloSqlServerPool | null = null;
|
||||
private resolvedEndpoint: KloSqlServerResolvedEndpoint | null = null;
|
||||
private readonly dialect = new KtxSqlServerDialect();
|
||||
private pool: KtxSqlServerPool | null = null;
|
||||
private resolvedEndpoint: KtxSqlServerResolvedEndpoint | null = null;
|
||||
|
||||
constructor(options: KloSqlServerScanConnectorOptions) {
|
||||
constructor(options: KtxSqlServerScanConnectorOptions) {
|
||||
this.connectionId = options.connectionId;
|
||||
this.connection = options.connection ?? {};
|
||||
const env = options.env ?? process.env;
|
||||
|
|
@ -327,9 +327,9 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
}
|
||||
}
|
||||
|
||||
async introspect(input: KloScanInput, _ctx: KloScanContext): Promise<KloSchemaSnapshot> {
|
||||
async introspect(input: KtxScanInput, _ctx: KtxScanContext): Promise<KtxSchemaSnapshot> {
|
||||
this.assertConnection(input.connectionId);
|
||||
const tables: KloSchemaTable[] = [];
|
||||
const tables: KtxSchemaTable[] = [];
|
||||
for (const schemaName of this.schemas) {
|
||||
tables.push(...(await this.introspectSchema(schemaName)));
|
||||
}
|
||||
|
|
@ -349,13 +349,13 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
};
|
||||
}
|
||||
|
||||
async sampleTable(input: KloTableSampleInput, _ctx: KloScanContext): Promise<KloSqlServerTableSampleResult> {
|
||||
async sampleTable(input: KtxTableSampleInput, _ctx: KtxScanContext): Promise<KtxSqlServerTableSampleResult> {
|
||||
this.assertConnection(input.connectionId);
|
||||
const result = await this.query(this.dialect.generateSampleQuery(this.qTableName(input.table), input.limit, input.columns));
|
||||
return { headers: result.headers, headerTypes: result.headerTypes, rows: result.rows, totalRows: result.totalRows };
|
||||
}
|
||||
|
||||
async sampleColumn(input: KloColumnSampleInput, _ctx: KloScanContext): Promise<KloColumnSampleResult> {
|
||||
async sampleColumn(input: KtxColumnSampleInput, _ctx: KtxScanContext): Promise<KtxColumnSampleResult> {
|
||||
this.assertConnection(input.connectionId);
|
||||
const result = await this.query(
|
||||
this.dialect.generateColumnSampleQuery(this.qTableName(input.table), input.column, input.limit),
|
||||
|
|
@ -364,11 +364,11 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
return { values, nullCount: null, distinctCount: null };
|
||||
}
|
||||
|
||||
async columnStats(_input: KloColumnStatsInput, _ctx: KloScanContext): Promise<KloColumnStatsResult | null> {
|
||||
async columnStats(_input: KtxColumnStatsInput, _ctx: KtxScanContext): Promise<KtxColumnStatsResult | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
async executeReadOnly(input: KloSqlServerReadOnlyQueryInput, _ctx: KloScanContext): Promise<KloQueryResult> {
|
||||
async executeReadOnly(input: KtxSqlServerReadOnlyQueryInput, _ctx: KtxScanContext): Promise<KtxQueryResult> {
|
||||
this.assertConnection(input.connectionId);
|
||||
const limitedSql = limitSqlForSqlServerExecution(input.sql, input.maxRows);
|
||||
const prepared = this.dialect.prepareQuery(limitedSql, input.params);
|
||||
|
|
@ -377,10 +377,10 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
}
|
||||
|
||||
async getColumnDistinctValues(
|
||||
table: KloTableRef,
|
||||
table: KtxTableRef,
|
||||
columnName: string,
|
||||
options: KloSqlServerColumnDistinctValuesOptions,
|
||||
): Promise<KloSqlServerColumnDistinctValuesResult | null> {
|
||||
options: KtxSqlServerColumnDistinctValuesOptions,
|
||||
): Promise<KtxSqlServerColumnDistinctValuesResult | null> {
|
||||
const tableName = this.qTableName(table);
|
||||
const quotedColumn = this.dialect.quoteIdentifier(columnName);
|
||||
const cardinalityRows = await this.queryRaw<{ cardinality: unknown }>(
|
||||
|
|
@ -418,7 +418,7 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
return firstNumber(rows[0]?.row_count) ?? 0;
|
||||
}
|
||||
|
||||
qTableName(table: Pick<KloTableRef, 'name'> & Partial<Pick<KloTableRef, 'catalog' | 'db'>>): string {
|
||||
qTableName(table: Pick<KtxTableRef, 'name'> & Partial<Pick<KtxTableRef, 'catalog' | 'db'>>): string {
|
||||
return this.dialect.formatTableName(table);
|
||||
}
|
||||
|
||||
|
|
@ -452,7 +452,7 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
}
|
||||
}
|
||||
|
||||
private async introspectSchema(schemaName: string): Promise<KloSchemaTable[]> {
|
||||
private async introspectSchema(schemaName: string): Promise<KtxSchemaTable[]> {
|
||||
const tables = await this.queryRaw<{ table_name: string; table_type: string }>(
|
||||
`
|
||||
SELECT TABLE_NAME AS table_name, TABLE_TYPE AS table_type
|
||||
|
|
@ -613,7 +613,7 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
column: { table_name: string; column_name: string; data_type: string; is_nullable: string },
|
||||
primaryKeys: Set<string>,
|
||||
comments: Map<string, string>,
|
||||
): KloSchemaColumn {
|
||||
): KtxSchemaColumn {
|
||||
return {
|
||||
name: column.column_name,
|
||||
nativeType: column.data_type,
|
||||
|
|
@ -631,7 +631,7 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
referenced_table_name: string;
|
||||
referenced_column_name: string;
|
||||
constraint_name: string;
|
||||
}): KloSchemaForeignKey {
|
||||
}): KtxSchemaForeignKey {
|
||||
return {
|
||||
fromColumn: row.column_name,
|
||||
toCatalog: this.poolConfig.database,
|
||||
|
|
@ -642,7 +642,7 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
};
|
||||
}
|
||||
|
||||
private async poolForQuery(): Promise<KloSqlServerPool> {
|
||||
private async poolForQuery(): Promise<KtxSqlServerPool> {
|
||||
if (!this.pool) {
|
||||
const config = { ...this.poolConfig };
|
||||
if (this.endpointResolver) {
|
||||
|
|
@ -671,7 +671,7 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
return (result.recordset ?? []) as T[];
|
||||
}
|
||||
|
||||
private async query(query: string, params?: Record<string, unknown>): Promise<Omit<KloQueryResult, 'rowCount'>> {
|
||||
private async query(query: string, params?: Record<string, unknown>): Promise<Omit<KtxQueryResult, 'rowCount'>> {
|
||||
const pool = await this.poolForQuery();
|
||||
const request = pool.request();
|
||||
if (params) {
|
||||
|
|
@ -695,7 +695,7 @@ export class KloSqlServerScanConnector implements KloScanConnector {
|
|||
|
||||
private assertConnection(connectionId: string): void {
|
||||
if (connectionId !== this.connectionId) {
|
||||
throw new Error(`KLO SQL Server connector ${this.id} cannot serve connection ${connectionId}`);
|
||||
throw new Error(`KTX SQL Server connector ${this.id} cannot serve connection ${connectionId}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { KloSqlServerDialect } from './dialect.js';
|
||||
import { KtxSqlServerDialect } from './dialect.js';
|
||||
|
||||
describe('KloSqlServerDialect', () => {
|
||||
const dialect = new KloSqlServerDialect();
|
||||
describe('KtxSqlServerDialect', () => {
|
||||
const dialect = new KtxSqlServerDialect();
|
||||
|
||||
it('quotes identifiers and formats schema-qualified table names', () => {
|
||||
expect(dialect.quoteIdentifier('events')).toBe('[events]');
|
||||
|
|
@ -11,7 +11,7 @@ describe('KloSqlServerDialect', () => {
|
|||
expect(dialect.formatTableName({ catalog: null, db: null, name: 'events' })).toBe('[events]');
|
||||
});
|
||||
|
||||
it('maps SQL Server types to KLO dimension types', () => {
|
||||
it('maps SQL Server types to KTX dimension types', () => {
|
||||
expect(dialect.mapToDimensionType('datetime2')).toBe('time');
|
||||
expect(dialect.mapToDimensionType('decimal(18, 2)')).toBe('number');
|
||||
expect(dialect.mapToDimensionType('bigint')).toBe('number');
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import type { KloSchemaDimensionType, KloTableRef } from '@klo/context/scan';
|
||||
import type { KtxSchemaDimensionType, KtxTableRef } from '@ktx/context/scan';
|
||||
|
||||
type SqlServerTableNameRef = Pick<KloTableRef, 'name'> & Partial<Pick<KloTableRef, 'catalog' | 'db'>>;
|
||||
type SqlServerTableNameRef = Pick<KtxTableRef, 'name'> & Partial<Pick<KtxTableRef, 'catalog' | 'db'>>;
|
||||
|
||||
export class KloSqlServerDialect {
|
||||
export class KtxSqlServerDialect {
|
||||
readonly type = 'sqlserver';
|
||||
|
||||
private readonly typeMappings: Record<string, KloSchemaDimensionType> = {
|
||||
private readonly typeMappings: Record<string, KtxSchemaDimensionType> = {
|
||||
datetime: 'time',
|
||||
datetime2: 'time',
|
||||
date: 'time',
|
||||
|
|
@ -48,7 +48,7 @@ export class KloSqlServerDialect {
|
|||
return nativeType;
|
||||
}
|
||||
|
||||
mapToDimensionType(nativeType: string): KloSchemaDimensionType {
|
||||
mapToDimensionType(nativeType: string): KtxSchemaDimensionType {
|
||||
if (!nativeType) {
|
||||
return 'string';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
export { KloSqlServerDialect } from './dialect.js';
|
||||
export { KtxSqlServerDialect } from './dialect.js';
|
||||
export {
|
||||
isKloSqlServerConnectionConfig,
|
||||
KloSqlServerScanConnector,
|
||||
isKtxSqlServerConnectionConfig,
|
||||
KtxSqlServerScanConnector,
|
||||
sqlServerConnectionPoolConfigFromConfig,
|
||||
type KloSqlServerColumnDistinctValuesOptions,
|
||||
type KloSqlServerColumnDistinctValuesResult,
|
||||
type KloSqlServerConnectionConfig,
|
||||
type KloSqlServerEndpointResolver,
|
||||
type KloSqlServerPool,
|
||||
type KloSqlServerPoolConfig,
|
||||
type KloSqlServerPoolFactory,
|
||||
type KloSqlServerQueryResult,
|
||||
type KloSqlServerReadOnlyQueryInput,
|
||||
type KloSqlServerScanConnectorOptions,
|
||||
type KtxSqlServerColumnDistinctValuesOptions,
|
||||
type KtxSqlServerColumnDistinctValuesResult,
|
||||
type KtxSqlServerConnectionConfig,
|
||||
type KtxSqlServerEndpointResolver,
|
||||
type KtxSqlServerPool,
|
||||
type KtxSqlServerPoolConfig,
|
||||
type KtxSqlServerPoolFactory,
|
||||
type KtxSqlServerQueryResult,
|
||||
type KtxSqlServerReadOnlyQueryInput,
|
||||
type KtxSqlServerScanConnectorOptions,
|
||||
} from './connector.js';
|
||||
export { createSqlServerLiveDatabaseIntrospection } from './live-database-introspection.js';
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import type { LiveDatabaseIntrospectionPort } from '@klo/context/ingest';
|
||||
import type { KloProjectConnectionConfig } from '@klo/context/project';
|
||||
import type { LiveDatabaseIntrospectionPort } from '@ktx/context/ingest';
|
||||
import type { KtxProjectConnectionConfig } from '@ktx/context/project';
|
||||
import {
|
||||
KloSqlServerScanConnector,
|
||||
type KloSqlServerConnectionConfig,
|
||||
type KloSqlServerEndpointResolver,
|
||||
type KloSqlServerPoolFactory,
|
||||
KtxSqlServerScanConnector,
|
||||
type KtxSqlServerConnectionConfig,
|
||||
type KtxSqlServerEndpointResolver,
|
||||
type KtxSqlServerPoolFactory,
|
||||
} from './connector.js';
|
||||
|
||||
interface CreateSqlServerLiveDatabaseIntrospectionOptions {
|
||||
connections: Record<string, KloProjectConnectionConfig>;
|
||||
poolFactory?: KloSqlServerPoolFactory;
|
||||
endpointResolver?: KloSqlServerEndpointResolver;
|
||||
connections: Record<string, KtxProjectConnectionConfig>;
|
||||
poolFactory?: KtxSqlServerPoolFactory;
|
||||
endpointResolver?: KtxSqlServerEndpointResolver;
|
||||
now?: () => Date;
|
||||
}
|
||||
|
||||
|
|
@ -19,8 +19,8 @@ export function createSqlServerLiveDatabaseIntrospection(
|
|||
): LiveDatabaseIntrospectionPort {
|
||||
return {
|
||||
async extractSchema(connectionId: string) {
|
||||
const connection = options.connections[connectionId] as KloSqlServerConnectionConfig | undefined;
|
||||
const connector = new KloSqlServerScanConnector({
|
||||
const connection = options.connections[connectionId] as KtxSqlServerConnectionConfig | undefined;
|
||||
const connector = new KtxSqlServerScanConnector({
|
||||
connectionId,
|
||||
connection,
|
||||
poolFactory: options.poolFactory,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('@klo/connector-sqlserver package exports', () => {
|
||||
describe('@ktx/connector-sqlserver package exports', () => {
|
||||
it('exports public connector APIs during package bootstrap', async () => {
|
||||
const connector = await import('./index.js');
|
||||
|
||||
expect(connector.KloSqlServerDialect).toBeTypeOf('function');
|
||||
expect(connector.KloSqlServerScanConnector).toBeTypeOf('function');
|
||||
expect(connector.KtxSqlServerDialect).toBeTypeOf('function');
|
||||
expect(connector.KtxSqlServerScanConnector).toBeTypeOf('function');
|
||||
expect(connector.createSqlServerLiveDatabaseIntrospection).toBeTypeOf('function');
|
||||
expect(connector.sqlServerConnectionPoolConfigFromConfig).toBeTypeOf('function');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue