common-ui/src/lib/services/stats.service.ts
2022-09-20 15:15:23 +03:00

69 lines
2.3 KiB
TypeScript

import { inject, Injectable } from '@angular/core';
import { BehaviorSubject, Observable, switchMap } 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<E, I = E> {
protected abstract readonly _primaryKey: string;
protected abstract readonly _entityClass: new (entityInterface: I, ...args: unknown[]) => E;
protected abstract readonly _defaultModelPath: string;
readonly #http = inject(HttpClient);
readonly #map = new Map<string, BehaviorSubject<E>>();
@Validate()
getFor(@RequiredParam() ids: string[]): Observable<E[]> {
const request = this.#http.post<I[]>(`/${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<E>(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<E> {
const subject = this.#map.get(key);
if (!subject) {
return this.getFor([key]).pipe(switchMap(() => this._getBehaviourSubject(key).asObservable()));
}
return subject.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<E> {
const subject = this.#map.get(key);
if (!subject) {
throw new Error(`No stats for key ${key}`);
}
return subject;
}
}