follows.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. import { GenericAggregate } from './shared'
  2. import {
  3. ChannelEvent,
  4. ChannelEventsBucketModel,
  5. ChannelEventType,
  6. UnsequencedChannelEvent,
  7. } from '../models/ChannelEvent'
  8. type ChannelEventsAggregationResult = {
  9. events?: ChannelEvent[]
  10. }[]
  11. export class FollowsAggregate implements GenericAggregate<ChannelEvent> {
  12. private channelFollowsMap: Record<string, number> = {}
  13. public channelFollows(channelId: string): number | null {
  14. return this.channelFollowsMap[channelId] ?? null
  15. }
  16. public getChannelFollowsMap() {
  17. return Object.freeze(this.channelFollowsMap)
  18. }
  19. public static async Build(): Promise<FollowsAggregate> {
  20. const aggregation: ChannelEventsAggregationResult = await ChannelEventsBucketModel.aggregate([
  21. { $unwind: '$events' },
  22. { $group: { _id: null, allEvents: { $push: '$events' } } },
  23. { $project: { events: '$allEvents' } },
  24. ])
  25. const events = aggregation[0]?.events || []
  26. const aggregate = new FollowsAggregate()
  27. events.forEach((event) => {
  28. aggregate.applyEvent(event)
  29. })
  30. return aggregate
  31. }
  32. public applyEvent(event: UnsequencedChannelEvent) {
  33. const currentChannelFollows = this.channelFollowsMap[event.channelId] || 0
  34. switch (event.type) {
  35. case ChannelEventType.FollowChannel:
  36. this.channelFollowsMap[event.channelId] = currentChannelFollows + 1
  37. break
  38. case ChannelEventType.UnfollowChannel:
  39. this.channelFollowsMap[event.channelId] = Math.max(currentChannelFollows - 1, 0)
  40. break
  41. default:
  42. console.error(`Parsing unknown channel event: ${event.type}`)
  43. }
  44. }
  45. }