I'm trying to wrap my head around how RxJS concat works, and how it works with Promises in general.
I have two observables:
currentConfirmation$ emits null
newConfirmation$ emits a new confirmation
Could someone explain why this works:
const finalConfirmation$ = currentConfirmation$.pipe(
switchMap((conf) => {
if (!conf) {
return newConfirmation$
}
return of(conf)
})
)
But this does not
const finalConfirmation$ = concat(currentConfirmation$, newConfirmation$).pipe(find((conf) => !!conf))
By not works I mean this test passes with the switchMap version and times out with the concat version
test("updateConfirmation should create the confirmation if it doesn't exist", (done) => {
updateConfirmation({ value: true, symbol: 'LTCUSD', name: 'LTC_TEST_CONFIRMATION_999' }).subscribe((conf) => {
expect(conf.entityData).toEqual({ value: true, symbol: 'LTCUSD', name: 'LTC_TEST_CONFIRMATION_999' })
done()
})
})
I would also love to know if there is a better approach to accomplishing the above than what I have come up with.
Edit: Here is all the relevant code for the test:
export const confirmationRepository$ = client$.pipe(
switchMap(async (client) => client.fetchRepository(schema)),
delayWhen((cr) => from(cr.createIndex())),
shareReplay(1)
)
export const updateConfirmation = (newData: Partial<Confirmation>) => {
// TODO: Just don't process the search if we get empty strings
const currentConfirmation$ = getConfirmation(newData.symbol || ' ', newData.name || ' ')
const newConfirmation$ = createConfirmation(newData)
// const finalConfirmation$ = concat(currentConfirmation$, newConfirmation$).pipe(find((conf) => !!conf))
const finalConfirmation$ = currentConfirmation$.pipe(
switchMap(async (conf) => {
if (!conf) {
return newConfirmation$
}
return of(conf)
}),
concatAll(),
combineLatestWith(confirmationRepository$),
concatMap(async ([conf, confRepo]) => {
conf.value = !!newData.value
await confRepo.save(conf)
return conf
})
)
return finalConfirmation$
}
export const getConfirmation = (symbol: string, name: string) => {
return confirmationRepository$.pipe(
switchMap((cr) => cr.search().where('symbol').equals(symbol).and('name').equals(name).first())
)
}
export const getConfirmations = (symbol: string) => {
return confirmationRepository$.pipe(switchMap((cr) => cr.search().where('symbol').equals(symbol).returnAll()))
}
concat only executes each observable passed in and returns each of them sequentially, and it does not mutate anything in between nor does it provide any other means to add conditional checks.
I can see your example using find that kinda hack the way through, as it completes the stream when the given condition is met, but it is probably not as semantic or natural as the switchMap version