diff --git a/jsr.json b/jsr.json index 99ff436..41b0ed5 100644 --- a/jsr.json +++ b/jsr.json @@ -9,6 +9,6 @@ "./sqlite": "./src/sqlite.ts", "./mysql": "./src/mysql.ts", "./postgres": "./src/postgres.ts", - "./driver": "./src/driver/jsr.ts" + "./driver": "./src/driver-jsr.ts" } } diff --git a/src/driver-jsr.ts b/src/driver-jsr.ts new file mode 100644 index 0000000..afa884d --- /dev/null +++ b/src/driver-jsr.ts @@ -0,0 +1 @@ +export {connect as '@db/sqlite'} from './driver/denodrivers-sqlite.ts' diff --git a/src/driver.ts b/src/driver.ts index e8013fe..75b2579 100644 --- a/src/driver.ts +++ b/src/driver.ts @@ -1,3 +1,7 @@ +export * from './driver-jsr.ts' +export {connect as 'better-sqlite3'} from './driver/better-sqlite3.ts' export {connect as 'bun:sqlite'} from './driver/bun-sqlite.ts' -export * from './driver/jsr.ts' -export * from './driver/npm.ts' +export {connect as 'mysql2'} from './driver/mysql2.ts' +export {connect as 'pg'} from './driver/pg.ts' +export {connect as '@electric-sql/pglite'} from './driver/pglite.ts' +export {connect as 'sql.js'} from './driver/sql.js.ts' diff --git a/src/driver/@electric-sql_pglite.ts b/src/driver/@electric-sql_pglite.ts deleted file mode 100644 index aeb8654..0000000 --- a/src/driver/@electric-sql_pglite.ts +++ /dev/null @@ -1,104 +0,0 @@ -import type {PGlite, Transaction} from '@electric-sql/pglite' -import {AsyncDatabase, type TransactionOptions} from '../core/Database.ts' -import type {AsyncDriver, AsyncStatement, BatchQuery} from '../core/Driver.ts' -import {postgresDialect} from '../postgres/dialect.ts' -import {postgresDiff} from '../postgres/diff.ts' -import {setTransaction} from '../postgres/transactions.ts' - -type Queryable = PGlite | Transaction - -class PreparedStatement implements AsyncStatement { - constructor( - private client: Queryable, - private sql: string - ) {} - - all(params: Array): Promise> { - return this.client - .query(this.sql, params, { - rowMode: 'object' - }) - .then(res => res.rows) - } - - async run(params: Array) { - await this.client.query(this.sql, params, { - rowMode: 'array' - }) - } - - get(params: Array): Promise { - return this.all(params).then(rows => rows[0] ?? null) - } - - values(params: Array): Promise>> { - return this.client - .query>(this.sql, params, { - rowMode: 'array' - }) - .then(res => res.rows) - } - - free() {} -} - -export class PGliteDriver implements AsyncDriver { - parsesJson = true - - constructor( - private client: Queryable, - private depth = 0 - ) {} - - async exec(query: string) { - await this.client.exec(query) - } - - close(): Promise { - if ('close' in this.client) { - return Promise.resolve() - // This fails currently - // return this.client.close() - } - throw new Error('Cannot close a transaction') - } - - prepare(sql: string): PreparedStatement { - return new PreparedStatement(this.client, sql) - } - - async batch(queries: Array): Promise>> { - const transact = async (tx: AsyncDriver) => { - const results = [] - for (const {sql, params} of queries) - results.push(await tx.prepare(sql).values(params)) - return results - } - if (this.depth > 0) return transact(this) - return this.transaction(transact, {}) - } - - async transaction( - run: (inner: AsyncDriver) => Promise, - options: TransactionOptions['postgres'] - ): Promise { - if (this.depth === 0 && 'transaction' in this.client) - return this.client.transaction(async (tx: Transaction) => { - await tx.query(setTransaction(options)) - return run(new PGliteDriver(tx, this.depth + 1)) - }) as Promise - await this.exec(`savepoint d${this.depth}`) - try { - const result = await run(new PGliteDriver(this.client, this.depth + 1)) - await this.exec(`release d${this.depth}`) - return result - } catch (error) { - await this.exec(`rollback to d${this.depth}`) - throw error - } - } -} - -export function connect(db: PGlite): AsyncDatabase<'postgres'> { - return new AsyncDatabase(new PGliteDriver(db), postgresDialect, postgresDiff) -} diff --git a/src/driver/@db_sqlite.ts b/src/driver/denodrivers-sqlite.ts similarity index 100% rename from src/driver/@db_sqlite.ts rename to src/driver/denodrivers-sqlite.ts diff --git a/src/driver/jsr.ts b/src/driver/jsr.ts deleted file mode 100644 index 4b8ae72..0000000 --- a/src/driver/jsr.ts +++ /dev/null @@ -1 +0,0 @@ -export {connect as '@db/sqlite'} from './@db_sqlite.ts' diff --git a/src/driver/npm.ts b/src/driver/npm.ts deleted file mode 100644 index 9d8a30f..0000000 --- a/src/driver/npm.ts +++ /dev/null @@ -1,5 +0,0 @@ -export {connect as '@electric-sql/pglite'} from './@electric-sql_pglite.ts' -export {connect as 'better-sqlite3'} from './better-sqlite3.ts' -export {connect as 'mysql2'} from './mysql2.ts' -export {connect as 'pg'} from './pg.ts' -export {connect as 'sql.js'} from './sql.js.ts' diff --git a/src/driver/pglite.ts b/src/driver/pglite.ts index d901b4d..aeb8654 100644 --- a/src/driver/pglite.ts +++ b/src/driver/pglite.ts @@ -1 +1,104 @@ -export * from './@electric-sql_pglite.ts' +import type {PGlite, Transaction} from '@electric-sql/pglite' +import {AsyncDatabase, type TransactionOptions} from '../core/Database.ts' +import type {AsyncDriver, AsyncStatement, BatchQuery} from '../core/Driver.ts' +import {postgresDialect} from '../postgres/dialect.ts' +import {postgresDiff} from '../postgres/diff.ts' +import {setTransaction} from '../postgres/transactions.ts' + +type Queryable = PGlite | Transaction + +class PreparedStatement implements AsyncStatement { + constructor( + private client: Queryable, + private sql: string + ) {} + + all(params: Array): Promise> { + return this.client + .query(this.sql, params, { + rowMode: 'object' + }) + .then(res => res.rows) + } + + async run(params: Array) { + await this.client.query(this.sql, params, { + rowMode: 'array' + }) + } + + get(params: Array): Promise { + return this.all(params).then(rows => rows[0] ?? null) + } + + values(params: Array): Promise>> { + return this.client + .query>(this.sql, params, { + rowMode: 'array' + }) + .then(res => res.rows) + } + + free() {} +} + +export class PGliteDriver implements AsyncDriver { + parsesJson = true + + constructor( + private client: Queryable, + private depth = 0 + ) {} + + async exec(query: string) { + await this.client.exec(query) + } + + close(): Promise { + if ('close' in this.client) { + return Promise.resolve() + // This fails currently + // return this.client.close() + } + throw new Error('Cannot close a transaction') + } + + prepare(sql: string): PreparedStatement { + return new PreparedStatement(this.client, sql) + } + + async batch(queries: Array): Promise>> { + const transact = async (tx: AsyncDriver) => { + const results = [] + for (const {sql, params} of queries) + results.push(await tx.prepare(sql).values(params)) + return results + } + if (this.depth > 0) return transact(this) + return this.transaction(transact, {}) + } + + async transaction( + run: (inner: AsyncDriver) => Promise, + options: TransactionOptions['postgres'] + ): Promise { + if (this.depth === 0 && 'transaction' in this.client) + return this.client.transaction(async (tx: Transaction) => { + await tx.query(setTransaction(options)) + return run(new PGliteDriver(tx, this.depth + 1)) + }) as Promise + await this.exec(`savepoint d${this.depth}`) + try { + const result = await run(new PGliteDriver(this.client, this.depth + 1)) + await this.exec(`release d${this.depth}`) + return result + } catch (error) { + await this.exec(`rollback to d${this.depth}`) + throw error + } + } +} + +export function connect(db: PGlite): AsyncDatabase<'postgres'> { + return new AsyncDatabase(new PGliteDriver(db), postgresDialect, postgresDiff) +}