feat(sqlite): Database file creation working, connection pending
- Successfully creates database file using plugin's open() method - Directory permissions and path handling verified working - Plugin initialization and echo test passing - Database file created at /home/matthew/Databases/TimeSafari/timesafariSQLite.db Key findings: - createConnection() returns undefined but doesn't error - open() silently creates the database file - Connection retrieval still needs work (getDatabaseConnectionOrThrowError fails) - Plugin structure confirmed: both class and default export available Next steps: - Refine connection handling after database creation - Add connection state verification - Consider adding retry logic for connection retrieval Technical details: - Using CapacitorSQLite from @capacitor-community/sqlite/electron - Database path: /home/matthew/Databases/TimeSafari/timesafariSQLite.db - Directory permissions: 755 (rwxr-xr-x) - Plugin version: 6.x (Capacitor 6+ compatible)
This commit is contained in:
@@ -34,8 +34,7 @@
|
||||
"CapacitorSQLite": {
|
||||
"electronIsEncryption": false,
|
||||
"electronMacLocation": "~/Library/Application Support/TimeSafari",
|
||||
"electronWindowsLocation": "C:\\ProgramData\\TimeSafari",
|
||||
"electronLinuxLocation": "~/.local/share/TimeSafari"
|
||||
"electronWindowsLocation": "C:\\ProgramData\\TimeSafari"
|
||||
}
|
||||
},
|
||||
"ios": {
|
||||
|
||||
@@ -3,20 +3,16 @@
|
||||
* Handles database path setup, plugin initialization, and IPC handlers
|
||||
*
|
||||
* Database Path Handling:
|
||||
* - Uses XDG Base Directory Specification for data storage
|
||||
* - Uses plugin's default path (/home/matthew/Databases/TimeSafari)
|
||||
* - Uses modern plugin conventions (Capacitor 6+ / Plugin 6.x+)
|
||||
* - Supports custom database names without enforced extensions
|
||||
* - Maintains backward compatibility with legacy paths
|
||||
*
|
||||
* XDG Base Directory Specification:
|
||||
* - Uses $XDG_DATA_HOME (defaults to ~/.local/share) for data files
|
||||
* - Falls back to legacy path if XDG environment variables are not set
|
||||
* - Lets plugin handle SQLite suffix and database naming
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
*/
|
||||
|
||||
import { app, ipcMain } from 'electron';
|
||||
import { CapacitorSQLite } from '@capacitor-community/sqlite/electron/dist/plugin.js';
|
||||
import * as SQLiteModule from '@capacitor-community/sqlite/electron/dist/plugin.js';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
@@ -30,50 +26,64 @@ const logger = {
|
||||
debug: (...args: unknown[]) => console.debug('[SQLite]', ...args),
|
||||
};
|
||||
|
||||
// Database path resolution utilities following XDG Base Directory Specification
|
||||
// Add debug logging utility
|
||||
const debugLog = (stage: string, data?: any) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
if (data) {
|
||||
logger.debug(`[${timestamp}] ${stage}:`, data);
|
||||
} else {
|
||||
logger.debug(`[${timestamp}] ${stage}`);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper to get all methods from an object, including prototype chain
|
||||
const getAllMethods = (obj: any): string[] => {
|
||||
if (!obj) return [];
|
||||
const methods = new Set<string>();
|
||||
|
||||
// Get own methods
|
||||
Object.getOwnPropertyNames(obj).forEach(prop => {
|
||||
if (typeof obj[prop] === 'function') {
|
||||
methods.add(prop);
|
||||
}
|
||||
});
|
||||
|
||||
// Get prototype methods
|
||||
let proto = Object.getPrototypeOf(obj);
|
||||
while (proto && proto !== Object.prototype) {
|
||||
Object.getOwnPropertyNames(proto).forEach(prop => {
|
||||
if (typeof proto[prop] === 'function' && !methods.has(prop)) {
|
||||
methods.add(prop);
|
||||
}
|
||||
});
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
|
||||
return Array.from(methods);
|
||||
};
|
||||
|
||||
// Database path resolution utilities
|
||||
const getAppDataPath = async (): Promise<string> => {
|
||||
try {
|
||||
// Get XDG_DATA_HOME or fallback to default
|
||||
const xdgDataHome = process.env.XDG_DATA_HOME || path.join(os.homedir(), '.local', 'share');
|
||||
logger.info('XDG_DATA_HOME:', xdgDataHome);
|
||||
|
||||
// Create app data directory following XDG spec
|
||||
const appDataDir = path.join(xdgDataHome, 'timesafari');
|
||||
// Use plugin's actual default path
|
||||
const appDataDir = path.join(os.homedir(), 'Databases', 'TimeSafari');
|
||||
logger.info('App data directory:', appDataDir);
|
||||
|
||||
// Ensure directory exists with proper permissions (700)
|
||||
// Ensure directory exists with proper permissions (755)
|
||||
if (!fs.existsSync(appDataDir)) {
|
||||
await fs.promises.mkdir(appDataDir, {
|
||||
recursive: true,
|
||||
mode: 0o700 // rwx------ for security
|
||||
mode: 0o755 // rwxr-xr-x to match plugin's expectations
|
||||
});
|
||||
} else {
|
||||
// Ensure existing directory has correct permissions
|
||||
await fs.promises.chmod(appDataDir, 0o700);
|
||||
await fs.promises.chmod(appDataDir, 0o755);
|
||||
}
|
||||
|
||||
return appDataDir;
|
||||
} catch (error) {
|
||||
logger.error('Error getting app data path:', error);
|
||||
// Fallback to legacy path in user's home
|
||||
const fallbackDir = path.join(os.homedir(), '.timesafari');
|
||||
logger.warn('Using fallback app data directory:', fallbackDir);
|
||||
|
||||
try {
|
||||
if (!fs.existsSync(fallbackDir)) {
|
||||
await fs.promises.mkdir(fallbackDir, {
|
||||
recursive: true,
|
||||
mode: 0o700
|
||||
});
|
||||
} else {
|
||||
await fs.promises.chmod(fallbackDir, 0o700);
|
||||
}
|
||||
} catch (mkdirError) {
|
||||
logger.error('Failed to create fallback directory:', mkdirError);
|
||||
throw new Error('Could not create any suitable data directory');
|
||||
}
|
||||
|
||||
return fallbackDir;
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,40 +99,45 @@ const initializeDatabasePaths = async (): Promise<void> => {
|
||||
|
||||
dbPathInitializationPromise = (async () => {
|
||||
try {
|
||||
// Get the app data directory in user's home
|
||||
// Get the absolute app data directory
|
||||
const absolutePath = await getAppDataPath();
|
||||
logger.info('Absolute database path:', absolutePath);
|
||||
|
||||
// For the plugin, we need to use a path relative to the electron folder
|
||||
// So we'll use a relative path from the electron folder to the home directory
|
||||
const electronPath = app.getAppPath();
|
||||
const relativeToElectron = path.relative(electronPath, absolutePath);
|
||||
dbDir = relativeToElectron;
|
||||
// Use absolute paths for everything
|
||||
dbDir = absolutePath;
|
||||
|
||||
logger.info('Database directory (relative to electron):', dbDir);
|
||||
// Use the exact format the plugin expects
|
||||
const dbFileName = 'timesafariSQLite.db';
|
||||
dbPath = path.join(dbDir, dbFileName);
|
||||
|
||||
// Ensure directory exists using absolute path
|
||||
logger.info('Database directory:', dbDir);
|
||||
logger.info('Database path:', dbPath);
|
||||
|
||||
// Ensure directory exists
|
||||
if (!fs.existsSync(absolutePath)) {
|
||||
await fs.promises.mkdir(absolutePath, { recursive: true });
|
||||
}
|
||||
|
||||
// Use modern plugin conventions - no enforced extension
|
||||
const baseName = 'timesafariSQLite';
|
||||
dbPath = path.join(dbDir, baseName);
|
||||
logger.info('Database path initialized (relative to electron):', dbPath);
|
||||
|
||||
// Verify we can write to the directory using absolute path
|
||||
// Verify we can write to the directory
|
||||
const testFile = path.join(absolutePath, '.write-test');
|
||||
try {
|
||||
await fs.promises.writeFile(testFile, 'test');
|
||||
await fs.promises.unlink(testFile);
|
||||
logger.info('Directory write test successful');
|
||||
} catch (error) {
|
||||
throw new Error(`Cannot write to database directory: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
}
|
||||
|
||||
// Set environment variable for the plugin using relative path
|
||||
process.env.CAPACITOR_SQLITE_DB_PATH = dbDir;
|
||||
logger.info('Set CAPACITOR_SQLITE_DB_PATH:', process.env.CAPACITOR_SQLITE_DB_PATH);
|
||||
// Verify the path exists and is writable
|
||||
logger.info('Verifying database directory permissions...');
|
||||
const stats = await fs.promises.stat(absolutePath);
|
||||
logger.info('Directory permissions:', {
|
||||
mode: stats.mode.toString(8),
|
||||
uid: stats.uid,
|
||||
gid: stats.gid,
|
||||
isDirectory: stats.isDirectory(),
|
||||
isWritable: !!(stats.mode & 0o200)
|
||||
});
|
||||
|
||||
dbPathInitialized = true;
|
||||
} catch (error) {
|
||||
@@ -144,6 +159,37 @@ let sqlitePlugin: any = null;
|
||||
let sqliteInitialized = false;
|
||||
let sqliteInitializationPromise: Promise<void> | null = null;
|
||||
|
||||
// Helper to get the actual plugin instance
|
||||
const getActualPluginInstance = (plugin: any): any => {
|
||||
// Try to get the actual instance through various means
|
||||
const possibleInstances = [
|
||||
plugin, // The object itself
|
||||
plugin.default, // If it's a module
|
||||
plugin.CapacitorSQLite, // If it's a namespace
|
||||
Object.getPrototypeOf(plugin), // Its prototype
|
||||
plugin.constructor?.prototype, // Constructor's prototype
|
||||
Object.getPrototypeOf(Object.getPrototypeOf(plugin)) // Grandparent prototype
|
||||
];
|
||||
|
||||
// Find the first instance that has createConnection
|
||||
const instance = possibleInstances.find(inst =>
|
||||
inst && typeof inst === 'object' && typeof inst.createConnection === 'function'
|
||||
);
|
||||
|
||||
if (!instance) {
|
||||
debugLog('No valid plugin instance found in:', {
|
||||
possibleInstances: possibleInstances.map(inst => ({
|
||||
type: typeof inst,
|
||||
constructor: inst?.constructor?.name,
|
||||
hasCreateConnection: inst && typeof inst.createConnection === 'function'
|
||||
}))
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
return instance;
|
||||
};
|
||||
|
||||
export async function initializeSQLite(): Promise<void> {
|
||||
if (sqliteInitializationPromise) {
|
||||
logger.info('SQLite initialization already in progress, waiting...');
|
||||
@@ -168,12 +214,67 @@ export async function initializeSQLite(): Promise<void> {
|
||||
|
||||
// Create plugin instance
|
||||
logger.info('Creating SQLite plugin instance...');
|
||||
sqlitePlugin = new CapacitorSQLite();
|
||||
|
||||
if (!sqlitePlugin) {
|
||||
throw new Error('Failed to create SQLite plugin instance');
|
||||
debugLog('SQLite module:', {
|
||||
hasDefault: !!SQLiteModule.default,
|
||||
defaultType: typeof SQLiteModule.default,
|
||||
defaultKeys: SQLiteModule.default ? Object.keys(SQLiteModule.default) : null,
|
||||
hasCapacitorSQLite: !!SQLiteModule.CapacitorSQLite,
|
||||
CapacitorSQLiteType: typeof SQLiteModule.CapacitorSQLite
|
||||
});
|
||||
|
||||
// Try both the class and default export
|
||||
let rawPlugin;
|
||||
try {
|
||||
// Try default export first
|
||||
if (SQLiteModule.default?.CapacitorSQLite) {
|
||||
debugLog('Using default export CapacitorSQLite');
|
||||
rawPlugin = new SQLiteModule.default.CapacitorSQLite();
|
||||
} else {
|
||||
debugLog('Using direct CapacitorSQLite class');
|
||||
rawPlugin = new CapacitorSQLite();
|
||||
}
|
||||
} catch (error) {
|
||||
debugLog('Error creating plugin instance:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!rawPlugin) {
|
||||
throw new Error('Failed to create SQLite plugin instance');
|
||||
}
|
||||
|
||||
// Get the actual plugin instance
|
||||
sqlitePlugin = getActualPluginInstance(rawPlugin);
|
||||
|
||||
if (!sqlitePlugin) {
|
||||
throw new Error('Failed to get valid SQLite plugin instance');
|
||||
}
|
||||
|
||||
// Debug plugin instance
|
||||
debugLog('Plugin instance details:', {
|
||||
type: typeof sqlitePlugin,
|
||||
constructor: sqlitePlugin.constructor?.name,
|
||||
prototype: Object.getPrototypeOf(sqlitePlugin)?.constructor?.name,
|
||||
allMethods: getAllMethods(sqlitePlugin),
|
||||
hasCreateConnection: typeof sqlitePlugin.createConnection === 'function',
|
||||
createConnectionType: typeof sqlitePlugin.createConnection,
|
||||
createConnectionProto: Object.getPrototypeOf(sqlitePlugin.createConnection)?.constructor?.name,
|
||||
// Add more details about the instance
|
||||
isProxy: sqlitePlugin.constructor?.name === 'Proxy',
|
||||
descriptors: Object.getOwnPropertyDescriptors(sqlitePlugin),
|
||||
prototypeChain: (() => {
|
||||
const chain = [];
|
||||
let proto = sqlitePlugin;
|
||||
while (proto && proto !== Object.prototype) {
|
||||
chain.push({
|
||||
name: proto.constructor?.name,
|
||||
methods: Object.getOwnPropertyNames(proto)
|
||||
});
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
return chain;
|
||||
})()
|
||||
});
|
||||
|
||||
// Test the plugin
|
||||
logger.info('Testing SQLite plugin...');
|
||||
const echoResult = await sqlitePlugin.echo({ value: 'test' });
|
||||
@@ -182,47 +283,239 @@ export async function initializeSQLite(): Promise<void> {
|
||||
}
|
||||
logger.info('SQLite plugin echo test successful');
|
||||
|
||||
// Initialize database connection using modern plugin conventions
|
||||
// Initialize database connection using plugin's default format
|
||||
debugLog('Starting connection creation');
|
||||
debugLog('Plugin utilities:', {
|
||||
sqliteUtil: sqlitePlugin.sqliteUtil ? Object.keys(sqlitePlugin.sqliteUtil) : null,
|
||||
fileUtil: sqlitePlugin.fileUtil ? Object.keys(sqlitePlugin.fileUtil) : null,
|
||||
globalUtil: sqlitePlugin.globalUtil ? Object.keys(sqlitePlugin.globalUtil) : null,
|
||||
prototype: Object.getOwnPropertyNames(Object.getPrototypeOf(sqlitePlugin))
|
||||
});
|
||||
|
||||
// Get the database path using Path.join
|
||||
const fullDbPath = sqlitePlugin.fileUtil?.Path?.join(dbDir, 'timesafariSQLite.db');
|
||||
debugLog('Database path from Path.join:', {
|
||||
path: fullDbPath,
|
||||
exists: fullDbPath ? fs.existsSync(fullDbPath) : false,
|
||||
pathType: typeof sqlitePlugin.fileUtil?.Path?.join
|
||||
});
|
||||
|
||||
// Let plugin handle database naming and suffix
|
||||
const connectionOptions = {
|
||||
database: 'timesafariSQLite',
|
||||
database: 'timesafari', // Base name only
|
||||
version: 1,
|
||||
readOnly: false,
|
||||
encryption: 'no-encryption',
|
||||
useNative: true,
|
||||
mode: 'rwc',
|
||||
location: dbDir // Use path relative to electron folder
|
||||
location: 'default', // Let plugin handle path resolution
|
||||
path: fullDbPath // Add explicit path
|
||||
};
|
||||
|
||||
logger.info('Creating initial database connection with options:', {
|
||||
debugLog('Connection options:', {
|
||||
...connectionOptions,
|
||||
expectedPath: dbPath // Path relative to electron folder
|
||||
absoluteLocation: dbDir,
|
||||
fullDbPath,
|
||||
expectedBehavior: 'Using prototype methods with explicit path'
|
||||
});
|
||||
|
||||
const db = await sqlitePlugin.createConnection(connectionOptions);
|
||||
|
||||
// Verify directory state before connection
|
||||
try {
|
||||
const dirStats = await fs.promises.stat(dbDir);
|
||||
debugLog('Directory state before connection:', {
|
||||
exists: true,
|
||||
isDirectory: dirStats.isDirectory(),
|
||||
mode: dirStats.mode.toString(8),
|
||||
uid: dirStats.uid,
|
||||
gid: dirStats.gid,
|
||||
size: dirStats.size,
|
||||
atime: dirStats.atime,
|
||||
mtime: dirStats.mtime,
|
||||
ctime: dirStats.ctime
|
||||
});
|
||||
|
||||
// Check if database file already exists
|
||||
try {
|
||||
const dbStats = await fs.promises.stat(fullDbPath);
|
||||
debugLog('Database file exists:', {
|
||||
size: dbStats.size,
|
||||
mode: dbStats.mode.toString(8),
|
||||
mtime: dbStats.mtime
|
||||
});
|
||||
} catch (error) {
|
||||
debugLog('Database file does not exist yet (this is expected)');
|
||||
}
|
||||
} catch (error) {
|
||||
debugLog('Error checking directory state:', error);
|
||||
}
|
||||
|
||||
// Create connection using prototype methods
|
||||
debugLog('Calling createConnection...');
|
||||
let db;
|
||||
try {
|
||||
// Get the prototype methods
|
||||
const proto = Object.getPrototypeOf(sqlitePlugin);
|
||||
debugLog('Prototype methods:', {
|
||||
methods: Object.getOwnPropertyNames(proto),
|
||||
createConnectionType: typeof proto.createConnection,
|
||||
openType: typeof proto.open,
|
||||
createConnectionProto: proto.createConnection?.prototype?.constructor?.name
|
||||
});
|
||||
|
||||
// Try to create connection using prototype method
|
||||
if (typeof proto.createConnection === 'function') {
|
||||
debugLog('Using prototype createConnection');
|
||||
|
||||
// First try to create the connection
|
||||
const boundCreateConnection = proto.createConnection.bind(sqlitePlugin);
|
||||
const result = await boundCreateConnection(connectionOptions);
|
||||
|
||||
debugLog('createConnection raw result:', {
|
||||
type: typeof result,
|
||||
isNull: result === null,
|
||||
isUndefined: result === undefined,
|
||||
value: result
|
||||
});
|
||||
|
||||
// Try to open the database directly
|
||||
debugLog('Attempting to open database directly...');
|
||||
try {
|
||||
const openResult = await sqlitePlugin.open({
|
||||
database: connectionOptions.database,
|
||||
path: fullDbPath,
|
||||
version: connectionOptions.version,
|
||||
readOnly: connectionOptions.readOnly,
|
||||
encryption: connectionOptions.encryption,
|
||||
useNative: connectionOptions.useNative,
|
||||
mode: connectionOptions.mode
|
||||
});
|
||||
|
||||
debugLog('open result:', {
|
||||
type: typeof openResult,
|
||||
isNull: openResult === null,
|
||||
isUndefined: openResult === undefined,
|
||||
value: openResult
|
||||
});
|
||||
|
||||
// Try to get the connection after opening
|
||||
if (sqlitePlugin.getDatabaseConnectionOrThrowError) {
|
||||
debugLog('Getting connection after open');
|
||||
db = await sqlitePlugin.getDatabaseConnectionOrThrowError(connectionOptions.database);
|
||||
}
|
||||
|
||||
// Verify the database exists
|
||||
const exists = await sqlitePlugin.isDBExists({
|
||||
database: connectionOptions.database,
|
||||
path: fullDbPath
|
||||
});
|
||||
|
||||
debugLog('Database exists check:', {
|
||||
exists,
|
||||
path: fullDbPath,
|
||||
fileExists: fs.existsSync(fullDbPath)
|
||||
});
|
||||
|
||||
// If database doesn't exist, try to create it
|
||||
if (!exists) {
|
||||
debugLog('Database does not exist, attempting to create...');
|
||||
// Create an empty file to ensure the directory is writable
|
||||
await fs.promises.writeFile(fullDbPath, '');
|
||||
|
||||
// Try opening again
|
||||
await sqlitePlugin.open({
|
||||
database: connectionOptions.database,
|
||||
path: fullDbPath,
|
||||
version: connectionOptions.version,
|
||||
readOnly: false, // Force read-write for creation
|
||||
encryption: connectionOptions.encryption,
|
||||
useNative: connectionOptions.useNative,
|
||||
mode: 'rwc' // Force create mode
|
||||
});
|
||||
|
||||
// Verify creation
|
||||
const created = await sqlitePlugin.isDBExists({
|
||||
database: connectionOptions.database,
|
||||
path: fullDbPath
|
||||
});
|
||||
|
||||
debugLog('Database creation result:', {
|
||||
created,
|
||||
path: fullDbPath,
|
||||
fileExists: fs.existsSync(fullDbPath),
|
||||
fileSize: fs.existsSync(fullDbPath) ? fs.statSync(fullDbPath).size : 0
|
||||
});
|
||||
}
|
||||
|
||||
// Get final connection
|
||||
if (sqlitePlugin.getDatabaseConnectionOrThrowError) {
|
||||
debugLog('Getting final connection');
|
||||
db = await sqlitePlugin.getDatabaseConnectionOrThrowError(connectionOptions.database);
|
||||
}
|
||||
|
||||
debugLog('Final connection state:', {
|
||||
hasConnection: !!db,
|
||||
type: typeof db,
|
||||
isNull: db === null,
|
||||
isUndefined: db === undefined,
|
||||
keys: db ? Object.keys(db) : null,
|
||||
methods: db ? Object.getOwnPropertyNames(Object.getPrototypeOf(db)) : null,
|
||||
prototype: db ? Object.getPrototypeOf(db)?.constructor?.name : null
|
||||
});
|
||||
|
||||
} catch (openError) {
|
||||
debugLog('Error during open/create:', {
|
||||
name: openError.name,
|
||||
message: openError.message,
|
||||
stack: openError.stack,
|
||||
code: (openError as any).code,
|
||||
errno: (openError as any).errno,
|
||||
syscall: (openError as any).syscall
|
||||
});
|
||||
throw openError;
|
||||
}
|
||||
} else {
|
||||
throw new Error('No valid createConnection method found on prototype');
|
||||
}
|
||||
} catch (error) {
|
||||
debugLog('createConnection/open error:', {
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
code: (error as any).code,
|
||||
errno: (error as any).errno,
|
||||
syscall: (error as any).syscall
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!db || typeof db !== 'object') {
|
||||
throw new Error(`Failed to create database connection - invalid response. Path: ${dbPath}`);
|
||||
debugLog('Invalid database connection response:', {
|
||||
value: db,
|
||||
type: typeof db,
|
||||
isNull: db === null,
|
||||
isUndefined: db === undefined
|
||||
});
|
||||
throw new Error(`Failed to create database connection - invalid response. Path: ${fullDbPath}`);
|
||||
}
|
||||
|
||||
// Verify connection with a simple query
|
||||
logger.info('Verifying database connection...');
|
||||
|
||||
// Verify connection state
|
||||
debugLog('Verifying connection state...');
|
||||
try {
|
||||
const result = await db.query({ statement: 'SELECT 1 as test;' });
|
||||
if (!result || !result.values || result.values.length === 0) {
|
||||
throw new Error('Database connection test query returned no results');
|
||||
}
|
||||
logger.info('Database connection verified successfully');
|
||||
const isOpen = await db.isDBOpen();
|
||||
debugLog('Connection state:', {
|
||||
isOpen,
|
||||
methods: Object.keys(db),
|
||||
prototype: Object.getOwnPropertyNames(Object.getPrototypeOf(db))
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(`Database connection test failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
debugLog('Error checking connection state:', error);
|
||||
}
|
||||
|
||||
|
||||
sqliteInitialized = true;
|
||||
logger.info('SQLite plugin initialization completed successfully');
|
||||
debugLog('SQLite plugin initialization completed successfully');
|
||||
} catch (error) {
|
||||
logger.error('SQLite plugin initialization failed:', error);
|
||||
// Store the error but don't throw
|
||||
initializationError = error instanceof Error ? error : new Error(String(error));
|
||||
// Reset state on failure but allow app to continue
|
||||
sqlitePlugin = null;
|
||||
sqliteInitialized = false;
|
||||
} finally {
|
||||
@@ -291,18 +584,22 @@ export function setupSQLiteHandlers(): void {
|
||||
throw new Error('Database path not initialized');
|
||||
}
|
||||
|
||||
// Use modern plugin conventions for connection options
|
||||
// Use same connection options format
|
||||
const connectionOptions = {
|
||||
...options,
|
||||
database: 'timesafariSQLite',
|
||||
database: 'timesafari', // Base name only
|
||||
readOnly: false,
|
||||
mode: 'rwc',
|
||||
encryption: 'no-encryption',
|
||||
useNative: true,
|
||||
location: dbDir // Use path relative to electron folder
|
||||
location: 'default' // Let plugin handle path resolution
|
||||
};
|
||||
|
||||
logger.info('Creating database connection with options:', connectionOptions);
|
||||
logger.info('Creating database connection with options:', {
|
||||
...connectionOptions,
|
||||
expectedBehavior: 'Plugin will append SQLite suffix and handle path resolution'
|
||||
});
|
||||
|
||||
const result = await sqlitePlugin.createConnection(connectionOptions);
|
||||
|
||||
if (!result || typeof result !== 'object') {
|
||||
|
||||
Reference in New Issue
Block a user