Skip to content

Commit

Permalink
Pagination in imports (#482)
Browse files Browse the repository at this point in the history
Closes #465
  • Loading branch information
chavda-bhavik authored Feb 1, 2024
2 parents 4a8da5e + 637cee2 commit f6ae5ef
Show file tree
Hide file tree
Showing 31 changed files with 5,087 additions and 4,911 deletions.
8 changes: 7 additions & 1 deletion apps/api/src/app/activity/activity.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ export class ActivityController {
date = undefined;
}

return this.uploadHistory.execute(_projectId, name, date, page, limit);
return this.uploadHistory.execute({
_projectId,
name,
date,
page,
limit,
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IsDefined, IsMongoId, IsOptional, IsString } from 'class-validator';
import { PaginationCommand } from '@shared/commands/pagination.command';

export class UploadHistoryCommand extends PaginationCommand {
@IsDefined()
@IsMongoId()
_projectId: string;

@IsOptional()
@IsString()
name?: string;

@IsOptional()
@IsString()
date?: string;
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { Injectable } from '@nestjs/common';
import { UploadRepository } from '@impler/dal';
import { PaginationResult } from '@impler/shared';
import { UploadHistoryCommand } from './upload-history.command';

@Injectable()
export class UploadHistory {
constructor(private uploadRepository: UploadRepository) {}

async execute(
_projectId: string,
name?: string,
date?: string,
page?: number,
limit?: number
): Promise<PaginationResult> {
async execute({ _projectId, date, limit, name, page }: UploadHistoryCommand): Promise<PaginationResult> {
const uploadResult = await this.uploadRepository.getList(_projectId, name, date, page, limit);
uploadResult.uploads = uploadResult.uploads.map((upload) => {
upload.name = upload._template.name;
Expand Down
39 changes: 39 additions & 0 deletions apps/api/src/app/project/dtos/import-list-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { IsDefined, IsNumber, IsString } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class ImportListResponseDto {
@ApiPropertyOptional({
description: 'Id of the import',
})
@IsString()
@IsDefined()
_id?: string;

@ApiProperty({
description: 'Name of the import',
})
@IsString()
@IsDefined()
name: string;

@ApiProperty({
description: 'Total number of uploads',
})
@IsNumber()
@IsDefined()
totalUploads: number;

@ApiProperty({
description: 'Total number of records imported',
})
@IsNumber()
@IsDefined()
totalRecords: number;

@ApiProperty({
description: 'Total number of invalid records',
})
@IsNumber()
@IsDefined()
totalInvalidRecords: number;
}
32 changes: 32 additions & 0 deletions apps/api/src/app/project/dtos/template-list-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { IsDefined, IsNumber, IsString } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

export class TemplateListResponseDto {
@ApiPropertyOptional({
description: 'Id of the template',
})
@IsString()
@IsDefined()
_id?: string;

@ApiProperty({
description: 'Name of the template',
})
@IsString()
@IsDefined()
name: string;

@ApiProperty({
description: 'URL to download samle csv file',
})
@IsString()
@IsDefined()
sampleFileUrl: string;

@ApiProperty({
description: 'Total number of columns in the template',
})
@IsDefined()
@IsNumber()
totalColumns: number;
}
43 changes: 36 additions & 7 deletions apps/api/src/app/project/project.controller.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Response } from 'express';
import { ApiOperation, ApiTags, ApiOkResponse, ApiSecurity } from '@nestjs/swagger';
import { Body, Controller, Delete, Get, Param, Post, Put, Res, UseGuards } from '@nestjs/common';
import { Body, Controller, Delete, Get, Param, Post, Put, Query, Res, UseGuards } from '@nestjs/common';

import { ACCESS_KEY_NAME, IJwtPayload } from '@impler/shared';
import { ACCESS_KEY_NAME, Defaults, IJwtPayload, PaginationResult } from '@impler/shared';
import { UserSession } from '@shared/framework/user.decorator';
import { ValidateMongoId } from '@shared/validations/valid-mongo-id.validation';

import { ProjectResponseDto } from './dtos/project-response.dto';
import { CreateProjectRequestDto } from './dtos/create-project-request.dto';
import { UpdateProjectRequestDto } from './dtos/update-project-request.dto';
import { TemplateResponseDto } from 'app/template/dtos/template-response.dto';
import { TemplateListResponseDto } from './dtos/template-list-response.dto';
import { ImportListResponseDto } from './dtos/import-list-response.dto';

import {
GetImports,
GetProjects,
GetTemplates,
CreateProject,
Expand All @@ -32,6 +34,7 @@ import { EnvironmentResponseDto } from 'app/environment/dtos/environment-respons
@UseGuards(JwtAuthGuard)
export class ProjectController {
constructor(
private getImports: GetImports,
private getProjectsUsecase: GetProjects,
private createProjectUsecase: CreateProject,
private updateProjectUsecase: UpdateProject,
Expand All @@ -41,7 +44,7 @@ export class ProjectController {
private getEnvironment: GetEnvironment
) {}

@Get('')
@Get()
@ApiOperation({
summary: 'Get projects',
})
Expand All @@ -57,12 +60,38 @@ export class ProjectController {
summary: 'Get all templates for project',
})
@ApiOkResponse({
type: [TemplateResponseDto],
type: [TemplateListResponseDto],
})
getTemplatesRoute(@Param('projectId', ValidateMongoId) projectId: string): Promise<TemplateResponseDto[]> {
getTemplatesRoute(@Param('projectId', ValidateMongoId) projectId: string): Promise<TemplateListResponseDto[]> {
return this.getTemplates.execute(projectId);
}

@Get(':projectId/imports')
@ApiOperation({
summary: 'Get all imports for project',
})
@ApiOkResponse({
type: [ImportListResponseDto],
})
getImportsRoute(
@Param('projectId', ValidateMongoId) _projectId: string,
@Query('page') page = Defaults.ONE,
@Query('limit') limit = Defaults.PAGE_LIMIT,
@Query('search') search: string
): Promise<PaginationResult<ImportListResponseDto>> {
if (isNaN(page)) page = Defaults.ONE;
else page = Number(page);
if (isNaN(limit)) limit = Defaults.PAGE_LIMIT;
else limit = Number(limit);

return this.getImports.execute({
_projectId,
limit,
page,
search,
});
}

@Get(':projectId/environment')
@ApiOperation({
summary: 'Get environment for project',
Expand All @@ -74,7 +103,7 @@ export class ProjectController {
return this.getEnvironment.execute(projectId);
}

@Post('')
@Post()
@ApiOperation({
summary: 'Create project',
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { IsDefined, IsString } from 'class-validator';
import { PaginationCommand } from '@shared/commands/pagination.command';

export class GetImportsCommand extends PaginationCommand {
@IsDefined()
@IsString()
_projectId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Injectable } from '@nestjs/common';
import { GetImportsCommand } from './get-imports.command';
import { TemplateRepository, CommonRepository } from '@impler/dal';
import { ImportListResponseDto } from 'app/project/dtos/import-list-response.dto';
import { PaginationResult } from '@impler/shared';

@Injectable()
export class GetImports {
constructor(private templateRepository: TemplateRepository, private commonRepository: CommonRepository) {}

async execute({
_projectId,
limit,
page,
search,
}: GetImportsCommand): Promise<PaginationResult<ImportListResponseDto>> {
const imports = await this.templateRepository.paginate(
{
_projectId: this.commonRepository.generateMongoId(_projectId),
name: {
$regex: search || '',
$options: 'i',
},
},
'name totalUploads totalRecords totalInvalidRecords',
{
skip: limit * (page - 1),
limit,
}
);

return {
page,
limit,
data: imports.data,
totalPages: Math.ceil(imports.total / limit),
totalRecords: imports.total,
};
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Injectable } from '@nestjs/common';
import { TemplateRepository, CommonRepository } from '@impler/dal';
import { WidgetTemplateResponseDto } from 'app/template/dtos/widget-templates-response.dto';
import { TemplateListResponseDto } from 'app/project/dtos/template-list-response.dto';

@Injectable()
export class GetTemplates {
constructor(private templateRepository: TemplateRepository, private commonRepository: CommonRepository) {}

async execute(_projectId: string): Promise<WidgetTemplateResponseDto[]> {
async execute(_projectId: string): Promise<TemplateListResponseDto[]> {
const templates = await this.templateRepository.aggregate([
{
$match: {
Expand All @@ -32,16 +32,9 @@ export class GetTemplates {
]);

return templates.map((template) => ({
_projectId: template._projectId,
callbackUrl: template.callbackUrl,
chunkSize: template.chunkSize,
_id: template._id,
name: template.name,
sampleFileUrl: template.sampleFileUrl,
_id: template._id,
totalUploads: template.totalUploads,
totalInvalidRecords: template.totalInvalidRecords,
totalRecords: template.totalRecords,
authHeaderName: template.authHeaderName,
totalColumns: template.columns?.length,
}));
}
Expand Down
4 changes: 3 additions & 1 deletion apps/api/src/app/project/usecases/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CreateProject } from './create-project/create-project.usecase';
import { CreateProjectCommand } from './create-project/create-project.command';
import { GetImports } from './get-imports/get-imports.usecase';
import { GetProjects } from './get-projects/get-projects.usecase';
import { UpdateProject } from './update-project/update-project.usecase';
import { UpdateProjectCommand } from './update-project/update-project.command';
Expand All @@ -13,9 +14,10 @@ export const USE_CASES = [
UpdateProject,
DeleteProject,
GetTemplates,
GetImports,
GetEnvironment,
//
];

export { CreateProject, GetProjects, UpdateProject, DeleteProject, GetTemplates, GetEnvironment };
export { CreateProject, GetProjects, UpdateProject, DeleteProject, GetTemplates, GetEnvironment, GetImports };
export { CreateProjectCommand, UpdateProjectCommand };
16 changes: 16 additions & 0 deletions apps/api/src/app/shared/commands/pagination.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IsNumber, IsOptional, IsString } from 'class-validator';
import { BaseCommand } from './base.command';

export class PaginationCommand extends BaseCommand {
@IsOptional()
@IsNumber()
page?: number;

@IsOptional()
@IsNumber()
limit?: number;

@IsOptional()
@IsString()
search?: string;
}
Loading

0 comments on commit f6ae5ef

Please sign in to comment.