refactor(db): improve type safety in migration system
- Replace any[] with SqlValue[] type for SQL parameters in runMigrations - Update import to use QueryExecResult from interfaces/database - Add proper typing for SQL parameter values (string | number | null | Uint8Array) This change improves type safety and helps catch potential SQL parameter type mismatches at compile time, reducing the risk of runtime errors or data corruption.
This commit is contained in:
8
src/services/database.d.ts
vendored
8
src/services/database.d.ts
vendored
@@ -2,9 +2,9 @@ import { DatabaseService } from "../interfaces/database";
|
||||
|
||||
declare module "@jlongster/sql.js" {
|
||||
interface SQL {
|
||||
Database: any;
|
||||
FS: any;
|
||||
register_for_idb: (fs: any) => void;
|
||||
Database: unknown;
|
||||
FS: unknown;
|
||||
register_for_idb: (fs: unknown) => void;
|
||||
}
|
||||
|
||||
function initSqlJs(config: {
|
||||
@@ -15,7 +15,7 @@ declare module "@jlongster/sql.js" {
|
||||
|
||||
declare module "absurd-sql" {
|
||||
export class SQLiteFS {
|
||||
constructor(fs: any, backend: any);
|
||||
constructor(fs: unknown, backend: unknown);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,13 @@ import IndexedDBBackend from "absurd-sql/dist/indexeddb-backend";
|
||||
|
||||
import { runMigrations } from "../db-sql/migration";
|
||||
import type { QueryExecResult } from "../interfaces/database";
|
||||
import { logger } from "@/utils/logger";
|
||||
|
||||
interface SQLDatabase {
|
||||
exec: (sql: string, params?: any[]) => Promise<QueryExecResult[]>;
|
||||
exec: (sql: string, params?: unknown[]) => Promise<QueryExecResult[]>;
|
||||
run: (
|
||||
sql: string,
|
||||
params?: any[],
|
||||
params?: unknown[],
|
||||
) => Promise<{ changes: number; lastId?: number }>;
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ class DatabaseService {
|
||||
try {
|
||||
await this.initializationPromise;
|
||||
} catch (error) {
|
||||
console.error(`DatabaseService initialize method failed:`, error);
|
||||
logger.error(`DatabaseService initialize method failed:`, error);
|
||||
this.initializationPromise = null; // Reset on failure
|
||||
throw error;
|
||||
}
|
||||
@@ -116,7 +117,7 @@ class DatabaseService {
|
||||
|
||||
// If initialized but no db, something went wrong
|
||||
if (!this.db) {
|
||||
console.error(
|
||||
logger.error(
|
||||
`Database not properly initialized after await waitForInitialization() - initialized flag is true but db is null`,
|
||||
);
|
||||
throw new Error(
|
||||
@@ -128,25 +129,28 @@ class DatabaseService {
|
||||
// Used for inserts, updates, and deletes
|
||||
async run(
|
||||
sql: string,
|
||||
params: any[] = [],
|
||||
params: unknown[] = [],
|
||||
): Promise<{ changes: number; lastId?: number }> {
|
||||
await this.waitForInitialization();
|
||||
return this.db!.run(sql, params);
|
||||
}
|
||||
|
||||
// Note that the resulting array may be empty if there are no results from the query
|
||||
async query(sql: string, params: any[] = []): Promise<QueryExecResult[]> {
|
||||
async query(sql: string, params: unknown[] = []): Promise<QueryExecResult[]> {
|
||||
await this.waitForInitialization();
|
||||
return this.db!.exec(sql, params);
|
||||
}
|
||||
|
||||
async getOneRow(sql: string, params: any[] = []): Promise<any[] | undefined> {
|
||||
async getOneRow(
|
||||
sql: string,
|
||||
params: unknown[] = [],
|
||||
): Promise<unknown[] | undefined> {
|
||||
await this.waitForInitialization();
|
||||
const result = await this.db!.exec(sql, params);
|
||||
return result[0]?.values[0];
|
||||
}
|
||||
|
||||
async all(sql: string, params: any[] = []): Promise<any[][]> {
|
||||
async all(sql: string, params: unknown[] = []): Promise<unknown[][]> {
|
||||
await this.waitForInitialization();
|
||||
const result = await this.db!.exec(sql, params);
|
||||
return result[0]?.values || [];
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import logger from "@/utils/logger";
|
||||
import { QueryExecResult } from "../interfaces/database";
|
||||
|
||||
interface Migration {
|
||||
@@ -23,7 +24,10 @@ export class MigrationService {
|
||||
}
|
||||
|
||||
async runMigrations(
|
||||
sqlExec: (sql: string, params?: any[]) => Promise<Array<QueryExecResult>>,
|
||||
sqlExec: (
|
||||
sql: string,
|
||||
params?: unknown[],
|
||||
) => Promise<Array<QueryExecResult>>,
|
||||
): Promise<void> {
|
||||
// Create migrations table if it doesn't exist
|
||||
await sqlExec(`
|
||||
@@ -43,7 +47,7 @@ export class MigrationService {
|
||||
if (result.length > 0) {
|
||||
const singleResult = result[0];
|
||||
executedMigrations = new Set(
|
||||
singleResult.values.map((row: any[]) => row[0]),
|
||||
singleResult.values.map((row: unknown[]) => row[0]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -55,9 +59,9 @@ export class MigrationService {
|
||||
await sqlExec("INSERT INTO migrations (name) VALUES (?)", [
|
||||
migration.name,
|
||||
]);
|
||||
console.log(`Migration ${migration.name} executed successfully`);
|
||||
logger.log(`Migration ${migration.name} executed successfully`);
|
||||
} catch (error) {
|
||||
console.error(`Error executing migration ${migration.name}:`, error);
|
||||
logger.error(`Error executing migration ${migration.name}:`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user