diff --git a/src/domain-services/flows/flow-search-service.ts b/src/domain-services/flows/flow-search-service.ts index 64a1a29a..2cc466de 100644 --- a/src/domain-services/flows/flow-search-service.ts +++ b/src/domain-services/flows/flow-search-service.ts @@ -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'; @@ -599,135 +593,6 @@ export class FlowSearchService { ); } - async searchTotalAmount( - models: Database, - databaseConnection: Knex, - args: SearchFlowsArgsNonPaginated - ): Promise { - 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 = 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, diff --git a/src/domain-services/flows/flow-service.ts b/src/domain-services/flows/flow-service.ts index de18762b..fc0e7807 100644 --- a/src/domain-services/flows/flow-service.ts +++ b/src/domain-services/flows/flow-service.ts @@ -39,7 +39,14 @@ export class FlowService { async getFlowsAsUniqueFlowEntity( args: GetFlowsArgs ): Promise { - const { databaseConnection, orderBy, conditions, offset, limit } = args; + const { + databaseConnection, + orderBy, + conditions, + offset, + limit, + whereClauses, + } = args; let query = databaseConnection! .queryBuilder() @@ -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 diff --git a/src/domain-services/flows/graphql/resolver.ts b/src/domain-services/flows/graphql/resolver.ts index 78c4d9d5..c1fcdcf2 100644 --- a/src/domain-services/flows/graphql/resolver.ts +++ b/src/domain-services/flows/graphql/resolver.ts @@ -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) @@ -28,19 +23,6 @@ export default class FlowResolver { ); } - @Query(() => FlowSearchTotalAmountResult) - async searchFlowsTotalAmountUSD( - @Ctx() context: Context, - @Args(() => SearchFlowsArgsNonPaginated, { validate: false }) - args: SearchFlowsArgsNonPaginated - ): Promise { - return await this.flowSearchService.searchTotalAmount( - context.models, - context.connection, - args - ); - } - @Query(() => FlowSearchResultNonPaginated) async searchFlowsBatches( @Ctx() context: Context, diff --git a/src/domain-services/flows/graphql/types.ts b/src/domain-services/flows/graphql/types.ts index 768d11c9..ab921638 100644 --- a/src/domain-services/flows/graphql/types.ts +++ b/src/domain-services/flows/graphql/types.ts @@ -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' diff --git a/src/domain-services/flows/model.ts b/src/domain-services/flows/model.ts index b3b3e1e7..c838c077 100644 --- a/src/domain-services/flows/model.ts +++ b/src/domain-services/flows/model.ts @@ -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; diff --git a/src/domain-services/flows/strategy/flow-search-strategy.ts b/src/domain-services/flows/strategy/flow-search-strategy.ts index 3cbb8e61..98402728 100644 --- a/src/domain-services/flows/strategy/flow-search-strategy.ts +++ b/src/domain-services/flows/strategy/flow-search-strategy.ts @@ -26,8 +26,8 @@ export interface FlowSearchArgs { nestedFlowFilters: NestedFlowFilters; shortcutFilter: FlowShortcutFilter; statusFilter: FlowStatusFilter | null; - limit?: number; - offset?: number; + limit: number; + offset: number; orderBy?: any; } diff --git a/src/domain-services/flows/strategy/impl/get-flowIds-flow-category-conditions-strategy-impl.ts b/src/domain-services/flows/strategy/impl/get-flowIds-flow-category-conditions-strategy-impl.ts index 95974de1..0f08538c 100644 --- a/src/domain-services/flows/strategy/impl/get-flowIds-flow-category-conditions-strategy-impl.ts +++ b/src/domain-services/flows/strategy/impl/get-flowIds-flow-category-conditions-strategy-impl.ts @@ -78,35 +78,56 @@ export class GetFlowIdsFromCategoryConditionsStrategyImpl } } - let query = databaseConnection! + let joinQuery = databaseConnection! .queryBuilder() - .distinct('objectID', 'versionID') - .from('categoryRef'); + .distinct('flow.id', 'flow.versionID') + .from('flow') + .join('categoryRef', function () { + this.on('flow.id', '=', 'categoryRef.objectID').andOn( + 'flow.versionID', + '=', + 'categoryRef.versionID' + ); + }); if (categoriesIds.length > 0) { - query = query - .orWhere('categoryID', 'IN', categoriesIds) - .andWhere('objectType', 'flow'); + joinQuery = joinQuery.orWhere(function () { + this.where('categoryRef.categoryID', 'IN', categoriesIds) + .andWhere('categoryRef.objectType', 'flow') + .andWhere('flow.deletedAt', null); + }); } if (categoriesIdsFromShortcutFilterIN.length > 0) { - query = query - .orWhere('categoryID', 'IN', categoriesIdsFromShortcutFilterIN) - .andWhere('objectType', 'flow'); + joinQuery = joinQuery.orWhere(function () { + this.where( + 'categoryRef.categoryID', + 'IN', + categoriesIdsFromShortcutFilterIN + ) + .andWhere('categoryRef.objectType', 'flow') + .andWhere('flow.deletedAt', null); + }); } if (categoriesIdsFromShortcutFilterNOTIN.length > 0) { - query = query - .orWhere('categoryID', 'NOT IN', categoriesIdsFromShortcutFilterNOTIN) - .andWhere('objectType', 'flow'); + joinQuery = joinQuery.orWhere(function () { + this.where( + 'categoryRef.categoryID', + 'NOT IN', + categoriesIdsFromShortcutFilterNOTIN + ) + .andWhere('categoryRef.objectType', 'flow') + .andWhere('flow.deletedAt', null); + }); } - const flows = await query; + const flows = await joinQuery; const mapFlows: UniqueFlowEntity[] = flows.map( (flow) => ({ - id: flow.objectID, + id: flow.id, versionID: flow.versionID, }) as UniqueFlowEntity ); diff --git a/src/domain-services/flows/strategy/impl/get-flowIds-flow-from-nested-flow-filters-strategy-impl.ts b/src/domain-services/flows/strategy/impl/get-flowIds-flow-from-nested-flow-filters-strategy-impl.ts index c3b2f493..d79070bb 100644 --- a/src/domain-services/flows/strategy/impl/get-flowIds-flow-from-nested-flow-filters-strategy-impl.ts +++ b/src/domain-services/flows/strategy/impl/get-flowIds-flow-from-nested-flow-filters-strategy-impl.ts @@ -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 @@ -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 { - const { models, nestedFlowFilters } = args; + const { databaseConnection, models, nestedFlowFilters } = args; let flowsReporterReferenceCode: UniqueFlowEntity[] = []; let flowsSourceSystemId: UniqueFlowEntity[] = []; @@ -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 }; } } diff --git a/src/domain-services/flows/strategy/impl/get-flowIds-flow-object-conditions-strategy-impl.ts b/src/domain-services/flows/strategy/impl/get-flowIds-flow-object-conditions-strategy-impl.ts index 6b00e9ea..c1adc62c 100644 --- a/src/domain-services/flows/strategy/impl/get-flowIds-flow-object-conditions-strategy-impl.ts +++ b/src/domain-services/flows/strategy/impl/get-flowIds-flow-object-conditions-strategy-impl.ts @@ -1,17 +1,22 @@ import { Service } from 'typedi'; import { FlowObjectService } from '../../../flow-object/flow-object-service'; +import { FlowService } from '../../flow-service'; import { type UniqueFlowEntity } from '../../model'; import { type FlowIDSearchStrategy, type FlowIdSearchStrategyArgs, type FlowIdSearchStrategyResponse, } from '../flowID-search-strategy'; +import { buildSearchFlowsConditions, defaultFlowOrderBy } from './utils'; @Service() export class GetFlowIdsFromObjectConditionsStrategyImpl implements FlowIDSearchStrategy { - constructor(private readonly flowObjectService: FlowObjectService) {} + constructor( + private readonly flowObjectService: FlowObjectService, + private readonly flowService: FlowService + ) {} async search( args: FlowIdSearchStrategyArgs @@ -39,6 +44,17 @@ export class GetFlowIdsFromObjectConditionsStrategyImpl }); } - return { flows: flowsFromFilteredFlowObjects }; + // 3. Once we have the flowIDs + // Search in the Flow table for the flowIDs and versionIDs + // To verify that the flows are not deleted + + const searchFlowArgs = { + databaseConnection, + orderBy: defaultFlowOrderBy(), + whereClauses: buildSearchFlowsConditions(flowsFromFilteredFlowObjects), + }; + const uniqueFlowsNotDeleted = + await this.flowService.getFlowsAsUniqueFlowEntity(searchFlowArgs); + return { flows: uniqueFlowsNotDeleted }; } } 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 a445b204..2a1c7050 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,9 +1,7 @@ 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 { type OrderBy } from '../../../../utils/database-types'; import { FlowService } from '../../flow-service'; -import { type SearchFlowsFilters } from '../../graphql/args'; import type { FlowEntity, UniqueFlowEntity } from '../../model'; import type { FlowSearchArgs, @@ -15,6 +13,8 @@ import { GetFlowIdsFromCategoryConditionsStrategyImpl } from './get-flowIds-flow import { GetFlowIdsFromNestedFlowFiltersStrategyImpl } from './get-flowIds-flow-from-nested-flow-filters-strategy-impl'; import { GetFlowIdsFromObjectConditionsStrategyImpl } from './get-flowIds-flow-object-conditions-strategy-impl'; import { + buildSearchFlowsConditions, + defaultFlowOrderBy, intersectUniqueFlowEntities, mapFlowOrderBy, prepareFlowConditions, @@ -31,8 +31,6 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { private readonly getFlowIdsFromNestedFlowFilters: GetFlowIdsFromNestedFlowFiltersStrategyImpl ) {} - private readonly MAX_DATABASE_CHUNK_SIZE = 5000; - async search(args: FlowSearchArgs): Promise { const { models, @@ -45,10 +43,9 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { offset, shortcutFilter, statusFilter, + orderBy, } = args; - let { orderBy } = args; - // 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 @@ -95,9 +92,6 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { } } - // Default orderBy for flows - orderBy = mapFlowOrderBy(orderBy); - // We need to fetch the flowIDs by the nestedFlowFilters // if there are any const isFilterByNestedFilters = nestedFlowFilters !== undefined; @@ -198,11 +192,12 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { statusFilter ); - const flows: FlowEntity[] = await this.flowService.getFlows({ - models, - conditions: flowConditions, - orderBy, - }); + const flows: UniqueFlowEntity[] = + await this.flowService.getFlowsAsUniqueFlowEntity({ + databaseConnection, + conditions: flowConditions, + orderBy, + }); // If after this filter we have no flows, we can return an empty array if (flows.length === 0) { @@ -214,11 +209,7 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { // When using the spread operator - a workaround is to use push fot each element // also, we need to map the FlowEntity to UniqueFlowEntity for (const flow of flows) { - const uniqueFlowEntity: UniqueFlowEntity = { - id: flow.id, - versionID: flow.versionID, - }; - flowsFromFlowFilters.push(uniqueFlowEntity); + flowsFromFlowFilters.push(flow); } } @@ -243,40 +234,19 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { sortedFlows = deduplicatedFlows; } - // Store the count const count = sortedFlows.length; - let flows: FlowEntity[] = []; - // This should only happen when doing the totalAmountSearch - if ( - limit === undefined && - offset === undefined && - sortedFlows.length > this.MAX_DATABASE_CHUNK_SIZE - ) { - // We need to paginate over the searchConditions - // Then collect the flows - flows = await this.progresiveChunkSearch( - models, - sortedFlows, - 0, - this.MAX_DATABASE_CHUNK_SIZE, - orderBy, - [] - ); - } else { - // Store the flows promise - const flowsResponse = await this.progresiveSearch( - models, - sortedFlows, - limit ?? 0, - offset ?? 0, - orderBy, - [] - ); + const flowEntityOrderBy = defaultFlowOrderBy(); + // Store the flows promise + const flows = await this.progresiveSearch( + models, + sortedFlows, + limit, + offset ?? 0, + flowEntityOrderBy, + [] + ); - // Store the flows - flows = flowsResponse; - } return { flows, count }; } @@ -308,7 +278,7 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { ): Promise { const reducedFlows = sortedFlows.slice(offset, offset + limit); - const whereConditions = this.buildConditions(reducedFlows); + const whereConditions = buildSearchFlowsConditions(reducedFlows); const flows = await this.flowService.getFlows({ models, @@ -333,86 +303,4 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy { flowResponse ); } - - /** - * This method have a similar behavior to the progresiveSearch method - * but the exit condition differs - * - * The exit condition is when - * the flowResponse length is equal to the sortedFlows length - * or the reducedFlows length is less than the chunkSize after doing the search - * @param models - * @param sortedFlows - * @param start - * @param chunkSize - * @param orderBy - * @param flowResponse - * @returns list of flows - */ - async progresiveChunkSearch( - models: Database, - sortedFlows: UniqueFlowEntity[], - start: number, - chunkSize: number, - orderBy: OrderBy, - flowResponse: FlowEntity[] - ): Promise { - const reducedFlows = sortedFlows.slice(start, start + chunkSize); - - const whereConditions = this.buildConditions(reducedFlows); - - const flows = await this.flowService.getFlows({ - models, - conditions: whereConditions, - orderBy, - }); - - flowResponse.push(...flows); - - if ( - flowResponse.length === sortedFlows.length || - reducedFlows.length < chunkSize - ) { - return flowResponse; - } - - // Recursive call - start += chunkSize; - return await this.progresiveChunkSearch( - models, - sortedFlows, - start, - chunkSize, - orderBy, - flowResponse - ); - } - - buildConditions( - uniqueFlowEntities: UniqueFlowEntity[], - flowFilters?: SearchFlowsFilters - ): any { - const whereClauses = uniqueFlowEntities.map((flow) => ({ - [Cond.AND]: [ - { id: flow.id }, - { versionID: flow.versionID }, - { deletedAt: null }, - ], - })); - - if (flowFilters) { - const flowConditions = prepareFlowConditions(flowFilters); - return { - [Cond.AND]: [ - { deletedAt: null }, - flowConditions, - { [Cond.OR]: whereClauses }, - ], - }; - } - - return { - [Cond.OR]: whereClauses, - }; - } } diff --git a/src/domain-services/flows/strategy/impl/utils.ts b/src/domain-services/flows/strategy/impl/utils.ts index f1d7a2eb..25d0fc9e 100644 --- a/src/domain-services/flows/strategy/impl/utils.ts +++ b/src/domain-services/flows/strategy/impl/utils.ts @@ -114,7 +114,7 @@ export const sortingColumnMapping: Map = new Map< export function mapFlowOrderBy(orderBy: any): OrderBy { if (!orderBy) { - return { column: 'updatedAt', order: 'DESC' }; + return defaultFlowOrderBy(); } if (orderBy.entity === 'flow') { @@ -134,6 +134,10 @@ export function mapFlowOrderBy(orderBy: any): OrderBy { return { column: columnToSort, order: orderBy.order }; } +export function defaultFlowOrderBy(): OrderBy { + return { column: 'updatedAt', order: 'DESC' }; +} + export function prepareFlowConditions(flowFilters: SearchFlowsFilters): any { let flowConditions = {}; @@ -290,3 +294,31 @@ export function prepareFlowStatusConditions( } return flowConditions; } + +export function buildSearchFlowsConditions( + uniqueFlowEntities: UniqueFlowEntity[], + flowFilters?: SearchFlowsFilters +): any { + const whereClauses = uniqueFlowEntities.map((flow) => ({ + [Cond.AND]: [ + { id: flow.id }, + { versionID: flow.versionID }, + { deletedAt: null }, + ], + })); + + if (flowFilters) { + const flowConditions = prepareFlowConditions(flowFilters); + return { + [Cond.AND]: [ + { deletedAt: null }, + flowConditions, + { [Cond.OR]: whereClauses }, + ], + }; + } + + return { + [Cond.OR]: whereClauses, + }; +}