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

feat: enable search with multiple types and statuses (MAPCO-4427, MAPCO-4430) #41

Merged
merged 6 commits into from
Jul 14, 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
58 changes: 58 additions & 0 deletions openapi3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,27 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/errorMessage'
/jobs/find:
post:
operationId: findJobsByCriteria
summary: gets jobs by criteria
tags:
- jobs
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/getJobsByCriteria'
responses:
'200':
description: Array of jobs
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/jobResponse'
/jobs/{jobId}:
parameters:
- $ref: '#/components/parameters/jobId'
Expand Down Expand Up @@ -668,6 +689,43 @@ components:
type: string
format: uuid
schemas:
getJobsByCriteria:
type: object
description: get jobs criteria
properties:
resourceId:
type: string
version:
type: string
isCleaned:
type: boolean
statuses:
type: array
items:
$ref: '#/components/schemas/status'
types:
type: array
items:
type: string
shouldReturnTasks:
type: boolean
default: false
fromDate:
type: string
format: date-time
tillDate:
type: string
format: date-time
productType:
type: string
internalId:
type: string
format: uuid
domain:
type: string
shouldReturnAvailableActions:
type: boolean
default: false
findTaskRequest:
type: object
description: task find model
Expand Down
39 changes: 39 additions & 0 deletions src/DAL/repositories/jobRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
IFindJobsRequest,
IUpdateJobRequest,
IJobsQuery,
IFindJobsByCriteriaBody,
} from '../../common/dataModels/jobs';
import { JobModelConvertor } from '../convertors/jobModelConverter';
import { OperationStatus } from '../../common/dataModels/enums';
Expand Down Expand Up @@ -69,6 +70,44 @@ export class JobRepository extends GeneralRepository<JobEntity> {
return models;
}

public async findJobsByCriteria(req: IFindJobsByCriteriaBody): Promise<FindJobsResponse> {
const filter: Record<string, unknown> = {
resourceId: req.resourceId,
version: req.version,
isCleaned: req.isCleaned,
productType: req.productType,
internalId: req.internalId,
domain: req.domain,
};

if (req.fromDate != undefined && req.tillDate != undefined) {
filter.updateTime = Between(req.fromDate, req.tillDate);
} else if (req.tillDate != undefined) {
filter.updateTime = LessThanOrEqual(req.tillDate);
} else if (req.fromDate != undefined) {
filter.updateTime = MoreThanOrEqual(req.fromDate);
}

for (const key of Object.keys(filter)) {
if (filter[key] == undefined) {
delete filter[key];
}
}
if (req.shouldReturnTasks !== false) {
filter.relations = ['tasks'];
}
const queryBuilder = this.createQueryBuilder().select('job').from(JobEntity, 'job').where(filter);
if ((req.types?.length ?? 0) > 0) {
queryBuilder.andWhere('job.type IN (:...types)', { types: req.types });
}
if ((req.statuses?.length ?? 0) > 0) {
queryBuilder.andWhere('job.status IN (:...statuses)', { statuses: req.statuses });
}
const entities = await queryBuilder.getMany();
const models = entities.map((entity) => this.jobConvertor.entityToModel(entity));
return models;
}

