import knex, { Knex } from 'knex' import knexStringcase from 'knex-stringcase' import { KnexTransaction, KnexTransactionImpl } from './KnexTransaction.js' import { Database } from '../../Database.js' import type { DbConfig } from '../../types.js' /** * Represents a KnexDatabase class that extends Database and provides methods for interacting with a Knex database. */ export class KnexDatabase extends Database { /** * A static property that provides a Knex instance based on the given configuration. * @param {knex.Knex.Config} config - The configuration object for Knex. * @returns {knex.Knex} A Knex instance based on the provided configuration. */ private static knexProvider: (config: knex.Knex.Config) => knex.Knex = knex /** * Represents a Knex client for interacting with a database. * @type {Knex} */ public readonly client: Knex /** * Constructor for creating a new instance of a database connection using Knex. * @param {DbConfig<'knex'>} config - The configuration object for the Knex database. * @returns None */ constructor(config: DbConfig<'knex'>) { super(config) this.client = KnexDatabase.knexProvider(this.constructConfig(config)) } /** * Constructs a Knex configuration object based on the provided DbConfig. * @param {DbConfig<'knex'>} config - The database configuration object. * @returns The Knex configuration object with appropriate settings based on the input config. */ private constructConfig(config: DbConfig<'knex'>) { const knexConfig = { client: config.driver, connection: { host: config.host, port: config.port, user: config.username, password: config.password, database: config.database, }, pool: { min: 1, max: config.maxConnections, }, } return config.convertCamelToSnake ? knexStringcase(knexConfig) : knexConfig } /** * Override method to start a new transaction using KnexTransactionImpl. * @returns {Promise} A promise that resolves to a KnexTransaction object. */ public override async transaction(): Promise { return await KnexTransactionImpl.newTransaction(this.client, this) } }