diff --git a/packages/core/src/storage/driver.ts b/packages/core/src/storage/driver.ts index 2358e01a..496aa975 100644 --- a/packages/core/src/storage/driver.ts +++ b/packages/core/src/storage/driver.ts @@ -55,7 +55,7 @@ export abstract class BaseStorageDriver implements IStorageDriver { protected _log!: Logger setup(log: Logger): void { - this._log = log + this._log = log.create('sqlite') } protected get loaded(): boolean { diff --git a/packages/deno/src/sqlite/driver.ts b/packages/deno/src/sqlite/driver.ts index fd58c458..5fe03fdd 100644 --- a/packages/deno/src/sqlite/driver.ts +++ b/packages/deno/src/sqlite/driver.ts @@ -1,4 +1,9 @@ -import { BaseSqliteStorageDriver, ISqliteDatabase } from '@mtcute/core' +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { BaseSqliteStorageDriver, ISqliteDatabase, ISqliteStatement } from '@mtcute/core' + +import { Logger } from '../utils.js' + +import type { BindParameters, Database as TDatabase, Statement as TStatement } from '@db/sqlite' let Database: typeof import('@db/sqlite').Database @@ -16,6 +21,66 @@ export interface SqliteStorageDriverOptions { disableWal?: boolean } +function replaceBigintsWithNumber(obj?: object): object | undefined { + if (!obj) return obj + + for (const [key, value] of Object.entries(obj)) { + if (typeof value === 'bigint') { + (obj as any)[key] = Number(value) + } + } + + return obj +} + +class WrappedStatement implements ISqliteStatement { + constructor( + private stmt: TStatement, + private sql: string, + private log: Logger, + ) {} + + run(...params: unknown[]): void { + this.log.verbose('RUN %s %o', this.sql, params) + this.stmt.run(...(params as BindParameters[])) + } + + get(...params: unknown[]): unknown { + this.log.verbose('GET %s %o', this.sql, params) + + return replaceBigintsWithNumber(this.stmt.get(...(params as BindParameters[]))) + } + + all(...params: unknown[]): unknown[] { + this.log.verbose('ALL %s %o', this.sql, params) + + return this.stmt.all(...(params as BindParameters[])).map(replaceBigintsWithNumber) + } +} + +class WrappedDatabase implements ISqliteDatabase { + constructor( + private db: TDatabase, + private log: Logger, + ) {} + + transaction(fn: any): any { + return this.db.transaction(fn) + } + + prepare(sql: string): ISqliteStatement { + return new WrappedStatement(this.db.prepare(sql), sql, this.log) + } + + exec(sql: string): void { + this.db.exec(sql) + } + + close(): void { + this.db.close() + } +} + export class SqliteStorageDriver extends BaseSqliteStorageDriver { constructor( readonly filename = ':memory:', @@ -34,14 +99,15 @@ export class SqliteStorageDriver extends BaseSqliteStorageDriver { } _createDatabase(): ISqliteDatabase { - const db = new Database(this.filename, { - int64: true, - }) + // non-int64 mode trims numbers to 32 bits, and we don't want that + // but int64 mode returns all numbers as bigints, but mtcute expects them + // as numbers, so we need to convert them... thx deno + const db = new Database(this.filename, { int64: true }) if (!this.params?.disableWal) { db.exec('PRAGMA journal_mode = WAL;') } - return db as ISqliteDatabase + return new WrappedDatabase(db, this._log) } }