Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(server): core IoC 39 - getFavoriteStreamsCollectionFactory #3220

Merged
merged 1 commit into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/server/modules/core/domain/streams/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ export type GetDiscoverableStreamsPage = (
params: GetDiscoverableStreamsParams
) => Promise<Stream[]>

export type GetFavoritedStreamsPage = (params: {
userId: string
cursor?: string | null
limit?: number
streamIdWhitelist?: Optional<string[]>
}) => Promise<{
streams: Stream[]
cursor: Nullable<string>
}>

export type GetFavoritedStreamsCount = (
userId: string,
streamIdWhitelist?: Optional<string[]>
) => Promise<number>

export type RevokeStreamPermissions = (params: {
streamId: string
userId: string
Expand Down Expand Up @@ -202,3 +217,10 @@ export type GetDiscoverableStreams = (
totalCount: number
items: Stream[]
}>

export type GetFavoriteStreamsCollection = (params: {
userId: string
limit?: number | undefined
cursor?: string | null | undefined
streamIdWhitelist?: string[] | undefined
}) => Promise<{ totalCount: number; cursor: Nullable<string>; items: Stream[] }>
8 changes: 7 additions & 1 deletion packages/server/modules/core/graph/resolvers/streams.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
getStreamUsers,
favoriteStream,
getFavoriteStreamsCollection,
getActiveUserStreamFavoriteDate,
getStreamFavoritesCount,
getOwnedFavoritesCount
Expand Down Expand Up @@ -34,6 +33,8 @@ import {
getDiscoverableStreamsPage,
countDiscoverableStreamsFactory,
legacyGetStreamsFactory,
getFavoritedStreamsCountFactory,
getFavoritedStreamsPageFactory,
getStreamCollaboratorsFactory
} from '@/modules/core/repositories/streams'
import {
Expand Down Expand Up @@ -86,7 +87,12 @@ import {
validateStreamAccessFactory
} from '@/modules/core/services/streams/access'
import { getDiscoverableStreamsFactory } from '@/modules/core/services/streams/discoverableStreams'
import { getFavoriteStreamsCollectionFactory } from '@/modules/core/services/streams/favorite'

const getFavoriteStreamsCollection = getFavoriteStreamsCollectionFactory({
getFavoritedStreamsCount: getFavoritedStreamsCountFactory({ db }),
getFavoritedStreamsPage: getFavoritedStreamsPageFactory({ db })
})
const saveActivity = saveActivityFactory({ db })
const getStream = getStreamFactory({ db })
const createStreamReturnRecord = createStreamReturnRecordFactory({
Expand Down
120 changes: 58 additions & 62 deletions packages/server/modules/core/repositories/streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,17 @@ import {
GetDiscoverableStreamsParams,
CountDiscoverableStreams,
GetDiscoverableStreamsPage,
LegacyGetStreams
LegacyGetStreams,
GetFavoritedStreamsPage,
GetFavoritedStreamsCount
} from '@/modules/core/domain/streams/operations'
export type { StreamWithOptionalRole, StreamWithCommitId }

const tables = {
streams: (db: Knex) => db<StreamRecord>(Streams.name),
streamAcl: (db: Knex) => db<StreamAclRecord>(StreamAcl.name),
streamCommits: (db: Knex) => db<StreamCommitRecord>(StreamCommits.name)
streamCommits: (db: Knex) => db<StreamCommitRecord>(StreamCommits.name),
streamFavorites: (db: Knex) => db<StreamFavoriteRecord>(StreamFavorites.name)
}

/**
Expand Down Expand Up @@ -256,32 +259,32 @@ export const getCommitStreamFactory =
* Get base query for finding or counting user favorited streams
* @param {string} userId The user's ID
*/
function getFavoritedStreamsQueryBase<
Result = Array<StreamFavoriteRecord & StreamRecord & StreamAclRecord>
>(userId: string, streamIdWhitelist?: Optional<string[]>) {
if (!userId)
throw new InvalidArgumentError(
'User ID must be specified to retrieve favorited streams'
)
const getFavoritedStreamsQueryBaseFactory =
(deps: { db: Knex }) => (userId: string, streamIdWhitelist?: Optional<string[]>) => {
if (!userId)
throw new InvalidArgumentError(
'User ID must be specified to retrieve favorited streams'
)

const query = StreamFavorites.knex<Result>()
.where(StreamFavorites.col.userId, userId)
.innerJoin(Streams.name, Streams.col.id, StreamFavorites.col.streamId)
.leftJoin(StreamAcl.name, (q) =>
q
.on(StreamAcl.col.resourceId, '=', StreamFavorites.col.streamId)
.andOnVal(StreamAcl.col.userId, userId)
)
.andWhere((q) =>
q.where(Streams.col.isPublic, true).orWhereNotNull(StreamAcl.col.resourceId)
)
const query = tables
.streamFavorites(deps.db)
.where(StreamFavorites.col.userId, userId)
.innerJoin(Streams.name, Streams.col.id, StreamFavorites.col.streamId)
.leftJoin(StreamAcl.name, (q) =>
q
.on(StreamAcl.col.resourceId, '=', StreamFavorites.col.streamId)
.andOnVal(StreamAcl.col.userId, userId)
)
.andWhere((q) =>
q.where(Streams.col.isPublic, true).orWhereNotNull(StreamAcl.col.resourceId)
)

if (streamIdWhitelist?.length) {
query.whereIn(Streams.col.id, streamIdWhitelist)
}
if (streamIdWhitelist?.length) {
query.whereIn(Streams.col.id, streamIdWhitelist)
}

return query
}
return query
}

/**
* Get favorited streams
Expand All @@ -290,52 +293,45 @@ function getFavoritedStreamsQueryBase<
* @param {string} [p.cursor] ISO8601 timestamp after which to look for favoirtes
* @param {number} [p.limit] Defaults to 25
*/
export async function getFavoritedStreams(params: {
userId: string
cursor?: string
limit?: number
streamIdWhitelist?: Optional<string[]>
}) {
const { userId, cursor, limit, streamIdWhitelist } = params
const finalLimit = _.clamp(limit || 25, 1, 25)
const query = getFavoritedStreamsQueryBase<
Array<StreamWithOptionalRole & { favoritedDate: Date; favCursor: string }>
>(userId, streamIdWhitelist)
query
.select([
...STREAM_WITH_OPTIONAL_ROLE_COLUMNS,
{ favoritedDate: StreamFavorites.col.createdAt },
{ favCursor: StreamFavorites.col.cursor }
])
.limit(finalLimit)
.orderBy(StreamFavorites.col.cursor, 'desc')
export const getFavoritedStreamsPageFactory =
(deps: { db: Knex }): GetFavoritedStreamsPage =>
async (params) => {
const { userId, cursor, limit, streamIdWhitelist } = params
const finalLimit = _.clamp(limit || 25, 1, 25)
const query = getFavoritedStreamsQueryBaseFactory(deps)(userId, streamIdWhitelist)
query
.select<
Array<StreamWithOptionalRole & { favoritedDate: Date; favCursor: string }>
>([
...STREAM_WITH_OPTIONAL_ROLE_COLUMNS,
{ favoritedDate: StreamFavorites.col.createdAt },
{ favCursor: StreamFavorites.col.cursor }
])
.limit(finalLimit)
.orderBy(StreamFavorites.col.cursor, 'desc')

if (cursor) query.andWhere(StreamFavorites.col.cursor, '<', cursor)
if (cursor) query.andWhere(StreamFavorites.col.cursor, '<', cursor)

const rows = await query
const rows = await query

return {
streams: rows,
cursor: rows.length > 0 ? rows[rows.length - 1].favCursor : null
return {
streams: rows,
cursor: rows.length > 0 ? rows[rows.length - 1].favCursor : null
}
}
}

/**
* Get total amount of streams favorited by user
*/
export async function getFavoritedStreamsCount(
userId: string,
streamIdWhitelist?: Optional<string[]>
) {
const query = getFavoritedStreamsQueryBase<[{ count: string }]>(
userId,
streamIdWhitelist
)
query.count()
export const getFavoritedStreamsCountFactory =
(deps: { db: Knex }): GetFavoritedStreamsCount =>
async (userId: string, streamIdWhitelist?: Optional<string[]>) => {
const query = getFavoritedStreamsQueryBaseFactory(deps)(userId, streamIdWhitelist)
query.count()

const [res] = await query
return parseInt(res.count)
}
const [res] = await query
return parseInt(res.count)
}

/**
* Set stream as favorited/unfavorited for a specific user
Expand Down
30 changes: 0 additions & 30 deletions packages/server/modules/core/services/streams.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
'use strict'
const _ = require('lodash')
const { StreamAcl, knex } = require('@/modules/core/dbSchema')
const {
getFavoritedStreams,
getFavoritedStreamsCount,
setStreamFavorited,
canUserFavoriteStream,
getStreamFactory
Expand Down Expand Up @@ -71,32 +67,6 @@ module.exports = {
return await getStream({ streamId, userId })
},

/**
* Get user favorited streams & metadata
* @param {Object} p
* @param {string} p.userId
* @param {number} [p.limit] Defaults to 25
* @param {string|null} [p.cursor] Optionally specify date after which to look for favorites
* @param {string[] | undefined} [p.streamIdWhitelist] Optionally specify a list of stream IDs to filter by
* @returns
*/
async getFavoriteStreamsCollection({ userId, limit, cursor, streamIdWhitelist }) {
limit = _.clamp(limit || 25, 1, 25)

// Get total count of favorited streams
const totalCount = await getFavoritedStreamsCount(userId, streamIdWhitelist)

// Get paginated streams
const { cursor: finalCursor, streams } = await getFavoritedStreams({
userId,
cursor,
limit,
streamIdWhitelist
})

return { totalCount, cursor: finalCursor, items: streams }
},

/**
* Get active user stream favorite date (using dataloader)
* @param {Object} p
Expand Down
37 changes: 37 additions & 0 deletions packages/server/modules/core/services/streams/favorite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
GetFavoritedStreamsCount,
GetFavoritedStreamsPage,
GetFavoriteStreamsCollection
} from '@/modules/core/domain/streams/operations'
import { clamp } from 'lodash'

/**
* Get user favorited streams & metadata
* @param {Object} p
* @param {string} p.userId
* @param {number} [p.limit] Defaults to 25
* @param {string|null} [p.cursor] Optionally specify date after which to look for favorites
* @param {string[] | undefined} [p.streamIdWhitelist] Optionally specify a list of stream IDs to filter by
* @returns
*/
export const getFavoriteStreamsCollectionFactory =
(deps: {
getFavoritedStreamsCount: GetFavoritedStreamsCount
getFavoritedStreamsPage: GetFavoritedStreamsPage
}): GetFavoriteStreamsCollection =>
async ({ userId, limit, cursor, streamIdWhitelist }) => {
limit = clamp(limit || 25, 1, 25)

// Get total count of favorited streams
const totalCount = await deps.getFavoritedStreamsCount(userId, streamIdWhitelist)

// Get paginated streams
const { cursor: finalCursor, streams } = await deps.getFavoritedStreamsPage({
userId,
cursor,
limit,
streamIdWhitelist
})

return { totalCount, cursor: finalCursor, items: streams }
}