forked from akai/readest
feat(database): add database service abstraction with libsql/turso backend (#3472)
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { Database, QueryResult } from 'tauri-plugin-libsql';
|
||||
import { DatabaseService, DatabaseExecResult, DatabaseRow } from '@/types/database';
|
||||
|
||||
export class NativeDatabaseService implements DatabaseService {
|
||||
private db: Database;
|
||||
|
||||
private constructor(db: Database) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
static async open(path: string): Promise<NativeDatabaseService> {
|
||||
const db = await Database.load(path);
|
||||
return new NativeDatabaseService(db);
|
||||
}
|
||||
|
||||
async execute(sql: string, params: unknown[] = []): Promise<DatabaseExecResult> {
|
||||
const result: QueryResult = await this.db.execute(sql, params);
|
||||
return {
|
||||
rowsAffected: result.rowsAffected,
|
||||
lastInsertId: result.lastInsertId,
|
||||
};
|
||||
}
|
||||
|
||||
async select<T extends DatabaseRow = DatabaseRow>(
|
||||
sql: string,
|
||||
params: unknown[] = [],
|
||||
): Promise<T[]> {
|
||||
return await this.db.select<T[]>(sql, params);
|
||||
}
|
||||
|
||||
async batch(statements: string[]): Promise<void> {
|
||||
await this.db.batch(statements);
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
await this.db.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { DatabaseService, DatabaseExecResult, DatabaseRow } from '@/types/database';
|
||||
|
||||
interface TursoRunResult {
|
||||
changes: number;
|
||||
lastInsertRowid: number;
|
||||
}
|
||||
|
||||
interface TursoStatement {
|
||||
run(...params: unknown[]): Promise<TursoRunResult>;
|
||||
all(...params: unknown[]): Promise<Record<string, unknown>[]>;
|
||||
}
|
||||
|
||||
interface TursoDatabase {
|
||||
prepare(sql: string): TursoStatement;
|
||||
exec(sql: string): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* DatabaseService implementation backed by @tursodatabase/database (Node.js native).
|
||||
* Uses the same libsql engine and API surface as the browser-based
|
||||
* @tursodatabase/database-wasm used by WebDatabaseService.
|
||||
*/
|
||||
export class NodeDatabaseService implements DatabaseService {
|
||||
private db: TursoDatabase;
|
||||
|
||||
private constructor(db: TursoDatabase) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
static async open(path: string): Promise<NodeDatabaseService> {
|
||||
const mod = await import('@tursodatabase/database');
|
||||
const db = (await mod.connect(path)) as unknown as TursoDatabase;
|
||||
return new NodeDatabaseService(db);
|
||||
}
|
||||
|
||||
async execute(sql: string, params: unknown[] = []): Promise<DatabaseExecResult> {
|
||||
const stmt = this.db.prepare(sql);
|
||||
const result = await stmt.run(...params);
|
||||
return {
|
||||
rowsAffected: result.changes,
|
||||
lastInsertId: Number(result.lastInsertRowid),
|
||||
};
|
||||
}
|
||||
|
||||
async select<T extends DatabaseRow = DatabaseRow>(
|
||||
sql: string,
|
||||
params: unknown[] = [],
|
||||
): Promise<T[]> {
|
||||
const stmt = this.db.prepare(sql);
|
||||
const rows = await stmt.all(...params);
|
||||
return rows as T[];
|
||||
}
|
||||
|
||||
async batch(statements: string[]): Promise<void> {
|
||||
await this.db.exec('BEGIN');
|
||||
try {
|
||||
for (const sql of statements) {
|
||||
await this.db.exec(sql);
|
||||
}
|
||||
await this.db.exec('COMMIT');
|
||||
} catch (error: unknown) {
|
||||
await this.db.exec('ROLLBACK');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
await this.db.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { DatabaseService, DatabaseExecResult, DatabaseRow } from '@/types/database';
|
||||
|
||||
interface WasmRunResult {
|
||||
changes: number;
|
||||
lastInsertRowid: number;
|
||||
}
|
||||
|
||||
interface WasmStatement {
|
||||
run(...params: unknown[]): Promise<WasmRunResult>;
|
||||
all(...params: unknown[]): Promise<Record<string, unknown>[]>;
|
||||
}
|
||||
|
||||
interface WasmDatabase {
|
||||
prepare(sql: string): WasmStatement;
|
||||
exec(sql: string): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
export class WebDatabaseService implements DatabaseService {
|
||||
private db: WasmDatabase;
|
||||
|
||||
private constructor(db: WasmDatabase) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
static async open(path: string): Promise<WebDatabaseService> {
|
||||
const mod = await import('@tursodatabase/database-wasm');
|
||||
const db = (await mod.connect(path)) as unknown as WasmDatabase;
|
||||
return new WebDatabaseService(db);
|
||||
}
|
||||
|
||||
async execute(sql: string, params: unknown[] = []): Promise<DatabaseExecResult> {
|
||||
const stmt = this.db.prepare(sql);
|
||||
const result = await stmt.run(...params);
|
||||
return {
|
||||
rowsAffected: result.changes,
|
||||
lastInsertId: Number(result.lastInsertRowid),
|
||||
};
|
||||
}
|
||||
|
||||
async select<T extends DatabaseRow = DatabaseRow>(
|
||||
sql: string,
|
||||
params: unknown[] = [],
|
||||
): Promise<T[]> {
|
||||
const stmt = this.db.prepare(sql);
|
||||
const rows = await stmt.all(...params);
|
||||
return rows as T[];
|
||||
}
|
||||
|
||||
async batch(statements: string[]): Promise<void> {
|
||||
await this.db.exec('BEGIN');
|
||||
try {
|
||||
for (const sql of statements) {
|
||||
await this.db.exec(sql);
|
||||
}
|
||||
await this.db.exec('COMMIT');
|
||||
} catch (error: unknown) {
|
||||
await this.db.exec('ROLLBACK');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
await this.db.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user