update to sqlite database WIP

This commit is contained in:
DocNR 2025-02-04 17:50:40 -05:00
parent 00a8157c7c
commit 855c034a35
3 changed files with 108 additions and 178 deletions

View File

@ -1,89 +1,24 @@
// types/sqlite.ts // types/sqlite.ts
// Database interfaces export interface SQLiteRow {
export interface SQLite { [key: string]: any;
rows: { }
_array: any[];
length: number; export interface SQLiteResult<T = SQLiteRow> {
item: (idx: number) => any; rows: {
}; _array: T[];
rowsAffected: number; length: number;
insertId?: number; item: (idx: number) => T;
} };
rowsAffected: number;
// Transaction interfaces insertId?: number;
export interface SQLiteCallback { }
(transaction: SQLTransaction, resultSet: SQLite): void;
} export interface SQLiteError extends Error {
code?: number;
export interface SQLErrorCallback { }
(transaction: SQLTransaction, error: Error): boolean;
} export interface SQLiteStatement {
executeSync<T>(params?: any[]): T[] | null;
export interface SQLTransaction { finalizeSync(): void;
executeSql: ( }
sqlStatement: string,
args?: (string | number | null)[],
callback?: SQLiteCallback,
errorCallback?: SQLErrorCallback
) => void;
}
// Database error interfaces
export interface SQLError extends Error {
code?: number;
}
// Database open options
export interface SQLiteOpenOptions {
enableChangeListener?: boolean;
useNewConnection?: boolean;
}
// Result interfaces
export interface SQLiteRunResult {
insertId: number;
rowsAffected: number;
}
export interface SQLiteRow {
[key: string]: any;
}
export interface SQLiteResultSet {
insertId?: number;
rowsAffected: number;
rows: {
length: number;
_array: SQLiteRow[];
item: (index: number) => SQLiteRow;
};
}
// Transaction callbacks
export interface TransactionCallback {
(tx: SQLTransaction): void;
}
export interface TransactionErrorCallback {
(error: SQLError): void;
}
export interface TransactionSuccessCallback {
(): void;
}
// Database static type
export interface Database {
transaction(
callback: TransactionCallback,
error?: TransactionErrorCallback,
success?: TransactionSuccessCallback
): void;
readTransaction(
callback: TransactionCallback,
error?: TransactionErrorCallback,
success?: TransactionSuccessCallback
): void;
closeAsync(): Promise<void>;
}

View File

