diff --git a/src/core/classes/database/database-table-proxy.ts b/src/core/classes/database/database-table-proxy.ts index 393e07ac4..ef7e50b35 100644 --- a/src/core/classes/database/database-table-proxy.ts +++ b/src/core/classes/database/database-table-proxy.ts @@ -12,8 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { CoreConstants } from '@/core/constants'; import { CorePromisedValue } from '@classes/promised-value'; import { SQLiteDB, SQLiteDBRecordValues } from '@classes/sqlitedb'; +import { CoreConfigProvider } from '@services/config'; +import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreDatabaseReducer, CoreDatabaseTable, CoreDatabaseConditions, GetDBRecordPrimaryKey } from './database-table'; import { CoreEagerDatabaseTable } from './eager-database-table'; import { CoreLazyDatabaseTable } from './lazy-database-table'; @@ -31,6 +34,7 @@ export class CoreDatabaseTableProxy< protected config: CoreDatabaseConfiguration; protected target: CorePromisedValue> = new CorePromisedValue(); + protected environmentObserver?: CoreEventObserver; constructor( config: Partial, @@ -47,11 +51,16 @@ export class CoreDatabaseTableProxy< * @inheritdoc */ async initialize(): Promise { - const target = this.createTarget(); + this.environmentObserver = CoreEvents.on(CoreConfigProvider.ENVIRONMENT_UPDATED, () => this.updateTarget()); - await target.initialize(); + await this.updateTarget(); + } - this.target.resolve(target); + /** + * @inheritdoc + */ + async destroy(): Promise { + this.environmentObserver?.off(); } /** @@ -146,13 +155,46 @@ export class CoreDatabaseTableProxy< }; } + /** + * Get database configuration to use at runtime. + * + * @returns Database configuration. + */ + protected getRuntimeConfig(): CoreDatabaseConfiguration { + return { + ...this.config, + ...CoreConstants.CONFIG.databaseOptimizations, + ...CoreConstants.CONFIG.databaseTableOptimizations?.[this.tableName], + }; + } + + /** + * Update underlying target instance. + */ + protected async updateTarget(): Promise { + const oldTarget = this.target.value; + const newTarget = this.createTarget(); + + if (oldTarget) { + await oldTarget.destroy(); + + this.target.reset(); + } + + await newTarget.initialize(); + + this.target.resolve(newTarget); + } + /** * Create proxy target. * * @returns Target instance. */ protected createTarget(): CoreDatabaseTable { - return this.createTable(this.config.cachingStrategy); + const config = this.getRuntimeConfig(); + + return this.createTable(config.cachingStrategy); } /** diff --git a/src/core/classes/promised-value.ts b/src/core/classes/promised-value.ts index ae7bbbdec..16051be37 100644 --- a/src/core/classes/promised-value.ts +++ b/src/core/classes/promised-value.ts @@ -134,6 +134,16 @@ export class CorePromisedValue implements Promise { this._reject(reason); } + /** + * Reset status and value. + */ + reset(): void { + delete this._resolvedValue; + delete this._rejectedReason; + + this.initPromise(); + } + /** * Initialize the promise and the callbacks. */ diff --git a/src/core/constants.ts b/src/core/constants.ts index 2c238261b..b83e896a8 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -145,23 +145,6 @@ export class CoreConstants { static readonly CONFIG = { ...envJson.config } as unknown as EnvironmentConfig; // Data parsed from config.json files. static readonly BUILD = envJson.build as unknown as EnvironmentBuild; // Build info. - /** - * Update config with the given values. - * - * @param config Config updates. - */ - static patchConfig(config: Partial): void { - Object.assign(this.CONFIG, config); - } - - /** - * Reset config values to its original state. - */ - static resetConfig(): void { - Object.keys(this.CONFIG).forEach(key => delete this.CONFIG[key]); - Object.assign(this.CONFIG, envJson.config); - } - } interface EnvironmentBuild { diff --git a/src/core/services/config.ts b/src/core/services/config.ts index 7b52fcd3e..d804535f1 100644 --- a/src/core/services/config.ts +++ b/src/core/services/config.ts @@ -12,14 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { EnvironmentConfig } from '@/types/config'; import { Injectable } from '@angular/core'; import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/database/database-table-proxy'; import { CoreApp } from '@services/app'; import { APP_SCHEMA, ConfigDBEntry, CONFIG_TABLE_NAME } from '@services/database/config'; import { makeSingleton } from '@singletons'; +import { CoreConstants } from '../constants'; +import { CoreEvents } from '@singletons/events'; import { CoreDatabaseTable } from '@classes/database/database-table'; import { CorePromisedValue } from '@classes/promised-value'; +declare module '@singletons/events' { + + /** + * Augment CoreEventsData interface with events specific to this service. + * + * @see https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation + */ + export interface CoreEventsData { + [CoreConfigProvider.ENVIRONMENT_UPDATED]: EnvironmentConfig; + } + +} + /** * Factory to provide access to dynamic and permanent config and settings. * It should not be abused into a temporary storage. @@ -27,7 +43,10 @@ import { CorePromisedValue } from '@classes/promised-value'; @Injectable({ providedIn: 'root' }) export class CoreConfigProvider { + static readonly ENVIRONMENT_UPDATED = 'environment_updated'; + protected table: CorePromisedValue> = new CorePromisedValue(); + protected defaultEnvironment?: EnvironmentConfig; /** * Initialize database. @@ -98,6 +117,33 @@ export class CoreConfigProvider { await table.insert({ name, value }); } + /** + * Update config with the given values. + * + * @param config Config updates. + */ + patchEnvironment(config: Partial): void { + this.defaultEnvironment = this.defaultEnvironment ?? CoreConstants.CONFIG; + + Object.assign(CoreConstants.CONFIG, config); + CoreEvents.trigger(CoreConfigProvider.ENVIRONMENT_UPDATED, CoreConstants.CONFIG); + } + + /** + * Reset config values to its original state. + */ + resetEnvironment(): void { + if (!this.defaultEnvironment) { + // The environment config hasn't been modified; there's not need to reset. + + return; + } + + Object.keys(CoreConstants.CONFIG).forEach(key => delete CoreConstants.CONFIG[key]); + Object.assign(CoreConstants.CONFIG, this.defaultEnvironment); + CoreEvents.trigger(CoreConfigProvider.ENVIRONMENT_UPDATED, CoreConstants.CONFIG); + } + } export const CoreConfig = makeSingleton(CoreConfigProvider); diff --git a/src/types/config.d.ts b/src/types/config.d.ts index c5627bc99..c8fa468bc 100644 --- a/src/types/config.d.ts +++ b/src/types/config.d.ts @@ -17,6 +17,7 @@ import { CoreMainMenuLocalizedCustomItem } from '@features/mainmenu/services/mai import { CoreSitesDemoSiteData } from '@services/sites'; import { OpenFileAction } from '@services/utils/utils'; import { CoreLoginSiteSelectorListMethod } from '@features/login/services/login-helper'; +import { CoreDatabaseConfiguration } from '@classes/database/database-table-proxy'; /* eslint-disable @typescript-eslint/naming-convention */ @@ -31,6 +32,8 @@ export interface EnvironmentConfig { cache_update_frequency_rarely: number; default_lang: string; languages: Record; + databaseOptimizations?: Partial; + databaseTableOptimizations?: Record>; wsservice: string; demo_sites: Record; zoomlevels: Record;