graphql: Subscription filter not working

I’m submitting a…


[ ] Regression 
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

For the following simple example:

  @Subscription(returns => Object, {
    filter: (payload: any, variables: any) => {
      console.log('payload', payload);
      console.log('variables', variables);
      return true;
    },
  })
  objectAdded() {
    return pubSub.asyncIterator<Station>('objectAdded');
  }

Got the following result:

TypeError: asyncIterator.return is not a function

Because in https://github.com/nestjs/graphql/blob/master/lib/services/resolvers-explorer.service.ts -> createSubscriptionMetadata, when filter is present the method withFilter is called with a promise as parameter instead of AsyncIterator.

Expected behavior

No error should occur.

Minimal reproduction of the problem with instructions

  @Subscription(returns => Object, {
    filter: (payload: any, variables: any) => {
      console.log('payload', payload);
      console.log('variables', variables);
      return true;
    },
  })
  objectAdded() {
    return pubSub.asyncIterator<Station>('objectAdded');
  }

What is the motivation / use case for changing the behavior?

Cannot update the project from 5.x to 6.x.

Environment


Nest version: 6.0.1

 
For Tooling issues:
- Node version: v10.15.0  
- Platform: Mac  

Others:


The project is a NX one.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 24 (7 by maintainers)

Most upvoted comments

A temp resolution for Code first style subscription. You need an asyncInterator filter function:

@Subscription(returns => Media)
mediaChanged(@Context() ctx) {
    return asyncFilter(
        pubSub.asyncIterator('mediaChanged'),
        payload => payload.mediaChanged.userId === ctx.session.id
    )
}

asyncFilter implement below (pay attention it’s NOT same as withFilter from ‘graphql-subscriptions’):

import { $$asyncIterator } from 'iterall'

export type FilterFn<T> = (rootValue?: T) => boolean | Promise<boolean>

export const asyncFilter = <T = any>(asyncIterator: AsyncIterator<T>, filterFn: FilterFn<T>): AsyncIterator<T> => {
    const getNextPromise = () => {
        return asyncIterator.next().then(payload => {
            if (payload.done === true) {
                return payload
            }

            return Promise.resolve(filterFn(payload.value))
                .catch(() => false)
                .then(filterResult => {
                    if (filterResult === true) {
                        return payload
                    }

                    // Skip the current value and wait for the next one
                    return getNextPromise()
                })
        })
    }

    return {
        next() {
            return getNextPromise()
        },
        return() {
            return asyncIterator.return()
        },
        throw(error) {
            return asyncIterator.throw(error)
        },
        [$$asyncIterator]() {
            return this
        },
    }
}

i got the same result #182 the filter function doesn’t run

I tried it too, and the initial error is not present anymore, but the filter method is not called. The result is a subscription without filter.

Published as 6.2.0 ($ npm i @nestjs/graphql@latest). You will also have to update @nestjs/core to 6.2.0 ($ npm i @nestjs/core@latest)

Same problem

Should be fixed in 6.0.2 😃 Let me know if you face any issues