chore: refactor pub/sub iterator usage across schema files

- Updated pub/sub iterator methods from `asyncIterableIterator` to `asyncIterator` in multiple schema files for improved compatibility with the latest GraphQL subscriptions.
- Refactored subscription logic in CollaborationSession, Document, Message, User, and other schema files to enhance readability and maintainability.
- Adjusted imports in GraphQL builder to utilize RedisPubSub for better performance in subscription handling.
This commit is contained in:
2024-12-08 21:54:23 +07:00
parent 8b36e7d05a
commit ba32ee8dc1
6 changed files with 19 additions and 21 deletions

View File

@@ -324,7 +324,9 @@ export class CollaborationSessionSchema extends PothosSchema {
if (!collaborationSession) { if (!collaborationSession) {
throw new Error('Collaboration session not found') throw new Error('Collaboration session not found')
} }
return ctx.websocket.pubSub.asyncIterableIterator(`collaborationSessionUpdated:${collaborationSession.id}`) return ctx.websocket.pubSub.asyncIterator([
`collaborationSessionUpdated:${collaborationSession.id}`,
]) as unknown as AsyncIterable<CollaborationSession>
}, },
resolve: async (payload: CollaborationSession) => payload, resolve: async (payload: CollaborationSession) => payload,
}), }),

View File

@@ -447,9 +447,6 @@ export class DocumentSchema extends PothosSchema {
if (!ctx.isSubscription) { if (!ctx.isSubscription) {
throw new Error('Not allowed') throw new Error('Not allowed')
} }
const {
websocket: { pubSub },
} = ctx
const documentId = args.documentId const documentId = args.documentId
// check user permission // check user permission
const document = await this.prisma.document.findUnique({ const document = await this.prisma.document.findUnique({
@@ -469,7 +466,7 @@ export class DocumentSchema extends PothosSchema {
throw new Error('User is not owner or collaborator of document') throw new Error('User is not owner or collaborator of document')
} }
} }
return pubSub.asyncIterableIterator([ return ctx.websocket.pubSub.asyncIterator([
`${DocumentEvent.CHANGED}.${documentId}`, `${DocumentEvent.CHANGED}.${documentId}`,
`${DocumentEvent.DELETED}.${documentId}`, `${DocumentEvent.DELETED}.${documentId}`,
`${DocumentEvent.SAVED}.${documentId}`, `${DocumentEvent.SAVED}.${documentId}`,

View File

@@ -12,8 +12,8 @@ import { User } from '@prisma/client'
import { JsonValue } from '@prisma/client/runtime/library' import { JsonValue } from '@prisma/client/runtime/library'
import { Request, Response } from 'express' import { Request, Response } from 'express'
import { Kind, ValueNode } from 'graphql' import { Kind, ValueNode } from 'graphql'
import { RedisPubSub } from 'graphql-redis-subscriptions'
import { JSONObjectResolver } from 'graphql-scalars' import { JSONObjectResolver } from 'graphql-scalars'
import { PubSub } from 'graphql-subscriptions'
// @ts-expect-error // @ts-expect-error
import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs' import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs'
// @ts-expect-error // @ts-expect-error
@@ -30,7 +30,7 @@ export type SchemaContext =
isSubscription: true isSubscription: true
websocket: { websocket: {
req: Request req: Request
pubSub: PubSub pubSub: RedisPubSub
sessionId: string sessionId: string
me: User me: User
generator: PrismaCrudGenerator<BuilderTypes> generator: PrismaCrudGenerator<BuilderTypes>
@@ -42,7 +42,7 @@ export type SchemaContext =
req: Request req: Request
res: Response res: Response
me: User | null me: User | null
pubSub: PubSub pubSub: RedisPubSub
invalidateCache: () => Promise<void> invalidateCache: () => Promise<void>
generator: PrismaCrudGenerator<BuilderTypes> generator: PrismaCrudGenerator<BuilderTypes>
} }
@@ -101,8 +101,8 @@ export class Builder extends SchemaBuilder<SchemaBuilderOption> {
debounceDelay: 1000, debounceDelay: 1000,
...subscribeOptionsFromIterator((name, context) => { ...subscribeOptionsFromIterator((name, context) => {
return context.isSubscription return context.isSubscription
? context.websocket.pubSub.asyncIterableIterator(name) ? context.websocket.pubSub.asyncIterator(name)
: context.http.pubSub.asyncIterableIterator(name) : context.http.pubSub.asyncIterator(name)
}), }),
}, },
zod: { zod: {

View File

@@ -119,6 +119,8 @@ import { GraphqlService } from './graphql.service'
} }
// @ts-expect-error: Request is not typed // @ts-expect-error: Request is not typed
ctx.extra.request.headers['x-session-id'] = ctx.connectionParams['x-session-id'] ctx.extra.request.headers['x-session-id'] = ctx.connectionParams['x-session-id']
// @ts-expect-error: Request is not typed
Logger.log(ctx.extra.request.headers['x-session-id'], 'Session ID')
}, },
}, },
}, },

View File

@@ -197,10 +197,9 @@ export class MessageSchema extends PothosSchema {
if (!ctx.isSubscription) { if (!ctx.isSubscription) {
throw new Error('Not allowed') throw new Error('Not allowed')
} }
const { return ctx.websocket.pubSub.asyncIterator([
websocket: { pubSub }, `${PubSubEvent.MESSAGE_SENT}.${args.chatRoomId}`,
} = ctx ]) as unknown as AsyncIterable<Message>
return pubSub.asyncIterableIterator([`${PubSubEvent.MESSAGE_SENT}.${args.chatRoomId}`])
}, },
resolve: (payload: Message) => payload, resolve: (payload: Message) => payload,
}), }),

View File

@@ -1,6 +1,6 @@
import { clerkClient } from '@clerk/express' import { clerkClient } from '@clerk/express'
import { Inject, Injectable, Logger } from '@nestjs/common' import { Inject, Injectable, Logger } from '@nestjs/common'
import { ChatRoom, Message, MessageContextType, MessageType, Role } from '@prisma/client' import { Message, Role } from '@prisma/client'
import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos' import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
import { ChatroomSchema } from '../ChatRoom/chatroom.schema' import { ChatroomSchema } from '../ChatRoom/chatroom.schema'
import { Builder, SchemaContext } from '../Graphql/graphql.builder' import { Builder, SchemaContext } from '../Graphql/graphql.builder'
@@ -547,17 +547,15 @@ export class UserSchema extends PothosSchema {
this.builder.subscriptionFields((t) => ({ this.builder.subscriptionFields((t) => ({
userScopedMessage: t.field({ userScopedMessage: t.field({
type: this.messageSchema.message(), type: this.messageSchema.message(),
subscribe: async (_, _args, ctx: SchemaContext) => { subscribe: async (_, _args, ctx) => {
if (!ctx.isSubscription) { if (!ctx.isSubscription) {
throw new Error('Not allowed') throw new Error('Not allowed')
} }
const {
websocket: { pubSub }, return ctx.websocket.pubSub.asyncIterator([
} = ctx
return pubSub.asyncIterableIterator([
`${PubSubEvent.NEW_MESSAGE}.${ctx.websocket.me?.id}`, `${PubSubEvent.NEW_MESSAGE}.${ctx.websocket.me?.id}`,
`${PubSubEvent.NOTIFICATION}.${ctx.websocket.me?.id}`, `${PubSubEvent.NOTIFICATION}.${ctx.websocket.me?.id}`,
]) ]) as unknown as AsyncIterable<Message>
}, },
resolve: async (payload: Message) => payload, resolve: async (payload: Message) => payload,
}), }),