feat(utils): createKeyedSignal key/value overload

This commit is contained in:
Josep M Sobrepere 2021-04-01 23:53:30 +02:00
parent ca8bfae61d
commit d92092f721
2 changed files with 77 additions and 8 deletions

View File

@ -42,6 +42,57 @@ describe("createKeyedSignal", () => {
subscription2.unsubscribe()
})
it("receives a key selector and returns a tuple with an observable-getter and its corresponding event-emitter", () => {
const [getFooBar$, onFooBar] = createKeyedSignal(
(signal: { key: string; foo: number; bar: string }) => signal.key,
)
let receivedValue1
let nHits1 = 0
const subscription1 = getFooBar$("key").subscribe((val) => {
receivedValue1 = val
nHits1++
})
expect(receivedValue1).toBe(undefined)
onFooBar({ key: "key", foo: 0, bar: "1" })
expect(receivedValue1).toEqual({ foo: 0, bar: "1", key: "key" })
expect(nHits1).toBe(1)
let receivedValue2
let nHits2 = 0
const subscription2 = getFooBar$("key").subscribe((val) => {
receivedValue2 = val
nHits2++
})
expect(receivedValue2).toBe(undefined)
onFooBar({ key: "key", foo: 1, bar: "2" })
expect(receivedValue1).toEqual({ foo: 1, bar: "2", key: "key" })
expect(nHits1).toBe(2)
expect(receivedValue2).toEqual({ foo: 1, bar: "2", key: "key" })
expect(nHits2).toBe(1)
onFooBar({ key: "key2", foo: 1, bar: "2" })
expect(nHits1).toBe(2)
expect(nHits2).toBe(1)
subscription1.unsubscribe()
subscription2.unsubscribe()
})
it("returns a tupe with a typed observable and its corresponding event-emitter for the key-value overload", () => {
const [foo$, onFoo] = createKeyedSignal<string, number>()
let receivedValue
foo$("foo").subscribe((val) => {
receivedValue = val
})
expect(receivedValue).toBe(undefined)
onFoo("foo", 5)
expect(receivedValue).toEqual(5)
})
it('returns a tuple with a typed observable and its corresponding event-emitter when no "event creator" is provided', () => {
const [foo$, onFoo] = createKeyedSignal<string>()
let receivedValue

View File

@ -1,4 +1,4 @@
import { GroupedObservable, identity, Observable, Observer } from "rxjs"
import { GroupedObservable, Observable, Observer } from "rxjs"
/**
* Creates a "keyed" signal. It's sugar for splitting the Observer and the Observable of a keyed signal.
@ -20,7 +20,20 @@ export function createKeyedSignal<T>(): [
* 1. The getter function that returns the GroupedObservable<K, T>
* 2. The emitter function.
*/
export function createKeyedSignal<T, K, A extends any[]>(
export function createKeyedSignal<K, T>(): [
(key: K) => GroupedObservable<K, T>,
(key: K, value: T) => void,
]
/**
* Creates a "keyed" signal. It's sugar for splitting the Observer and the Observable of a keyed signal.
*
* @param keySelector a function that extracts the key from the emitted value
* @returns [1, 2]
* 1. The getter function that returns the GroupedObservable<K, T>
* 2. The emitter function.
*/
export function createKeyedSignal<K, T>(
keySelector: (signal: T) => K,
): [(key: K) => GroupedObservable<K, T>, (signal: T) => void]
@ -33,14 +46,14 @@ export function createKeyedSignal<T, K, A extends any[]>(
* 1. The getter function that returns the GroupedObservable<K, T>
* 2. The emitter function (...args: any[]) => T.
*/
export function createKeyedSignal<T, K, A extends any[]>(
export function createKeyedSignal<K, T, A extends any[]>(
keySelector: (signal: T) => K,
mapper: (...args: A) => T,
): [(key: K) => GroupedObservable<K, T>, (...args: A) => void]
export function createKeyedSignal<T, K, A extends any[]>(
keySelector: (signal: T) => K = identity as any,
mapper: (...args: A) => T = identity as any,
export function createKeyedSignal<K, T, A extends any[]>(
keySelector?: (signal: T) => K,
mapper?: (...args: A) => T,
): [(key: K) => GroupedObservable<K, T>, (...args: A) => void] {
const observersMap = new Map<K, Set<Observer<T>>>()
@ -63,8 +76,13 @@ export function createKeyedSignal<T, K, A extends any[]>(
return res
},
(...args: A) => {
const payload = mapper(...args)
observersMap.get(keySelector(payload))?.forEach((o) => {
const payload = mapper
? mapper(...args)
: args.length === 2
? args[1]
: args[0]
const key = keySelector ? keySelector(payload) : args[0]
observersMap.get(key)?.forEach((o) => {
o.next(payload)
})
},