import { CamelCasePlugin, Kysely, PostgresDialect } from 'kysely' import pg from 'pg' import { KyselyTransaction, KyselyTransactionImpl } from './KyselyTransaction.js' import { Database } from '../../Database.js' import type { DbBaseConfig, DbConfig } from '../../types.js' /** * Represents a database connection using the Kysely library with support for transactions. * @template DBSchema - The schema type for the database. */ export class KyselyDatabase extends Database> { /** * Represents a PostgreSQL provider for querying data using the PostgresDialect. * @type {PostgresDialect} */ private static kyselyPgProvider = PostgresDialect /** * A public static property that provides access to the Kysely class. * This property can be accessed without creating an instance of the class. */ private static kyselyProvider = Kysely /** * A static property that represents a connection pool for PostgreSQL database connections. * @type {Pool} */ private static pgProvider = pg.Pool /** * Represents a PostgreSQL client using the PostgresDialect. */ private readonly pgClient: PostgresDialect /** * Represents a client for querying the database with the specified schema. * @type {Kysely} client - The client for querying the database. */ public readonly client: Kysely /** * Optional property representing the Postgres dialect for reading in a database client. */ private readonly pgReadClient?: PostgresDialect /** * Represents a client for reading from the database. * @type {Kysely | undefined} - The client for reading from the database. */ public readonly readClient?: Kysely /** * Constructor for creating a database connection using the provided configuration. * @param {DbConfig<'kysely'>} config - The configuration object for the database connection. * @returns None */ constructor(config: DbConfig<'kysely'>) { super(config) this.pgClient = this.dialectFactory(config) this.client = this.providerFactory(this.pgClient) if (config.readReplica) { this.pgReadClient = this.dialectFactory(config.readReplica) this.readClient = this.providerFactory(this.pgReadClient) } } /** * Override method that starts a new transaction using the provided client and read client. * @returns A Promise that resolves to a KyselyTransaction object for the specified database schema. */ public override async transaction(): Promise> { return KyselyTransactionImpl.newTransaction(this.client, this, this.readClient) } /** * Creates a database dialect based on the provided configuration. * @param {DbBaseConfig} config - The configuration object for the database connection. * @returns A database dialect instance based on the provided configuration. */ private dialectFactory(config: DbBaseConfig) { return new KyselyDatabase.kyselyPgProvider({ pool: new KyselyDatabase.pgProvider({ host: config.host, port: config.port, user: config.username, password: config.password, database: config.database, max: config.maxConnections, }), }) } /** * Creates a provider for interacting with a database using the specified Postgres dialect. * @param {PostgresDialect} dialect - The Postgres dialect to use for the database connection. * @returns A database provider for interacting with the database. */ private providerFactory(dialect: PostgresDialect) { return new KyselyDatabase.kyselyProvider({ dialect, plugins: [new CamelCasePlugin()], }) } }