diff --git a/apps/server/src/core/label/label.controller.ts b/apps/server/src/core/label/label.controller.ts index bd18eb19..ee0f196b 100644 --- a/apps/server/src/core/label/label.controller.ts +++ b/apps/server/src/core/label/label.controller.ts @@ -26,6 +26,7 @@ import { } from '../casl/interfaces/space-ability.type'; import { PageRepo } from '@docmost/db/repos/page/page.repo'; import { LabelRepo } from '@docmost/db/repos/label/label.repo'; +import { PaginationOptions } from '@docmost/db/pagination/pagination-options'; @UseGuards(JwtAuthGuard) @Controller('labels') @@ -37,6 +38,15 @@ export class LabelController { private readonly spaceAbility: SpaceAbilityFactory, ) {} + @HttpCode(HttpStatus.OK) + @Post('/') + async getLabels( + @Body() pagination: PaginationOptions, + @AuthWorkspace() workspace: Workspace, + ) { + return this.labelService.getLabels(workspace.id, pagination); + } + @HttpCode(HttpStatus.OK) @Post('add') async addLabels( @@ -84,6 +94,7 @@ export class LabelController { @Post('page') async getPageLabels( @Body() dto: PageLabelsDto, + @Body() pagination: PaginationOptions, @AuthUser() user: User, ) { const page = await this.pageRepo.findById(dto.pageId); @@ -96,7 +107,7 @@ export class LabelController { throw new ForbiddenException(); } - return this.labelService.getPageLabels(page.id); + return this.labelService.getPageLabels(page.id, pagination); } @HttpCode(HttpStatus.OK) diff --git a/apps/server/src/core/label/label.service.ts b/apps/server/src/core/label/label.service.ts index 75f6faec..168ec3fd 100644 --- a/apps/server/src/core/label/label.service.ts +++ b/apps/server/src/core/label/label.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@nestjs/common'; import { LabelRepo, LabelType } from '@docmost/db/repos/label/label.repo'; import { InjectKysely } from 'nestjs-kysely'; import { KyselyDB } from '@docmost/db/types/kysely.types'; -import { Label } from '@docmost/db/types/entity.types'; import { executeTx } from '@docmost/db/utils'; +import { PaginationOptions } from '@docmost/db/pagination/pagination-options'; @Injectable() export class LabelService { @@ -16,7 +16,7 @@ export class LabelService { pageId: string, names: string[], workspaceId: string, - ): Promise { + ) { await executeTx(this.db, async (trx) => { for (const name of names) { const label = await this.labelRepo.findOrCreate( @@ -29,7 +29,7 @@ export class LabelService { } }); - return this.labelRepo.findLabelsByPageId(pageId); + return this.labelRepo.findLabelsByPageId(pageId, { limit: 100 } as PaginationOptions); } async removeLabelFromPage( @@ -46,8 +46,15 @@ export class LabelService { }); } - async getPageLabels(pageId: string): Promise { - return this.labelRepo.findLabelsByPageId(pageId); + async getPageLabels(pageId: string, pagination: PaginationOptions) { + return this.labelRepo.findLabelsByPageId(pageId, pagination); + } + + async getLabels( + workspaceId: string, + pagination: PaginationOptions, + ) { + return this.labelRepo.findLabels(workspaceId, LabelType.PAGE, pagination); } async searchPagesByLabel( diff --git a/apps/server/src/database/repos/label/label.repo.ts b/apps/server/src/database/repos/label/label.repo.ts index 5f1d4953..13f88771 100644 --- a/apps/server/src/database/repos/label/label.repo.ts +++ b/apps/server/src/database/repos/label/label.repo.ts @@ -4,6 +4,8 @@ import { KyselyDB, KyselyTransaction } from '../../types/kysely.types'; import { Label } from '@docmost/db/types/entity.types'; import { dbOrTx } from '@docmost/db/utils'; import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo'; +import { PaginationOptions } from '@docmost/db/pagination/pagination-options'; +import { executeWithCursorPagination } from '@docmost/db/pagination/cursor-pagination'; export const LabelType = { PAGE: 'page', @@ -72,15 +74,68 @@ export class LabelRepo { return this.findByNameAndWorkspace(normalizedName, workspaceId, type, trx); } - async findLabelsByPageId(pageId: string): Promise { - return this.db + async findLabelsByPageId(pageId: string, pagination: PaginationOptions) { + const query = this.db .selectFrom('labels') .innerJoin('pageLabels', 'pageLabels.labelId', 'labels.id') - .select(['labels.id', 'labels.name', 'labels.type', 'labels.createdAt', 'labels.updatedAt', 'labels.workspaceId']) + .select([ + 'labels.id', + 'labels.name', + 'labels.type', + 'labels.createdAt', + 'labels.updatedAt', + 'labels.workspaceId', + ]) .where('pageLabels.pageId', '=', pageId) - .where('labels.type', '=', LabelType.PAGE) - .orderBy('labels.name', 'asc') - .execute(); + .where('labels.type', '=', LabelType.PAGE); + + return executeWithCursorPagination(query, { + perPage: pagination.limit, + cursor: pagination.cursor, + beforeCursor: pagination.beforeCursor, + fields: [ + { expression: 'labels.name', direction: 'asc', key: 'name' }, + { expression: 'labels.id', direction: 'asc', key: 'id' }, + ], + parseCursor: (cursor) => ({ + name: cursor.name, + id: cursor.id, + }), + }); + } + + async findLabels( + workspaceId: string, + type: LabelType, + pagination: PaginationOptions, + ) { + let query = this.db + .selectFrom('labels') + .select(['id', 'name', 'type', 'createdAt', 'updatedAt', 'workspaceId']) + .where('workspaceId', '=', workspaceId) + .where('type', '=', type); + + if (pagination.query) { + query = query.where( + 'name', + 'like', + `%${pagination.query.toLowerCase()}%`, + ); + } + + return executeWithCursorPagination(query, { + perPage: pagination.limit, + cursor: pagination.cursor, + beforeCursor: pagination.beforeCursor, + fields: [ + { expression: 'name', direction: 'asc' }, + { expression: 'id', direction: 'asc' }, + ], + parseCursor: (cursor) => ({ + name: cursor.name, + id: cursor.id, + }), + }); } async addLabelToPage(