From af433f29c09e618eaf3fbd5b663465b343eb6b56 Mon Sep 17 00:00:00 2001 From: Cole Walker Date: Sun, 20 Sep 2020 13:21:21 -0400 Subject: [PATCH 1/2] feat: :sparkles: add stream search --- src/schema/stream-type-schema.test.ts | 44 ++++++++++++++++ src/schema/stream-type-schema.ts | 73 ++++++++++++++++++++++++++- src/schema/user-type-schema.ts | 10 ++-- 3 files changed, 121 insertions(+), 6 deletions(-) diff --git a/src/schema/stream-type-schema.test.ts b/src/schema/stream-type-schema.test.ts index b2c6e24..db7ff4a 100644 --- a/src/schema/stream-type-schema.test.ts +++ b/src/schema/stream-type-schema.test.ts @@ -82,4 +82,48 @@ describe('StreamModule', () => { const stream = result?.data?.latestSub?.user?.stream expect(stream).toMatchObject(expectedStream) }) + + it('getStreams', async () => { + const app = createApplication({ + modules: [ + QueryModule, + SubscriberModule, + UserModule, + UserSubscriberLinkModule, + StreamModule, + StreamUserLinkModule, + ], + }) + const schema = app.createSchemaForApollo() + + const document = parse(` + { + getStreams( + streamFilter: { + userNames: ["supcole"] + } + ) { + nodes { + language + gameId + id + title + viewers + thumbnailUrl + userDisplayName + userId + } + } + } + `) + const contextValue = { request: {}, response: {} } + const result = await execute({ + schema, + contextValue, + document, + }) + expect(result?.errors?.length).toBeFalsy() + const stream = result?.data?.getStreams?.nodes + expect(stream).toMatchObject([expectedStream]) + }) }) diff --git a/src/schema/stream-type-schema.ts b/src/schema/stream-type-schema.ts index a3e8773..5f71b7a 100644 --- a/src/schema/stream-type-schema.ts +++ b/src/schema/stream-type-schema.ts @@ -1,7 +1,53 @@ import { createModule, gql } from 'graphql-modules' -import { HelixStream } from 'twitch/lib' +import { HelixStream } from 'twitch' +import { HelixStreamFilter } from 'twitch/lib/API/Helix/Stream/HelixStreamApi' +import { TwitchClients } from '../injections/Twitch-Clients' +import { TwitchId } from '../injections/Twitch-Id' +import { UserId } from '../injections/User-Id' export const StreamResolvers = { + Query: { + async getStreams( + _parent: unknown, + args: { streamFilter: any; maxPages: number }, + { injector }: GraphQLModules.ModuleContext + ) { + const clients = injector.get(TwitchClients) + const apiClient = await clients.apiClient() + let gameIds: string[] = [] + + if (args?.streamFilter?.gameNames?.length) { + gameIds = ( + await apiClient.helix.games.getGamesByNames( + args.streamFilter.gameNames + ) + )?.map((x) => x.id) + } + + const streamFilter: HelixStreamFilter = { + ...args.streamFilter, + game: args.streamFilter?.gameIds + ? [...args.streamFilter?.gameIds, ...gameIds] + : [...gameIds], + } + + const page = apiClient.helix.streams.getStreamsPaginated(streamFilter) + + let pages = [] + if (page.current) pages.push(...page.current) + + for (let i = 1; i <= args?.maxPages; i++) { + await page.getNext() + if (page.current) pages.push(...page.current) + } + + return { + nodes: pages.map((el) => new HelixStream(el, apiClient)), + cursor: page.currentCursor, + total: pages?.length, + } + }, + }, Stream: { language(stream: HelixStream) { return stream.language @@ -41,11 +87,36 @@ export const StreamSchema = gql` userDisplayName: String! userId: String! } + + type StreamConnection { + total: Int! + nodes: [Stream] + cursor: String + } + + extend type Query { + getStreams(streamFilter: StreamFilter!, maxPages: Int = 1): StreamConnection + } + + input StreamFilter { + gameIds: [String] + gameNames: [String] + languages: [String] + type: StreamType + userIds: [String] + userNames: [String] + } + + enum StreamType { + live + none + } ` export const StreamModule = createModule({ id: `stream-module`, dirname: __dirname, + providers: [TwitchClients, TwitchId, UserId], typeDefs: StreamSchema, resolvers: StreamResolvers, }) diff --git a/src/schema/user-type-schema.ts b/src/schema/user-type-schema.ts index ba8358f..8c527bd 100644 --- a/src/schema/user-type-schema.ts +++ b/src/schema/user-type-schema.ts @@ -11,7 +11,7 @@ export const UserResolvers = { args: { displayName: string }, { injector }: GraphQLModules.ModuleContext ) { - const clients = await injector.get(TwitchClients) + const clients = injector.get(TwitchClients) const apiClient = await clients.apiClient() return apiClient.helix.users.getUserByName(args.displayName) @@ -21,7 +21,7 @@ export const UserResolvers = { args: { userId: string }, { injector }: GraphQLModules.ModuleContext ) { - const clients = await injector.get(TwitchClients) + const clients = injector.get(TwitchClients) const apiClient = await clients.apiClient() return apiClient.helix.users.getUserById(args.userId) @@ -52,7 +52,7 @@ export const UserResolvers = { args: { displayName: string }, { injector }: GraphQLModules.ModuleContext ) { - const clients = await injector.get(TwitchClients) + const clients = injector.get(TwitchClients) const apiClient = await clients.apiClient() const followed = await apiClient.helix.users.getUserByName( @@ -69,7 +69,7 @@ export const UserResolvers = { args: { displayName: string }, { injector }: GraphQLModules.ModuleContext ) { - const clients = await injector.get(TwitchClients) + const clients = injector.get(TwitchClients) const apiClient = await clients.apiClient() const followed = await apiClient.helix.users.getUserByName( @@ -83,7 +83,7 @@ export const UserResolvers = { args: { maxPages: number }, { injector }: GraphQLModules.ModuleContext ) { - const clients = await injector.get(TwitchClients) + const clients = injector.get(TwitchClients) const apiClient = await clients.apiClient() const page = await apiClient.helix.users.getFollowsPaginated({ user: user, From a0eb1a7b51741bd90ada2560560d18989a627f3f Mon Sep 17 00:00:00 2001 From: Cole Walker Date: Sun, 20 Sep 2020 13:22:27 -0400 Subject: [PATCH 2/2] docs: :pencil: add stream search to docs --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 86f547f..a3bd77a 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,30 @@ type Stream { userDisplayName: String! userId: String! } + +type StreamConnection { + total: Int! + nodes: [Stream] + cursor: String +} + +extend type Query { + getStreams(streamFilter: StreamFilter!, maxPages: Int = 1): StreamConnection +} + +input StreamFilter { + gameIds: [String] + gameNames: [String] + languages: [String] + type: StreamType + userIds: [String] + userNames: [String] +} + +enum StreamType { + live + none +} ``` ### StreamUserLink