Skip to content

Commit

Permalink
WIP:unit tests strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
manelcecs committed Nov 11, 2023
1 parent fa06bb0 commit 96fd14b
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 80 deletions.
5 changes: 4 additions & 1 deletion src/domain-services/flows/flow-link-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export class FlowLinkService {
});

// Group flowLinks by flow ID for easy mapping
const flowLinksMap = new Map<number, InstanceOfModel<Database['flowLink']>[]>();
const flowLinksMap = new Map<
number,
InstanceOfModel<Database['flowLink']>[]
>();

// Populate the map with flowLinks for each flow
flowLinks.forEach((flowLink) => {
Expand Down
74 changes: 35 additions & 39 deletions src/domain-services/flows/flow-search-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ import {
SearchFlowsArgs,
SearchFlowsFilters,
} from './graphql/args';
import {
FlowSearchResult
} from './graphql/types';
import { FlowSearchResult } from './graphql/types';
import { FlowSearchStrategy } from './strategy/flow-search-strategy';
import { OnlyFlowFiltersStrategy } from './strategy/impl/only-flow-conditions-strategy';

@Service()
export class FlowSearchService {
constructor(
private readonly onlyFlowFiltersStrategy: OnlyFlowFiltersStrategy
) { }
) {}

async search(
models: Database,
Expand Down Expand Up @@ -45,39 +43,28 @@ export class FlowSearchService {
}

const orderBy = {
column: sortField??'updatedAt',
column: sortField ?? 'updatedAt',
order: sortOrder ?? 'desc',
};

const { flowFilters, flowObjectFilters } = filters;

let onlyFlowFilters = false;
let onlyFlowObjectFilters = false;
let bothFlowFilters = false;

if (
(!flowFilters && !flowObjectFilters) ||
(flowFilters && !flowObjectFilters)
) {
onlyFlowFilters = true;
} else if (!flowFilters && flowObjectFilters) {
onlyFlowObjectFilters = true;
} else if (flowFilters && flowObjectFilters) {
bothFlowFilters = true;
}

let conditions: any = { ...cursorCondition };
const strategy = this.determineStrategy(flowFilters, flowObjectFilters, conditions);

return await strategy.search(conditions, orderBy, limit, cursorCondition, models);

const { strategy, conditions } = this.determineStrategy(
flowFilters,
flowObjectFilters,
cursorCondition
);

return await strategy.search(
conditions,
orderBy,
limit,
cursorCondition,
models
);
}





private prepareFlowObjectConditions(
prepareFlowObjectConditions(
flowObjectFilters: FlowObjectFilters[]
): Map<string, Map<string, number[]>> {
const flowObjectConditions = new Map<string, Map<string, number[]>>();
Expand Down Expand Up @@ -108,25 +95,33 @@ export class FlowSearchService {
return flowObjectConditions;
}

private prepareFlowConditions(flowFilters: SearchFlowsFilters): Map<string, any> {
const flowConditions = new Map<string, any>();
prepareFlowConditions(flowFilters: SearchFlowsFilters): any {
let flowConditions = {};

if (flowFilters) {
Object.entries(flowFilters).forEach(([key, value]) => {
if (value !== undefined) {
flowConditions.set(key, value);
flowConditions = { ...flowConditions, [key]: value };
}
});
}

return flowConditions;
}

private determineStrategy(flowFilters: SearchFlowsFilters, flowObjectFilters: FlowObjectFilters[], conditions: any): FlowSearchStrategy {
if ((!flowFilters && (!flowObjectFilters || flowObjectFilters.length === 0)) || (flowFilters && (!flowObjectFilters || flowObjectFilters.length === 0))) {
determineStrategy(
flowFilters: SearchFlowsFilters,
flowObjectFilters: FlowObjectFilters[],
conditions: any
): { strategy: FlowSearchStrategy; conditions: any } {
if (
(!flowFilters &&
(!flowObjectFilters || flowObjectFilters.length === 0)) ||
(flowFilters && (!flowObjectFilters || flowObjectFilters.length === 0))
) {
const flowConditions = this.prepareFlowConditions(flowFilters);
conditions = { ...conditions, ...flowConditions }
return this.onlyFlowFiltersStrategy;
conditions = { ...conditions, ...flowConditions };
return { strategy: this.onlyFlowFiltersStrategy, conditions };
}
// else if (!flowFilters && flowObjectFilters.length !== 0) {
// const flowObjectConditions = this.prepareFlowObjectConditions(flowObjectFilters);
Expand All @@ -139,7 +134,8 @@ export class FlowSearchService {
// return new BothFlowFiltersStrategy(this);
// }

throw new Error('Invalid combination of flowFilters and flowObjectFilters - temp: only provide flowFilters');
throw new Error(
'Invalid combination of flowFilters and flowObjectFilters - temp: only provide flowFilters'
);
}

}
4 changes: 1 addition & 3 deletions src/domain-services/flows/graphql/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,12 @@ export class FlowObjectFilters {
}

@InputType()
export class FlowCategory{

export class FlowCategory {
@Field({ nullable: false })
id: number;

@Field({ nullable: false })
group: string;

}

@ArgsType()
Expand Down
16 changes: 11 additions & 5 deletions src/domain-services/flows/strategy/flow-search-strategy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Database } from "@unocha/hpc-api-core/src/db";
import { FlowSearchResult } from "../graphql/types";
import { Database } from '@unocha/hpc-api-core/src/db';
import { FlowSearchResult } from '../graphql/types';

export interface FlowSearchStrategy{
search(flowConditions: Map<string, any>, orderBy: any, limit: number, cursorCondition: any, models: Database): Promise<FlowSearchResult>;
}
export interface FlowSearchStrategy {
search(
flowConditions: Map<string, any>,
orderBy: any,
limit: number,
cursorCondition: any,
models: Database
): Promise<FlowSearchResult>;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Database } from '@unocha/hpc-api-core/src/db';
import { Ctx } from 'type-graphql';
import { Service } from 'typedi';
import Context from '../../../Context';
import { FlowId } from '@unocha/hpc-api-core/src/db/models/flow';
import { CategoryService } from '../../../categories/category-service';
import { ExternalReferenceService } from '../../../external-reference/external-reference-service';
Expand All @@ -18,8 +16,6 @@ import { Op } from '@unocha/hpc-api-core/src/db/util/conditions';

@Service()
export class OnlyFlowFiltersStrategy implements FlowSearchStrategy {


constructor(
private readonly organizationService: OrganizationService,
private readonly locationService: LocationService,
Expand All @@ -29,30 +25,25 @@ export class OnlyFlowFiltersStrategy implements FlowSearchStrategy {
private readonly flowLinkService: FlowLinkService,
private readonly externalReferenceService: ExternalReferenceService,
private readonly reportDetailService: ReportDetailService,
private readonly flowService: FlowService) {
}

async search(flowConditions: Map<string, any>, orderBy: any, limit: number, cursorCondition: any, models: Database): Promise<FlowSearchResult> {

// Fetch one more item to check for hasNextPage
private readonly flowService: FlowService
) {}

async search(
flowConditions: Map<string, any>,
orderBy: any,
limit: number,
cursorCondition: any,
models: Database
): Promise<FlowSearchResult> {
// Fetch one more item to check for hasNextPage
const limitComputed = limit + 1;

// Build conditions object
const conditions: any = { ...cursorCondition };

if (flowConditions.size > 0) {
flowConditions.forEach((value, key) => {
conditions[key] = value;
});
}
const conditions: any = { ...cursorCondition, ...flowConditions };

console.log('conditions in OnlyFlowFiltersStrategy', conditions);
const [flows, countRes] = await Promise.all([
this.flowService.getFlows(
models,
conditions,
orderBy,
limitComputed
),
this.flowService.getFlows(models, conditions, orderBy, limitComputed),
this.flowService.getFlowsCount(models, conditions),
]);

Expand Down Expand Up @@ -121,7 +112,7 @@ export class OnlyFlowFiltersStrategy implements FlowSearchStrategy {

const parkedParentSource: FlowParkedParentSource[] = [];
if (flow.activeStatus && flowLink.length > 0) {
this.getParketParents(flow, flowLink, models, parkedParentSource);
this.getParketParents(flow, flowLink, models); //, parkedParentSource);
}

const childIDs: number[] = flowLinksMap
Expand Down Expand Up @@ -168,7 +159,7 @@ export class OnlyFlowFiltersStrategy implements FlowSearchStrategy {
return {
flows: items,
hasNextPage: limit <= flows.length,
hasPreviousPage: false,// TODO: cursorCondition['id'].GT !== undefined,
hasPreviousPage: false, // TODO: cursorCondition['id'].GT !== undefined,
startCursor: flows.length ? flows[0].id.valueOf() : 0,
endCursor: flows.length ? flows[flows.length - 1].id.valueOf() : 0,
pageSize: flows.length,
Expand Down Expand Up @@ -210,18 +201,18 @@ export class OnlyFlowFiltersStrategy implements FlowSearchStrategy {
private async getParketParents(
flow: any,
flowLink: any[],
models: Database,
parkedParentSource: FlowParkedParentSource[]
models: Database
// parkedParentSource: FlowParkedParentSource[]
): Promise<any> {
const flowLinksDepth0 = flowLink.filter((flowLink) => flowLink.depth === 0);

const flowLinksParent = flowLinksDepth0.filter(
(flowLink) => flowLink.parentID === flow.id
);

const parentFlowIds = flowLinksParent.map((flowLink) =>
flowLink.parentID.valueOf()
);
// const parentFlowIds = flowLinksParent.map((flowLink) =>
// flowLink.parentID.valueOf()
// );

const categories = await models.category.find({
where: {
Expand All @@ -247,6 +238,7 @@ export class OnlyFlowFiltersStrategy implements FlowSearchStrategy {
categoryRef.objectID.valueOf() === flowLink.parentID.valueOf()
);
});
}

}
return parentFlows;
}
}
73 changes: 73 additions & 0 deletions tests/unit/flow-search-service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Container from 'typedi';
import { FlowSearchService } from '../../src/domain-services/flows/flow-search-service';
import { SearchFlowsFilters } from '../../src/domain-services/flows/graphql/args';

describe('PrepareFlowConditions', () => {
let flowSearchService: FlowSearchService;

beforeEach(() => {
// Initialize your class instance if needed
flowSearchService = Container.get(FlowSearchService);
});

it('should prepare flow conditions with valid filters', () => {
const flowFilters = new SearchFlowsFilters();
flowFilters.id = 1;
flowFilters.activeStatus = true;
flowFilters.status = 'commitment';
flowFilters.type = 'carryover';
flowFilters.amountUSD = 1000;
flowFilters.reporterReferenceCode = 123;
flowFilters.sourceSystemId = 456;
flowFilters.legacyId = 789;

const result = flowSearchService.prepareFlowConditions(flowFilters);

expect(result).toEqual({
id: 1,
activeStatus: true,
status: 'commitment',
type: 'carryover',
amountUSD: 1000,
reporterReferenceCode: 123,
sourceSystemId: 456,
legacyId: 789,
});
});

it('should prepare flow conditions with some filters set to undefined', () => {
const flowFilters = new SearchFlowsFilters();
flowFilters.id = 1;
flowFilters.activeStatus = true;

const result = flowSearchService.prepareFlowConditions(flowFilters);

expect(result).toEqual({
id: 1,
activeStatus: true,
});
});

it('should prepare flow conditions with all filters set to undefined', () => {
const flowFilters = new SearchFlowsFilters();

const result = flowSearchService.prepareFlowConditions(flowFilters);

expect(result).toEqual({});
});

it('should prepare flow conditions with some filters having falsy values', () => {
const flowFilters = new SearchFlowsFilters();
flowFilters.id = 0;
flowFilters.activeStatus = false;
flowFilters.amountUSD = 0;

const result = flowSearchService.prepareFlowConditions(flowFilters);

expect(result).toEqual({
id: 0,
activeStatus: false,
amountUSD: 0,
});
});
});

0 comments on commit 96fd14b

Please sign in to comment.