public async getJobByJobParameters(parameters: JobParameters): Promise<FindJobsResponse> {
this.appLogger.info({ parameters }, 'Getting jobs by jobs parameters');
try {
Expand Down
15 changes: 15 additions & 0 deletions src/common/dataModels/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ export interface IFindJobsRequest {
domain?: string;
}

export interface IFindJobsByCriteriaBody {
resourceId?: string;
version?: string;
isCleaned?: boolean;
statuses?: OperationStatus[];
types?: string[];
shouldReturnTasks?: boolean;
shouldReturnAvailableActions?: boolean;
productType?: string;
fromDate?: string;
tillDate?: string;
internalId?: string;
domain?: string;
}

export interface ICreateJobBody {
resourceId: string;
version: string;
Expand Down
11 changes: 11 additions & 0 deletions src/jobs/controllers/jobController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
FindJobsResponse,
ICreateJobBody,
ICreateJobResponse,
IFindJobsByCriteriaBody,
IFindJobsRequest,
IGetJobResponse,
IIsResettableResponse,
Expand All @@ -22,6 +23,7 @@ import { JobParameters } from '../../DAL/repositories/jobRepository';

type CreateResourceHandler = RequestHandler<undefined, ICreateJobResponse, ICreateJobBody>;
type FindResourceHandler = RequestHandler<undefined, FindJobsResponse, undefined, IFindJobsRequest>;
type FindResourceByCriteriaHandler = RequestHandler<undefined, FindJobsResponse, IFindJobsByCriteriaBody>;
type GetJobsByJobsParametersHandler = RequestHandler<undefined, FindJobsResponse, undefined, JobParameters>;
type GetResourceHandler = RequestHandler<IJobsParams, IGetJobResponse, undefined, IJobsQuery>;
type DeleteResourceHandler = RequestHandler<IJobsParams, DefaultResponse>;
Expand Down Expand Up @@ -50,6 +52,15 @@ export class JobController {
}
};

public findResourceByCriteria: FindResourceByCriteriaHandler = async (req, res, next) => {
try {
const jobsRes = await this.manager.findJobsByCriteria(req.body);
return res.status(httpStatus.OK).json(jobsRes);
} catch (err) {
return next(err);
}
};

public getJobByJobsParameters: GetJobsByJobsParametersHandler = async (req, res, next) => {
try {
const jobsRes = await this.manager.getJobsByJobsParameters(req.query);
Expand Down
19 changes: 19 additions & 0 deletions src/jobs/models/jobManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
IIsResettableResponse,
IResetJobRequest,
IAvailableActions,
IFindJobsByCriteriaBody,
} from '../../common/dataModels/jobs';
import { JobParameters, JobRepository } from '../../DAL/repositories/jobRepository';
import { TransactionActions } from '../../DAL/repositories/transactionActions';
Expand Down Expand Up @@ -51,6 +52,24 @@ export class JobManager {
return res;
}

@withSpanAsyncV4
public async findJobsByCriteria(req: IFindJobsByCriteriaBody): Promise<FindJobsResponse> {
const repo = await this.getRepository();
let res = await repo.findJobsByCriteria(req);

if (req.shouldReturnAvailableActions === true) {
if (res.length !== 0) {
res = await Promise.all(
res.map(async (job) => ({
...job,
availableActions: await this.getAvailableActions(job),
}))
);
}
}
return res;
}

@withSpanAsyncV4
public async getJobsByJobsParameters(req: JobParameters): Promise<FindJobsResponse> {
const repo = await this.getRepository();
Expand Down
1 change: 1 addition & 0 deletions src/jobs/routes/jobRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const jobRouterFactory: FactoryFunction<Router> = (dependencyContainer) => {
const tasksController = dependencyContainer.resolve(TaskController);

router.get('/', jobsController.findResource);
router.post('/find', jobsController.findResourceByCriteria);
router.post('/', jobsController.createResource);
router.get('/parameters', jobsController.getJobByJobsParameters);
router.get('/:jobId', jobsController.getResource);
Expand Down
7 changes: 1 addition & 6 deletions tests/configurations/integration/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
module.exports = {
transform: {
'^.+\\.ts$': 'ts-jest',
},
globals: {
'ts-jest': {
tsconfig: 'tsconfig.test.json',
},
'^.+\\.ts$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
},
coverageReporters: ['text', 'html'],
collectCoverage: true,
Expand Down
8 changes: 2 additions & 6 deletions tests/configurations/unit/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
module.exports = {
transform: {
'^.+\\.ts$': 'ts-jest',
},
globals: {
'ts-jest': {
tsconfig: 'tsconfig.test.json',
},
'^.+\\.ts$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
},
testMatch: ['<rootDir>/tests/unit/**/*.spec.ts'],
coverageReporters: ['text', 'html'],
Expand All @@ -18,6 +13,7 @@ module.exports = {
'!**/controllers/**',
'!**/routes/**',
'!<rootDir>/src/*',
'!<rootDir>/src/DAL/*',
],
coverageDirectory: '<rootDir>/coverage',
reporters: [
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/jobs/helpers/jobsRequestSender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export class JobsRequestSender {
return supertest.agent(this.app).post(`/jobs`).set('Content-Type', 'application/json').send(body);
}

public async findJobs(body: Record<string, unknown>): Promise<supertest.Response> {
return supertest.agent(this.app).post(`/jobs/find`).set('Content-Type', 'application/json').send(body);
}

public async deleteResource(id: string): Promise<supertest.Response> {
return supertest.agent(this.app).delete(`/jobs/${id}`).set('Content-Type', 'application/json');
}
Expand Down
62 changes: 62 additions & 0 deletions tests/integration/jobs/jobs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,68 @@ describe('job', function () {
});
});

describe('findJobsByCriteria', () => {
it('should get all jobs and return 200', async function () {
const filter = {
isCleaned: true,
resourceId: '1',
statuses: ['Pending'],
types: ['2'],
version: '3',
};
const jobModel = createJobDataForFind();
const jobEntity = jobModelToEntity(jobModel);
const select = jobRepositoryMocks.queryBuilder.select;
const from = jobRepositoryMocks.queryBuilder.from;
const where = jobRepositoryMocks.queryBuilder.where;
const andWhere = jobRepositoryMocks.queryBuilder.andWhere;
const getMany = jobRepositoryMocks.queryBuilder.getMany;
getMany.mockResolvedValue([jobEntity]);

const response = await requestSender.findJobs(filter);

expect(response.status).toBe(httpStatusCodes.OK);
expect(select).toHaveBeenCalledTimes(1);
expect(from).toHaveBeenCalledTimes(1);
expect(where).toHaveBeenCalledTimes(1);
expect(andWhere).toHaveBeenCalledTimes(2);
expect(getMany).toHaveBeenCalledTimes(1);

const jobs = response.body as unknown;
expect(jobs).toEqual([jobModel]);
expect(response).toSatisfyApiSpec();
});

it('should not find matched jobs and return status 200 with an empty array', async function () {
const filter = {
isCleaned: true,
resourceId: '1',
statuses: ['Pending'],
types: ['2'],
version: '3',
};

const select = jobRepositoryMocks.queryBuilder.select;
const from = jobRepositoryMocks.queryBuilder.from;
const where = jobRepositoryMocks.queryBuilder.where;
const andWhere = jobRepositoryMocks.queryBuilder.andWhere;
const getMany = jobRepositoryMocks.queryBuilder.getMany;
getMany.mockResolvedValue([]);

const response = await requestSender.findJobs(filter);

expect(response.status).toBe(httpStatusCodes.OK);
CL-SHLOMIKONCHA marked this conversation as resolved.
Show resolved Hide resolved
expect(select).toHaveBeenCalledTimes(1);
expect(from).toHaveBeenCalledTimes(1);
expect(where).toHaveBeenCalledTimes(1);
expect(andWhere).toHaveBeenCalledTimes(2);
expect(getMany).toHaveBeenCalledTimes(1);
expect(response.body).toEqual([]);

expect(response).toSatisfyApiSpec();
});
});

describe('getJob', () => {
it('should get specific job and return 200', async function () {
const jobModel = createJobDataForGetJob();
Expand Down
Loading