|
|
@ -8,23 +8,28 @@ |
|
|
|
* - Class-level service caching for performance |
|
|
|
* - Vue composition API patterns for modern development |
|
|
|
* - Mixin pattern for easy integration with existing class components |
|
|
|
* - Enhanced utility methods for common patterns |
|
|
|
* - Robust error handling and logging |
|
|
|
* |
|
|
|
* Benefits: |
|
|
|
* - Eliminates repeated PlatformServiceFactory.getInstance() calls |
|
|
|
* - Provides consistent service access pattern across components |
|
|
|
* - Improves performance with cached instances |
|
|
|
* - Maintains type safety with TypeScript |
|
|
|
* - Includes common database utility patterns |
|
|
|
* - Enhanced error handling and logging |
|
|
|
* |
|
|
|
* @author Matthew Raymer |
|
|
|
* @version 1.0.0 |
|
|
|
* @version 2.0.0 |
|
|
|
* @since 2025-07-02 |
|
|
|
*/ |
|
|
|
|
|
|
|
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory"; |
|
|
|
import type { PlatformService } from "@/services/PlatformService"; |
|
|
|
import { mapColumnsToValues, parseJsonField } from "@/db/databaseUtil"; |
|
|
|
|
|
|
|
/** |
|
|
|
* Mixin that provides cached platform service access to Vue components |
|
|
|
* Enhanced mixin that provides cached platform service access and utility methods |
|
|
|
* |
|
|
|
* Usage: |
|
|
|
* ```typescript
|
|
|
@ -33,8 +38,11 @@ import type { PlatformService } from "@/services/PlatformService"; |
|
|
|
* }) |
|
|
|
* export default class MyComponent extends Vue { |
|
|
|
* async someMethod() { |
|
|
|
* // Access cached platform service directly
|
|
|
|
* const result = await this.platformService.dbQuery('SELECT * FROM users'); |
|
|
|
* // Direct access without type assertions
|
|
|
|
* const result = await this.$dbQuery('SELECT * FROM users'); |
|
|
|
* |
|
|
|
* // Utility methods for common patterns
|
|
|
|
* const settings = await this.$getSettings('user123'); |
|
|
|
* } |
|
|
|
* } |
|
|
|
* ``` |
|
|
@ -96,39 +104,204 @@ export const PlatformServiceMixin = { |
|
|
|
|
|
|
|
methods: { |
|
|
|
/** |
|
|
|
* Convenient database query method |
|
|
|
* Shorthand for this.platformService.dbQuery() |
|
|
|
* Enhanced database query method with error handling |
|
|
|
* Prefixed with $ to avoid naming conflicts and improve discoverability |
|
|
|
*/ |
|
|
|
async $dbQuery(sql: string, params?: unknown[]) { |
|
|
|
try { |
|
|
|
return await (this as any).platformService.dbQuery(sql, params); |
|
|
|
} catch (error) { |
|
|
|
console.error( |
|
|
|
`[${(this as any).$options.name}] Database query failed:`, |
|
|
|
{ |
|
|
|
sql, |
|
|
|
params, |
|
|
|
error, |
|
|
|
}, |
|
|
|
); |
|
|
|
throw error; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* Enhanced database execution method with error handling |
|
|
|
*/ |
|
|
|
async dbQuery(sql: string, params?: unknown[]) { |
|
|
|
return await (this as any).platformService.dbQuery(sql, params); |
|
|
|
async $dbExec(sql: string, params?: unknown[]) { |
|
|
|
try { |
|
|
|
return await (this as any).platformService.dbExec(sql, params); |
|
|
|
} catch (error) { |
|
|
|
console.error( |
|
|
|
`[${(this as any).$options.name}] Database exec failed:`, |
|
|
|
{ |
|
|
|
sql, |
|
|
|
params, |
|
|
|
error, |
|
|
|
}, |
|
|
|
); |
|
|
|
throw error; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* Convenient database execution method |
|
|
|
* Shorthand for this.platformService.dbExec() |
|
|
|
* Enhanced database single row method with error handling |
|
|
|
*/ |
|
|
|
async dbExec(sql: string, params?: unknown[]) { |
|
|
|
return await (this as any).platformService.dbExec(sql, params); |
|
|
|
async $dbGetOneRow(sql: string, params?: unknown[]) { |
|
|
|
try { |
|
|
|
return await (this as any).platformService.dbGetOneRow(sql, params); |
|
|
|
} catch (error) { |
|
|
|
console.error( |
|
|
|
`[${(this as any).$options.name}] Database getOneRow failed:`, |
|
|
|
{ |
|
|
|
sql, |
|
|
|
params, |
|
|
|
error, |
|
|
|
}, |
|
|
|
); |
|
|
|
throw error; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* Convenient database single row method |
|
|
|
* Shorthand for this.platformService.dbGetOneRow() |
|
|
|
* Utility method for retrieving and parsing settings |
|
|
|
* Common pattern used across many components |
|
|
|
*/ |
|
|
|
async dbGetOneRow(sql: string, params?: unknown[]) { |
|
|
|
return await (this as any).platformService.dbGetOneRow(sql, params); |
|
|
|
async $getSettings(key: string, fallback: any = null) { |
|
|
|
try { |
|
|
|
const result = await this.$dbQuery( |
|
|
|
"SELECT * FROM settings WHERE id = ? OR accountDid = ?", |
|
|
|
[key, key], |
|
|
|
); |
|
|
|
|
|
|
|
if (!result?.values?.length) { |
|
|
|
return fallback; |
|
|
|
} |
|
|
|
|
|
|
|
const settings = mapColumnsToValues( |
|
|
|
result.columns, |
|
|
|
result.values, |
|
|
|
)[0] as any; |
|
|
|
|
|
|
|
// Handle JSON field parsing
|
|
|
|
if (settings.searchBoxes) { |
|
|
|
settings.searchBoxes = parseJsonField(settings.searchBoxes, []); |
|
|
|
} |
|
|
|
|
|
|
|
return settings; |
|
|
|
} catch (error) { |
|
|
|
console.error( |
|
|
|
`[${(this as any).$options.name}] Failed to get settings:`, |
|
|
|
{ |
|
|
|
key, |
|
|
|
error, |
|
|
|
}, |
|
|
|
); |
|
|
|
return fallback; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* Utility method for merging default and account-specific settings |
|
|
|
* Handles the common pattern of layered settings |
|
|
|
*/ |
|
|
|
async $getMergedSettings( |
|
|
|
defaultKey: string, |
|
|
|
accountDid?: string, |
|
|
|
defaultFallback: any = {}, |
|
|
|
) { |
|
|
|
try { |
|
|
|
// Get default settings
|
|
|
|
const defaultSettings = await this.$getSettings( |
|
|
|
defaultKey, |
|
|
|
defaultFallback, |
|
|
|
); |
|
|
|
|
|
|
|
// If no account DID, return defaults
|
|
|
|
if (!accountDid) { |
|
|
|
return defaultSettings; |
|
|
|
} |
|
|
|
|
|
|
|
// Get account-specific overrides
|
|
|
|
const accountResult = await this.$dbQuery( |
|
|
|
"SELECT * FROM settings WHERE accountDid = ?", |
|
|
|
[accountDid], |
|
|
|
); |
|
|
|
|
|
|
|
if (!accountResult?.values?.length) { |
|
|
|
return defaultSettings; |
|
|
|
} |
|
|
|
|
|
|
|
// Map and filter non-null overrides
|
|
|
|
const overrideSettings = mapColumnsToValues( |
|
|
|
accountResult.columns, |
|
|
|
accountResult.values, |
|
|
|
)[0] as any; |
|
|
|
|
|
|
|
const filteredOverrides = Object.fromEntries( |
|
|
|
Object.entries(overrideSettings).filter(([_, v]) => v !== null), |
|
|
|
); |
|
|
|
|
|
|
|
// Merge settings with overrides taking precedence
|
|
|
|
const mergedSettings = { ...defaultSettings, ...filteredOverrides }; |
|
|
|
|
|
|
|
// Handle JSON field parsing
|
|
|
|
if (mergedSettings.searchBoxes) { |
|
|
|
mergedSettings.searchBoxes = parseJsonField( |
|
|
|
mergedSettings.searchBoxes, |
|
|
|
[], |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
return mergedSettings; |
|
|
|
} catch (error) { |
|
|
|
console.error( |
|
|
|
`[${(this as any).$options.name}] Failed to get merged settings:`, |
|
|
|
{ |
|
|
|
defaultKey, |
|
|
|
accountDid, |
|
|
|
error, |
|
|
|
}, |
|
|
|
); |
|
|
|
return defaultFallback; |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
/** |
|
|
|
* Utility method for safe database transactions |
|
|
|
* Handles common transaction patterns with proper error handling |
|
|
|
*/ |
|
|
|
async $withTransaction<T>(callback: () => Promise<T>): Promise<T> { |
|
|
|
try { |
|
|
|
await this.$dbExec("BEGIN TRANSACTION"); |
|
|
|
const result = await callback(); |
|
|
|
await this.$dbExec("COMMIT"); |
|
|
|
return result; |
|
|
|
} catch (error) { |
|
|
|
await this.$dbExec("ROLLBACK"); |
|
|
|
console.error( |
|
|
|
`[${(this as any).$options.name}] Transaction failed:`, |
|
|
|
error, |
|
|
|
); |
|
|
|
throw error; |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Type-only export for components that need to declare the mixin interface |
|
|
|
* Enhanced interface with utility methods |
|
|
|
*/ |
|
|
|
export interface IPlatformServiceMixin { |
|
|
|
platformService: PlatformService; |
|
|
|
dbQuery(sql: string, params?: unknown[]): Promise<any>; |
|
|
|
dbExec(sql: string, params?: unknown[]): Promise<any>; |
|
|
|
dbGetOneRow(sql: string, params?: unknown[]): Promise<any>; |
|
|
|
$dbQuery(sql: string, params?: unknown[]): Promise<any>; |
|
|
|
$dbExec(sql: string, params?: unknown[]): Promise<any>; |
|
|
|
$dbGetOneRow(sql: string, params?: unknown[]): Promise<any>; |
|
|
|
$getSettings(key: string, fallback?: any): Promise<any>; |
|
|
|
$getMergedSettings( |
|
|
|
defaultKey: string, |
|
|
|
accountDid?: string, |
|
|
|
defaultFallback?: any, |
|
|
|
): Promise<any>; |
|
|
|
$withTransaction<T>(callback: () => Promise<T>): Promise<T>; |
|
|
|
isCapacitor: boolean; |
|
|
|
isWeb: boolean; |
|
|
|
isElectron: boolean; |
|
|
|