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

Add select service for testing #7

Merged
merged 2 commits into from
Oct 9, 2023
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
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ COMPOSE_PATH_SEPARATOR=;
TAG=latest
QUERY_PORT=127.0.0.1:5511
POSTGRES_HOST=localhost
POSTGRES_PORT=127.0.0.1:5512
POSTGRES_PORT=5512
POSTGRES_DB=query
POSTGRES_USER=productopener
POSTGRES_PASSWORD=productopener
Expand Down
9 changes: 7 additions & 2 deletions src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { Body, Controller, Get, Post, Query, All } from '@nestjs/common';
import { ImportService } from './domain/services/import.service';
import { QueryService } from './domain/services/query.service';

Expand Down Expand Up @@ -27,8 +27,13 @@ export class AppController {
return await this.queryService.aggregate(body);
}

@Post('count')
@All('count')
async count(@Body() body: any) {
return await this.queryService.count(body);
}

@Post('select')
async select(@Body() body: any) {
return await this.queryService.select(body);
}
}
27 changes: 26 additions & 1 deletion src/domain/services/query.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ describe('count', () => {
expect(response).toBe(1);
});
});
it('should cope with no filters', async () => {
await createTestingModule([DomainModule], async (app) => {
const { originValue, aminoValue, neucleotideValue } =
await createTestTags(app);
const queryService = app.get(QueryService);
const response = await queryService.count(null);
expect(response).toBeGreaterThan(2);
});
});
});

describe('aggregate', () => {
Expand Down Expand Up @@ -172,6 +181,22 @@ describe('aggregate', () => {
});
});

describe('select', () => {
it('should return matching products', async () =>{
await createTestingModule([DomainModule], async (app) => {
const { originValue, aminoValue, neucleotideValue, product1, product2, product3 } =
await createTestTags(app);
const queryService = app.get(QueryService);
const response = await queryService.select({
amino_acids_tags: aminoValue,
});
expect(response).toHaveLength(2);
const p1 = response.find((r) => r.code === product1.code);
expect(p1).toBeTruthy();
});
});
});

async function createTestTags(app) {
const em = app.get(EntityManager);
// Create some dummy products with a specific tag
Expand Down Expand Up @@ -221,5 +246,5 @@ async function createTestTags(app) {
});

await em.flush();
return { originValue, aminoValue, neucleotideValue };
return { originValue, aminoValue, neucleotideValue, product1, product2, product3 };
}
49 changes: 34 additions & 15 deletions src/domain/services/query.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class QueryService {
return results;
}

private addMatches(match: any, qb: QueryBuilder<object>) {
private addMatches(match: any, qb: QueryBuilder<object>, parentKey = 'pt.product_id') {
const whereLog = [];
for (const [matchTag, matchValue] of Object.entries(match)) {
let whereValue = matchValue;
Expand All @@ -76,7 +76,7 @@ export class QueryService {
const qbWhere = this.em
.createQueryBuilder(matchEntity, 'pt2')
.select('*')
.where(`pt2.product_id = pt.product_id and pt2.${matchColumn} = ?`, [
.where(`pt2.product_id = ${parentKey} and pt2.${matchColumn} = ?`, [
whereValue,
]);
qb.andWhere(`${not ? 'NOT ' : ''}EXISTS (${qbWhere.getKnexQuery()})`);
Expand All @@ -89,37 +89,56 @@ export class QueryService {
const start = Date.now();
this.logger.debug(body);

const tags = Object.keys(body);
const tag = tags[0];
const tags = Object.keys(body ?? {});
const tag = tags?.[0];
const { entity, column } = this.getEntityAndColumn(tag);
const qb = this.em.createQueryBuilder(entity, 'pt');
qb.select(`count(*) count`);
qb.where('not pt.obsolete');

let matchValue = body[tag];
const not = matchValue?.['$ne'];
if (not) {
matchValue = not;
let whereLog = [];
if (tag) {
let matchValue = body[tag];
const not = matchValue?.['$ne'];
whereLog.push(`${tag} ${not ? '!=' : '=='} ${matchValue}`);
if (not) {
matchValue = not;
}
qb.andWhere(`${not ? 'NOT ' : ''}pt.${column} = ?`, [matchValue]);
delete body[tag];
whereLog.push(...this.addMatches(body, qb));
}
qb.andWhere(`${not ? 'NOT ' : ''}pt.${column} = ?`, [matchValue]);
delete body[tag];
const whereLog = this.addMatches(body, qb);

this.logger.debug(qb.getFormattedQuery());
const results = await qb.execute();
const response = results[0].count;
this.logger.log(
`Processed ${tag} ${not ? '!=' : '=='} ${matchValue}${
whereLog.length ? ` and ${whereLog.join(' and ')}` : ''
} in ${Date.now() - start} ms. Count: ${response}`,
`Processed ${whereLog.join(' and ')} in ${Date.now() - start} ms. Count: ${response}`,
);
return parseInt(response);
}

async select(body: any) {
const start = Date.now();
this.logger.debug(body);

const tags = Object.keys(body);
let entity: EntityName<object> = Product;
const qb = this.em.createQueryBuilder(entity, 'p');
qb.select(`*`);
qb.where('not p.obsolete');

const whereLog = this.addMatches(body, qb, 'p.id');

this.logger.debug(qb.getFormattedQuery());
const results = await qb.execute();
return results;
}

private getEntityAndColumn(tag: any) {
let entity: EntityName<object>;
let column = 'value';
if (MAPPED_FIELDS.includes(tag)) {
if (!tag || MAPPED_FIELDS.includes(tag)) {
entity = Product;
column = tag;
} else {
Expand Down
Loading