69 lines
2.3 KiB
TypeScript
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;
|
|
}
|
|
}
|