import { CompiledQuery, SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler, } from 'kysely'; import type { DatabaseConnection, Dialect, Driver, QueryResult } from 'kysely'; import { SQLocal } from '../index.js'; import type { Transaction } from '../types.js'; import { convertRowsToObjects } from '../lib/convert-rows-to-objects.js'; import { sqlTag } from '../lib/sql-tag.js'; /** * A subclass of the `SQLocal` client that provides an additional property * for using SQLocal as a dialect for the Kysely query builder. * @see {@link https://sqlocal.dev/kysely/setup} */ export class SQLocalKysely extends SQLocal { /** * A Kysely dialect that implements the interface needed for * Kysely to interact with databases through SQLocal. * @see {@link https://sqlocal.dev/kysely/setup} */ dialect: Dialect = { createAdapter: () => new SqliteAdapter(), createDriver: () => new SQLocalKyselyDriver(this), createIntrospector: (db) => new SqliteIntrospector(db), createQueryCompiler: () => new SqliteQueryCompiler(), }; } class SQLocalKyselyDriver implements Driver { constructor(private client: SQLocalKysely) {} async init(): Promise {} async acquireConnection(): Promise { return new SQLocalKyselyConnection(this.client); } async releaseConnection(): Promise {} async beginTransaction(connection: SQLocalKyselyConnection): Promise { connection.transaction = await this.client.beginTransaction(); } async commitTransaction(connection: SQLocalKyselyConnection): Promise { await connection.transaction?.commit(); connection.transaction = null; } async rollbackTransaction( connection: SQLocalKyselyConnection ): Promise { await connection.transaction?.rollback(); connection.transaction = null; } async destroy(): Promise { await this.client.destroy(); } } class SQLocalKyselyConnection implements DatabaseConnection { transaction: Transaction | null = null; constructor(private client: SQLocalKysely) {} async executeQuery( query: CompiledQuery ): Promise> { let rows; let affectedRows: bigint | undefined; if (this.transaction === null) { const statement = sqlTag(query.sql, query.parameters); const result = await this.client.exec( statement.sql, statement.params, 'all' ); rows = convertRowsToObjects(result.rows, result.columns); affectedRows = result.numAffectedRows; } else { rows = await this.transaction.query(query); affectedRows = this.transaction.lastAffectedRows; } return { rows: rows as Result[], numAffectedRows: affectedRows, }; } async *streamQuery(): AsyncGenerator { throw new Error('SQLite3 does not support streaming.'); } }