diff --git a/src/core/services/database/local-notifications.ts b/src/core/services/database/local-notifications.ts index b8c735a93..80326c6f3 100644 --- a/src/core/services/database/local-notifications.ts +++ b/src/core/services/database/local-notifications.ts @@ -74,7 +74,22 @@ export const APP_SCHEMA: CoreAppSchema = { }; export type CodeRequestsQueueItem = { - table: string; + table: typeof SITES_TABLE_NAME | typeof COMPONENTS_TABLE_NAME; id: string; deferreds: CorePromisedValue[]; }; + +export type CoreLocalNotificationsSitesDBRecord = { + id: string; + code: number; +}; + +export type CoreLocalNotificationsComponentsDBRecord = { + id: string; + code: number; +}; + +export type CoreLocalNotificationsTriggeredDBRecord = { + id: number; + at: number; +}; diff --git a/src/core/services/local-notifications.ts b/src/core/services/local-notifications.ts index f7cc1b4ba..f6ea2cdd5 100644 --- a/src/core/services/local-notifications.ts +++ b/src/core/services/local-notifications.ts @@ -20,7 +20,6 @@ import { CoreApp } from '@services/app'; import { CoreConfig } from '@services/config'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreTextUtils } from '@services/utils/text'; -import { SQLiteDB } from '@classes/sqlitedb'; import { CoreQueueRunner } from '@classes/queue-runner'; import { CoreError } from '@classes/errors/error'; import { CoreConstants } from '@/core/constants'; @@ -32,10 +31,16 @@ import { COMPONENTS_TABLE_NAME, SITES_TABLE_NAME, CodeRequestsQueueItem, + CoreLocalNotificationsTriggeredDBRecord, + CoreLocalNotificationsComponentsDBRecord, + CoreLocalNotificationsSitesDBRecord, } from '@services/database/local-notifications'; import { CorePromisedValue } from '@classes/promised-value'; import { CorePlatform } from '@services/platform'; import { Push } from '@features/native/plugins'; +import { AsyncInstance, asyncInstance } from '@/core/utils/async-instance'; +import { CoreDatabaseTable } from '@classes/database/database-table'; +import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/database/database-table-proxy'; /** * Service to handle local notifications. @@ -56,12 +61,11 @@ export class CoreLocalNotificationsProvider { protected updateSubscription?: Subscription; protected queueRunner: CoreQueueRunner; // Queue to decrease the number of concurrent calls to the plugin (see MOBILE-3477). - // Variables for DB. - protected appDB: Promise; - protected resolveAppDB!: (appDB: SQLiteDB) => void; + protected sitesTable = asyncInstance>(); + protected componentsTable = asyncInstance>(); + protected triggeredTable = asyncInstance>(); constructor() { - this.appDB = new Promise(resolve => this.resolveAppDB = resolve); this.logger = CoreLogger.getInstance('CoreLocalNotificationsProvider'); this.queueRunner = new CoreQueueRunner(10); } @@ -127,7 +131,36 @@ export class CoreLocalNotificationsProvider { // Ignore errors. } - this.resolveAppDB(CoreApp.getDB()); + const database = CoreApp.getDB(); + const sitesTable = new CoreDatabaseTableProxy( + { cachingStrategy: CoreDatabaseCachingStrategy.None }, + database, + SITES_TABLE_NAME, + ['id'], + null, + ); + const componentsTable = new CoreDatabaseTableProxy( + { cachingStrategy: CoreDatabaseCachingStrategy.None }, + database, + COMPONENTS_TABLE_NAME, + ['id'], + null, + ); + const triggeredTable = new CoreDatabaseTableProxy( + { cachingStrategy: CoreDatabaseCachingStrategy.None }, + database, + TRIGGERED_TABLE_NAME, + ); + + await Promise.all([ + sitesTable.initialize(), + componentsTable.initialize(), + triggeredTable.initialize(), + ]); + + this.sitesTable.setInstance(sitesTable); + this.componentsTable.setInstance(componentsTable); + this.triggeredTable.setInstance(triggeredTable); } /** @@ -222,7 +255,10 @@ export class CoreLocalNotificationsProvider { * @param id ID of the element to get its code. * @returns Promise resolved when the code is retrieved. */ - protected async getCode(table: string, id: string): Promise { + protected async getCode( + table: AsyncInstance>, + id: string, + ): Promise { const key = table + '#' + id; // Check if the code is already in memory. @@ -230,25 +266,27 @@ export class CoreLocalNotificationsProvider { return this.codes[key]; } - const db = await this.appDB; - try { // Check if we already have a code stored for that ID. - const entry = await db.getRecord<{id: string; code: number}>(table, { id: id }); + const entry = await table.getOneByPrimaryKey({ id: id }); this.codes[key] = entry.code; return entry.code; } catch (err) { // No code stored for that ID. Create a new code for it. - const entries = await db.getRecords<{id: string; code: number}>(table, undefined, 'code DESC'); + const entries = await table.getMany(undefined, { + sorting: [ + { code: 'desc' }, + ], + }); let newCode = 0; if (entries.length > 0) { newCode = entries[0].code + 1; } - await db.insertRecord(table, { id: id, code: newCode }); + await table.insert({ id: id, code: newCode }); this.codes[key] = newCode; return newCode; @@ -347,13 +385,12 @@ export class CoreLocalNotificationsProvider { * @returns Promise resolved with a boolean indicating if promise is triggered (true) or not. */ async isTriggered(notification: ILocalNotification, useQueue: boolean = true): Promise { - const db = await this.appDB; + if (notification.id === undefined) { + return false; + } try { - const stored = await db.getRecord<{ id: number; at: number }>( - TRIGGERED_TABLE_NAME, - { id: notification.id }, - ); + const stored = await this.triggeredTable.getOneByPrimaryKey({ id: notification.id }); let triggered = (notification.trigger && notification.trigger.at) || 0; @@ -439,7 +476,18 @@ export class CoreLocalNotificationsProvider { } // Get the code and resolve/reject all the promises of this request. - const code = await this.getCode(request.table, request.id); + const getCodeFromTable = async () => { + switch (request.table) { + case SITES_TABLE_NAME: + return this.getCode(this.sitesTable, request.id); + case COMPONENTS_TABLE_NAME: + return this.getCode(this.componentsTable, request.id); + default: + throw new Error(`Unknown local-notifications table: ${request.table}`); + } + }; + + const code = await getCodeFromTable(); request.deferreds.forEach((p) => { p.resolve(code); @@ -506,9 +554,7 @@ export class CoreLocalNotificationsProvider { * @returns Promise resolved when it is removed. */ async removeTriggered(id: number): Promise { - const db = await this.appDB; - - await db.deleteRecords(TRIGGERED_TABLE_NAME, { id: id }); + await this.triggeredTable.deleteByPrimaryKey({ id }); } /** @@ -518,7 +564,7 @@ export class CoreLocalNotificationsProvider { * @param id ID of the element to get its code. * @returns Promise resolved when the code is retrieved. */ - protected requestCode(table: string, id: string): Promise { + protected requestCode(table: typeof SITES_TABLE_NAME | typeof COMPONENTS_TABLE_NAME, id: string): Promise { const deferred = new CorePromisedValue(); const key = table + '#' + id; const isQueueEmpty = Object.keys(this.codeRequestsQueue).length == 0; @@ -529,8 +575,8 @@ export class CoreLocalNotificationsProvider { } else { // Add a pending request to the queue. this.codeRequestsQueue[key] = { - table: table, - id: id, + table, + id, deferreds: [deferred], }; } @@ -664,7 +710,6 @@ export class CoreLocalNotificationsProvider { * @returns Promise resolved when stored, rejected otherwise. */ async trigger(notification: ILocalNotification): Promise { - const db = await this.appDB; let time = Date.now(); if (notification.trigger?.at) { // The type says "at" is a Date, but in Android we can receive timestamps instead. @@ -675,12 +720,10 @@ export class CoreLocalNotificationsProvider { } } - const entry = { + return this.triggeredTable.insert({ id: notification.id, at: time, - }; - - return db.insertRecord(TRIGGERED_TABLE_NAME, entry); + }); } /** @@ -691,12 +734,10 @@ export class CoreLocalNotificationsProvider { * @returns Promise resolved when done. */ async updateComponentName(oldName: string, newName: string): Promise { - const db = await this.appDB; - const oldId = COMPONENTS_TABLE_NAME + '#' + oldName; const newId = COMPONENTS_TABLE_NAME + '#' + newName; - await db.updateRecords(COMPONENTS_TABLE_NAME, { id: newId }, { id: oldId }); + await this.componentsTable.update({ id: newId }, { id: oldId }); } }