From 750430e91fca03d32e3cab28a84bb6de5f3831e7 Mon Sep 17 00:00:00 2001 From: smartass Date: Thu, 11 Jun 2026 23:36:00 +0500 Subject: [PATCH] feat: add driver interface, database resolution --- src/db/driver.ts | 90 +++++++++++++++++++++++++++++++++++++ test/unit/db/driver.test.ts | 25 +++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/db/driver.ts create mode 100644 test/unit/db/driver.test.ts diff --git a/src/db/driver.ts b/src/db/driver.ts new file mode 100644 index 0000000..cfc1015 --- /dev/null +++ b/src/db/driver.ts @@ -0,0 +1,90 @@ +import type { ConnectionConfig } from '../config/types.js' + +export type QueryResult = { + columns: string[] + rows: unknown[][] + rowCount: number + truncated: boolean + lastInsertId?: string +} + +export type QueryArgs = { + sql: string + params?: unknown[] + database?: string + rowLimit: number +} + +export type DatabaseInfo = { + name: string + sizeBytes: number | null +} + +export type TableInfo = { + schema: string + name: string + rowEstimate: number | null +} + +export type ColumnInfo = { + name: string + type: string + nullable: boolean + default: string | null +} + +export type IndexInfo = { + name: string + columns: string[] + unique: boolean +} + +export type ForeignKeyInfo = { + name: string + columns: string[] + referencedTable: string + referencedColumns: string[] +} + +export type TableDescription = { + columns: ColumnInfo[] + primaryKey: string[] + indexes: IndexInfo[] + foreignKeys: ForeignKeyInfo[] +} + +export type Driver = { + query: (args: QueryArgs) => Promise + listDatabases: () => Promise + listTables: (args: { database?: string; schema?: string }) => Promise + describeTable: (args: { + table: string + database?: string + schema?: string + }) => Promise + serverVersion: () => Promise + dispose: () => Promise +} + +export type DriverTarget = { + config: ConnectionConfig + host: string + port: number +} + +export class MissingDatabaseError extends Error { + constructor() { + super( + 'no database specified: pass the database parameter or set a default database on the connection' + ) + this.name = 'MissingDatabaseError' + } +} + +export const resolveDatabase = (config: ConnectionConfig, database?: string): string => { + const resolved = database ?? config.database + if (!resolved) { + throw new MissingDatabaseError() + } + return resolved +} diff --git a/test/unit/db/driver.test.ts b/test/unit/db/driver.test.ts new file mode 100644 index 0000000..ede3f9b --- /dev/null +++ b/test/unit/db/driver.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it } from 'vitest' +import type { ConnectionConfig } from '../../../src/config/types.js' +import { MissingDatabaseError, resolveDatabase } from '../../../src/db/driver.js' + +const config: ConnectionConfig = { + name: 'c', + type: 'postgres', + host: 'h', + user: 'u', + readonly: false +} + +describe('resolveDatabase', () => { + it('prefers the explicit parameter', () => { + expect(resolveDatabase({ ...config, database: 'default-db' }, 'explicit')).toBe('explicit') + }) + + it('falls back to the connection default', () => { + expect(resolveDatabase({ ...config, database: 'default-db' }, undefined)).toBe('default-db') + }) + + it('throws when neither is set', () => { + expect(() => resolveDatabase(config, undefined)).toThrow(MissingDatabaseError) + }) +})