Further refactoring of branching.
This commit is contained in:
parent
29532a2810
commit
18567f5fe7
|
@ -7,7 +7,7 @@ import {
|
||||||
} from "../automations/utils"
|
} from "../automations/utils"
|
||||||
import * as actions from "../automations/actions"
|
import * as actions from "../automations/actions"
|
||||||
import * as automationUtils from "../automations/automationUtils"
|
import * as automationUtils from "../automations/automationUtils"
|
||||||
import { dataFilters, helpers, utils } from "@budibase/shared-core"
|
import { dataFilters, helpers } from "@budibase/shared-core"
|
||||||
import { default as AutomationEmitter } from "../events/AutomationEmitter"
|
import { default as AutomationEmitter } from "../events/AutomationEmitter"
|
||||||
import { generateAutomationMetadataID, isProdAppID } from "../db/utils"
|
import { generateAutomationMetadataID, isProdAppID } from "../db/utils"
|
||||||
import { automations } from "@budibase/shared-core"
|
import { automations } from "@budibase/shared-core"
|
||||||
|
@ -24,15 +24,15 @@ import {
|
||||||
AutomationStepStatus,
|
AutomationStepStatus,
|
||||||
BranchSearchFilters,
|
BranchSearchFilters,
|
||||||
BranchStep,
|
BranchStep,
|
||||||
isLogicalSearchOperator,
|
|
||||||
LoopStep,
|
LoopStep,
|
||||||
UserBindings,
|
UserBindings,
|
||||||
isBasicSearchOperator,
|
|
||||||
ContextEmitter,
|
ContextEmitter,
|
||||||
LoopStepType,
|
LoopStepType,
|
||||||
AutomationTriggerResult,
|
AutomationTriggerResult,
|
||||||
AutomationResults,
|
AutomationResults,
|
||||||
AutomationStepResult,
|
AutomationStepResult,
|
||||||
|
isLogicalFilter,
|
||||||
|
Branch,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import { AutomationContext } from "../definitions/automations"
|
import { AutomationContext } from "../definitions/automations"
|
||||||
import { WorkerCallback } from "./definitions"
|
import { WorkerCallback } from "./definitions"
|
||||||
|
@ -84,6 +84,41 @@ function getLoopIterable(loopStep: LoopStep): any[] {
|
||||||
return Array.isArray(input) ? input : [input]
|
return Array.isArray(input) ? input : [input]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function branchMatches(ctx: AutomationContext, branch: Branch) {
|
||||||
|
const toFilter: Record<string, any> = {}
|
||||||
|
|
||||||
|
const recurseSearchFilters = (
|
||||||
|
filters: BranchSearchFilters
|
||||||
|
): BranchSearchFilters => {
|
||||||
|
for (const filter of Object.values(filters)) {
|
||||||
|
if (!filter) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLogicalFilter(filter)) {
|
||||||
|
filter.conditions = filter.conditions.map(condition =>
|
||||||
|
recurseSearchFilters(condition)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
for (const [field, value] of Object.entries(filter)) {
|
||||||
|
toFilter[field] = processStringSync(field, prepareContext(ctx))
|
||||||
|
if (typeof value === "string" && findHBSBlocks(value).length > 0) {
|
||||||
|
filter[field] = processStringSync(value, prepareContext(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = dataFilters.runQuery(
|
||||||
|
[toFilter],
|
||||||
|
recurseSearchFilters(branch.condition)
|
||||||
|
)
|
||||||
|
return result.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
function prepareContext(context: AutomationContext) {
|
function prepareContext(context: AutomationContext) {
|
||||||
return {
|
return {
|
||||||
...context,
|
...context,
|
||||||
|
@ -434,14 +469,12 @@ class Orchestrator {
|
||||||
|
|
||||||
ctx.loop = { currentItem }
|
ctx.loop = { currentItem }
|
||||||
const loopedStepResult = await this.executeStep(ctx, stepToLoop)
|
const loopedStepResult = await this.executeStep(ctx, stepToLoop)
|
||||||
items.push(loopedStepResult.outputs)
|
|
||||||
ctx.loop = undefined
|
ctx.loop = undefined
|
||||||
|
items.push(loopedStepResult.outputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: stepToLoop.id,
|
...result,
|
||||||
stepId: stepToLoop.stepId,
|
|
||||||
inputs: stepToLoop.inputs,
|
|
||||||
outputs: {
|
outputs: {
|
||||||
success: true,
|
success: true,
|
||||||
status:
|
status:
|
||||||
|
@ -459,11 +492,7 @@ class Orchestrator {
|
||||||
const { branches, children } = branchStep.inputs
|
const { branches, children } = branchStep.inputs
|
||||||
|
|
||||||
for (const branch of branches) {
|
for (const branch of branches) {
|
||||||
const condition = await this.evaluateBranchCondition(
|
if (await branchMatches(ctx, branch)) {
|
||||||
ctx,
|
|
||||||
branch.condition
|
|
||||||
)
|
|
||||||
if (condition) {
|
|
||||||
const steps = children?.[branch.id] || []
|
const steps = children?.[branch.id] || []
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
@ -478,7 +507,6 @@ class Orchestrator {
|
||||||
branchId: `${branch.id}`,
|
branchId: `${branch.id}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// A final +1 to accommodate the branch step itself
|
|
||||||
...(await this.executeSteps(ctx, steps)),
|
...(await this.executeSteps(ctx, steps)),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -496,52 +524,6 @@ class Orchestrator {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private async evaluateBranchCondition(
|
|
||||||
ctx: AutomationContext,
|
|
||||||
conditions: BranchSearchFilters
|
|
||||||
): Promise<boolean> {
|
|
||||||
const toFilter: Record<string, any> = {}
|
|
||||||
|
|
||||||
const recurseSearchFilters = (
|
|
||||||
filters: BranchSearchFilters
|
|
||||||
): BranchSearchFilters => {
|
|
||||||
for (const filterKey of Object.keys(
|
|
||||||
filters
|
|
||||||
) as (keyof typeof filters)[]) {
|
|
||||||
if (!filters[filterKey]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLogicalSearchOperator(filterKey)) {
|
|
||||||
filters[filterKey].conditions = filters[filterKey].conditions.map(
|
|
||||||
condition => recurseSearchFilters(condition)
|
|
||||||
)
|
|
||||||
} else if (isBasicSearchOperator(filterKey)) {
|
|
||||||
for (const [field, value] of Object.entries(filters[filterKey])) {
|
|
||||||
const fromContext = processStringSync(field, prepareContext(ctx))
|
|
||||||
toFilter[field] = fromContext
|
|
||||||
|
|
||||||
if (typeof value === "string" && findHBSBlocks(value).length > 0) {
|
|
||||||
const processedVal = processStringSync(value, prepareContext(ctx))
|
|
||||||
|
|
||||||
filters[filterKey][field] = processedVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We want to types to complain if we extend BranchSearchFilters, but not to throw if the request comes with some extra data. It will just be ignored
|
|
||||||
utils.unreachable(filterKey, { doNotThrow: true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filters
|
|
||||||
}
|
|
||||||
|
|
||||||
const processedConditions = recurseSearchFilters(conditions)
|
|
||||||
|
|
||||||
const result = dataFilters.runQuery([toFilter], processedConditions)
|
|
||||||
return result.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
private async executeStep(
|
private async executeStep(
|
||||||
ctx: AutomationContext,
|
ctx: AutomationContext,
|
||||||
step: AutomationStep
|
step: AutomationStep
|
||||||
|
|
|
@ -82,6 +82,10 @@ type RangeFilter = Record<
|
||||||
|
|
||||||
type LogicalFilter = { conditions: SearchFilters[] }
|
type LogicalFilter = { conditions: SearchFilters[] }
|
||||||
|
|
||||||
|
export function isLogicalFilter(filter: any): filter is LogicalFilter {
|
||||||
|
return "conditions" in filter
|
||||||
|
}
|
||||||
|
|
||||||
export type AnySearchFilter = BasicFilter | ArrayFilter | RangeFilter
|
export type AnySearchFilter = BasicFilter | ArrayFilter | RangeFilter
|
||||||
|
|
||||||
export interface SearchFilters {
|
export interface SearchFilters {
|
||||||
|
|
Loading…
Reference in New Issue