Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscription: make Subscription resolver independent of resolvers for Create and Update records #259

Open
1 of 4 tasks
Mingyang-Li opened this issue Jun 24, 2022 · 0 comments

Comments

@Mingyang-Li
Copy link

Mingyang-Li commented Jun 24, 2022

How do you make a Subscription resolver independent of resolvers for Creating and Updating records

❌ Current behaviour: subscribeTasks resolver doesn't have proper filters, nor does it return me the latest Task items

✔️ Expected behaviour: subscribeTasks resolver returns me all Task items given a filter parameter (based on TaskWhereInput) in the query

I'm building a GraphQL API using NestJS.

The API is simple, it has to do CRUD operations on Task entity - I'm using PostgreSQL

Data model:

import { Field } from '@nestjs/graphql';
import { ObjectType } from '@nestjs/graphql';
import { ID } from '@nestjs/graphql';

@ObjectType()
export class Task {
  @Field(() => ID, { nullable: false })
  id!: string;

  @Field(() => String, { nullable: true })
  title!: string | null;

  @Field(() => Date, { nullable: true })
  createdAt!: Date | null;

  @Field(() => Boolean, { nullable: true, defaultValue: false })
  completed!: boolean | null;

  @Field(() => Date, { nullable: true })
  completedAt!: Date | null;
}

The API needs to have the following 3 core resolvers:

  • createTask => creates a task in db
  • updateTask => update a task in db
  • subscribeTasks => subscribe to tasks given a filter parameter, and the tasks subscribed need to update whenever a Task is created or updated

⚠️My biggest question:

How do I make sure subscribeTasks resolver only updates the tasks subscribed BASED ON CHANGES IN THE DB? (rather than triggering updates all the tasks subscribed using PubSub by publishing pubSubEvents in createTask and updateTask resolvers?)

I also need a proper filter to be applied on subscribeTasks resolver. So that I can write subscription queries like how I'd do with a normal gql query like this:

subscription {
  subscribeTasks (
    where: {
      completed: {
        equals: false
      },
      createdAt: {
        equals: "2022-06-25"
      }
    }
  ) {
    id
    title
    completed
    completedAt
    createdAt
  }
}

TaskWhereInput:

@InputType()
export class TaskWhereInput {
  @Field(() => [TaskWhereInput], { nullable: true })
  AND?: Array<TaskWhereInput>;

  @Field(() => [TaskWhereInput], { nullable: true })
  OR?: Array<TaskWhereInput>;

  @Field(() => [TaskWhereInput], { nullable: true })
  NOT?: Array<TaskWhereInput>;

  @Field(() => StringFilter, { nullable: true })
  id?: StringFilter;

  @Field(() => StringNullableFilter, { nullable: true })
  title?: StringNullableFilter;

  @Field(() => DateTimeNullableFilter, { nullable: true })
  createdAt?: DateTimeNullableFilter;

  @Field(() => BoolNullableFilter, { nullable: true })
  completed?: BoolNullableFilter;

  @Field(() => DateTimeNullableFilter, { nullable: true })
  completedAt?: DateTimeNullableFilter;
}

This is how my resolvers look like:

import { Resolver, Mutation, Subscription, Args, Query } from '@nestjs/graphql';
import { PubSub } from 'graphql-subscriptions';
import { TaskCreateInput } from 'src/generated/task/task-create.input';
import { TaskUpdateInput } from 'src/generated/task/task-update.input';
import { TaskWhereUniqueInput } from 'src/generated/task/task-where-unique.input';
import { TaskWhereInput } from 'src/generated/task/task-where.input';
import { Task } from 'src/generated/task/task.model';
import { TaskService } from './Task.service';

@Resolver(() => Task)
export class TaskResolver {
  constructor(
    private readonly taskService: TaskService,
    private pubsub: PubSub,
  ) {}

  @Mutation(() => [Task])
  public async createTask(@Args('input') input: TaskCreateInput) {
    try {
      const res = await this.taskService.createTask(input);
      this.pubsub.publish('taskUpdatedEvent', { taskUpdatedEvent: res });
      return res;
    } catch (error) {
      throw error;
    }
  }

  @Mutation(() => [Task])
  public async updateTask(
    @Args('where') where: TaskWhereUniqueInput,
    @Args('data') data: TaskUpdateInput,
  ) {
    try {
      const res = await this.taskService.updateTask(where, data);
      this.pubsub.publish('taskAddedEvent', { taskAddedEvent: res });
      return res;
    } catch (error) {
      throw error;
    }
  }

  @Subscription(() => [Task])
  public async subscribeTasks(
    @Args('where', { nullable: true }) where?: TaskWhereInput,
  ) {
    this.pubsub.asyncIterator('taskAddedEvent');
    this.pubsub.asyncIterator('taskUpdatedEvent');
    return await this.taskService.tasks(where);
  }

  @Query(() => [Task])
  async tasks(@Args('where', { nullable: true }) where: TaskWhereInput) {
    return await this.taskService.tasks(where);
  }
}

Speaking of subscription filters, I also have no idea how to apply what's on NestJS doc in my use case (MANY filters, not just one)

NestJS doc filter demo:

@Subscription(returns => Comment, {
  filter: (payload, variables) =>
    payload.commentAdded.title === variables.title,
})
commentAdded(@Args('title') title: string) {
  return pubSub.asyncIterator('commentAdded');
}
  • has-reproduction
  • feature
  • blocking
  • good first issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant