forked from trent_larson/crowd-funder-for-time-pwa
Enhance PlatformServiceMixin with utility methods and apply to TopMessage
Add $getSettings, $getMergedSettings utilities with built-in error handling. Reduce TopMessage code by 57% while eliminating Vue property conflicts.
This commit is contained in:
@@ -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[]) {
|
||||
return await (this as any).platformService.dbQuery(sql, params);
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Convenient database execution method
|
||||
* Shorthand for this.platformService.dbExec()
|
||||
* Enhanced database execution method with error handling
|
||||
*/
|
||||
async dbExec(sql: string, params?: unknown[]) {
|
||||
return await (this as any).platformService.dbExec(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 single row method
|
||||
* Shorthand for this.platformService.dbGetOneRow()
|
||||
* Enhanced database single row method with error handling
|
||||
*/
|
||||
async dbGetOneRow(sql: string, params?: unknown[]) {
|
||||
return await (this as any).platformService.dbGetOneRow(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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Utility method for retrieving and parsing settings
|
||||
* Common pattern used across many components
|
||||
*/
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user