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

125 backend module filter backup data by backup tasks ids #145

Merged
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
51 changes: 39 additions & 12 deletions apps/backend/src/app/backupData/backupData.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ describe('BackupDataController (e2e)', () => {
});
});

it('/backupData (GET) with pagination should return paginated backup data entries', async () => {
it('/backupData/filter (POST) with pagination should return paginated backup data entries', async () => {
const response = await request(app.getHttpServer())
.get('/backupData?offset=0&limit=1')
.expect(200);
.post('/backupData/filter?offset=0&limit=1')
.expect(201);

expect(response.body).toEqual({
data: [
Expand All @@ -117,10 +117,10 @@ describe('BackupDataController (e2e)', () => {
});
});

it('/backupData (GET) with date range should return backup data entries within date range', async () => {
it('/backupData/filter (POST) with date range should return backup data entries within date range', async () => {
const response = await request(app.getHttpServer())
.get('/backupData?fromDate=2023-12-01&toDate=2023-12-31')
.expect(200);
.post('/backupData/filter?fromDate=2023-12-01&toDate=2023-12-31')
.expect(201);

expect(response.body).toEqual({
data: [
Expand All @@ -139,21 +139,21 @@ describe('BackupDataController (e2e)', () => {
where: { creationDate: expect.any(Object), type: BackupType.FULL },
});
});
it('/backupData (GET) with taskId should return backup data entries with the specified taskId', async () => {
it('/backupData/filter (POST) with taskId should return backup data entries with the specified taskId', async () => {
await request(app.getHttpServer())
.get('/backupData?taskId=task-123')
.expect(200);
.post('/backupData/filter?taskId=task-123')
.expect(201);

expect(mockBackupDataRepository.findAndCount).toBeCalledWith({
order: { creationDate: 'DESC' },
where: { taskId: { id: 'task-123' }, type: BackupType.FULL },
});
});

it('/backupData (GET) with taskName should return backup data entries with the specified taskName', async () => {
it('/backupData/filter (POST) with taskName should return backup data entries with the specified taskName', async () => {
await request(app.getHttpServer())
.get('/backupData?taskName=backup-task')
.expect(200);
.post('/backupData/filter?taskName=backup-task')
.expect(201);

expect(mockBackupDataRepository.findAndCount).toBeCalledWith({
order: { creationDate: 'DESC' },
Expand All @@ -163,4 +163,31 @@ describe('BackupDataController (e2e)', () => {
},
});
});

it('/backupData/filter (POST) with multiple taskIds should return backup data entries with the specified taskIds', async () => {
const response = await request(app.getHttpServer())
.post('/backupData/filter')
.send({ taskIds: ['task-1', 'task-2'] })
.expect(201);

expect(response.body).toEqual({
data: [
{
...mockBackupDataEntity,
creationDate: mockBackupDataEntity.creationDate.toISOString(),
},
],
paginationData: {
total: 1,
},
});

expect(mockBackupDataRepository.findAndCount).toBeCalledWith({
order: { creationDate: 'DESC' },
where: {
taskId: [{ id: 'task-1' }, { id: 'task-2' }],
type: BackupType.FULL,
},
});
});
});
14 changes: 11 additions & 3 deletions apps/backend/src/app/backupData/backupData.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Query,
} from '@nestjs/common';
import {
ApiBody,
ApiCreatedResponse,
ApiOkResponse,
ApiOperation,
Expand All @@ -21,6 +22,7 @@ import { PaginationDto } from '../utils/pagination/PaginationDto';
import { PaginationOptionsDto } from '../utils/pagination/PaginationOptionsDto';
import { BackupDataFilterDto } from './dto/backupDataFilter.dto';
import { BackupDataOrderOptionsDto } from './dto/backupDataOrderOptions.dto';
import { BackupDataFilterByTaskIdsDto } from './dto/backupDataFilterByTaskIds.dto';

@ApiTags('Backup Data')
@Controller('backupData')
Expand All @@ -41,18 +43,24 @@ export class BackupDataController {
return entity;
}

@Get()
@Post('filter')
@ApiOperation({ summary: 'Returns all backupData Objects.' })
@ApiOkResponse()
@ApiBody({
type: BackupDataFilterByTaskIdsDto,
required: false,
})
async findAll(
@Query() paginationOptionsDto: PaginationOptionsDto,
@Query() backupDataFilterDto: BackupDataFilterDto,
@Query() backupDataOrderOptionsDto: BackupDataOrderOptionsDto
@Query() backupDataOrderOptionsDto: BackupDataOrderOptionsDto,
@Body() backupDataFilterByTaskIdsDto?: BackupDataFilterByTaskIdsDto
): Promise<PaginationDto<BackupDataDto>> {
return this.backupDataService.findAll(
paginationOptionsDto,
backupDataOrderOptionsDto,
backupDataFilterDto
backupDataFilterDto,
backupDataFilterByTaskIdsDto
);
}

Expand Down
10 changes: 10 additions & 0 deletions apps/backend/src/app/backupData/backupData.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ describe('BackupDataService', () => {
type: BackupType.FULL,
});
});

it('should create a where clause for multiple taskIds', () => {
const filterDto: BackupDataFilterDto = {};
const filterByTaskIdsDto = { taskIds: ['task-1', 'task-2'] };
const where = service.createWhereClause(filterDto, filterByTaskIdsDto);
expect(where).toEqual({
taskId: [{ id: 'task-1' }, { id: 'task-2' }],
type: BackupType.FULL,
});
});
});

describe('createOrderClause', () => {
Expand Down
22 changes: 19 additions & 3 deletions apps/backend/src/app/backupData/backupData.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { BackupDataDto } from './dto/backupData.dto';
import { BackupDataFilterDto } from './dto/backupDataFilter.dto';
import { BackupDataOrderOptionsDto } from './dto/backupDataOrderOptions.dto';
import { BackupType } from './dto/backupType';
import { BackupDataFilterByTaskIdsDto } from './dto/backupDataFilterByTaskIds.dto';
import { TaskEntity } from '../tasks/entity/task.entity';

@Injectable()
export class BackupDataService extends PaginationService {
Expand All @@ -41,12 +43,13 @@ export class BackupDataService extends PaginationService {
async findAll(
paginationOptionsDto: PaginationOptionsDto,
backupDataOrderOptionsDto: BackupDataOrderOptionsDto,
backupDataFilterDto: BackupDataFilterDto
backupDataFilterDto: BackupDataFilterDto,
backupDataFilterByTaskIdsDto?: BackupDataFilterByTaskIdsDto
): Promise<PaginationDto<BackupDataDto>> {
return await this.paginate<BackupDataEntity>(
this.backupDataRepository,
this.createOrderClause(backupDataOrderOptionsDto),
this.createWhereClause(backupDataFilterDto),
this.createWhereClause(backupDataFilterDto, backupDataFilterByTaskIdsDto),
paginationOptionsDto
);
}
Expand Down Expand Up @@ -79,7 +82,10 @@ export class BackupDataService extends PaginationService {
* Create where clause.
* @param backupDataFilterDto
*/
createWhereClause(backupDataFilterDto: BackupDataFilterDto) {
createWhereClause(
backupDataFilterDto: BackupDataFilterDto,
backupDataFilterByTaskIdsDto?: BackupDataFilterByTaskIdsDto
) {
const where: FindOptionsWhere<BackupDataEntity> = {};

//ID search
Expand Down Expand Up @@ -144,6 +150,16 @@ export class BackupDataService extends PaginationService {
where.taskId = { id: backupDataFilterDto.taskId };
}

//Multiple Task ids from body search
if (backupDataFilterByTaskIdsDto?.taskIds) {
const taskIdFilter: FindOptionsWhere<TaskEntity>[] = [];
const taskIds = backupDataFilterByTaskIdsDto.taskIds;
for (const taskId of taskIds) {
taskIdFilter.push({ id: taskId });
}
where.taskId = taskIdFilter;
}

//Task name search
if (backupDataFilterDto.taskName) {
where.taskId = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional } from 'class-validator';

export class BackupDataFilterByTaskIdsDto {
@ApiProperty({
description: 'Array of task ids to be filtered by',
})
@IsOptional()
taskIds?: string[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import { fail } from 'assert';
describe('BackupService', () => {
let service: BackupService;
let httpClientMock: {
get: ReturnType<typeof vi.fn>;
post: ReturnType<typeof vi.fn>;
};
const baseUrl = 'http://test-url';

beforeEach(() => {
httpClientMock = {
get: vi.fn(),
post: vi.fn(),
};

service = new BackupService(
Expand Down Expand Up @@ -46,16 +46,17 @@ describe('BackupService', () => {
},
};

httpClientMock.get.mockReturnValue(of(mockResponse));
httpClientMock.post.mockReturnValue(of(mockResponse));

service.getAllBackups(mockFilterParams).subscribe((response) => {
expect(httpClientMock.get).toHaveBeenCalledWith(
`${baseUrl}/backupData`,
expect(httpClientMock.post).toHaveBeenCalledWith(
`${baseUrl}/backupData/filter`,
null,
{
params: expect.any(HttpParams),
}
);
const passedParams = httpClientMock.get.mock.calls[0][1].params;
const passedParams = httpClientMock.post.mock.calls[0][2].params;
expect(passedParams.keys()).toEqual(['offset', 'limit']);
});
});
Expand All @@ -79,17 +80,18 @@ describe('BackupService', () => {
},
};

httpClientMock.get.mockReturnValue(of(mockResponse));
httpClientMock.post.mockReturnValue(of(mockResponse));

service.getAllBackups(mockFilterParams).subscribe((response) => {
expect(httpClientMock.get).toHaveBeenCalledWith(
`${baseUrl}/backupData`,
expect(httpClientMock.post).toHaveBeenCalledWith(
`${baseUrl}/backupData/filter`,
null,
{
params: expect.any(HttpParams),
}
);

const passedParams = httpClientMock.get.mock.calls[0][1].params;
const passedParams = httpClientMock.post.mock.calls[0][2].params;
expect(passedParams.get('limit')).toBe('10');
expect(passedParams.get('offset')).toBe('0');
expect(passedParams.get('orderBy')).toBe('createdAt');
Expand All @@ -114,14 +116,14 @@ describe('BackupService', () => {
},
};

httpClientMock.get.mockReturnValue(of(mockResponse));
httpClientMock.post.mockReturnValue(of(mockResponse));

const observable = service.getAllBackups(mockFilterParams);

observable.subscribe();
observable.subscribe();

expect(httpClientMock.get).toHaveBeenCalledTimes(1);
expect(httpClientMock.post).toHaveBeenCalledTimes(1);
});

it('should handle empty filter params', () => {
Expand All @@ -134,17 +136,18 @@ describe('BackupService', () => {
},
};

httpClientMock.get.mockReturnValue(of(mockResponse));
httpClientMock.post.mockReturnValue(of(mockResponse));

service.getAllBackups(mockFilterParams).subscribe((response) => {
expect(httpClientMock.get).toHaveBeenCalledWith(
`${baseUrl}/backupData`,
expect(httpClientMock.post).toHaveBeenCalledWith(
`${baseUrl}/backupData/filter`,
null,
{
params: expect.any(HttpParams),
}
);

const passedParams = httpClientMock.get.mock.calls[0][1].params;
const passedParams = httpClientMock.post.mock.calls[0][2].params;
expect(passedParams.keys().length).toBe(0);
});
});
Expand All @@ -157,7 +160,7 @@ describe('BackupService', () => {

const mockError = new Error('Network error');

httpClientMock.get.mockReturnValue(throwError(() => mockError));
httpClientMock.post.mockReturnValue(throwError(() => mockError));
service.getAllBackups(mockFilterParams).subscribe({
next: () => fail('expected an error, not backups'),
error: (error) => expect(error).toBe(mockError),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class BackupService {
const params = new HttpParams({ fromObject: cleanParams });

return this.http
.get<APIResponse<Backup>>(`${this.baseUrl}/backupData`, {
.post<APIResponse<Backup>>(`${this.baseUrl}/backupData/filter`, null, {
params: params,
})
.pipe(shareReplay(1));
Expand Down
Loading