import { Dialect } from './dialect/dialect.js' ; import { SchemaModule } from './schema/schema.js' ; import { DynamicModule } from './dynamic/dynamic.js' ; import { DefaultConnectionProvider } from './driver/default-connection-provider.js' ; import { QueryExecutor } from './query-executor/query-executor.js' ; import { QueryCreator , QueryCreatorProps } from './query-creator.js' ; import { KyselyPlugin } from './plugin/kysely-plugin.js' ; import { DefaultQueryExecutor } from './query-executor/default-query-executor.js' ; import { DatabaseIntrospector } from './dialect/database-introspector.js' ; import { freeze , isObject } from './util/object-utils.js' ; import { RuntimeDriver } from './driver/runtime-driver.js' ; import { SingleConnectionProvider } from './driver/single-connection-provider.js' ; import { Driver , IsolationLevel , TransactionSettings , TRANSACTION_ISOLATION_LEVELS , } from './driver/driver.js' ; import { preventAwait } from './util/prevent-await.js' ; import { DefaultParseContext , ParseContext } from './parser/parse-context.js' ; import { FunctionBuilder } from './query-builder/function-builder.js' ; import { Log , LogConfig } from './util/log.js' ; import { PRIVATE_ADAPTER } from './util/private-symbols.js' ; import { DialectAdapter } from './dialect/dialect-adapter.js' ; /**
 * The main Kysely class.
 *
 * You should create one instance of `Kysely` per database using the  Kysely * constructor. Each `Kysely` instance maintains it's own connection pool.
 *
 * ### Examples
 *
 * This example assumes your database has tables `person` and `pet`:
 *
 * ```ts
 * interface Person {
 *   id: number
 *   first_name: string
 *   last_name: string
 * }
 *
 * interface Pet {
 *   id: number
 *   owner_id: number
 *   name: string
 *   species 'cat' | 'dog'
 * }
 *
 * interface Database {
 *   person: Person,
 *   pet: Pet
 * }
 *
 * const db = new Kysely<Database>({
 *   dialect: new PostgresDialect({
 *     host: 'localhost',
 *     database: 'kysely_test',
 *   })
 * })
 * ```
 *
 *  typeParam export class Kysely < DB > extends QueryCreator < DB > { readonly #props : KyselyProps ; constructor ( args ) ; constructor ( args ) ; constructor ( args ) { let superProps ; let props ; if ( isKyselyProps ( args ) ) { superProps = { executor : args . executor , parseContext : args . parseContext } ; props = { ... args } ; } else { const dialect = args . dialect ; const driver = dialect . createDriver ( ) ; const compiler = dialect . createQueryCompiler ( ) ; const adapter = dialect . createAdapter ( ) ; const log = new Log ( args . log ?? [ ] ) ; const parseContext = new DefaultParseContext ( adapter ) ; const runtimeDriver = new RuntimeDriver ( driver , log ) ; const connectionProvider = new DefaultConnectionProvider ( runtimeDriver ) ; const executor = new DefaultQueryExecutor ( compiler , connectionProvider , args . plugins ?? [ ] ) ; superProps = { executor , parseContext } ; props = { config : args , executor , dialect , driver : runtimeDriver , parseContext , } ; } super ( superProps ) ; this . #props = freeze ( props ) ; } /**
     * Returns the  SchemaModule module for building database schema.
      get schema ( ) : SchemaModule { return new SchemaModule ( this . #props . executor ) ; } /**
     * Returns a the  DynamicModule module.
     *
     * The  DynamicModule module can be used to bypass strict typing and
     * passing in dynamic values for the queries.
      get dynamic ( ) : DynamicModule { return new DynamicModule ( ) ; } /**
     * Returns a  DatabaseIntrospector .
      get introspection ( ) : DatabaseIntrospector { return this . #props . dialect . createIntrospector ( this . withoutPlugins ( ) ) ; } /**
     * Returns a  FunctionBuilder that can be used to write type safe function
     * calls.
     *
     * ```ts
     * const { count } = db.fn
     *
     * await db.selectFrom('person')
     *   .innerJoin('pet', 'pet.owner_id', 'person.id')
     *   .select([
     *     'person.id',
     *     count('pet.id').as('pet_count')
     *   ])
     *   .groupBy('person.id')
     *   .having(count('pet.id'), '>', 10)
     *   .execute()
     * ```
     *
     * The generated SQL (PostgreSQL):
     *
     * ```sql
     * select "person"."id", count("pet"."id") as "pet_count"
     * from "person"
     * inner join "pet" on "pet"."owner_id" = "person"."id"
     * group by "person"."id"
     * having count("pet"."id") > $1
     * ```
      get fn ( ) : FunctionBuilder < DB , keyof DB > { return new FunctionBuilder ( { executor : this . #props . executor } ) ; } /**
     * Creates a  TransactionBuilder that can be used to run queries inside a transaction.
     *
     * The returned  TransactionBuilder can be used to configure the transaction. The
     *  TransactionBuilder . execute method can then be called to run the transaction.
     *  TransactionBuilder . execute takes a function that is run inside the
     * transaction. If the function throws, the transaction is rolled back. Otherwise
     * the transaction is committed.
     *
     * The callback function passed to the  TransactionBuilder . execute * method gets the transaction object as its only argument. The transaction is
     * of type  Transaction which inherits  Kysely . Any query
     * started through the transaction object is executed inside the transaction.
     *
     * ### Examples
     *
     * ```ts
     * const catto = await db.transaction().execute(async (trx) => {
     *   const jennifer = await trx.insertInto('person')
     *     .values({
     *       first_name: 'Jennifer',
     *       last_name: 'Aniston',
     *     })
     *     .returning('id')
     *     .executeTakeFirstOrThrow()
     *
     *   await someFunction(trx, jennifer)
     *
     *   return await trx.insertInto('pet')
     *     .values({
     *       user_id: jennifer.id,
     *       name: 'Catto',
     *       species: 'cat'
     *     })
     *     .returning('*')
     *     .executeTakeFirst()
     * })
     * ```
     *
     * Setting the isolation level:
     *
     * ```ts
     * await db
     *   .transaction()
     *   .setIsolationLevel('serializable')
     *   .execute(async (trx) => {
     *     await doStuff(trx)
     *   })
     * ```
      transaction ( ) { return new TransactionBuilder ( { ... this . #props } ) ; } /**
     * Provides a kysely instance bound to a single database connection.
     *
     * ### Examples
     *
     * ```ts
     * await db
     *   .connection()
     *   .execute(async (db) => {
     *     // `db` is an instance of `Kysely` that's bound to a single
     *     // database connection. All queries executed through `db` use
     *     // the same connection.
     *     await doStuff(db)
     *   })
     * ```
     */ connection ( ) { return new ConnectionBuilder ( { ... this . #props } ) ; } /**
     * Returns a copy of this Kysely instance with the given plugin installed.
     */ withPlugin ( plugin ) { return new Kysely ( { ... this . #props , executor : this . #props . executor . withPlugin ( plugin ) , } ) ; } /**
     * Returns a copy of this Kysely instance without any plugins.
     */ withoutPlugins ( ) { return new Kysely ( { ... this . #props , executor : this . #props . executor . withoutPlugins ( ) , } ) ; } example withTables < T extends Record < string , Record < string , any > > > ( ) { return new Kysely ( { ... this . #props } ) ; } /**
     * Releases all resources and disconnects from the database.
     *
     * You need to call this when you are done using the `Kysely` instance.
     */ async destroy ( ) { await this . #props . driver . destroy ( ) ; } /**
     * Returns true if this `Kysely` instance is a transaction.
     *
     * You can also use `db instanceof Transaction`.
     */ get isTransaction ( ) : boolean { return false ; } internal private get [ PRIVATE_ADAPTER ] ( ) : DialectAdapter { return this . #props . parseContext . adapter ; } } export class Transaction < DB > extends Kysely < DB > { readonly #props : KyselyProps ; constructor ( props ) { super ( props ) ; this . #props = props ; } get isTransaction ( ) : true { return true ; } transaction ( ) { throw new Error ( 'calling the transaction method for a Transaction is not supported' ) ; } connection ( ) { throw new Error ( 'calling the connection method for a Transaction is not supported' ) ; } async destroy ( ) { throw new Error ( 'calling the destroy method for a Transaction is not supported' ) ; } override withPlugin ( plugin ) { return new Transaction ( { ... this . #props , executor : this . #props . executor . withPlugin ( plugin ) , } ) ; } override withoutPlugins ( ) { return new Transaction ( { ... this . #props , executor : this . #props . executor . withoutPlugins ( ) , } ) ; } override withTables < T extends Record < string , Record < string , any > > > ( ) { return new Transaction ( { ... this . #props } ) ; } } export interface KyselyProps { readonly config : KyselyConfig ; readonly driver : Driver ; readonly executor : QueryExecutor ; readonly dialect : Dialect ; readonly parseContext : ParseContext ; } export function isKyselyProps ( obj ) { return ( isObject ( obj ) && isObject ( obj . config ) && isObject ( obj . driver ) && isObject ( obj . executor ) && isObject ( obj . dialect ) && isObject ( obj . parseContext ) ) ; } export interface KyselyConfig { readonly dialect : Dialect ; readonly plugins ? : KyselyPlugin [ ] ; /**
     * A list of log levels to log or a custom logger function.
     *
     * Currently there's only two levels: `query` and `error`.
     * This will be expanded based on user feedback later.
     *
     * ### Examples
     *
     * ```ts
     * const db = new Kysely<Database>({
     *   dialect: new PostgresDialect(postgresConfig),
     *   log: ['query', 'error']
     * })
     * ```
     *
     * ```ts
     * const db = new Kysely<Database>({
     *   dialect: new PostgresDialect(postgresConfig),
     *   log(event): void {
     *     if (event.level === 'query') {
     *       console.log(event.query.sql)
     *       console.log(event.query.parameters)
     *     }
     *   }
     * })
     * ```
     */ readonly log ? : LogConfig ; } export class ConnectionBuilder < DB > { readonly #props : ConnectionBuilderProps ; constructor ( props ) { this . #props = freeze ( props ) ; } async execute < T > ( callback ) { const connection = await this . #props . driver . acquireConnection ( ) ; const connectionProvider = new SingleConnectionProvider ( connection ) ; const transaction = new Kysely < DB > ( { ... this . #props , executor : this . #props . executor . withConnectionProvider ( connectionProvider ) , } ) ; try { return await callback ( transaction ) ; } finally { await this . #props . driver . releaseConnection ( connection ) ; } } } interface ConnectionBuilderProps extends KyselyProps { } preventAwait ( ConnectionBuilder , "don't await ConnectionBuilder instances directly. To execute the query you need to call the `execute` method" ) ; export class TransactionBuilder < DB > { readonly #props : TransactionBuilderProps ; constructor ( props ) { this . #props = freeze ( props ) ; } setIsolationLevel ( isolationLevel ) { return new TransactionBuilder ( { ... this . #props , isolationLevel , } ) ; } async execute < T > ( callback ) { const { isolationLevel , ... kyselyProps } = this . #props ; const settings = { isolationLevel } ; validateTransactionSettings ( settings ) ; const connection = await this . #props . driver . acquireConnection ( ) ; const connectionProvider = new SingleConnectionProvider ( connection ) ; const transaction = new Transaction < DB > ( { ... kyselyProps , executor : this . #props . executor . withConnectionProvider ( connectionProvider ) , } ) ; try { await this . #props . driver . beginTransaction ( connection , settings ) ; const result = await callback ( transaction ) ; await this . #props . driver . commitTransaction ( connection ) ; return result ; } catch ( error ) { await this . #props . driver . rollbackTransaction ( connection ) ; throw error ; } finally { await this . #props . driver . releaseConnection ( connection ) ; } } } interface TransactionBuilderProps extends KyselyProps { readonly isolationLevel ? : IsolationLevel ; } preventAwait ( TransactionBuilder , "don't await TransactionBuilder instances directly. To execute the transaction you need to call the `execute` method" ) ; function validateTransactionSettings ( settings ) { if ( settings . isolationLevel && ! TRANSACTION_ISOLATION_LEVELS . includes ( settings . isolationLevel ) ) { throw new Error ( `invalid transaction isolation level ${ settings . isolationLevel }` ) ; } }