Search code examples
typescriptrxjstypeorm

RxJS and TypeORM: uncontrolled saving of objects using iif()


I am implementing a findOrSave method for an ORM entity and wanted to combine the observables using rxjs functions concatMap and iif.

However, somehow my code doesn't work:

return from(this.repository.findOne({ where: { label: ILike('%' + title + '%') } })).pipe(concatMap(ge => {
  return iif(() => !!ge, of(ge), from(this.repository.save({label: title})));
}))

I have a non-key but unique value such as label and want to retrieve the entity using findOne. If findOne returns an entity, it should be returned. Else it should be saved and the stored entity should be returned.

While the findOne seems to work perfectly, somehow the save method is called even if the first argument of iif returns false.

I cannot really grasp this, since this snippets works:

return from(this.repository.findOne({ where: { label: ILike('%' + title + '%') } })).pipe(concatMap(ge => {
            return iif(() => !!ge, of(ge), new Observable<GreaterEntity>(subs => {
                from(this.repository.save({label:title})).subscribe(v => {
                    console.log('Saving id '+v.id)
                    subs.next(v);
                })
            }));
        }))

If someone could point me to the mistake I made, I'd be very grateful :)


Solution

  • The problem is that when are calling iif, you pass from(this.repository.save({label: title})). This immediately invokes this.repository.save() without waiting for any subscription.

    To avoid this, you can use defer.

    from(
      this.repository.findOne({ where: { label: ILike('%' + title + '%') } })
    ).pipe(
      concatMap(ge => iif(
        () => !!ge, 
        of(ge), 
        defer(() => from(this.repository.save({label: title})))
      ))
    )
    

    The callback in defer is only invoked when something subscribes to it.