/* oxlint-disable */ import { Effect } from "effect" import type { SqlError } from "effect/unstable/sql/SqlError" import type { EffectCacheShape } from "drizzle-orm/cache/core/cache-effect" import type { MutationOption } from "drizzle-orm/cache/core/cache" import type { QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" import { entityKind } from "drizzle-orm/entity" import type { TypedQueryBuilder } from "drizzle-orm/query-builders/query-builder" import type { AnyRelations, EmptyRelations } from "drizzle-orm/relations" import { SelectionProxyHandler } from "drizzle-orm/selection-proxy" import { type ColumnsSelection, type SQL, sql, type SQLWrapper } from "drizzle-orm/sql/sql" import type { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core/dialect" import { QueryBuilder } from "drizzle-orm/sqlite-core/query-builders/query-builder" import type { SelectedFields } from "drizzle-orm/sqlite-core/query-builders/select.types" import type { SQLiteTransactionConfig } from "drizzle-orm/sqlite-core/session" import type { SQLiteTable } from "drizzle-orm/sqlite-core/table" import type { SQLiteViewBase } from "drizzle-orm/sqlite-core/view-base" import { WithSubquery } from "drizzle-orm/subquery" import type { WithBuilder } from "drizzle-orm/sqlite-core/subquery" import { SQLiteEffectCountBuilder } from "./count" import { SQLiteEffectDeleteBase } from "./delete" import { SQLiteEffectInsertBuilder } from "./insert" import { SQLiteEffectRelationalQueryBuilder } from "./query" import { SQLiteEffectRaw } from "./raw" import { SQLiteEffectSelectBuilder } from "./select" import type { SQLiteEffectSelectBase } from "./select" import type { SQLiteEffectSession, SQLiteEffectTransaction } from "./session" import { SQLiteEffectUpdateBuilder } from "./update" export class SQLiteEffectDatabase< TEffectHKT extends QueryEffectHKTBase, TRunResult, TRelations extends AnyRelations = EmptyRelations, > { static readonly [entityKind]: string = "SQLiteEffectDatabase" declare readonly _: { readonly relations: TRelations readonly session: SQLiteEffectSession } query: { [K in keyof TRelations]: SQLiteEffectRelationalQueryBuilder } constructor( /** @internal */ readonly dialect: SQLiteAsyncDialect, /** @internal */ readonly session: SQLiteEffectSession, relations: TRelations, readonly rowModeRQB?: boolean, readonly forbidJsonb?: boolean, ) { this._ = { relations, session, } this.query = {} as (typeof this)["query"] for (const [tableName, relation] of Object.entries(relations)) { ;(this.query as SQLiteEffectDatabase["query"])[tableName] = new SQLiteEffectRelationalQueryBuilder( relations, relations[relation.name]!.table as SQLiteTable, relation, dialect, session, rowModeRQB, forbidJsonb, ) } this.$cache = { invalidate: (_params: MutationOption) => Effect.void, } } $with: WithBuilder = (alias: string, selection?: ColumnsSelection) => { const self = this const as = ( qb: | TypedQueryBuilder | SQL | ((qb: QueryBuilder) => TypedQueryBuilder | SQL), ) => { if (typeof qb === "function") { qb = qb(new QueryBuilder(self.dialect)) } return new Proxy( new WithSubquery( qb.getSQL(), selection ?? (("getSelectedFields" in qb ? ((qb as { getSelectedFields(): SelectedFields | undefined }).getSelectedFields() ?? {}) : {}) as SelectedFields), alias, true, ), new SelectionProxyHandler({ alias, sqlAliasedBehavior: "alias", sqlBehavior: "error" }), ) } return { as } } $cache: { invalidate: EffectCacheShape["onMutate"] } $count(source: SQLiteTable | SQLiteViewBase | SQL | SQLWrapper, filters?: SQL) { return new SQLiteEffectCountBuilder({ source, filters, session: this.session }) } with(...queries: WithSubquery[]) { const self = this function select(): SQLiteEffectSelectBuilder function select( fields: TSelection, ): SQLiteEffectSelectBuilder function select( fields?: SelectedFields, ): SQLiteEffectSelectBuilder { return new SQLiteEffectSelectBuilder({ fields: fields ?? undefined, session: self.session, dialect: self.dialect, withList: queries, }) } function selectDistinct(): SQLiteEffectSelectBuilder function selectDistinct( fields: TSelection, ): SQLiteEffectSelectBuilder function selectDistinct( fields?: SelectedFields, ): SQLiteEffectSelectBuilder { return new SQLiteEffectSelectBuilder({ fields: fields ?? undefined, session: self.session, dialect: self.dialect, withList: queries, distinct: true, }) } function update( table: TTable, ): SQLiteEffectUpdateBuilder { return new SQLiteEffectUpdateBuilder(table, self.session, self.dialect, queries) } function insert( into: TTable, ): SQLiteEffectInsertBuilder { return new SQLiteEffectInsertBuilder(into, self.session, self.dialect, queries) } function delete_( from: TTable, ): SQLiteEffectDeleteBase { return new SQLiteEffectDeleteBase(from, self.session, self.dialect, queries) } return { select, selectDistinct, update, insert, delete: delete_ } } select(): SQLiteEffectSelectBuilder select( fields: TSelection, ): SQLiteEffectSelectBuilder select(fields?: SelectedFields): SQLiteEffectSelectBuilder { return new SQLiteEffectSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect }) } selectDistinct(): SQLiteEffectSelectBuilder selectDistinct( fields: TSelection, ): SQLiteEffectSelectBuilder selectDistinct( fields?: SelectedFields, ): SQLiteEffectSelectBuilder { return new SQLiteEffectSelectBuilder({ fields: fields ?? undefined, session: this.session, dialect: this.dialect, distinct: true, }) } update(table: TTable): SQLiteEffectUpdateBuilder { return new SQLiteEffectUpdateBuilder(table, this.session, this.dialect) } insert(into: TTable): SQLiteEffectInsertBuilder { return new SQLiteEffectInsertBuilder(into, this.session, this.dialect) } delete( from: TTable, ): SQLiteEffectDeleteBase { return new SQLiteEffectDeleteBase(from, this.session, this.dialect) } private raw( query: SQLWrapper | string, action: "all" | "get" | "run" | "values", execute: (query: SQL) => Effect.Effect, ): SQLiteEffectRaw { const sequel = typeof query === "string" ? sql.raw(query) : query.getSQL() return new SQLiteEffectRaw( () => execute(sequel), () => sequel, action, this.dialect, (result) => result, ) } run(query: SQLWrapper | string): SQLiteEffectRaw { return this.raw(query, "run", (sequel) => this.session.run(sequel)) } all(query: SQLWrapper | string): SQLiteEffectRaw { return this.raw(query, "all", (sequel) => this.session.all(sequel)) } get(query: SQLWrapper | string): SQLiteEffectRaw { return this.raw(query, "get", (sequel) => this.session.get(sequel)) } values(query: SQLWrapper | string): SQLiteEffectRaw { return this.raw(query, "values", (sequel) => this.session.values(sequel)) } transaction: ( transaction: (tx: SQLiteEffectTransaction) => Effect.Effect, config?: SQLiteTransactionConfig, ) => Effect.Effect = (tx, config) => this.session.transaction(tx, config) } export type SQLiteEffectWithReplicas = Q & { $primary: Q; $replicas: Q[] } export const withReplicas = < TEffectHKT extends QueryEffectHKTBase, TRunResult, TRelations extends AnyRelations, Q extends SQLiteEffectDatabase, >( primary: Q, replicas: [Q, ...Q[]], getReplica: (replicas: Q[]) => Q = () => replicas[Math.floor(Math.random() * replicas.length)]!, ): SQLiteEffectWithReplicas => { const select: Q["select"] = (...args: []) => getReplica(replicas).select(...args) const selectDistinct: Q["selectDistinct"] = (...args: []) => getReplica(replicas).selectDistinct(...args) const $count: Q["$count"] = (...args: [any]) => getReplica(replicas).$count(...args) const _with: Q["with"] = (...args: []) => getReplica(replicas).with(...args) const $with = ((...args: [string] | [string, ColumnsSelection]) => args.length === 1 ? getReplica(replicas).$with(args[0]) : getReplica(replicas).$with(args[0], args[1])) as Q["$with"] const update: Q["update"] = (...args: [any]) => primary.update(...args) const insert: Q["insert"] = (...args: [any]) => primary.insert(...args) const $delete: Q["delete"] = (...args: [any]) => primary.delete(...args) const run: Q["run"] = (...args: [any]) => primary.run(...args) const all: Q["all"] = (...args: [any]) => primary.all(...args) const get: Q["get"] = (...args: [any]) => primary.get(...args) const values: Q["values"] = (...args: [any]) => primary.values(...args) const transaction: Q["transaction"] = (...args: [any]) => primary.transaction(...args) return { ...primary, update, insert, delete: $delete, run, all, get, values, transaction, $primary: primary, $replicas: replicas, select, selectDistinct, $count, $with, with: _with, get query() { return getReplica(replicas).query }, } } export type AnySQLiteEffectDatabase = SQLiteEffectDatabase export type AnySQLiteEffectSelectBase = SQLiteEffectSelectBase