You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
8.3 KiB
309 lines
8.3 KiB
/**
|
|
* Platform Service Mixin for Vue Components
|
|
*
|
|
* Provides class-level caching of platform service instances to avoid
|
|
* repeated PlatformServiceFactory.getInstance() calls throughout components.
|
|
*
|
|
* This mixin implements a hybrid approach combining:
|
|
* - 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 2.0.0
|
|
* @since 2025-07-02
|
|
*/
|
|
|
|
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
|
import type { PlatformService } from "@/services/PlatformService";
|
|
import { mapColumnsToValues, parseJsonField } from "@/db/databaseUtil";
|
|
|
|
/**
|
|
* Enhanced mixin that provides cached platform service access and utility methods
|
|
*
|
|
* Usage:
|
|
* ```typescript
|
|
* @Component({
|
|
* mixins: [PlatformServiceMixin]
|
|
* })
|
|
* export default class MyComponent extends Vue {
|
|
* async someMethod() {
|
|
* // Direct access without type assertions
|
|
* const result = await this.$dbQuery('SELECT * FROM users');
|
|
*
|
|
* // Utility methods for common patterns
|
|
* const settings = await this.$getSettings('user123');
|
|
* }
|
|
* }
|
|
* ```
|
|
*/
|
|
export const PlatformServiceMixin = {
|
|
data() {
|
|
return {
|
|
_platformService: null as PlatformService | null,
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
/**
|
|
* Get the cached platform service instance
|
|
* Creates and caches the instance on first access
|
|
*/
|
|
platformService(): PlatformService {
|
|
if (!(this as any)._platformService) {
|
|
(this as any)._platformService = PlatformServiceFactory.getInstance();
|
|
}
|
|
return (this as any)._platformService;
|
|
},
|
|
|
|
/**
|
|
* Check if running on Capacitor platform
|
|
*/
|
|
isCapacitor(): boolean {
|
|
const service = (this as any).platformService as any;
|
|
return typeof service.isCapacitor === "function"
|
|
? service.isCapacitor()
|
|
: false;
|
|
},
|
|
|
|
/**
|
|
* Check if running on web platform
|
|
*/
|
|
isWeb(): boolean {
|
|
const service = (this as any).platformService as any;
|
|
return typeof service.isWeb === "function" ? service.isWeb() : false;
|
|
},
|
|
|
|
/**
|
|
* Check if running on Electron platform
|
|
*/
|
|
isElectron(): boolean {
|
|
const service = (this as any).platformService as any;
|
|
return typeof service.isElectron === "function"
|
|
? service.isElectron()
|
|
: false;
|
|
},
|
|
|
|
/**
|
|
* Get platform capabilities
|
|
*/
|
|
capabilities() {
|
|
return (this as any).platformService.getCapabilities();
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
/**
|
|
* 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 $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;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Enhanced database single row method with error handling
|
|
*/
|
|
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;
|
|
}
|
|
},
|
|
},
|
|
};
|
|
|
|
/**
|
|
* 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>;
|
|
$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;
|
|
capabilities: any;
|
|
}
|
|
|