Rafal Pawlow vor 3 Jahren
Ursprung
Commit
ff109d1dd8
6 geänderte Dateien mit 52 neuen und 46 gelöschten Zeilen
  1. 3 3
      schema.graphql
  2. 4 4
      src/aggregates/views.ts
  3. 21 15
      src/resolvers/viewsInfo.ts
  4. 1 1
      src/server.ts
  5. 6 6
      tests/queries/views.ts
  6. 17 17
      tests/views.test.ts

+ 3 - 3
schema.graphql

@@ -41,13 +41,13 @@ type Query {
   channelViews(channelId: ID!): EntityViewsInfo
 
   """Get most viewed list of categories"""
-  mostViewedCategories(limit: Int, period: Int): [EntityViewsInfo!]
+  mostViewedCategories(limit: Int, period: Int!): [EntityViewsInfo!]
 
   """Get most viewed list of channels"""
-  mostViewedChannels(limit: Int, period: Int): [EntityViewsInfo!]
+  mostViewedChannels(limit: Int, period: Int!): [EntityViewsInfo!]
 
   """Get most viewed list of videos"""
-  mostViewedVideos(limit: Int, period: Int): [EntityViewsInfo!]
+  mostViewedVideos(limit: Int, period: Int!): [EntityViewsInfo!]
 
   """Get views count for a single video"""
   videoViews(videoId: ID!): EntityViewsInfo

+ 4 - 4
src/aggregates/views.ts

@@ -48,13 +48,13 @@ export class ViewsAggregate {
 
   public applyEvent(event: UnsequencedVideoEvent) {
     const { videoId, channelId, categoryId, timestamp, type } = event
-    const currentVideoViews = this.videoViewsMap[videoId] || 0
-    const currentChannelViews = this.channelViewsMap[channelId] || 0
+    const currentVideoViews = videoId ? this.videoViewsMap[videoId] || 0 : 0
+    const currentChannelViews = channelId ? this.channelViewsMap[channelId] || 0 : 0
     const currentCategoryViews = categoryId ? this.categoryViewsMap[categoryId] || 0 : 0
     switch (type) {
       case VideoEventType.AddView:
-        this.videoViewsMap[videoId] = currentVideoViews + 1
-        this.channelViewsMap[channelId] = currentChannelViews + 1
+        if (videoId) this.videoViewsMap[videoId] = currentVideoViews + 1
+        if (channelId) this.channelViewsMap[channelId] = currentChannelViews + 1
         if (categoryId) this.categoryViewsMap[categoryId] = currentCategoryViews + 1
         this.allViewsEvents = [...this.allViewsEvents, { videoId, channelId, categoryId, timestamp }]
         break

+ 21 - 15
src/resolvers/viewsInfo.ts

@@ -1,4 +1,5 @@
 import { Args, ArgsType, Ctx, Field, ID, Int, Mutation, Query, Resolver } from 'type-graphql'
+import { Min, Max } from 'class-validator'
 import { differenceInCalendarDays } from 'date-fns'
 import { EntityViewsInfo } from '../entities/EntityViewsInfo'
 import { saveVideoEvent, VideoEventType, UnsequencedVideoEvent } from '../models/VideoEvent'
@@ -18,8 +19,10 @@ class BatchedVideoViewsArgs {
 
 @ArgsType()
 class MostViewedVideosArgs {
-  @Field(() => Int, { nullable: true })
-  period?: number
+  @Field(() => Int)
+  @Min(1)
+  @Max(30)
+  period: number
 
   @Field(() => Int, { nullable: true })
   limit?: number
@@ -27,8 +30,10 @@ class MostViewedVideosArgs {
 
 @ArgsType()
 class MostViewedChannelArgs {
-  @Field(() => Int, { nullable: true })
-  period?: number
+  @Field(() => Int)
+  @Min(1)
+  @Max(30)
+  period: number
 
   @Field(() => Int, { nullable: true })
   limit?: number
@@ -48,8 +53,10 @@ class BatchedChannelViewsArgs {
 
 @ArgsType()
 class MostViewedCategoriesArgs {
-  @Field(() => Int, { nullable: true })
-  period?: number
+  @Field(() => Int)
+  @Min(1)
+  @Max(30)
+  period: number
 
   @Field(() => Int, { nullable: true })
   limit?: number
@@ -151,33 +158,32 @@ const mapMostViewedArray = (views: Record<string, number>, limit?: number) =>
         .slice(0, limit)
     : []
 
-const filterAllViewsByPeriod = (ctx: OrionContext, period?: number): Partial<UnsequencedVideoEvent>[] => {
-  const views = [...ctx.viewsAggregate.getAllViewsEvents()].reverse()
+const filterAllViewsByPeriod = (ctx: OrionContext, period: number): Partial<UnsequencedVideoEvent>[] => {
+  const views = ctx.viewsAggregate.getAllViewsEvents()
   const filteredViews = []
-  if (!period) return views
 
-  for (const view of views) {
-    const { timestamp } = view
+  for (let i = views.length - 1; i >= 0; i--) {
+    const { timestamp } = views[i]
     if (timestamp && differenceInCalendarDays(new Date(), timestamp) > period) break
-    filteredViews.push(view)
+    filteredViews.push(views[i])
   }
 
   return filteredViews
 }
 
-const buildMostViewedVideosArray = (ctx: OrionContext, period?: number) =>
+const buildMostViewedVideosArray = (ctx: OrionContext, period: number) =>
   filterAllViewsByPeriod(ctx, period).reduce(
     (entity: Record<string, number>, { videoId = '' }) => ({ ...entity, [videoId]: (entity[videoId] || 0) + 1 }),
     {}
   )
 
-const buildMostViewedChannelsArray = (ctx: OrionContext, period?: number) =>
+const buildMostViewedChannelsArray = (ctx: OrionContext, period: number) =>
   filterAllViewsByPeriod(ctx, period).reduce(
     (entity: Record<string, number>, { channelId = '' }) => ({ ...entity, [channelId]: (entity[channelId] || 0) + 1 }),
     {}
   )
 
-const buildMostViewedCategoriesArray = (ctx: OrionContext, period?: number) =>
+const buildMostViewedCategoriesArray = (ctx: OrionContext, period: number) =>
   filterAllViewsByPeriod(ctx, period).reduce((entity: Record<string, number>, { categoryId }) => {
     return categoryId ? { ...entity, [categoryId]: (entity[categoryId] || 0) + 1 } : entity
   }, {})

+ 1 - 1
src/server.ts

@@ -15,7 +15,7 @@ export const createServer = async (mongoose: Mongoose, aggregates: Aggregates) =
   const schema = await buildSchema({
     resolvers: [VideoViewsInfosResolver, ChannelFollowsInfosResolver],
     emitSchemaFile: 'schema.graphql',
-    validate: false,
+    validate: true,
   })
 
   const contextFn: ContextFunction<ExpressContext, OrionContext> = ({ req }) => ({

+ 6 - 6
tests/queries/views.ts

@@ -11,7 +11,7 @@ export const GET_VIDEO_VIEWS = gql`
 `
 
 export const GET_MOST_VIEWED_VIDEOS = gql`
-  query GetMostViewedVideos($period: Int) {
+  query GetMostViewedVideos($period: Int!) {
     mostViewedVideos(period: $period) {
       id
       views
@@ -28,7 +28,7 @@ export type GetVideoViewsArgs = {
   videoId: string
 }
 export type GetMostViewedVideosArgs = {
-  period?: number
+  period: number
 }
 
 export const GET_CHANNEL_VIEWS = gql`
@@ -41,7 +41,7 @@ export const GET_CHANNEL_VIEWS = gql`
 `
 
 export const GET_MOST_VIEWED_CHANNELS = gql`
-  query GetMostViewedChannels($period: Int) {
+  query GetMostViewedChannels($period: Int!) {
     mostViewedChannels(period: $period) {
       id
       views
@@ -58,11 +58,11 @@ export type GetChannelViewsArgs = {
   channelId: string
 }
 export type GetMostViewedChannelsArgs = {
-  period?: number
+  period: number
 }
 
 export const GET_MOST_VIEWED_CATEGORIES = gql`
-  query GetMostViewedCategories($period: Int) {
+  query GetMostViewedCategories($period: Int!) {
     mostViewedCategories(period: $period) {
       id
       views
@@ -74,7 +74,7 @@ export type GetMostViewedCategories = {
   mostViewedCategories: EntityViewsInfo[]
 }
 export type GetMostViewedCategoriessArgs = {
-  period?: number
+  period: number
 }
 
 export const ADD_VIDEO_VIEW = gql`

+ 17 - 17
tests/views.test.ts

@@ -74,7 +74,7 @@ describe('Video and channel views resolver', () => {
     return videoViewsResponse.data?.videoViews
   }
 
-  const getMostViewedVideos = async (period?: number) => {
+  const getMostViewedVideos = async (period: number) => {
     const mostViewedVideosResponse = await query<GetMostViewedVideos, GetMostViewedVideosArgs>({
       query: GET_MOST_VIEWED_VIDEOS,
       variables: { period },
@@ -92,7 +92,7 @@ describe('Video and channel views resolver', () => {
     return channelViewsResponse.data?.channelViews
   }
 
-  const getMostViewedChannels = async (period?: number) => {
+  const getMostViewedChannels = async (period: number) => {
     const mostViewedChannelsResponse = await query<GetMostViewedChannels, GetMostViewedChannelsArgs>({
       query: GET_MOST_VIEWED_CHANNELS,
       variables: { period },
@@ -101,7 +101,7 @@ describe('Video and channel views resolver', () => {
     return mostViewedChannelsResponse.data?.mostViewedChannels
   }
 
-  const getMostViewedCategories = async (period?: number) => {
+  const getMostViewedCategories = async (period: number) => {
     const mostViewedCategoriesResponse = await query<GetMostViewedCategories, GetMostViewedCategoriessArgs>({
       query: GET_MOST_VIEWED_CATEGORIES,
       variables: { period },
@@ -112,10 +112,10 @@ describe('Video and channel views resolver', () => {
 
   it('should return null for unknown video, channel and category views', async () => {
     const videoViews = await getVideoViews(FIRST_VIDEO_ID)
-    const mostViewedVideos = await getMostViewedVideos()
+    const mostViewedVideos = await getMostViewedVideos(30)
     const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
-    const mostViewedChannels = await getMostViewedChannels()
-    const mostViewedCategories = await getMostViewedCategories()
+    const mostViewedChannels = await getMostViewedChannels(30)
+    const mostViewedCategories = await getMostViewedCategories(30)
 
     expect(videoViews).toBeNull()
     expect(mostViewedVideos).toHaveLength(0)
@@ -139,10 +139,10 @@ describe('Video and channel views resolver', () => {
     }
     const checkViews = async () => {
       const videoViews = await getVideoViews(FIRST_VIDEO_ID)
-      const mostViewedVideos = await getMostViewedVideos()
+      const mostViewedVideos = await getMostViewedVideos(30)
       const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
-      const mostViewedChannels = await getMostViewedChannels()
-      const mostViewedCategories = await getMostViewedCategories()
+      const mostViewedChannels = await getMostViewedChannels(30)
+      const mostViewedCategories = await getMostViewedCategories(30)
 
       expect(videoViews).toEqual(expectedVideoViews)
       expect(mostViewedVideos).toEqual([expectedVideoViews])
@@ -188,7 +188,7 @@ describe('Video and channel views resolver', () => {
 
     const firstVideoViews = await getVideoViews(FIRST_VIDEO_ID)
     const secondVideoViews = await getVideoViews(SECOND_VIDEO_ID)
-    const mostViewedVideos = await getMostViewedVideos()
+    const mostViewedVideos = await getMostViewedVideos(30)
 
     expect(firstVideoViews).toEqual(expectedFirstVideoViews)
     expect(secondVideoViews).toEqual(expectedSecondVideoViews)
@@ -210,7 +210,7 @@ describe('Video and channel views resolver', () => {
 
     const firstChannelViews = await getChannelViews(FIRST_CHANNEL_ID)
     const secondChannelViews = await getChannelViews(SECOND_CHANNEL_ID)
-    const mostViewedChannels = await getMostViewedChannels()
+    const mostViewedChannels = await getMostViewedChannels(30)
 
     expect(firstChannelViews).toEqual(expectedFirstChanelViews)
     expect(secondChannelViews).toEqual(expectedSecondChannelViews)
@@ -227,7 +227,7 @@ describe('Video and channel views resolver', () => {
     await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID)
 
     const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
-    const mostViewedChannels = await getMostViewedChannels()
+    const mostViewedChannels = await getMostViewedChannels(30)
 
     expect(channelViews).toEqual(expectedChannelViews)
     expect(mostViewedChannels).toEqual([expectedChannelViews])
@@ -242,7 +242,7 @@ describe('Video and channel views resolver', () => {
     await addVideoView(FIRST_VIDEO_ID, FIRST_CHANNEL_ID, FIRST_CATEGORY_ID)
     await addVideoView(SECOND_VIDEO_ID, FIRST_CHANNEL_ID, FIRST_CATEGORY_ID)
 
-    const mostViewedCategories = await getMostViewedCategories()
+    const mostViewedCategories = await getMostViewedCategories(30)
 
     expect(mostViewedCategories).toEqual([expectedChannelViews])
   })
@@ -269,9 +269,9 @@ describe('Video and channel views resolver', () => {
       const firstVideoViews = await getVideoViews(FIRST_VIDEO_ID)
       const secondVideoViews = await getVideoViews(SECOND_VIDEO_ID)
       const channelViews = await getChannelViews(FIRST_CHANNEL_ID)
-      const mostViewedVideos = await getMostViewedVideos()
-      const mostViewedChannels = await getMostViewedChannels()
-      const mostViewedCategories = await getMostViewedCategories()
+      const mostViewedVideos = await getMostViewedVideos(30)
+      const mostViewedChannels = await getMostViewedChannels(30)
+      const mostViewedCategories = await getMostViewedCategories(30)
 
       expect(firstVideoViews).toEqual(expectedFirstVideoViews)
       expect(secondVideoViews).toEqual(expectedSecondVideoViews)
@@ -314,7 +314,7 @@ describe('Video and channel views resolver', () => {
     }
 
     const videoViews = await getVideoViews(FIRST_VIDEO_ID)
-    const mostViewedVideos = await getMostViewedVideos()
+    const mostViewedVideos = await getMostViewedVideos(30)
     expect(videoViews).toEqual(expectedVideoViews)
     expect(mostViewedVideos).toEqual([expectedVideoViews])
   })