Skip to content

Commit

Permalink
Remove 'searchTotalAmountUSD' resolver
Browse files Browse the repository at this point in the history
Remove methods and types related to 'searchTotalAmountUSD' resolver

Refactor after removing 'searchTotalAmountUSD' needs from the search methods and strategies

Added extra steps when filtering to discart 'deleted' flows
  • Loading branch information
manelcecs committed Apr 16, 2024
1 parent 8f1752a commit 95d03f1
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 325 deletions.
163 changes: 14 additions & 149 deletions src/domain-services/flows/flow-search-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,23 @@ import { ReportDetailService } from '../report-details/report-detail-service';
import { type UsageYear } from '../usage-years/grpahql/types';
import { UsageYearService } from '../usage-years/usage-year-service';
import { FlowService } from './flow-service';
import {
import type {
FlowCategory,
FlowObjectFilters,
NestedFlowFilters,
SearchFlowsArgs,
SearchFlowsFilters,
type FlowCategory,
type FlowObjectFilters,
type NestedFlowFilters,
type SearchFlowsArgs,
type SearchFlowsArgsNonPaginated,
} from './graphql/args';
import {
type Flow,
type FlowParkedParentSource,
type FlowSearchResult,
type FlowSearchResultNonPaginated,
type FlowSearchTotalAmountResult,
type FlowShortcutFilter,
type FlowSortField,
type FlowStatusFilter,
import type {
Flow,
FlowParkedParentSource,
FlowSearchResult,
FlowSearchResultNonPaginated,
FlowShortcutFilter,
FlowSortField,
FlowStatusFilter,
} from './graphql/types';
import {
type FlowEntity,
type FlowNestedDirection,
type FlowOrderBy,
} from './model';
import type { FlowEntity, FlowNestedDirection, FlowOrderBy } from './model';
import { type FlowSearchStrategy } from './strategy/flow-search-strategy';
import { OnlyFlowFiltersStrategy } from './strategy/impl/only-flow-conditions-strategy-impl';
import { SearchFlowByFiltersStrategy } from './strategy/impl/search-flow-by-filters-strategy-impl';
Expand Down Expand Up @@ -599,135 +593,6 @@ export class FlowSearchService {
);
}

async searchTotalAmount(
models: Database,
databaseConnection: Knex,
args: SearchFlowsArgsNonPaginated
): Promise<FlowSearchTotalAmountResult> {
let { flowFilters } = args;
const {
flowObjectFilters,
flowCategoryFilters,
pending: isPendingFlows,
commitment: isCommitmentFlows,
paid: isPaidFlows,
pledge: isPledgedFlows,
carryover: isCarryoverFlows,
parked: isParkedFlows,
pass_through: isPassThroughFlows,
standard: isStandardFlows,
nestedFlowFilters,
status,
} = args;

if (!flowFilters) {
flowFilters = new SearchFlowsFilters();
flowFilters.activeStatus = true;
} else if (!flowFilters.activeStatus) {
flowFilters.activeStatus = true;
}

if (flowObjectFilters) {
const usageYearFilter = flowObjectFilters.find(
(filter) => filter.objectType === 'usageYear'
);

if (!usageYearFilter) {
// Find the flowObjectFilters since 2021 until currentYear
let startYear = 2021;
const currentYear = new Date().getFullYear();

const usageYearsArrayFilter: string[] = [];
while (startYear <= currentYear) {
usageYearsArrayFilter.push(startYear.toString());
startYear++;
}
const usageYears = await models.usageYear.find({
where: {
year: {
[Op.IN]: usageYearsArrayFilter,
},
},
});

for (const usageYear of usageYears) {
// Map the usageYear filters to the flowObjectFilters
const sourceUsageYearFilter: FlowObjectFilters = {
objectType: 'usageYear',
direction: 'source',
objectID: usageYear.id.valueOf(),
inclusive: true,
};

const destinationUsageYearFilter: FlowObjectFilters = {
objectType: 'usageYear',
direction: 'destination',
objectID: usageYear.id.valueOf(),
inclusive: true,
};

flowObjectFilters.push(
sourceUsageYearFilter,
destinationUsageYearFilter
);
}
}
}

// This filter MUST apply always
flowFilters.restricted = false;

// Validate the shortcut filters
const shortcutFilter: ShortcutCategoryFilter[] | null =
this.mapShortcutFilters(
isPendingFlows,
isCommitmentFlows,
isPaidFlows,
isPledgedFlows,
isCarryoverFlows,
isParkedFlows,
isPassThroughFlows,
isStandardFlows
);

// Once we've gathered all the filters, we need to determine the strategy
// to use in order to obtain the flowIDs
const strategy: FlowSearchStrategy = this.determineStrategy(
flowFilters,
flowObjectFilters,
flowCategoryFilters,
nestedFlowFilters,
shortcutFilter,
status
);

const { flows, count } = await strategy.search({
models,
databaseConnection,
flowFilters,
flowObjectFilters,
flowCategoryFilters,
nestedFlowFilters,
// Shortcuts for categories
shortcutFilter,
statusFilter: status,
});

const flowsAmountUSD: Array<string | number> = flows.map(
(flow) => flow.amountUSD
);

const totalAmount = flowsAmountUSD.reduce((a, b) => +a + +b, 0);

return {
totalAmountUSD: totalAmount.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}),
flowsCount: count,
};
}

