Browse Source

add channel views query

Klaudiusz Dembler 4 years ago
parent
commit
b868170740

+ 14 - 8
schema.graphql

@@ -3,20 +3,26 @@
 # !!!   DO NOT MODIFY THIS FILE BY YOURSELF   !!!
 # -----------------------------------------------
 
+type EntityViewsInfo {
+  id: ID!
+  views: Int!
+}
+
 type Mutation {
   """Add a single view to the target video's count"""
-  addVideoView(channelId: ID!, videoId: ID!): VideoViewsInfo!
+  addVideoView(channelId: ID!, videoId: ID!): EntityViewsInfo!
 }
 
 type Query {
+  """Get views counts for a list of channels"""
+  batchedChannelsViews(channelIdList: [ID!]!): [EntityViewsInfo]!
+
   """Get views counts for a list of videos"""
-  batchedVideoViews(videoIdList: [ID!]!): [VideoViewsInfo]!
+  batchedVideoViews(videoIdList: [ID!]!): [EntityViewsInfo]!
 
-  """Get views count for a single video"""
-  videoViews(videoId: ID!): VideoViewsInfo
-}
+  """Get views count for a single channel"""
+  channelViews(channelId: ID!): EntityViewsInfo
 
-type VideoViewsInfo {
-  id: ID!
-  views: Int!
+  """Get views count for a single video"""
+  videoViews(videoId: ID!): EntityViewsInfo
 }

+ 3 - 3
src/aggregate.ts → src/aggregates/views.ts

@@ -1,10 +1,10 @@
-import { UnsequencedVideoEvent, VideoEvent, VideoEventsBucketModel, VideoEventType } from './models/VideoEvent'
+import { UnsequencedVideoEvent, VideoEvent, VideoEventsBucketModel, VideoEventType } from '../models/VideoEvent'
 
 type VideoEventsAggregationResult = {
   events?: VideoEvent[]
 }[]
 
