You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
daton/orm/src/db/PostgresConnection.ts

133 lines
4.2 KiB

import { Connection, ConnectionNotReadyError } from './Connection.ts'
import { Client } from '../../../lib/src/external/db.ts'
import {collect, Collection} from '../../../lib/src/collection/Collection.ts'
import { QueryResult, QueryRow } from './types.ts'
import { logger } from '../../../lib/src/service/logging/global.ts'
import {Database} from "../schema/tree/Database.ts";
import {escape} from "../builder/types.ts";
import {Table} from "../schema/tree/Table.ts";
import {Builder} from "../builder/Builder.ts";
/**
* Database connection class for PostgreSQL connections.
* @extends Connection
*/
export default class PostgresConnection extends Connection {
/**
* The underlying PostgreSQL client.
* @type Client
*/
private _client?: Client
public async init() {
this._client = new Client(this.config)
logger.info(`Opening PostgreSQL database for connection: ${this.name}`)
await this._client.connect()
}
public async query(query: string) {
if ( !this._client ) throw new ConnectionNotReadyError(this.name)
logger.verbose(`Executing query: \n${query}`)
const result = await this._client.query(query)
let base_i = 0
const cols = collect(result?.rowDescription?.columns || []).map(col => {
col.index = base_i
base_i += 1
return col
})
const rows = new Collection<QueryRow>()
for ( const row of result.rows ) {
const row_obj: { [key: string]: any } = {}
for ( const col of cols ) {
// @ts-ignore
row_obj[col.name] = row[col.index]
}
rows.push(row_obj)
}
logger.verbose(`Query result returned ${result.rowCount} row(s).`)
return {
rows,
row_count: result.rowCount,
} as QueryResult
}
public async close() {
if ( this._client )
await this._client.end()
}
public async databases() {
const query = (new Builder).select('datname')
.from('pg_database')
.target_connection(this)
const database_names: Collection<string> = (await query.execute()).rows.pluck('datname')
const databases: Collection<Database> = new Collection<Database>()
for ( const name of database_names ) {
const db = this.make(Database, this, name)
await db.introspect()
databases.push(db)
}
return databases
}
public async database(name: string) {
const query = (new Builder).select('datname')
.from('pg_database')
.target_connection(this)
const database_names: Collection<string> = (await query.execute()).rows.pluck('datname')
if ( database_names.includes(name) ) {
const db = this.make(Database, this, name)
await db.introspect()
return db
}
}
public async database_as_schema(name: string) {
const db = await this.database(name)
if ( db ) return db
return this.make(Database, this, name)
}
public async tables(database_name: string) {
const query = (new Builder).select('tablename')
.from('pg_catalog.pg_tables')
.where('pg_tables.tableowner', '=', database_name)
.target_connection(this)
const table_names: Collection<string> = (await query.execute()).rows.pluck('tablename')
const tables: Collection<Table> = new Collection<Table>()
for ( const name of table_names ) {
tables.push(this.make(Table, this, database_name, name))
}
return tables
}
public async table(database_name: string, table_name: string) {
const database = await this.database(database_name)
if ( database ) {
const query = (new Builder).select('tablename')
.from('pg_catalog.pg_tables')
.where('tableowner', '=', database_name)
.target_connection(this)
const table_names: Collection<string> = (await query.execute()).rows.pluck('tablename')
if ( table_names.includes(table_name) ) {
return this.make(Table, this, database_name, table_name)
}
}
}
}