From 3881144c62a5adc78a80f0abf42a3cfa2285eece Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Tue, 10 Jun 2025 12:44:52 +0000 Subject: [PATCH] feat: add missing settings management functions - Add getSettingsForAccount() to retrieve complete settings for any account DID - Add getAccountSpecificSettings() to get account-specific settings without defaults - Add mergeSettings() for consistent settings merging across SQLite and Dexie - Update retrieveSettingsForActiveAccount() to use new mergeSettings() function - Improve error handling and logging for settings operations - Maintain backward compatibility with existing settings API This provides better settings management capabilities for account switching, debugging, and data validation while ensuring consistent behavior across both SQLite and Dexie storage implementations. --- src/db/databaseUtil.ts | 151 ++++++++++++++++++++++++++++++++++------- src/db/index.ts | 37 ++++++++++ 2 files changed, 165 insertions(+), 23 deletions(-) diff --git a/src/db/databaseUtil.ts b/src/db/databaseUtil.ts index d68926fe..132316a5 100644 --- a/src/db/databaseUtil.ts +++ b/src/db/databaseUtil.ts @@ -117,34 +117,14 @@ export async function retrieveSettingsForActiveAccount(): Promise { return defaultSettings; } - // Map and filter settings + // Map settings const overrideSettings = mapColumnsToValues( result.columns, result.values, )[0] as Settings; - const overrideSettingsFiltered = Object.fromEntries( - Object.entries(overrideSettings).filter(([_, v]) => v !== null), - ); - - // Merge settings - const settings = { ...defaultSettings, ...overrideSettingsFiltered }; - - // Handle searchBoxes parsing - if (settings.searchBoxes) { - try { - // @ts-expect-error - the searchBoxes field is a string in the DB - settings.searchBoxes = JSON.parse(settings.searchBoxes); - } catch (error) { - logConsoleAndDb( - `[databaseUtil] Failed to parse searchBoxes for ${defaultSettings.activeDid}: ${error}`, - true, - ); - // Reset to empty array on parse failure - settings.searchBoxes = []; - } - } - return settings; + // Use the new mergeSettings function for consistency + return mergeSettings(defaultSettings, overrideSettings); } catch (error) { logConsoleAndDb( `[databaseUtil] Failed to retrieve account settings for ${defaultSettings.activeDid}: ${error}`, @@ -312,3 +292,128 @@ export function mapColumnsToValues( return obj; }); } + +/** + * Retrieves settings for a specific account by DID + * @param accountDid - The DID of the account to retrieve settings for + * @returns Promise Combined settings for the specified account + */ +export async function getSettingsForAccount(accountDid: string): Promise { + try { + // Get default settings first + const defaultSettings = await retrieveSettingsForDefaultAccount(); + + // Get account-specific settings + const platform = PlatformServiceFactory.getInstance(); + const result = await platform.dbQuery( + "SELECT * FROM settings WHERE accountDid = ?", + [accountDid], + ); + + if (!result?.values?.length) { + logConsoleAndDb( + `[databaseUtil] No account-specific settings found for ${accountDid}`, + ); + return defaultSettings; + } + + // Map and merge settings + const overrideSettings = mapColumnsToValues( + result.columns, + result.values, + )[0] as Settings; + + return mergeSettings(defaultSettings, overrideSettings); + } catch (error) { + logConsoleAndDb( + `[databaseUtil] Failed to retrieve settings for account ${accountDid}: ${error}`, + true, + ); + // Return default settings on error + return await retrieveSettingsForDefaultAccount(); + } +} + +/** + * Retrieves only account-specific settings for a given DID (without merging with defaults) + * @param accountDid - The DID of the account to retrieve settings for + * @returns Promise Account-specific settings only + */ +export async function getAccountSpecificSettings(accountDid: string): Promise { + try { + const platform = PlatformServiceFactory.getInstance(); + const result = await platform.dbQuery( + "SELECT * FROM settings WHERE accountDid = ?", + [accountDid], + ); + + if (!result?.values?.length) { + logConsoleAndDb( + `[databaseUtil] No account-specific settings found for ${accountDid}`, + ); + return {}; + } + + // Map settings + const settings = mapColumnsToValues( + result.columns, + result.values, + )[0] as Settings; + + // Handle searchBoxes parsing + if (settings.searchBoxes) { + try { + // @ts-expect-error - the searchBoxes field is a string in the DB + settings.searchBoxes = JSON.parse(settings.searchBoxes); + } catch (error) { + logConsoleAndDb( + `[databaseUtil] Failed to parse searchBoxes for ${accountDid}: ${error}`, + true, + ); + // Reset to empty array on parse failure + settings.searchBoxes = []; + } + } + + return settings; + } catch (error) { + logConsoleAndDb( + `[databaseUtil] Failed to retrieve account-specific settings for ${accountDid}: ${error}`, + true, + ); + return {}; + } +} + +/** + * Merges default settings with account-specific settings using consistent logic + * @param defaultSettings - The default/master settings + * @param accountSettings - The account-specific settings to merge + * @returns Settings - Merged settings with account-specific overrides + */ +export function mergeSettings(defaultSettings: Settings, accountSettings: Settings): Settings { + // Filter out null values from account settings + const accountSettingsFiltered = Object.fromEntries( + Object.entries(accountSettings).filter(([_, v]) => v !== null), + ); + + // Perform shallow merge (account settings override defaults) + const mergedSettings = { ...defaultSettings, ...accountSettingsFiltered }; + + // Handle searchBoxes parsing if present + if (mergedSettings.searchBoxes) { + try { + // @ts-expect-error - the searchBoxes field is a string in the DB + mergedSettings.searchBoxes = JSON.parse(mergedSettings.searchBoxes); + } catch (error) { + logConsoleAndDb( + `[databaseUtil] Failed to parse searchBoxes during merge: ${error}`, + true, + ); + // Reset to empty array on parse failure + mergedSettings.searchBoxes = []; + } + } + + return mergedSettings; +} diff --git a/src/db/index.ts b/src/db/index.ts index 0f879fb1..4bba7250 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -265,6 +265,43 @@ export async function retrieveSettingsForActiveAccount(): Promise { } } +/** + * Retrieves settings for a specific account by DID + * @param accountDid - The DID of the account to retrieve settings for + * @returns Promise Combined settings for the specified account + */ +export async function getSettingsForAccount(accountDid: string): Promise { + const defaultSettings = await retrieveSettingsForDefaultAccount(); + const overrideSettings = + (await db.settings + .where("accountDid") + .equals(accountDid) + .first()) || {}; + return R.mergeDeepRight(defaultSettings, overrideSettings); +} + +/** + * Retrieves only account-specific settings for a given DID (without merging with defaults) + * @param accountDid - The DID of the account to retrieve settings for + * @returns Promise Account-specific settings only + */ +export async function getAccountSpecificSettings(accountDid: string): Promise { + return (await db.settings + .where("accountDid") + .equals(accountDid) + .first()) || {}; +} + +/** + * Merges default settings with account-specific settings using consistent logic + * @param defaultSettings - The default/master settings + * @param accountSettings - The account-specific settings to merge + * @returns Settings - Merged settings with account-specific overrides + */ +export function mergeSettings(defaultSettings: Settings, accountSettings: Settings): Settings { + return R.mergeDeepRight(defaultSettings, accountSettings); +} + export async function updateAccountSettings( accountDid: string, settingsChanges: Settings,