-export class VideoAggregate {
+export class ViewsAggregate {
   private videoViewsMap: Record<string, number> = {}
   private channelViewsMap: Record<string, number> = {}
 
@@ -49,4 +49,4 @@ export class VideoAggregate {
   }
 }
 
-export const videoAggregate = new VideoAggregate()
+export const viewsAggregate = new ViewsAggregate()

+ 2 - 2
src/entities/VideoViewsInfo.ts → src/entities/EntityViewsInfo.ts

@@ -1,9 +1,9 @@
 import { Field, ID, Int, ObjectType } from 'type-graphql'
 
 @ObjectType()
-export class VideoViewsInfo {
+export class EntityViewsInfo {
   @Field(() => ID, { name: 'id' })
-  videoId: string
+  id: string
 
   @Field(() => Int)
   views: number

+ 0 - 74
src/resolvers/videoViewsInfos.ts

@@ -1,74 +0,0 @@
-import { Args, ArgsType, Field, ID, Mutation, Query, Resolver } from 'type-graphql'
-import { VideoViewsInfo } from '../entities/VideoViewsInfo'
-import { videoAggregate } from '../aggregate'
-import { insertVideoEventIntoBucket, VideoEventType, UnsequencedVideoEvent } from '../models/VideoEvent'
-
-@ArgsType()
-class VideoViewsArgs {
-  @Field(() => ID)
-  videoId: string
-}
-
-@ArgsType()
-class BatchedVideoViewsArgs {
-  @Field(() => [ID])
-  videoIdList: string[]
-}
-
-@ArgsType()
-class AddVideoViewArgs {
-  @Field(() => ID)
-  videoId: string
-
-  @Field(() => ID)
-  channelId: string
-}
-
-@Resolver()
-export class VideoViewsInfosResolver {
-  @Query(() => VideoViewsInfo, { nullable: true, description: 'Get views count for a single video' })
-  async videoViews(@Args() { videoId }: VideoViewsArgs): Promise<VideoViewsInfo | null> {
-    const views = videoAggregate.videoViews(videoId)
-    if (views) {
-      return {
-        videoId,
-        views,
-      }
-    }
-    return null
-  }
-
-  @Query(() => [VideoViewsInfo], { description: 'Get views counts for a list of videos', nullable: 'items' })
-  async batchedVideoViews(@Args() { videoIdList }: BatchedVideoViewsArgs): Promise<(VideoViewsInfo | null)[]> {
-    return videoIdList.map((videoId) => {
-      const videoViews = videoAggregate.videoViews(videoId)
-      if (videoViews) {
-        const videoViewsInfo: VideoViewsInfo = {
-          videoId,
-          views: videoViews,
-        }
-        return videoViewsInfo
-      }
-      return null
-    })
-  }
-
-  @Mutation(() => VideoViewsInfo, { description: "Add a single view to the target video's count" })
-  async addVideoView(@Args() { videoId, channelId }: AddVideoViewArgs): Promise<VideoViewsInfo> {
-    const event: UnsequencedVideoEvent = {
-      videoId,
-      channelId,
-      eventType: VideoEventType.AddView,
-      timestamp: new Date(),
-    }
-
-    await insertVideoEventIntoBucket(event)
-    videoAggregate.applyEvent(event)
-
-    const views = videoAggregate.videoViews(videoId)
-    return {
-      videoId,
-      views,
-    }
-  }
-}

+ 113 - 0
src/resolvers/viewsInfo.ts

@@ -0,0 +1,113 @@
+import { Args, ArgsType, Field, ID, Mutation, Query, Resolver } from 'type-graphql'
+import { EntityViewsInfo } from '../entities/EntityViewsInfo'
+import { viewsAggregate } from '../aggregates/views'
+import { insertVideoEventIntoBucket, VideoEventType, UnsequencedVideoEvent } from '../models/VideoEvent'
+
+@ArgsType()
+class VideoViewsArgs {
+  @Field(() => ID)
+  videoId: string
+}
+
+@ArgsType()
+class BatchedVideoViewsArgs {
+  @Field(() => [ID])
+  videoIdList: string[]
+}
+
+@ArgsType()
+class ChannelViewsArgs {
+  @Field(() => ID)
+  channelId: string
+}
+
+@ArgsType()
+class BatchedChannelViewsArgs {
+  @Field(() => [ID])
+  channelIdList: string[]
+}
+
+@ArgsType()
+class AddVideoViewArgs {
+  @Field(() => ID)
+  videoId: string
+
+  @Field(() => ID)
+  channelId: string
+}
+
+@Resolver()
+export class VideoViewsInfosResolver {
+  @Query(() => EntityViewsInfo, { nullable: true, description: 'Get views count for a single video' })
+  async videoViews(@Args() { videoId }: VideoViewsArgs): Promise<EntityViewsInfo | null> {
+    const views = viewsAggregate.videoViews(videoId)
+    if (views) {
+      return {
+        id: videoId,
+        views,
+      }
+    }
+    return null
+  }
+
+  @Query(() => [EntityViewsInfo], { description: 'Get views counts for a list of videos', nullable: 'items' })
+  async batchedVideoViews(@Args() { videoIdList }: BatchedVideoViewsArgs): Promise<(EntityViewsInfo | null)[]> {
+    return videoIdList.map((videoId) => {
+      const videoViews = viewsAggregate.videoViews(videoId)
+      if (videoViews) {
+        const videoViewsInfo: EntityViewsInfo = {
+          id: videoId,
+          views: videoViews,
+        }
+        return videoViewsInfo
+      }
+      return null
+    })
+  }
+
+  @Query(() => EntityViewsInfo, { nullable: true, description: 'Get views count for a single channel' })
+  async channelViews(@Args() { channelId }: ChannelViewsArgs): Promise<EntityViewsInfo | null> {
+    const views = viewsAggregate.channelViews(channelId)
+    if (views) {
+      return {
+        id: channelId,
+        views,
+      }
+    }
+    return null
+  }
+
+  @Query(() => [EntityViewsInfo], { description: 'Get views counts for a list of channels', nullable: 'items' })
+  async batchedChannelsViews(@Args() { channelIdList }: BatchedChannelViewsArgs): Promise<(EntityViewsInfo | null)[]> {
+    return channelIdList.map((channelId) => {
+      const channelViews = viewsAggregate.channelViews(channelId)
+      if (channelViews) {
+        const channelViewsInfo: EntityViewsInfo = {
+          id: channelId,
+          views: channelViews,
+        }
+        return channelViewsInfo
+      }
+      return null
+    })
+  }
+
+  @Mutation(() => EntityViewsInfo, { description: "Add a single view to the target video's count" })
+  async addVideoView(@Args() { videoId, channelId }: AddVideoViewArgs): Promise<EntityViewsInfo> {
+    const event: UnsequencedVideoEvent = {
+      videoId,
+      channelId,
+      eventType: VideoEventType.AddView,
+      timestamp: new Date(),
+    }
+
+    await insertVideoEventIntoBucket(event)
+    viewsAggregate.applyEvent(event)
+
+    const views = viewsAggregate.videoViews(videoId)
+    return {
+      id: videoId,
+      views,
+    }
+  }
+}

+ 3 - 3
src/server.ts

@@ -3,9 +3,9 @@ import { ApolloServer } from 'apollo-server-express'
 import Express from 'express'
 import { connect } from 'mongoose'
 import { buildSchema } from 'type-graphql'
-import { VideoViewsInfosResolver } from './resolvers/videoViewsInfos'
+import { VideoViewsInfosResolver } from './resolvers/viewsInfo'
 import config from './config'
-import { videoAggregate } from './aggregate'
+import { viewsAggregate } from './aggregates/views'
 
 const main = async () => {
   await getMongooseConnection()
@@ -46,7 +46,7 @@ const getMongooseConnection = async () => {
 const rebuildAggregates = async () => {
   process.stdout.write('Rebuilding video events aggregate...')
   try {
-    await videoAggregate.rebuild()
+    await viewsAggregate.rebuild()
   } catch (error) {
     process.stdout.write(' Failed!\n')
     console.error(error)