From f4ffa08f867558f1835b19428442935c62187e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Fri, 17 Dec 2021 10:52:16 +0200 Subject: [PATCH] Stats generic service --- src/lib/dialog/base-dialog.component.ts | 2 +- src/lib/services/index.ts | 1 + src/lib/services/stats.service.ts | 62 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/lib/services/stats.service.ts diff --git a/src/lib/dialog/base-dialog.component.ts b/src/lib/dialog/base-dialog.component.ts index 017173d..13d1e7b 100644 --- a/src/lib/dialog/base-dialog.component.ts +++ b/src/lib/dialog/base-dialog.component.ts @@ -9,7 +9,7 @@ import { IqserEventTarget } from '../utils'; * However, some components (e.g. redaction-select, color picker) don't set focus on the input after choosing a value. * Also, other components (e.g. dropdown select) trigger a different action on enter, instead of submit. * - * Make sure to remove property type="submit" from the save button and the (submit)="save()" property from the form + * Make sure to remove the (submit)="save()" property from the form and to set type="button" on the save button * (otherwise the save request will be triggered twice). * */ export abstract class BaseDialogComponent { diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts index 214c413..026ff9d 100644 --- a/src/lib/services/index.ts +++ b/src/lib/services/index.ts @@ -3,3 +3,4 @@ export * from './toaster.service'; export * from './error-message.service'; export * from './generic.service'; export * from './composite-route.guard'; +export * from './stats.service'; diff --git a/src/lib/services/stats.service.ts b/src/lib/services/stats.service.ts new file mode 100644 index 0000000..3be767c --- /dev/null +++ b/src/lib/services/stats.service.ts @@ -0,0 +1,62 @@ +import { Inject, Injectable, Injector } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import { tap } from 'rxjs/operators'; +import { HeadersConfiguration, mapEach, RequiredParam, Validate } from '../utils'; + +@Injectable() +export abstract class StatsService { + private readonly _http = this._injector.get(HttpClient); + private readonly _map = new Map>(); + + protected constructor( + protected readonly _injector: Injector, + @Inject('ENTITY_PRIMARY_KEY') protected readonly _primaryKey: string, + @Inject('ENTITY_CLASS') private readonly _entityClass: new (entityInterface: I, ...args: unknown[]) => E, + @Inject('ENTITY_PATH') protected readonly _defaultModelPath: string, + ) {} + + @Validate() + getFor(@RequiredParam() ids: string[]): Observable { + const request = this._http.post(`/${encodeURI(this._defaultModelPath)}`, ids, { + headers: HeadersConfiguration.getHeaders(), + observe: 'body', + }); + + return request.pipe( + mapEach(entity => new this._entityClass(entity)), + tap(entities => entities.forEach(entity => this.set(entity))), + ); + } + + get(key: string): E { + return this._getBehaviourSubject(key).value; + } + + set(stats: E): void { + if (!this._map.has(this._pluckPrimaryKey(stats))) { + this._map.set(this._pluckPrimaryKey(stats), new BehaviorSubject(stats)); + return; + } + + const old = this.get(this._pluckPrimaryKey(stats)); + if (JSON.stringify(old) !== JSON.stringify(stats)) { + this._getBehaviourSubject(this._pluckPrimaryKey(stats)).next(stats); + } + } + + watch$(key: string): Observable { + return this._getBehaviourSubject(key).asObservable(); + } + + private _pluckPrimaryKey(stats: E): string { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + return stats[this._primaryKey] as string; + } + + private _getBehaviourSubject(key: string): BehaviorSubject { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return this._map.get(key)!; + } +}