disable SQLite in Java & Swift (since they don't compile) & add SQL queueing on startup
At this point, the app compiles and runs in Android & iOS but DB operations fail.
This commit is contained in:
@@ -10,10 +10,9 @@ import {
|
||||
SQLiteConnection,
|
||||
SQLiteDBConnection,
|
||||
CapacitorSQLite,
|
||||
Changes,
|
||||
} from "@capacitor-community/sqlite";
|
||||
import { logger } from "../../utils/logger";
|
||||
import { QueryExecResult, SqlValue } from "@/interfaces/database";
|
||||
import { QueryExecResult } from "@/interfaces/database";
|
||||
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
|
||||
|
||||
interface Migration {
|
||||
@@ -21,6 +20,14 @@ interface Migration {
|
||||
sql: string;
|
||||
}
|
||||
|
||||
interface QueuedOperation {
|
||||
type: "run" | "query" | "getOneRow" | "getAll";
|
||||
sql: string;
|
||||
params: unknown[];
|
||||
resolve: (value: unknown) => void;
|
||||
reject: (reason: unknown) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Platform service implementation for Capacitor (mobile) platform.
|
||||
* Provides native mobile functionality through Capacitor plugins for:
|
||||
@@ -34,12 +41,40 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
private db: SQLiteDBConnection | null = null;
|
||||
private dbName = "timesafari.db";
|
||||
private initialized = false;
|
||||
private initializationPromise: Promise<void> | null = null;
|
||||
private operationQueue: Array<QueuedOperation> = [];
|
||||
private isProcessingQueue: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this.sqlite = new SQLiteConnection(CapacitorSQLite);
|
||||
}
|
||||
|
||||
private async initializeDatabase(): Promise<void> {
|
||||
// If already initialized, return immediately
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If initialization is in progress, wait for it
|
||||
if (this.initializationPromise) {
|
||||
return this.initializationPromise;
|
||||
}
|
||||
|
||||
// Start initialization
|
||||
this.initializationPromise = this._initialize();
|
||||
try {
|
||||
await this.initializationPromise;
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
"[CapacitorPlatformService] Initialize method failed:",
|
||||
error,
|
||||
);
|
||||
this.initializationPromise = null; // Reset on failure
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private async _initialize(): Promise<void> {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
@@ -57,16 +92,142 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
await this.db.open();
|
||||
|
||||
// Set journal mode to WAL for better performance
|
||||
await this.db.execute("PRAGMA journal_mode=WAL;");
|
||||
// await this.db.execute("PRAGMA journal_mode=WAL;");
|
||||
|
||||
// Run migrations
|
||||
await this.runMigrations();
|
||||
|
||||
this.initialized = true;
|
||||
logger.log("SQLite database initialized successfully");
|
||||
logger.log(
|
||||
"[CapacitorPlatformService] SQLite database initialized successfully",
|
||||
);
|
||||
|
||||
// Start processing the queue after initialization
|
||||
this.processQueue();
|
||||
} catch (error) {
|
||||
logger.error("Error initializing SQLite database:", error);
|
||||
throw new Error("Failed to initialize database");
|
||||
logger.error(
|
||||
"[CapacitorPlatformService] Error initializing SQLite database:",
|
||||
error,
|
||||
);
|
||||
throw new Error(
|
||||
"[CapacitorPlatformService] Failed to initialize database",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async processQueue(): Promise<void> {
|
||||
if (this.isProcessingQueue || !this.initialized || !this.db) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isProcessingQueue = true;
|
||||
|
||||
while (this.operationQueue.length > 0) {
|
||||
const operation = this.operationQueue.shift();
|
||||
if (!operation) continue;
|
||||
|
||||
try {
|
||||
let result: unknown;
|
||||
switch (operation.type) {
|
||||
case "run": {
|
||||
const runResult = await this.db.run(
|
||||
operation.sql,
|
||||
operation.params,
|
||||
);
|
||||
result = {
|
||||
changes: runResult.changes?.changes || 0,
|
||||
lastId: runResult.changes?.lastId,
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "query": {
|
||||
const queryResult = await this.db.query(
|
||||
operation.sql,
|
||||
operation.params,
|
||||
);
|
||||
result = {
|
||||
columns: [], // SQLite plugin doesn't provide column names
|
||||
values: queryResult.values || [],
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "getOneRow": {
|
||||
const oneRowResult = await this.db.query(
|
||||
operation.sql,
|
||||
operation.params,
|
||||
);
|
||||
result = oneRowResult.values?.[0];
|
||||
break;
|
||||
}
|
||||
case "getAll": {
|
||||
const allResult = await this.db.query(
|
||||
operation.sql,
|
||||
operation.params,
|
||||
);
|
||||
result = allResult.values || [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
operation.resolve(result);
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
"[CapacitorPlatformService] Error while processing SQL queue:",
|
||||
error,
|
||||
" ... for sql:",
|
||||
operation.sql,
|
||||
" ... with params:",
|
||||
operation.params,
|
||||
);
|
||||
operation.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
this.isProcessingQueue = false;
|
||||
}
|
||||
|
||||
private async queueOperation<R>(
|
||||
type: QueuedOperation["type"],
|
||||
sql: string,
|
||||
params: unknown[] = [],
|
||||
): Promise<R> {
|
||||
return new Promise<R>((resolve, reject) => {
|
||||
const operation: QueuedOperation = {
|
||||
type,
|
||||
sql,
|
||||
params,
|
||||
resolve: (value: unknown) => resolve(value as R),
|
||||
reject,
|
||||
};
|
||||
this.operationQueue.push(operation);
|
||||
|
||||
// If we're already initialized, start processing the queue
|
||||
if (this.initialized && this.db) {
|
||||
this.processQueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async waitForInitialization(): Promise<void> {
|
||||
// If we have an initialization promise, wait for it
|
||||
if (this.initializationPromise) {
|
||||
await this.initializationPromise;
|
||||
return;
|
||||
}
|
||||
|
||||
// If not initialized and no promise, start initialization
|
||||
if (!this.initialized) {
|
||||
await this.initializeDatabase();
|
||||
return;
|
||||
}
|
||||
|
||||
// If initialized but no db, something went wrong
|
||||
if (!this.db) {
|
||||
logger.error(
|
||||
"[CapacitorPlatformService] Database not properly initialized after await waitForInitialization() - initialized flag is true but db is null",
|
||||
);
|
||||
throw new Error(
|
||||
"[CapacitorPlatformService] The database could not be initialized. We recommend you restart or reinstall.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +327,7 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
CREATE INDEX IF NOT EXISTS idx_contacts_name ON contacts(name);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS logs (
|
||||
date TEXT PRIMARY KEY,
|
||||
date TEXT,
|
||||
message TEXT NOT NULL
|
||||
);
|
||||
|
||||
@@ -660,24 +821,8 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
* @see PlatformService.dbQuery
|
||||
*/
|
||||
async dbQuery(sql: string, params?: unknown[]): Promise<QueryExecResult> {
|
||||
await this.initializeDatabase();
|
||||
if (!this.db) {
|
||||
throw new Error("Database not initialized");
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.db.query(sql, params || []);
|
||||
const values = result.values || [];
|
||||
return {
|
||||
columns: [], // SQLite plugin doesn't provide column names in query result
|
||||
values: values as SqlValue[][],
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error("Error executing query:", error);
|
||||
throw new Error(
|
||||
`Database query failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
await this.waitForInitialization();
|
||||
return this.queueOperation<QueryExecResult>("query", sql, params || []);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -687,23 +832,11 @@ export class CapacitorPlatformService implements PlatformService {
|
||||
sql: string,
|
||||
params?: unknown[],
|
||||
): Promise<{ changes: number; lastId?: number }> {
|
||||
await this.initializeDatabase();
|
||||
if (!this.db) {
|
||||
throw new Error("Database not initialized");
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.db.run(sql, params || []);
|
||||
const changes = result.changes as Changes;
|
||||
return {
|
||||
changes: changes?.changes || 0,
|
||||
lastId: changes?.lastId,
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error("Error executing statement:", error);
|
||||
throw new Error(
|
||||
`Database execution failed: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
await this.waitForInitialization();
|
||||
return this.queueOperation<{ changes: number; lastId?: number }>(
|
||||
"run",
|
||||
sql,
|
||||
params || [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user