Behzad Moradi
Behzad Moradi

Reputation: 83

ERROR [ExceptionsHandler] no elements in sequence after upgrading to NestJS v8 and RxJS v7

After upgrading to NestJS v8, I had to upgrade my RxJS version as well from 6 to 7 then it started throwing ERROR [ExceptionsHandler] no elements in sequence error.

This is a sample method in one of the app services:

  show(): Observable<any> {
    return from(this.repository.fetch()).pipe(
      filter((data) => data.length > 0),
      map((data) => data.map((datum) => parseData(datum)),
    );
  }

While I had NestJS v7 and RxJS v6, the method was working just fine; in other words, if the filter operation is not passed, the map operator wouldn't be called at all and the Observable stops there.

But after upgrading to NestJS v8 and RxJS v7, if my repository does not return any data, the app starts throwing ERROR [ExceptionsHandler] no elements in sequence error.

A workaround I came up with is as follows:

  show(): Observable<any> {
    return from(this.repository.fetch()).pipe(
      filter((data) => data.length > 0),
      defaultIfEmpty([]),
      map((data) => data.map((datum) => parseData(datum)),
    );
  }

This way the error is gone but I have two more problems:

1- the map operator still runs which I do not want

2- the second one which is way more important to me is that I have to update all my services/methods which have a validation like this which is really crazy.

my dependencies are as follows:

 "dependencies": {
    "@nestjs/common": "^8.4.2",
    "@nestjs/core": "^8.4.2",
    "rxjs": "^7.5.5"
  },

Upvotes: 7

Views: 4593

Answers (1)

Jay McDoniel
Jay McDoniel

Reputation: 70201

We determined on Discord that an interceptor could be used here to set the defaultIfEmpty like so:

import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor
} from '@nestjs/common'
import { defaultIfEmpty } from 'rxjs/operators'

@Injectable()
export class DefaultIfEmptyInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    return next.handle().pipe(defaultIfEmpty([]))
  }
}

And then bind it globally in the providers part of the module with:

import { DefaultIfEmptyInterceptor } from '../defaultIfEmpty.interceptor'
import { APP_INTERCEPTOR } from '@nestjs/core'
// ...

{
  provide: APP_INTERCEPTOR,
  useClass: DefaultIfEmptyInterceptor,
}

Upvotes: 6

Related Questions