feat: add driver interface, database resolution
This commit is contained in:
@@ -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<QueryResult>
|
||||||
|
listDatabases: () => Promise<DatabaseInfo[]>
|
||||||
|
listTables: (args: { database?: string; schema?: string }) => Promise<TableInfo[]>
|
||||||
|
describeTable: (args: {
|
||||||
|
table: string
|
||||||
|
database?: string
|
||||||
|
schema?: string
|
||||||
|
}) => Promise<TableDescription>
|
||||||
|
serverVersion: () => Promise<string>
|
||||||
|
dispose: () => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user