async searchBatches(
models: Database,
databaseConnection: Knex,
Expand Down
12 changes: 11 additions & 1 deletion src/domain-services/flows/flow-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ export class FlowService {
async getFlowsAsUniqueFlowEntity(
args: GetFlowsArgs
): Promise<UniqueFlowEntity[]> {
const { databaseConnection, orderBy, conditions, offset, limit } = args;
const {
databaseConnection,
orderBy,
conditions,
offset,
limit,
whereClauses,
} = args;

let query = databaseConnection!
.queryBuilder()
Expand All @@ -51,6 +58,9 @@ export class FlowService {
if (conditions) {
query = applySearchFilters(query, conditions);
}
if (whereClauses) {
query = query.andWhere(prepareCondition(whereClauses));
}

// Because this list can be really large (+330K entries), we need to split it in chunks
// Using limit and offset as cursors
Expand Down
22 changes: 2 additions & 20 deletions src/domain-services/flows/graphql/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@ import { Args, Ctx, Query, Resolver } from 'type-graphql';
import { Service } from 'typedi';
import Context from '../../Context';
import { FlowSearchService } from '../flow-search-service';
import { SearchFlowsArgs, SearchFlowsArgsNonPaginated } from './args';
import {
Flow,
FlowSearchResult,
FlowSearchResultNonPaginated,
FlowSearchTotalAmountResult,
} from './types';
import { SearchFlowsArgs } from './args';
import { Flow, FlowSearchResult, FlowSearchResultNonPaginated } from './types';

@Service()
@Resolver(Flow)
Expand All @@ -28,19 +23,6 @@ export default class FlowResolver {
);
}

@Query(() => FlowSearchTotalAmountResult)
async searchFlowsTotalAmountUSD(
@Ctx() context: Context,
@Args(() => SearchFlowsArgsNonPaginated, { validate: false })
args: SearchFlowsArgsNonPaginated
): Promise<FlowSearchTotalAmountResult> {
return await this.flowSearchService.searchTotalAmount(
context.models,
context.connection,
args
);
}

@Query(() => FlowSearchResultNonPaginated)
async searchFlowsBatches(
@Ctx() context: Context,
Expand Down
9 changes: 0 additions & 9 deletions src/domain-services/flows/graphql/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,6 @@ export class FlowSearchResultNonPaginated {
flowsCount: number;
}

@ObjectType()
export class FlowSearchTotalAmountResult {
@Field(() => String, { nullable: false })
totalAmountUSD: string;

@Field(() => Number, { nullable: false })
flowsCount: number;
}

export type FlowSortField =
| 'flow.id'
| 'flow.versionID'
Expand Down
3 changes: 2 additions & 1 deletion src/domain-services/flows/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export type FlowNestedDirection = 'source' | 'destination';
export type GetFlowsArgs = {
models?: Database;
databaseConnection?: Knex;
conditions: any;
conditions?: any;
whereClauses?: any;
offset?: number;
orderBy?: any;
limit?: number;
Expand Down
4 changes: 2 additions & 2 deletions src/domain-services/flows/strategy/flow-search-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export interface FlowSearchArgs {
nestedFlowFilters: NestedFlowFilters;
shortcutFilter: FlowShortcutFilter;
statusFilter: FlowStatusFilter | null;
limit?: number;
offset?: number;
limit: number;
offset: number;
orderBy?: any;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ import { Op } from '@unocha/hpc-api-core/src/db/util/conditions';
import { createBrandedValue } from '@unocha/hpc-api-core/src/util/types';
import { Service } from 'typedi';
import { CategoryService } from '../../../categories/category-service';
import { FlowService } from '../../flow-service';
import { type UniqueFlowEntity } from '../../model';
import {
type FlowIDSearchStrategy,
type FlowIdSearchStrategyArgs,
type FlowIdSearchStrategyResponse,
} from '../flowID-search-strategy';
import { mapFlowCategoryConditionsToWhereClause } from './utils';
import {
buildSearchFlowsConditions,
defaultFlowOrderBy,
mapFlowCategoryConditionsToWhereClause,
} from './utils';

@Service()
export class GetFlowIdsFromCategoryConditionsStrategyImpl
implements FlowIDSearchStrategy
{
constructor(private readonly categoryService: CategoryService) {}
constructor(
private readonly categoryService: CategoryService,
private readonly flowService: FlowService
) {}

private readonly categoryIDsMap: Map<string, number> = new Map<
string,
Expand Down Expand Up @@ -111,6 +119,17 @@ export class GetFlowIdsFromCategoryConditionsStrategyImpl
}) as UniqueFlowEntity
);

return { flows: mapFlows };
// Once we have the flowIDs from the category conditions
// Look after this uniqueFlows in the flow table
// to check if they are not 'deleted' (by the key: 'deletedAt')
const searchFlowArgs = {
databaseConnection,
orderBy: defaultFlowOrderBy(),
whereClauses: buildSearchFlowsConditions(mapFlows),
};
const uniqueEntitiesFlow =
await this.flowService.getFlowsAsUniqueFlowEntity(searchFlowArgs);

return { flows: uniqueEntitiesFlow };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import { Service } from 'typedi';
import { ExternalReferenceService } from '../../../external-reference/external-reference-service';
import { LegacyService } from '../../../legacy/legacy-service';
import { ReportDetailService } from '../../../report-details/report-detail-service';
import { FlowService } from '../../flow-service';
import { type UniqueFlowEntity } from '../../model';
import {
type FlowIDSearchStrategy,
type FlowIdSearchStrategyArgs,
type FlowIdSearchStrategyResponse,
} from '../flowID-search-strategy';
import { intersectUniqueFlowEntities } from './utils';
import {
buildSearchFlowsConditions,
defaultFlowOrderBy,
intersectUniqueFlowEntities,
} from './utils';

@Service()
export class GetFlowIdsFromNestedFlowFiltersStrategyImpl
Expand All @@ -17,13 +22,14 @@ export class GetFlowIdsFromNestedFlowFiltersStrategyImpl
constructor(
private readonly reportDetailService: ReportDetailService,
private readonly legacyService: LegacyService,
private readonly externalRefenceService: ExternalReferenceService
private readonly externalRefenceService: ExternalReferenceService,
private readonly flowService: FlowService
) {}

async search(
args: FlowIdSearchStrategyArgs
): Promise<FlowIdSearchStrategyResponse> {
const { models, nestedFlowFilters } = args;
const { databaseConnection, models, nestedFlowFilters } = args;

let flowsReporterReferenceCode: UniqueFlowEntity[] = [];
let flowsSourceSystemId: UniqueFlowEntity[] = [];
Expand Down Expand Up @@ -81,6 +87,16 @@ export class GetFlowIdsFromNestedFlowFiltersStrategyImpl
flowsLegacyId
);

return { flows: flowIDsFromNestedFlowFilters };
// Once gathered and disjoined the flowIDs from the nestedFlowFilters
// Look after this uniqueFlows in the flow table
// To verify the flow is not deleted
const getFlowArgs = {
databaseConnection,
orderBy: defaultFlowOrderBy(),
whereClauses: buildSearchFlowsConditions(flowIDsFromNestedFlowFilters),
};
const uniqueFlowsNotDeleted =
await this.flowService.getFlowsAsUniqueFlowEntity(getFlowArgs);
return { flows: uniqueFlowsNotDeleted };
}
}
Loading

0 comments on commit 95d03f1

Please sign in to comment.