diff --git a/src/domain-services/flows/flow-search-service.ts b/src/domain-services/flows/flow-search-service.ts index dd837274..b3d1bbfa 100644 --- a/src/domain-services/flows/flow-search-service.ts +++ b/src/domain-services/flows/flow-search-service.ts @@ -41,7 +41,6 @@ import { type FlowOrderBy, } from './model'; import { type FlowSearchStrategy } from './strategy/flow-search-strategy'; -import { FlowObjectFiltersStrategy } from './strategy/impl/flow-object-conditions-strategy-impl'; import { OnlyFlowFiltersStrategy } from './strategy/impl/only-flow-conditions-strategy-impl'; import { SearchFlowByFiltersStrategy } from './strategy/impl/search-flow-by-filters-strategy-impl'; @@ -49,7 +48,6 @@ import { SearchFlowByFiltersStrategy } from './strategy/impl/search-flow-by-filt export class FlowSearchService { constructor( private readonly onlyFlowFiltersStrategy: OnlyFlowFiltersStrategy, - private readonly flowObjectFiltersStrategy: FlowObjectFiltersStrategy, private readonly searchFlowByFiltersStrategy: SearchFlowByFiltersStrategy, private readonly organizationService: OrganizationService, private readonly locationService: LocationService, @@ -63,305 +61,6 @@ export class FlowSearchService { ) {} async search( - models: Database, - filters: SearchFlowsArgs - ): Promise { - const { - limit, - nextPageCursor, - prevPageCursor, - sortField, - sortOrder, - pending: isPendingFlows, - } = filters; - - const orderBy: FlowOrderBy = this.buildOrderBy(sortField, sortOrder); - - const { flowFilters, flowObjectFilters, flowCategoryFilters } = filters; - - const cursorCondition = this.buildCursorCondition( - prevPageCursor, - nextPageCursor, - orderBy - ); - - // Determine strategy of how to search for flows - const { strategy, conditions } = this.determineStrategy( - flowFilters, - flowObjectFilters, - flowCategoryFilters, - isPendingFlows - ); - - // Fetch one more item to check for hasNextPage - const limitComputed = limit + 1; - - // Obtain flows and its count based on the strategy selected - const { flows, count } = await strategy.search( - conditions, - models, - orderBy, - limitComputed, - cursorCondition, - isPendingFlows - ); - - // Remove the extra item used to check hasNextPage - const hasNextPage = flows.length > limit; - if (hasNextPage) { - flows.pop(); - } - - const flowIds: FlowId[] = []; - const flowWithVersion: Map = new Map(); - - // Obtain flow IDs and flow version IDs - for (const flow of flows) { - flowIds.push(flow.id); - if (!flowWithVersion.has(flow.id)) { - flowWithVersion.set(flow.id, []); - } - const flowVersionIDs = flowWithVersion.get(flow.id)!; - flowVersionIDs.push(flow.versionID); - } - - // Obtain external references and flow objects in parallel - const [externalReferencesMap, flowObjects] = await Promise.all([ - this.externalReferenceService.getExternalReferencesForFlows( - flowIds, - models - ), - this.flowObjectService.getFlowObjectByFlowId(models, flowIds), - ]); - - // Map flow objects to their respective arrays - const organizationsFO: FlowObject[] = []; - const locationsFO: FlowObject[] = []; - const plansFO: FlowObject[] = []; - const usageYearsFO: FlowObject[] = []; - - this.groupByFlowObjectType( - flowObjects, - organizationsFO, - locationsFO, - plansFO, - usageYearsFO - ); - - // Obtain flow links - const flowLinksMap = await this.flowLinkService.getFlowLinksForFlows( - flowIds, - models - ); - - // Perform all nested queries in parallel - const [ - categoriesMap, - organizationsMap, - locationsMap, - plansMap, - usageYearsMap, - reportDetailsMap, - ] = await Promise.all([ - this.categoryService.getCategoriesForFlows(flowWithVersion, models), - this.organizationService.getOrganizationsForFlows( - organizationsFO, - models - ), - this.locationService.getLocationsForFlows(locationsFO, models), - this.planService.getPlansForFlows(plansFO, models), - this.usageYearService.getUsageYearsForFlows(usageYearsFO, models), - this.reportDetailService.getReportDetailsForFlows(flowIds, models), - ]); - - const items = await Promise.all( - flows.map(async (flow) => { - const flowLink = flowLinksMap.get(flow.id) ?? []; - - // Categories Map follows the structure: - // flowID: { versionID: [categories]} - // So we need to get the categories for the flow version - const categories = - categoriesMap.get(flow.id)!.get(flow.versionID) ?? []; - const organizations = organizationsMap.get(flow.id) ?? []; - const locations = locationsMap.get(flow.id) ?? []; - const plans = plansMap.get(flow.id) ?? []; - const usageYears = usageYearsMap.get(flow.id) ?? []; - const externalReferences = externalReferencesMap.get(flow.id) ?? []; - const reportDetails = reportDetailsMap.get(flow.id) ?? []; - - const reportDetailsWithChannel = - this.reportDetailService.addChannelToReportDetails( - reportDetails, - categories - ); - - let parkedParentSource: FlowParkedParentSource | null = null; - if (flow.activeStatus && flowLink.length > 0) { - parkedParentSource = await this.getParketParents( - flow, - flowLink, - models - ); - } - - const childIDs: number[] = - (flowLinksMap - .get(flow.id) - ?.filter( - (flowLink) => flowLink.parentID === flow.id && flowLink.depth > 0 - ) - .map((flowLink) => flowLink.childID.valueOf()) as number[]) ?? []; - - const parentIDs: number[] = - (flowLinksMap - .get(flow.id) - ?.filter( - (flowLink) => flowLink.childID === flow.id && flowLink.depth > 0 - ) - .map((flowLink) => flowLink.parentID.valueOf()) as number[]) ?? []; - - return this.buildFlowDTO( - flow, - categories, - organizations, - locations, - plans, - usageYears, - childIDs, - parentIDs, - externalReferences, - reportDetailsWithChannel, - parkedParentSource - ); - }) - ); - - // Sort items - // FIXME: this sorts the page, not the whole result set - items.sort((a: Flow, b: Flow) => { - const entityKey = orderBy.entity as keyof Flow; - - const nestedA = a[entityKey]; - const nestedB = b[entityKey]; - - if (nestedA && nestedB) { - if (orderBy.direction) { - // This means the orderBy came in the format: - // column: 'nestedEntity.direction.property' - // So we need to get the entry of the nested entity - // which its direction matches the orderBy direction - // and sort by the property using the orderBy order - - // Fisrt, check if the nestedEntity is trusy an Array - if (!Array.isArray(nestedA)) { - return 0; - } - if (!Array.isArray(nestedB)) { - return 0; - } - - // Now we ensure both properties are arrays - // we can assume that the nestedEntity is one of the following: - // organizations, locations, plans, usageYears - const directionEntityA = nestedA as unknown as - | Organization[] - | BaseLocation[] - | BasePlan[] - | UsageYear[]; - const directionEntityB = nestedB as unknown as - | Organization[] - | BaseLocation[] - | BasePlan[] - | UsageYear[]; - - // Then we find the entry of the nestedEntity that matches the orderBy direction - const nestedEntityA = directionEntityA.find( - (nestedEntity: any) => orderBy.direction === nestedEntity.direction - ); - const nestedEntityB = directionEntityB.find( - (nestedEntity: any) => orderBy.direction === nestedEntity.direction - ); - - // After, we need to check there is an entry that matches the orderBy direction - // if not, we return 0 - if (!nestedEntityA) { - return 0; - } - if (!nestedEntityB) { - return 0; - } - - // Now we can sort by the property using the orderBy order - const propertyA = - nestedEntityA[orderBy.column as keyof typeof nestedEntityA]; - const propertyB = - nestedEntityB[orderBy.column as keyof typeof nestedEntityB]; - - // Finally, we check that the property is defined - // and if so - we sort by the property using the orderBy order - if (propertyA && propertyB) { - if (orderBy.order === 'asc') { - return propertyA > propertyB ? 1 : -1; - } - return propertyA < propertyB ? 1 : -1; - } - } - // Since there is no direction expecified in the orderBy - // we can assume that the nestedEntity is one of the following: - // childIDs, parentIDs, externalReferences, reportDetails, parkedParentSource, categories - // and we can sort by the property using the orderBy order - const propertyA = nestedA[orderBy.column as keyof typeof nestedA]; - const propertyB = nestedB[orderBy.column as keyof typeof nestedB]; - - // Finally, we check that the property is defined - // and if so - we sort by the property using the orderBy order - if (propertyA && propertyB) { - if (orderBy.order === 'asc') { - return propertyA > propertyB ? 1 : -1; - } - return propertyA < propertyB ? 1 : -1; - } - } - - return 0; - }); - - const isOrderByForFlows = orderBy.entity === 'flow'; - const firstItem = items[0]; - const prevPageCursorEntity = isOrderByForFlows - ? firstItem - : firstItem[orderBy.entity as keyof typeof firstItem]; - const prevPageCursorValue = prevPageCursorEntity - ? prevPageCursorEntity[ - orderBy.column as keyof typeof prevPageCursorEntity - ] ?? '' - : ''; - - const lastItem = items.at(-1); - const nextPageCursorEntity = isOrderByForFlows - ? lastItem - : lastItem![orderBy.entity as keyof typeof lastItem]; - const nextPageCursorValue = nextPageCursorEntity - ? nextPageCursorEntity[ - orderBy.column as keyof typeof nextPageCursorEntity - ]?.toString() ?? '' - : ''; - - return { - flows: items, - hasNextPage: limit <= flows.length, - hasPreviousPage: nextPageCursor !== undefined, - prevPageCursor: prevPageCursorValue, - nextPageCursor: nextPageCursorValue, - pageSize: flows.length, - sortField: `${orderBy.entity}.${orderBy.column}` as FlowSortField, - sortOrder: sortOrder ?? 'desc', - total: count, - }; - } - - async searchV2( models: Database, databaseConnection: Knex, filters: SearchFlowsArgs @@ -372,7 +71,7 @@ export class FlowSearchService { prevPageCursor, sortField, sortOrder, - includeChildrenOfParkedFlows: shouldIncludeChildrenOfParkedFlows, + shouldIncludeChildrenOfParkedFlows, } = filters; const orderBy: FlowOrderBy = this.buildOrderBy(sortField, sortOrder); @@ -386,7 +85,7 @@ export class FlowSearchService { // 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.determineStrategyV2( + const strategy: FlowSearchStrategy = this.determineStrategy( flowFilters, flowObjectFilters, flowCategoryFilters, @@ -401,7 +100,7 @@ export class FlowSearchService { orderBy ); - const { flows, count } = await strategy.searchV2( + const { flows, count } = await strategy.search({ models, databaseConnection, limit, @@ -410,8 +109,8 @@ export class FlowSearchService { flowFilters, flowObjectFilters, flowCategoryFilters, - isPendingFlows - ); + searchPendingFlows: isPendingFlows, + }); // Remove the extra item used to check hasNextPage const hasNextPage = flows.length > limit; @@ -581,12 +280,12 @@ export class FlowSearchService { }; } - determineStrategyV2( + determineStrategy( flowFilters: SearchFlowsFilters, flowObjectFilters: FlowObjectFilters[], flowCategoryFilters: FlowCategory[], isPendingFlows: boolean, - orderBy: FlowOrderBy + orderBy?: FlowOrderBy ) { // If there are no filters (flowFilters, flowObjectFilters, flowCategoryFilters or pending) // and there is no sortByEntity (orderBy.entity === 'flow') @@ -594,7 +293,7 @@ export class FlowSearchService { // If there are no sortByEntity (orderBy.entity === 'flow') // but flowFilters only // use onlyFlowFiltersStrategy - const isOrderByEntityFlow = orderBy.entity === 'flow'; + const isOrderByEntityFlow = orderBy?.entity === 'flow'; const isFlowFiltersDefined = flowFilters !== undefined; const isFlowObjectFiltersDefined = flowObjectFilters !== undefined; const isFlowCategoryFiltersDefined = flowCategoryFilters !== undefined; @@ -725,68 +424,6 @@ export class FlowSearchService { return flowObjectsConditions; } - determineStrategy( - flowFilters: SearchFlowsFilters, - flowObjectFilters: FlowObjectFilters[], - flowCategoryFilters: FlowCategory[], - isFilterByPendingFlows: boolean - ): { strategy: FlowSearchStrategy; conditions: any } { - const isFlowFilterDefined = flowFilters !== undefined; - const isFlowObjectFilterDefined = flowObjectFilters !== undefined; - const isFlowObjectFiltersNotEmpty = - isFlowObjectFilterDefined && flowObjectFilters.length !== 0; - - const isFlowCategoryFilterDefined = flowCategoryFilters !== undefined; - const isFlowCategoryFilterNotEmpty = - isFlowCategoryFilterDefined && flowCategoryFilters.length !== 0; - - const isFilterByPendingFlowsDefined = isFilterByPendingFlows !== undefined; - if ( - (!isFlowFilterDefined && - (!isFlowObjectFilterDefined || !isFlowObjectFiltersNotEmpty) && - !isFlowCategoryFilterNotEmpty && - !isFilterByPendingFlowsDefined) || - (isFlowFilterDefined && - (!isFlowObjectFilterDefined || !isFlowObjectFiltersNotEmpty) && - !isFlowCategoryFilterNotEmpty && - !isFilterByPendingFlowsDefined) - ) { - const flowConditions = this.prepareFlowConditions(flowFilters); - return { - strategy: this.onlyFlowFiltersStrategy, - conditions: flowConditions, - }; - } else if ( - isFlowObjectFiltersNotEmpty || - isFlowCategoryFilterNotEmpty || - isFilterByPendingFlowsDefined - ) { - const flowConditions = this.prepareFlowConditions(flowFilters); - const flowObjectConditions = - this.prepareFlowObjectConditions(flowObjectFilters); - - return { - strategy: this.flowObjectFiltersStrategy, - conditions: { - conditionsMap: this.buildConditionsMap( - flowConditions, - flowObjectConditions - ), - flowCategoryFilters, - }, - }; - } - - throw new Error('Invalid combination of flowFilters and flowObjectFilters'); - } - - private buildConditionsMap(flowConditions: any, flowObjectConditions: any) { - const conditionsMap = new Map(); - conditionsMap.set('flowObjects', flowObjectConditions); - conditionsMap.set('flow', flowConditions); - return conditionsMap; - } - private groupByFlowObjectType( flowObjects: FlowObject[], organizationsFO: FlowObject[], @@ -1038,6 +675,7 @@ export class FlowSearchService { async searchTotalAmount( models: Database, + databaseConnection: Knex, args: SearchFlowsArgsNonPaginated ): Promise { let { flowFilters } = args; @@ -1054,21 +692,23 @@ export class FlowSearchService { flowFilters.activeStatus = true; } - const { strategy, conditions } = this.determineStrategy( + // 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, isPendingFlows ); - const { flows, count } = await strategy.search( - conditions, + const { flows, count } = await strategy.search({ models, - undefined, - undefined, - undefined, - isPendingFlows - ); + databaseConnection, + flowFilters, + flowObjectFilters, + flowCategoryFilters, + searchPendingFlows: isPendingFlows, + }); const flowsAmountUSD: Array = flows.map( (flow) => flow.amountUSD @@ -1087,9 +727,14 @@ export class FlowSearchService { async searchBatches( models: Database, + databaseConnection: Knex, args: SearchFlowsArgs ): Promise { - const flowSearchResponse = await this.search(models, args); + const flowSearchResponse = await this.search( + models, + databaseConnection, + args + ); const flows: Flow[] = flowSearchResponse.flows; @@ -1100,7 +745,11 @@ export class FlowSearchService { let nextFlowSearchResponse: FlowSearchResult; while (hasNextPage) { - nextFlowSearchResponse = await this.search(models, nextArgs); + nextFlowSearchResponse = await this.search( + models, + databaseConnection, + nextArgs + ); flows.push(...nextFlowSearchResponse.flows); diff --git a/src/domain-services/flows/flow-service.ts b/src/domain-services/flows/flow-service.ts index 4980b82b..e08c44c7 100644 --- a/src/domain-services/flows/flow-service.ts +++ b/src/domain-services/flows/flow-service.ts @@ -33,7 +33,7 @@ export class FlowService { models: Database, dbConnection: Knex, orderBy: FlowOrderBy, - limit: number + limit?: number ): Promise { const entity = orderBy.subEntity ?? orderBy.entity; @@ -58,8 +58,11 @@ export class FlowService { .andWhere('objectType', entityCondKey) .andWhere('refDirection', orderBy.direction!) .orderByRaw(`array_position(ARRAY[${entityIDs.join(',')}], "objectID")`) - .orderBy('flowID', orderBy.order) - .limit(limit); + .orderBy('flowID', orderBy.order); + + if (limit) { + query.limit(limit); + } const flowIDs = await query; return flowIDs.map((flowID) => flowID.flowID); diff --git a/src/domain-services/flows/graphql/resolver.ts b/src/domain-services/flows/graphql/resolver.ts index a44538e7..78c4d9d5 100644 --- a/src/domain-services/flows/graphql/resolver.ts +++ b/src/domain-services/flows/graphql/resolver.ts @@ -21,7 +21,7 @@ export default class FlowResolver { @Args(() => SearchFlowsArgs, { validate: false }) args: SearchFlowsArgs ): Promise { - return await this.flowSearchService.searchV2( + return await this.flowSearchService.search( context.models, context.connection, args @@ -34,7 +34,11 @@ export default class FlowResolver { @Args(() => SearchFlowsArgsNonPaginated, { validate: false }) args: SearchFlowsArgsNonPaginated ): Promise { - return await this.flowSearchService.searchTotalAmount(context.models, args); + return await this.flowSearchService.searchTotalAmount( + context.models, + context.connection, + args + ); } @Query(() => FlowSearchResultNonPaginated) @@ -45,6 +49,10 @@ export default class FlowResolver { ): Promise { // Set default batch size to 1000 args.limit = args.limit > 0 ? args.limit : 1000; - return await this.flowSearchService.searchBatches(context.models, args); + return await this.flowSearchService.searchBatches( + context.models, + context.connection, + args + ); } } diff --git a/src/domain-services/flows/strategy/flow-search-strategy.ts b/src/domain-services/flows/strategy/flow-search-strategy.ts index 9dfa94d3..4264cf70 100644 --- a/src/domain-services/flows/strategy/flow-search-strategy.ts +++ b/src/domain-services/flows/strategy/flow-search-strategy.ts @@ -12,27 +12,18 @@ export interface FlowSearchStrategyResponse { count: number; } -export interface FlowSearchStrategy { - search( - flowConditions: - | Map - | { conditionsMap: Map; flowCategoryFilters: any }, - models: Database, - orderBy?: any, - limit?: number, - cursorCondition?: any, - filterByPendingFlows?: boolean - ): Promise; +export interface FlowSearchArgs { + models: Database; + databaseConnection: Knex; + flowFilters: SearchFlowsFilters; + flowObjectFilters: FlowObjectFilters[]; + flowCategoryFilters: FlowCategory[]; + limit?: number; + orderBy?: any; + cursorCondition?: any; + searchPendingFlows?: boolean; +} - searchV2( - models: Database, - databaseConnection: Knex, - limit: number, - orderBy: any, - cursorCondition: any | undefined, - flowFilters: SearchFlowsFilters, - flowObjectFilters: FlowObjectFilters[], - flowCategoryFilters: FlowCategory[], - searchPendingFlows: boolean | undefined - ): Promise; +export interface FlowSearchStrategy { + search(args: FlowSearchArgs): Promise; } diff --git a/src/domain-services/flows/strategy/impl/flow-object-conditions-strategy-impl.ts b/src/domain-services/flows/strategy/impl/flow-object-conditions-strategy-impl.ts deleted file mode 100644 index 234a8ee9..00000000 --- a/src/domain-services/flows/strategy/impl/flow-object-conditions-strategy-impl.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { type Database } from '@unocha/hpc-api-core/src/db'; -import { Cond } from '@unocha/hpc-api-core/src/db/util/conditions'; -import { Service } from 'typedi'; -import { FlowService } from '../../flow-service'; -import { type FlowCategory } from '../../graphql/args'; -import { - type FlowSearchStrategy, - type FlowSearchStrategyResponse, -} from '../flow-search-strategy'; -import { - type FlowIDSearchStrategy, - type FlowIdSearchStrategyResponse, -} from '../flowID-search-strategy'; -import { GetFlowIdsFromCategoryConditionsStrategyImpl } from './get-flowIds-flow-category-conditions-strategy-impl'; -import { GetFlowIdsFromMixedConditionsStrategyImpl } from './get-flowIds-flow-mixed-conditions-strategy-impl'; -import { mapFlowOrderBy } from './utils'; - -@Service() -export class FlowObjectFiltersStrategy implements FlowSearchStrategy { - constructor( - private readonly flowService: FlowService, - private readonly getFlowIdsFromObjectConditions: GetFlowIdsFromMixedConditionsStrategyImpl, - private readonly getFlowIdsFromCategoryConditions: GetFlowIdsFromCategoryConditionsStrategyImpl, - private readonly getFlowIdsFromMixedConditions: GetFlowIdsFromMixedConditionsStrategyImpl - ) {} - - async search( - flowConditions: { - conditionsMap: Map; - flowCategoryFilters: FlowCategory[]; - }, - models: Database, - orderBy?: any, - limit?: number, - cursorCondition?: any, - filterByPendingFlows?: boolean - ): Promise { - const flowConditionsMap = flowConditions.conditionsMap; - // Obtain flowObjects conditions - const flowObjectsConditions: Map< - string, - Map - > = flowConditionsMap.get('flowObjects') ?? new Map(); - - // Obtain flow conditions - const flowEntityConditions = flowConditionsMap.get('flow') ?? new Map(); - - // Obtain flowCategory conditions - const flowCategoryConditions = flowConditions.flowCategoryFilters ?? []; - - const searchFlowIdsStrategy: FlowIDSearchStrategy = this.determineStrategy( - flowObjectsConditions, - flowCategoryConditions, - filterByPendingFlows - ); - - const { flowIDs: flowIdsToFilter }: FlowIdSearchStrategyResponse = - await searchFlowIdsStrategy.search( - models, - flowObjectsConditions, - flowCategoryConditions, - filterByPendingFlows - ); - - const whereClauseFromStrategy = searchFlowIdsStrategy.generateWhereClause( - flowIdsToFilter, - flowCategoryConditions, - filterByPendingFlows - ); - - // Combine conditions from flowObjects FlowIDs and flow conditions - const countConditions = { - [Cond.AND]: [flowEntityConditions ?? {}, whereClauseFromStrategy ?? {}], - }; - - // Combine cursor condition with flow conditions - const searchConditions = { - [Cond.AND]: [ - flowEntityConditions ?? {}, - cursorCondition ?? {}, - whereClauseFromStrategy ?? {}, - ], - }; - - // check and map orderBy to be from entity 'flow' - const orderByFlow = mapFlowOrderBy(orderBy); - - // Obtain flows and flowCount based on flowIDs from filtered flowObjects - // and flow conditions - const [flows, countRes] = await Promise.all([ - this.flowService.getFlows(models, searchConditions, orderByFlow, limit), - this.flowService.getFlowsCount(models, countConditions), - ]); - - // Map count result query to count object - const countObject = countRes[0] as { count: number }; - - return { flows, count: countObject.count }; - } - - // Determine the strategy to use in order to obtain flowIDs - // aiming to have the least amount of flowIDs to filter - // in the next step - // If there are flowObjects conditions - // use flowObjects strategy - // otherwise use flowCategories strategy - // If there are both flowObjects and flowCategories conditions - // use both and merge the results keeping only flowIDs - // present in both arrays - // otherwise keep all flowIDs from the one that is not empty - determineStrategy( - flowObjectsConditions: Map>, - flowCategoryConditions: any, - filterByPendingFlows?: boolean - ): any { - const isFlowObjectsConditionsIsDefined = - flowObjectsConditions !== undefined; - const isFlowCategoryConditionsIsDefined = - flowCategoryConditions !== undefined; - const isFilterByPendingFlowsIsDefined = filterByPendingFlows !== undefined; - - const flowObjectsConditionsIsNotEmpty = - isFlowObjectsConditionsIsDefined && flowObjectsConditions.size; - const isFlowCategoryConditionsIsNotEmpty = - isFlowCategoryConditionsIsDefined && flowCategoryConditions.length !== 0; - - if ( - flowObjectsConditionsIsNotEmpty && - (isFlowCategoryConditionsIsNotEmpty || isFilterByPendingFlowsIsDefined) - ) { - return this.getFlowIdsFromMixedConditions; - } else if (flowObjectsConditionsIsNotEmpty) { - return this.getFlowIdsFromObjectConditions; - } else if ( - isFlowCategoryConditionsIsNotEmpty || - isFilterByPendingFlowsIsDefined - ) { - return this.getFlowIdsFromCategoryConditions; - } - throw new Error( - 'No strategy found for flowObjectsConditions and flowCategoryConditions' - ); - } - - searchV2( - _models: Database, - _databaseConnection: any, - _limit: number, - _orderBy: any, - _cursorCondition: any, - _flowFilters: any, - _flowObjectFilters: any, - _flowCategoryFilters: any, - _filterByPendingFlows?: boolean - ): Promise { - throw new Error('Method not implemented.'); - } -} diff --git a/src/domain-services/flows/strategy/impl/only-flow-conditions-strategy-impl.ts b/src/domain-services/flows/strategy/impl/only-flow-conditions-strategy-impl.ts index 6ca0d548..d77cbf8d 100644 --- a/src/domain-services/flows/strategy/impl/only-flow-conditions-strategy-impl.ts +++ b/src/domain-services/flows/strategy/impl/only-flow-conditions-strategy-impl.ts @@ -1,15 +1,8 @@ -import { type Database } from '@unocha/hpc-api-core/src/db'; import { Cond } from '@unocha/hpc-api-core/src/db/util/conditions'; -import type Knex from 'knex'; import { Service } from 'typedi'; import { FlowService } from '../../flow-service'; import { - type FlowCategory, - type FlowObjectFilters, - type SearchFlowsFilters, -} from '../../graphql/args'; -import { type FlowOrderBy } from '../../model'; -import { + type FlowSearchArgs, type FlowSearchStrategy, type FlowSearchStrategyResponse, } from '../flow-search-strategy'; @@ -23,43 +16,8 @@ import { export class OnlyFlowFiltersStrategy implements FlowSearchStrategy { constructor(private readonly flowService: FlowService) {} - async search( - flowConditions: any, - models: Database, - orderBy?: any, - limit?: number, - cursorCondition?: any - ): Promise { - // Build conditions object - const searchConditions = { - [Cond.AND]: [flowConditions ?? {}, cursorCondition ?? {}], - }; - - // check and map orderBy to be from entity 'flow' - const orderByFlow = mapFlowOrderBy(orderBy); - - const [flows, countRes] = await Promise.all([ - this.flowService.getFlows(models, searchConditions, orderByFlow, limit), - this.flowService.getFlowsCount(models, flowConditions), - ]); - - // Map count result query to count object - const countObject = countRes[0] as { count: number }; - - return { flows, count: countObject.count }; - } - - async searchV2( - models: Database, - _databaseConnection: Knex, - limit: number, - orderBy: FlowOrderBy, - cursorCondition: any | undefined, - flowFilters: SearchFlowsFilters, - _flowObjectFilters: FlowObjectFilters[], - _flowCategoryFilters: FlowCategory[], - _searchPendingFlows: boolean | undefined - ): Promise { + async search(args: FlowSearchArgs): Promise { + const { models, flowFilters, orderBy, limit, cursorCondition } = args; // Map flowConditions to where clause const flowConditions = prepareFlowConditions(flowFilters); diff --git a/src/domain-services/flows/strategy/impl/search-flow-by-filters-strategy-impl.ts b/src/domain-services/flows/strategy/impl/search-flow-by-filters-strategy-impl.ts index bf493a7d..34d69c1c 100644 --- a/src/domain-services/flows/strategy/impl/search-flow-by-filters-strategy-impl.ts +++ b/src/domain-services/flows/strategy/impl/search-flow-by-filters-strategy-impl.ts @@ -1,16 +1,9 @@ -import { type Database } from '@unocha/hpc-api-core/src/db'; import { type FlowId } from '@unocha/hpc-api-core/src/db/models/flow'; import { Cond, Op } from '@unocha/hpc-api-core/src/db/util/conditions'; -import type Knex from 'knex'; import { Service } from 'typedi'; import { FlowService } from '../../flow-service'; import { - type FlowCategory, - type FlowObjectFilters, - type SearchFlowsFilters, -} from '../../graphql/args'; -import { type FlowOrderBy } from '../../model'; -import { + type FlowSearchArgs, type FlowSearchStrategy, type FlowSearchStrategyResponse, } from '../flow-search-strategy'; @@ -32,28 +25,18 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { private readonly getFlowIdsFromObjectConditions: GetFlowIdsFromObjectConditionsStrategyImpl ) {} - search( - _flowConditions: any, - _models: Database, - _orderBy?: any, - _limit?: number, - _cursorCondition?: any, - _filterByPendingFlows?: boolean - ): Promise { - throw new Error('Method not implemented.'); - } + async search(args: FlowSearchArgs): Promise { + const { + models, + databaseConnection, + flowFilters, + flowObjectFilters, + flowCategoryFilters, + orderBy, + limit, + searchPendingFlows: isSearchPendingFlows, + } = args; - async searchV2( - models: Database, - databaseConnection: Knex, - limit: number, - orderBy: FlowOrderBy, - cursorCondition: any | undefined, - flowFilters: SearchFlowsFilters, - flowObjectFilters: FlowObjectFilters[], - flowCategoryFilters: FlowCategory[], - searchPendingFlows: boolean | undefined - ): Promise { // First, we need to check if we need to sort by a certain entity // and if so, we need to map the orderBy to be from that entity // obtain the entities relation to the flow @@ -76,7 +59,7 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { // Now we need to check if we need to filter by category // if it's using the shorcut 'pending' // or if there are any flowCategoryFilters - const isSearchByPendingDefined = searchPendingFlows !== undefined; + const isSearchByPendingDefined = isSearchPendingFlows !== undefined; const isFilterByCategory = isSearchByPendingDefined || flowCategoryFilters?.length > 0; @@ -89,7 +72,7 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { models, new Map(), flowCategoryFilters ?? [], - searchPendingFlows + isSearchPendingFlows ); flowIDsFromCategoryFilters.push(...flowIDsFromCategoryStrategy.flowIDs); } @@ -117,7 +100,7 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { { isFilterByFlowObjects, isFilterByCategory, - willSearchPendingFlows: searchPendingFlows, + willSearchPendingFlows: isSearchPendingFlows, isSearchByPendingDefined, }, {