diff --git a/packages/server/modules/core/domain/streams/operations.ts b/packages/server/modules/core/domain/streams/operations.ts index afd4af769..36ed220f0 100644 --- a/packages/server/modules/core/domain/streams/operations.ts +++ b/packages/server/modules/core/domain/streams/operations.ts @@ -20,6 +20,18 @@ import { ContextResourceAccessRules } from '@/modules/core/helpers/token' import { MaybeNullOrUndefined, Nullable, Optional, StreamRoles } from '@speckle/shared' import { Knex } from 'knex' +export type LegacyGetStreams = (params: { + cursor?: string | Date | null | undefined + limit: number + orderBy?: string | null | undefined + visibility?: string | null | undefined + searchQuery?: string | null | undefined + streamIdWhitelist?: string[] | null | undefined + workspaceIdWhitelist?: string[] | null | undefined + offset?: MaybeNullOrUndefined + publicOnly?: MaybeNullOrUndefined +}) => Promise<{ streams: Stream[]; totalCount: number; cursorDate: Nullable }> + export type GetStreams = ( streamIds: string[], options?: Partial<{ diff --git a/packages/server/modules/core/graph/resolvers/streams.ts b/packages/server/modules/core/graph/resolvers/streams.ts index d6279e148..d272b2999 100644 --- a/packages/server/modules/core/graph/resolvers/streams.ts +++ b/packages/server/modules/core/graph/resolvers/streams.ts @@ -1,5 +1,4 @@ import { - getStreams, getStreamUsers, favoriteStream, getFavoriteStreamsCollection, @@ -34,6 +33,7 @@ import { grantStreamPermissionsFactory, getDiscoverableStreamsPage, countDiscoverableStreamsFactory, + legacyGetStreamsFactory, getStreamCollaboratorsFactory } from '@/modules/core/repositories/streams' import { @@ -166,6 +166,7 @@ const getDiscoverableStreams = getDiscoverableStreamsFactory({ getDiscoverableStreamsPage: getDiscoverableStreamsPage({ db }), countDiscoverableStreams: countDiscoverableStreamsFactory({ db }) }) +const getStreams = legacyGetStreamsFactory({ db }) const getUserStreamsCore = async ( forOtherUser: boolean, diff --git a/packages/server/modules/core/repositories/streams.ts b/packages/server/modules/core/repositories/streams.ts index 222a0065e..464bc9121 100644 --- a/packages/server/modules/core/repositories/streams.ts +++ b/packages/server/modules/core/repositories/streams.ts @@ -83,7 +83,8 @@ import { GetOnboardingBaseStream, GetDiscoverableStreamsParams, CountDiscoverableStreams, - GetDiscoverableStreamsPage + GetDiscoverableStreamsPage, + LegacyGetStreams } from '@/modules/core/domain/streams/operations' export type { StreamWithOptionalRole, StreamWithCommitId } @@ -1241,3 +1242,87 @@ export const getRolesByUserIdFactory = } return await query } + +/** + * @deprecated Use getStreams() from the repository directly + */ +export const legacyGetStreamsFactory = + (deps: { db: Knex }): LegacyGetStreams => + async ({ + cursor, + limit, + orderBy, + visibility, + searchQuery, + streamIdWhitelist, + workspaceIdWhitelist, + offset, + publicOnly + }) => { + const query = tables.streams(deps.db) + const countQuery = tables.streams(deps.db) + + if (searchQuery) { + const whereFunc: Knex.QueryCallback = function () { + this.where('streams.name', 'ILIKE', `%${searchQuery}%`).orWhere( + 'streams.description', + 'ILIKE', + `%${searchQuery}%` + ) + } + query.where(whereFunc) + countQuery.where(whereFunc) + } + + if (publicOnly) { + visibility = 'public' + } + + if (visibility && visibility !== 'all') { + if (!['private', 'public'].includes(visibility)) + throw new Error('Stream visibility should be either private, public or all') + const isPublic = visibility === 'public' + const publicFunc: Knex.QueryCallback = function () { + this.where({ isPublic }) + } + query.andWhere(publicFunc) + countQuery.andWhere(publicFunc) + } + + if (streamIdWhitelist?.length) { + query.whereIn('id', streamIdWhitelist) + countQuery.whereIn('id', streamIdWhitelist) + } + + if (workspaceIdWhitelist?.length) { + query.whereIn('workspaceId', workspaceIdWhitelist) + countQuery.whereIn('workspaceId', workspaceIdWhitelist) + } + + const [res] = await countQuery.count() + const count = parseInt(res.count + '') + + if (!count) return { streams: [], totalCount: 0, cursorDate: null } + + orderBy = orderBy || 'updatedAt,desc' + + const [columnName, order] = orderBy.split(',') + + if (cursor) query.where(columnName, order === 'desc' ? '<' : '>', cursor) + + query.orderBy(`${columnName}`, order).limit(limit) + if (offset) { + query.offset(offset) + } + + const rows = await query + + const cursorDate = rows.length + ? rows.slice(-1)[0][columnName as keyof StreamRecord] + : null + return { + streams: rows, + totalCount: count, + cursorDate: cursorDate as Nullable + } + } diff --git a/packages/server/modules/core/services/admin.ts b/packages/server/modules/core/services/admin.ts index dc3d5cddb..2512935f1 100644 --- a/packages/server/modules/core/services/admin.ts +++ b/packages/server/modules/core/services/admin.ts @@ -1,8 +1,8 @@ import db from '@/db/knex' import { ServerInviteGraphQLReturnType } from '@/modules/core/helpers/graphTypes' import { StreamRecord, UserRecord } from '@/modules/core/helpers/types' +import { legacyGetStreamsFactory } from '@/modules/core/repositories/streams' import { listUsers, countUsers } from '@/modules/core/repositories/users' -import { getStreams } from '@/modules/core/services/streams' import { ServerInviteRecord } from '@/modules/serverinvites/domain/types' import { countServerInvitesFactory, @@ -103,6 +103,7 @@ export const adminProjectList = async ( args: AdminProjectListArgs & { streamIdWhitelist?: string[] } ): Promise> => { const parsedCursor = args.cursor ? parseCursorToDate(args.cursor) : null + const getStreams = legacyGetStreamsFactory({ db }) const { streams, totalCount, cursorDate } = await getStreams({ ...args, searchQuery: args.query, diff --git a/packages/server/modules/core/services/streams.js b/packages/server/modules/core/services/streams.js index 728a80fc5..a1824d799 100644 --- a/packages/server/modules/core/services/streams.js +++ b/packages/server/modules/core/services/streams.js @@ -1,6 +1,6 @@ 'use strict' const _ = require('lodash') -const { Streams, StreamAcl, knex } = require('@/modules/core/dbSchema') +const { StreamAcl, knex } = require('@/modules/core/dbSchema') const { getFavoritedStreams, getFavoritedStreamsCount, @@ -24,93 +24,6 @@ const { module.exports = { setStreamFavorited, - /** - * @param {Object} p - * @param {string | Date | null} [p.cursor] - * @param {number} p.limit - * @param {string | null} [p.orderBy] - * @param {string | null} [p.visibility] - * @param {string | null} [p.searchQuery] - * @param {string[] | null} [p.streamIdWhitelist] - * @param {string[] | null} [p.workspaceIdWhitelist] - * @param {number | null} [p.offset] - * @param {boolean | null} [p.publicOnly] - * @deprecated Use getStreams() from the repository directly - */ - async getStreams({ - cursor, - limit, - orderBy, - visibility, - searchQuery, - streamIdWhitelist, - workspaceIdWhitelist, - offset, - publicOnly - }) { - const query = knex.select().from('streams') - - const countQuery = Streams.knex() - - if (searchQuery) { - const whereFunc = function () { - this.where('streams.name', 'ILIKE', `%${searchQuery}%`).orWhere( - 'streams.description', - 'ILIKE', - `%${searchQuery}%` - ) - } - query.where(whereFunc) - countQuery.where(whereFunc) - } - - if (publicOnly) { - visibility = 'public' - } - - if (visibility && visibility !== 'all') { - if (!['private', 'public'].includes(visibility)) - throw new Error('Stream visibility should be either private, public or all') - const isPublic = visibility === 'public' - const publicFunc = function () { - this.where({ isPublic }) - } - query.andWhere(publicFunc) - countQuery.andWhere(publicFunc) - } - - if (streamIdWhitelist?.length) { - query.whereIn('id', streamIdWhitelist) - countQuery.whereIn('id', streamIdWhitelist) - } - - if (workspaceIdWhitelist?.length) { - query.whereIn('workspaceId', workspaceIdWhitelist) - countQuery.whereIn('workspaceId', workspaceIdWhitelist) - } - - const [res] = await countQuery.count() - const count = parseInt(res.count) - - if (!count) return { streams: [], totalCount: 0 } - - orderBy = orderBy || 'updatedAt,desc' - - const [columnName, order] = orderBy.split(',') - - if (cursor) query.where(columnName, order === 'desc' ? '<' : '>', cursor) - - query.orderBy(`${columnName}`, order).limit(limit) - if (offset) { - query.offset(offset) - } - - const rows = await query - - const cursorDate = rows.length ? rows.slice(-1)[0][columnName] : null - return { streams: rows, totalCount: count, cursorDate } - }, - /** * @returns {Promise<{role: string, id: string, name: string, company: string, avatar: string}[]>} */ diff --git a/packages/server/modules/workspaces/events/eventListener.ts b/packages/server/modules/workspaces/events/eventListener.ts index f1de50b80..a6c1defac 100644 --- a/packages/server/modules/workspaces/events/eventListener.ts +++ b/packages/server/modules/workspaces/events/eventListener.ts @@ -6,6 +6,7 @@ import { import { deleteProjectRoleFactory, getStreamFactory, + legacyGetStreamsFactory, upsertProjectRoleFactory } from '@/modules/core/repositories/streams' import { @@ -42,7 +43,6 @@ import { queryAllWorkspaceProjectsFactory, getWorkspaceRoleToDefaultProjectRoleMappingFactory } from '@/modules/workspaces/services/projects' -import { getStreams } from '@/modules/core/services/streams' import { withTransaction } from '@/modules/shared/helpers/dbHelper' import { findVerifiedEmailsByUserIdFactory } from '@/modules/core/repositories/userEmails' import { GetStream } from '@/modules/core/domain/streams/operations' @@ -217,6 +217,7 @@ export const initializeEventListenersFactory = ({ db }: { db: Knex }) => () => { const eventBus = getEventBus() + const getStreams = legacyGetStreamsFactory({ db }) const quitCbs = [ ProjectsEmitter.listen(ProjectEvents.Created, async (payload) => { const onProjectCreated = onProjectCreatedFactory({ diff --git a/packages/server/modules/workspaces/graph/resolvers/workspaces.ts b/packages/server/modules/workspaces/graph/resolvers/workspaces.ts index 3e349704e..a7de1375a 100644 --- a/packages/server/modules/workspaces/graph/resolvers/workspaces.ts +++ b/packages/server/modules/workspaces/graph/resolvers/workspaces.ts @@ -12,10 +12,10 @@ import { getStreamFactory, deleteStreamFactory, revokeStreamPermissionsFactory, - grantStreamPermissionsFactory + grantStreamPermissionsFactory, + legacyGetStreamsFactory } from '@/modules/core/repositories/streams' import { getUser, getUsers } from '@/modules/core/repositories/users' -import { getStreams } from '@/modules/core/services/streams' import { InviteCreateValidationError } from '@/modules/serverinvites/errors' import { deleteAllResourceInvitesFactory, @@ -396,6 +396,7 @@ export = FF_WORKSPACES_MODULE_ENABLED ) // Delete workspace and associated resources (i.e. invites) + const getStreams = legacyGetStreamsFactory({ db }) const deleteWorkspace = deleteWorkspaceFactory({ deleteWorkspace: repoDeleteWorkspaceFactory({ db }), deleteProject: deleteStream, diff --git a/packages/server/modules/workspaces/services/projects.ts b/packages/server/modules/workspaces/services/projects.ts index fc6e78c05..bc7d3957c 100644 --- a/packages/server/modules/workspaces/services/projects.ts +++ b/packages/server/modules/workspaces/services/projects.ts @@ -1,5 +1,4 @@ import { StreamRecord } from '@/modules/core/helpers/types' -import { getStreams as serviceGetStreams } from '@/modules/core/services/streams' import { getUserStreams } from '@/modules/core/repositories/streams' import { GetWorkspace, @@ -23,12 +22,12 @@ import { chunk } from 'lodash' import { Roles, StreamRoles } from '@speckle/shared' import { orderByWeight } from '@/modules/shared/domain/rolesAndScopes/logic' import coreUserRoles from '@/modules/core/roles' +import { LegacyGetStreams } from '@/modules/core/domain/streams/operations' export const queryAllWorkspaceProjectsFactory = ({ getStreams }: { - // TODO: Core service factory functions - getStreams: typeof serviceGetStreams + getStreams: LegacyGetStreams }): QueryAllWorkspaceProjects => async function* queryAllWorkspaceProjects({ workspaceId