|
|
|
import {QueryResult} from '../../db/types.ts'
|
|
|
|
import {make} from '../../../../di/src/global.ts'
|
|
|
|
import Database from '../../service/Database.ts'
|
|
|
|
import {logger} from '../../../../lib/src/service/logging/global.ts'
|
|
|
|
import {Connection} from '../../db/Connection.ts'
|
|
|
|
import {ResultCollection} from './result/ResultCollection.ts'
|
|
|
|
import {ResultIterable} from './result/ResultIterable.ts'
|
|
|
|
import ResultOperator from './result/ResultOperator.ts'
|
|
|
|
import {collect, Collection} from '../../../../lib/src/collection/Collection.ts'
|
|
|
|
import NoTargetOperatorError from '../../error/NoTargetOperatorError.ts'
|
|
|
|
|
|
|
|
export default abstract class ConnectionExecutable<T> {
|
|
|
|
abstract sql(level: number): string
|
|
|
|
|
|
|
|
to_count(): string {
|
|
|
|
return `SELECT COUNT(*) AS to_count FROM (${this.sql(0)}) AS target_query`
|
|
|
|
}
|
|
|
|
|
|
|
|
async get_row(i: number): Promise<T | undefined> {
|
|
|
|
if ( !(this.__target_connection instanceof Connection) ) {
|
|
|
|
throw new Error('Unable to execute database item: no target connection.')
|
|
|
|
}
|
|
|
|
|
|
|
|
const query = `SELECT * FROM (${this.sql(0)}) AS target_query OFFSET ${i} LIMIT 1`
|
|
|
|
const result = await this.__target_connection.query(query)
|
|
|
|
const row = result.rows.first()
|
|
|
|
if ( row ) {
|
|
|
|
if ( !this.__target_operator ) throw new NoTargetOperatorError()
|
|
|
|
|
|
|
|
const inflated = this.__target_operator.inflate_row(row)
|
|
|
|
await this.__target_operator.process_eager_loads(this, collect([inflated]))
|
|
|
|
|
|
|
|
return inflated
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async get_range(start: number, end: number): Promise<Collection<T>> {
|
|
|
|
if ( !(this.__target_connection instanceof Connection) ) {
|
|
|
|
throw new Error('Unable to execute database item: no target connection.')
|
|
|
|
}
|
|
|
|
|
|
|
|
const query = `SELECT * FROM (${this.sql(0)}) AS target_query OFFSET ${start} LIMIT ${(end - start) + 1}`
|
|
|
|
const result = await this.__target_connection.query(query)
|
|
|
|
const inflated = result.rows.map(row => {
|
|
|
|
if ( !this.__target_operator ) throw new NoTargetOperatorError()
|
|
|
|
return this.__target_operator.inflate_row(row)
|
|
|
|
})
|
|
|
|
|
|
|
|
if ( !this.__target_operator ) throw new NoTargetOperatorError()
|
|
|
|
await this.__target_operator.process_eager_loads(this, inflated)
|
|
|
|
|
|
|
|
return inflated
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator(): ResultIterable<T> {
|
|
|
|
return new ResultIterable<T>(this)
|
|
|
|
}
|
|
|
|
|
|
|
|
results(chunk_size = 1000) {
|
|
|
|
return new ResultCollection<T>(this.iterator(), chunk_size)
|
|
|
|
}
|
|
|
|
|
|
|
|
__target_connection?: Connection
|
|
|
|
__target_operator?: ResultOperator<T>
|
|
|
|
|
|
|
|
target_connection(connection: string | Connection) {
|
|
|
|
this.__target_connection = typeof connection === 'string' ? make(Database).connection(connection) : connection
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
|
|
|
target_operator(operator: ResultOperator<T>) {
|
|
|
|
this.__target_operator = operator
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
|
|
|
async execute(): Promise<QueryResult> {
|
|
|
|
if ( !(this.__target_connection instanceof Connection) ) {
|
|
|
|
throw new Error('Unable to execute database item: no target connection.')
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.execute_in_connection(this.__target_connection)
|
|
|
|
}
|
|
|
|
|
|
|
|
async count(): Promise<number> {
|
|
|
|
if ( !(this.__target_connection instanceof Connection) ) {
|
|
|
|
throw new Error('Unable to execute database item: no target connection.')
|
|
|
|
}
|
|
|
|
|
|
|
|
const result = await this.__target_connection.query(this.to_count())
|
|
|
|
const row = result.rows.first()
|
|
|
|
if ( row ) return Number(row.to_count)
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
async exists(): Promise<boolean> {
|
|
|
|
return (await this.count()) > 0
|
|
|
|
}
|
|
|
|
|
|
|
|
async execute_in_connection(connection: string | Connection): Promise<QueryResult> {
|
|
|
|
const conn = typeof connection === 'string' ? make(Database).connection(connection) : connection
|
|
|
|
|
|
|
|
logger.debug(`Executing statement in connection: ${conn.name}`)
|
|
|
|
|
|
|
|
const sql = this.sql(0)
|
|
|
|
logger.verbose(sql)
|
|
|
|
|
|
|
|
return conn.query(sql)
|
|
|
|
}
|
|
|
|
}
|