Merge pull request #5817 from Budibase/fix/loop-hbs-usage

Fix HBS usage in automation looping action
This commit is contained in:
Michael Drury 2022-05-11 12:40:58 +01:00 committed by GitHub
commit f572afeb08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 54 additions and 31 deletions

View File

@ -208,5 +208,10 @@ exports.AutomationErrors = {
FAILURE_CONDITION: "FAILURE_CONDITION_MET",
}
exports.LoopStepTypes = {
ARRAY: "Array",
STRING: "String",
}
// pass through the list from the auth/core lib
exports.ObjectStoreBuckets = ObjectStoreBuckets

View File

@ -8,7 +8,7 @@ const { DocumentTypes } = require("../db/utils")
const { doInTenant } = require("@budibase/backend-core/tenancy")
const { definitions: triggerDefs } = require("../automations/triggerInfo")
const { doInAppContext, getAppDB } = require("@budibase/backend-core/context")
const { AutomationErrors } = require("../constants")
const { AutomationErrors, LoopStepTypes } = require("../constants")
const FILTER_STEP_ID = actions.ACTION_DEFINITIONS.FILTER.stepId
const LOOP_STEP_ID = actions.ACTION_DEFINITIONS.LOOP.stepId
@ -17,6 +17,41 @@ const STOPPED_STATUS = { success: false, status: "STOPPED" }
const { cloneDeep } = require("lodash/fp")
const env = require("../environment")
function typecastForLooping(loopStep, input) {
if (!input || !input.binding) {
return null
}
const isArray = Array.isArray(input.binding),
isString = typeof input.binding === "string"
try {
switch (loopStep.inputs.option) {
case LoopStepTypes.ARRAY:
if (isString) {
return JSON.parse(input.binding)
}
break
case LoopStepTypes.STRING:
if (isArray) {
return input.binding.join(",")
}
break
}
} catch (err) {
throw new Error("Unable to cast to correct type")
}
return input.binding
}
function getLoopIterations(loopStep, input) {
const binding = typecastForLooping(loopStep, input)
if (!loopStep || !binding) {
return 1
}
return Array.isArray(binding)
? binding.length
: automationUtils.stringSplit(binding).length
}
/**
* The automation orchestrator is a class responsible for executing automations.
* It handles the context of the automation and makes sure each step gets the correct
@ -107,7 +142,9 @@ class Orchestrator {
let loopSteps = []
for (let step of automation.definition.steps) {
stepCount++
let input
let input,
iterations = 1,
iterationCount = 0
if (step.stepId === LOOP_STEP_ID) {
loopStep = step
loopStepNumber = stepCount
@ -116,13 +153,9 @@ class Orchestrator {
if (loopStep) {
input = await processObject(loopStep.inputs, this._context)
iterations = getLoopIterations(loopStep, input)
}
let iterations = loopStep
? Array.isArray(input.binding)
? input.binding.length
: automationUtils.stringSplit(input.binding).length
: 1
let iterationCount = 0
for (let index = 0; index < iterations; index++) {
let originalStepInput = cloneDeep(step.inputs)
@ -132,18 +165,11 @@ class Orchestrator {
loopStep.inputs,
cloneDeep(this._context)
)
newInput = automationUtils.cleanInputValues(
newInput,
loopStep.schema.inputs
)
let tempOutput = { items: loopSteps, iterations: iterationCount }
if (
(loopStep.inputs.option === "Array" &&
!Array.isArray(newInput.binding)) ||
(loopStep.inputs.option === "String" &&
typeof newInput.binding !== "string")
) {
try {
newInput.binding = typecastForLooping(loopStep, newInput)
} catch (err) {
this.updateContextAndOutput(loopStepNumber, step, tempOutput, {
status: AutomationErrors.INCORRECT_TYPE,
success: false,
@ -205,21 +231,13 @@ class Orchestrator {
}
let isFailure = false
if (
typeof this._context.steps[loopStepNumber]?.currentItem === "object"
) {
isFailure = Object.keys(
this._context.steps[loopStepNumber].currentItem
).some(value => {
return (
this._context.steps[loopStepNumber].currentItem[value] ===
loopStep.inputs.failure
)
const currentItem = this._context.steps[loopStepNumber]?.currentItem
if (currentItem && typeof currentItem === "object") {
isFailure = Object.keys(currentItem).some(value => {
return currentItem[value] === loopStep.inputs.failure
})
} else {
isFailure =
this._context.steps[loopStepNumber]?.currentItem ===
loopStep.inputs.failure
isFailure = currentItem && currentItem === loopStep.inputs.failure
}
if (isFailure) {