Add Epoch<T> and use it in for the memberships$ behavior and its
derivatives.
This commit is contained in:
@@ -12,7 +12,9 @@ import {
|
||||
EMPTY,
|
||||
endWith,
|
||||
filter,
|
||||
map,
|
||||
type Observable,
|
||||
type OperatorFunction,
|
||||
share,
|
||||
take,
|
||||
takeUntil,
|
||||
@@ -151,3 +153,107 @@ export class ObservableScope {
|
||||
* The global scope, a scope which never ends.
|
||||
*/
|
||||
export const globalScope = new ObservableScope();
|
||||
|
||||
/**
|
||||
* `Epoch`'s can be used to create `Behavior`s and `Observable`s which derivitives can be merged
|
||||
* with `combinedLatest` without duplicated emissions.
|
||||
*
|
||||
* This is useful in the following example:
|
||||
* ```
|
||||
* const rootObs$ = of("red","green","blue");
|
||||
* const derivedObs$ = rootObs$.pipe(
|
||||
* map((v)=> {red:"fire", green:"grass", blue:"water"}[v])
|
||||
* );
|
||||
* const otherDerivedObs$ = rootObs$.pipe(
|
||||
* map((v)=> {red:"tomatoes", green:"leaves", blue:"sky"}[v])
|
||||
* );
|
||||
* const mergedObs$ = combineLatest([rootObs$, derivedObs$, otherDerivedObs$]).pipe(
|
||||
* map(([color, a,b]) => color + " like " + a + " and " + b)
|
||||
* );
|
||||
*
|
||||
* ```
|
||||
* will result in 6 emissions with mismatching items like "red like fire and leaves"
|
||||
*
|
||||
* # Use Epoch
|
||||
* ```
|
||||
* const rootObs$ = of(1,2,3).pipe(trackEpoch());
|
||||
* const derivedObs$ = rootObs$.pipe(
|
||||
* mapEpoch((v)=> "this number: " + v)
|
||||
* );
|
||||
* const otherDerivedObs$ = rootObs$.pipe(
|
||||
* mapEpoch((v)=> "multiplied by: " + v)
|
||||
* );
|
||||
* const mergedObs$ = combineLatest([derivedObs$, otherDerivedObs$]).pipe(
|
||||
* filter((values) => values.every((v) => v.epoch === values[0].v)),
|
||||
* map(([color, a, b]) => color + " like " + a + " and " + b)
|
||||
* );
|
||||
*
|
||||
* ```
|
||||
* will result in 3 emissions all matching (e.g. "blue like water and sky")
|
||||
*/
|
||||
export class Epoch<T> {
|
||||
public readonly epoch: number;
|
||||
public readonly value: T;
|
||||
|
||||
public constructor(value: T, epoch?: number) {
|
||||
this.value = value;
|
||||
this.epoch = epoch ?? 0;
|
||||
}
|
||||
/**
|
||||
* Maps the value inside the epoch to a new value while keeping the epoch number.
|
||||
* # usage
|
||||
* ```
|
||||
* const myEpoch$ = myObservable$.pipe(
|
||||
* map(trackEpoch()),
|
||||
* // this is the preferred way using mapEpoch
|
||||
* mapEpoch((v)=> v+1)
|
||||
* // This is how inner map can be used:
|
||||
* map((epoch) => epoch.innerMap((v)=> v+1))
|
||||
* // It is equivalent to:
|
||||
* map((epoch) => new Epoch(epoch.value + 1, epoch.epoch))
|
||||
* )
|
||||
* ```
|
||||
* See also `Epoch<T>`
|
||||
*/
|
||||
public mapInner<U>(map: (value: T) => U): Epoch<U> {
|
||||
return new Epoch<U>(map(this.value), this.epoch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `pipe` compatible map oparator that keeps the epoch in tact but allows mapping the value.
|
||||
* # usage
|
||||
* ```
|
||||
* const myEpoch$ = myObservable$.pipe(
|
||||
* map(trackEpoch()),
|
||||
* // this is the preferred way using mapEpoch
|
||||
* mapEpoch((v)=> v+1)
|
||||
* // This is how inner map can be used:
|
||||
* map((epoch) => epoch.innerMap((v)=> v+1))
|
||||
* // It is equivalent to:
|
||||
* map((epoch) => new Epoch(epoch.value + 1, epoch.epoch))
|
||||
* )
|
||||
* ```
|
||||
* See also `Epoch<T>`
|
||||
*/
|
||||
export function mapEpoch<T, U>(
|
||||
mapFn: (value: T) => U,
|
||||
): OperatorFunction<Epoch<T>, Epoch<U>> {
|
||||
return map((e) => e.mapInner(mapFn));
|
||||
}
|
||||
/**
|
||||
* # usage
|
||||
* ```
|
||||
* const myEpoch$ = myObservable$.pipe(
|
||||
* map(trackEpoch()),
|
||||
* map((epoch) => epoch.innerMap((v)=> v+1))
|
||||
* )
|
||||
* const derived = myEpoch$.pipe(
|
||||
* mapEpoch((v)=>v^2)
|
||||
* )
|
||||
* ```
|
||||
* See also `Epoch<T>`
|
||||
*/
|
||||
export function trackEpoch<T>(): OperatorFunction<T, Epoch<T>> {
|
||||
return map<T, Epoch<T>>((value, number) => new Epoch(value, number));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user