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:
Matt Raymer
2025-05-25 23:09:53 -04:00
parent 75f6e99200
commit ee441d1aea
14 changed files with 56 additions and 1510 deletions

View File

@@ -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);
}
}

View File

@@ -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 || [];

View File

@@ -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;
}
}