@ -1,119 +1,105 @@
// utils/db/db-service.ts // utils/db/db-service.ts
import * as SQLite from 'expo-sqlite';
import { import {
SQLite as SQLiteResult, openDatabaseSync,
SQLTransaction, SQLiteDatabase
SQLiteCallback, } from 'expo-sqlite';
SQLErrorCallback, import {
SQLError, SQLiteResult,
TransactionCallback, SQLiteError,
TransactionErrorCallback, SQLiteRow
TransactionSuccessCallback
} from '@/types/sqlite'; } from '@/types/sqlite';
export class DbService { export class DbService {
private db: SQLite.SQLiteDatabase; private db: SQLiteDatabase | null = null;
constructor(dbName: string) { constructor(dbName: string) {
this.db = SQLite.openDatabaseSync(dbName); try {
this.db = openDatabaseSync(dbName);
console.log('Database opened:', this.db);
} catch (error) {
console.error('Error opening database:', error);
throw error;
}
} }
async executeSql(sql: string, params: (string | number | null)[] = []): Promise<SQLiteResult> { async executeSql<T extends SQLiteRow = any>(
return new Promise((resolve, reject) => { sql: string,
this.db.withTransactionAsync(async (tx) => { params: (string | number | null)[] = []
tx.executeSql( ): Promise<SQLiteResult<T>> {
sql, if (!this.db) {
params, throw new Error('Database not initialized');
(_, result) => resolve(result), }
(_, error) => {
console.error('SQL Error:', error); try {
reject(error); const statement = this.db.prepareSync(sql);
return false; const result = statement.executeSync<T>(params);
} statement.finalizeSync();
);
}).catch(error => { return {
console.error('Transaction Error:', error); rows: {
reject(error); _array: Array.isArray(result) ? result : [],
}); length: Array.isArray(result) ? result.length : 0,
}); item: (idx: number) => (Array.isArray(result) ? result[idx] : null) as T
},
rowsAffected: Array.isArray(result) ? result.length : 0,
insertId: undefined // SQLite doesn't provide this directly
};
} catch (error) {
console.error('SQL Error:', error, sql, params);
throw error;
}
} }
async executeWrite(sql: string, params: (string | number | null)[] = []): Promise<SQLiteResult> { async executeWrite<T extends SQLiteRow = any>(
return this.executeSql(sql, params); sql: string,
params: (string | number | null)[] = []
): Promise<SQLiteResult<T>> {
return this.executeSql<T>(sql, params);
} }
async executeWriteMany(queries: { sql: string; args?: (string | number | null)[] }[]): Promise<SQLiteResult[]> { async executeWriteMany<T extends SQLiteRow = any>(
return new Promise((resolve, reject) => { queries: Array<{
const results: SQLiteResult[] = []; sql: string;
args?: (string | number | null)[]
this.db.withTransactionAsync(async (tx) => { }>
try { ): Promise<SQLiteResult<T>[]> {
for (const query of queries) { if (!this.db) {
await new Promise<void>((resolveQuery, rejectQuery) => { throw new Error('Database not initialized');
tx.executeSql( }
query.sql,
query.args || [],
(_, result) => {
results.push(result);
resolveQuery();
},
(_, error) => {
console.error('SQL Error:', error);
rejectQuery(error);
return false;
}
);
});
}
resolve(results);
} catch (error) {
console.error('Transaction Error:', error);
reject(error);
}
}).catch(error => {
console.error('Transaction Error:', error);
reject(error);
});
});
}
async withTransaction<T>( const results: SQLiteResult<T>[] = [];
callback: (tx: SQLTransaction) => Promise<T>
): Promise<T> { for (const query of queries) {
return new Promise((resolve, reject) => { try {
this.db.withTransactionAsync(async (tx) => { const result = await this.executeSql<T>(query.sql, query.args || []);
try { results.push(result);
const result = await callback(tx); } catch (error) {
resolve(result); console.error('Error executing query:', query, error);
} catch (error) { throw error;
console.error('Transaction Error:', error); }
reject(error); }
}
}).catch(error => { return results;
console.error('Transaction Error:', error);
reject(error);
});
});
} }
async tableExists(tableName: string): Promise<boolean> { async tableExists(tableName: string): Promise<boolean> {
try { try {
const result = await this.executeSql( const result = await this.executeSql<{ name: string }>(
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`, `SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
[tableName] [tableName]
); );
return result.rows.length > 0; return result.rows._array.length > 0;
} catch (error) { } catch (error) {
console.error('Error checking table existence:', error); console.error('Error checking table existence:', error);
return false; return false;
} }
} }
async close(): Promise<void> { async initialize(): Promise<void> {
try { try {
await this.db.closeAsync(); await this.executeSql('PRAGMA foreign_keys = ON;');
} catch (error) { } catch (error) {
console.error('Error closing database:', error); console.error('Error initializing database:', error);
throw error; throw error;
} }
} }

View File

@ -203,10 +203,19 @@ class Schema {
} }
private async setVersion(version: number): Promise<void> { private async setVersion(version: number): Promise<void> {
await this.db.executeSql( try {
'INSERT INTO schema_version (version, updated_at) VALUES (?, ?)', await this.db.executeSql(
[version, Date.now()] 'DELETE FROM schema_version WHERE version = ?',
); [version]
);
await this.db.executeSql(
'INSERT INTO schema_version (version, updated_at) VALUES (?, ?)',
[version, Date.now()]
);
} catch (error) {
console.error('Error setting schema version:', error);
throw error;
}
} }
} }