Move api name & version into ScriptRevision; make the records that go into record-scripts be api versions of records.

This commit is contained in:
2023-04-28 12:11:56 -05:00
parent 4135607a4c
commit 6f99111c52
15 changed files with 283 additions and 99 deletions

View File

@ -278,6 +278,7 @@ public class PollingAutomationPerTableRunner implements Runnable
.withPriority(record.getValueInteger("priority"))
.withCodeReference(new QCodeReference(RunRecordScriptAutomationHandler.class))
.withValues(MapBuilder.of("scriptId", record.getValue("scriptId")))
.withIncludeRecordAssociations(true)
);
}
}
@ -392,6 +393,8 @@ public class PollingAutomationPerTableRunner implements Runnable
queryInput.setFilter(filter);
queryInput.setIncludeAssociations(action.getIncludeRecordAssociations());
return (new QueryAction().execute(queryInput).getRecords());
}

View File

@ -25,13 +25,21 @@ package com.kingsrook.qqq.backend.core.actions.scripts;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.Log4jCodeExecutionLogger;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.ScriptExecutionLoggerInterface;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.StoreScriptLogAndScriptLogLineExecutionLogger;
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.scripts.AbstractRunScriptInput;
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeOutput;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
@ -49,6 +57,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
*******************************************************************************/
public class ExecuteCodeAction
{
private static final QLogger LOG = QLogger.getLogger(ExecuteCodeAction.class);
/*******************************************************************************
**
@ -68,10 +79,10 @@ public class ExecuteCodeAction
try
{
String languageExecutor = switch(codeReference.getCodeType())
{
case JAVA -> "com.kingsrook.qqq.backend.core.actions.scripts.QJavaExecutor";
case JAVA_SCRIPT -> "com.kingsrook.qqq.languages.javascript.QJavaScriptExecutor";
};
{
case JAVA -> "com.kingsrook.qqq.backend.core.actions.scripts.QJavaExecutor";
case JAVA_SCRIPT -> "com.kingsrook.qqq.languages.javascript.QJavaScriptExecutor";
};
@SuppressWarnings("unchecked")
Class<? extends QCodeExecutor> executorClass = (Class<? extends QCodeExecutor>) Class.forName(languageExecutor);
@ -108,6 +119,89 @@ public class ExecuteCodeAction
/*******************************************************************************
**
*******************************************************************************/
public static ExecuteCodeInput setupExecuteCodeInput(AbstractRunScriptInput<?> input, ScriptRevision scriptRevision)
{
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput();
executeCodeInput.setInput(new HashMap<>(Objects.requireNonNullElseGet(input.getInputValues(), HashMap::new)));
executeCodeInput.setContext(new HashMap<>());
if(input.getOutputObject() != null)
{
executeCodeInput.getContext().put("output", input.getOutputObject());
}
if(input.getScriptUtils() != null)
{
executeCodeInput.getContext().put("scriptUtils", input.getScriptUtils());
}
executeCodeInput.setCodeReference(new QCodeReference().withInlineCode(scriptRevision.getContents()).withCodeType(QCodeType.JAVA_SCRIPT)); // todo - code type as attribute of script!!
ExecuteCodeAction.addApiUtilityToContext(executeCodeInput.getContext(), scriptRevision);
ExecuteCodeAction.setExecutionLoggerInExecuteCodeInput(input, scriptRevision, executeCodeInput);
return (executeCodeInput);
}
/*******************************************************************************
** Try to (dynamically) load the ApiScriptUtils object from the api middleware
** module -- in case the runtime doesn't have that module deployed (e.g, not in
** the project pom).
*******************************************************************************/
private static void addApiUtilityToContext(Map<String, Serializable> context, ScriptRevision scriptRevision)
{
if(!StringUtils.hasContent(scriptRevision.getApiName()) || !StringUtils.hasContent(scriptRevision.getApiVersion()))
{
return;
}
try
{
Class<?> apiScriptUtilsClass = Class.forName("com.kingsrook.qqq.api.utils.ApiScriptUtils");
Object apiScriptUtilsObject = apiScriptUtilsClass.getConstructor(String.class, String.class).newInstance(scriptRevision.getApiName(), scriptRevision.getApiVersion());
context.put("api", (Serializable) apiScriptUtilsObject);
}
catch(ClassNotFoundException e)
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// this is the only exception we're kinda expecting here - so catch for it specifically, and just log.trace - others, warn //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
LOG.trace("Couldn't load ApiScriptUtils class - qqq-middleware-api not on the classpath?");
}
catch(Exception e)
{
LOG.warn("Error adding api utility to script context", e);
}
}
/*******************************************************************************
**
*******************************************************************************/
private static void setExecutionLoggerInExecuteCodeInput(AbstractRunScriptInput<?> input, ScriptRevision scriptRevision, ExecuteCodeInput executeCodeInput)
{
/////////////////////////////////////////////////////////////////////////////////////////////////
// let caller supply a logger, or by default use StoreScriptLogAndScriptLogLineExecutionLogger //
/////////////////////////////////////////////////////////////////////////////////////////////////
QCodeExecutionLoggerInterface executionLogger = Objects.requireNonNullElseGet(input.getLogger(), () -> new StoreScriptLogAndScriptLogLineExecutionLogger(scriptRevision.getScriptId(), scriptRevision.getId()));
executeCodeInput.setExecutionLogger(executionLogger);
if(executionLogger instanceof ScriptExecutionLoggerInterface scriptExecutionLoggerInterface)
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// if logger is aware of scripts (as opposed to a generic CodeExecution logger), give it the ids. //
////////////////////////////////////////////////////////////////////////////////////////////////////
scriptExecutionLoggerInterface.setScriptId(scriptRevision.getScriptId());
scriptExecutionLoggerInterface.setScriptRevisionId(scriptRevision.getId());
}
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -23,15 +23,13 @@ package com.kingsrook.qqq.backend.core.actions.scripts;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.ScriptExecutionLoggerInterface;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.StoreScriptLogAndScriptLogLineExecutionLogger;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.context.QContext;
@ -50,13 +48,10 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
import com.kingsrook.qqq.backend.core.model.metadata.code.AdHocScriptCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.scripts.Script;
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
/*******************************************************************************
@ -98,6 +93,7 @@ public class RunAdHocRecordScriptAction
QueryInput queryInput = new QueryInput();
queryInput.setTableName(input.getTableName());
queryInput.setFilter(new QQueryFilter(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, input.getRecordPrimaryKeyList())));
queryInput.setIncludeAssociations(true);
QueryOutput queryOutput = new QueryAction().execute(queryInput);
input.setRecordList(queryOutput.getRecords());
}
@ -114,43 +110,14 @@ public class RunAdHocRecordScriptAction
/////////////
// run it! //
/////////////
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput();
executeCodeInput.setInput(new HashMap<>(Objects.requireNonNullElseGet(input.getInputValues(), HashMap::new)));
executeCodeInput.getInput().put("records", new ArrayList<>(input.getRecordList()));
executeCodeInput.setContext(new HashMap<>());
if(input.getOutputObject() != null)
{
executeCodeInput.getContext().put("output", input.getOutputObject());
}
if(input.getScriptUtils() != null)
{
executeCodeInput.getContext().put("scriptUtils", input.getScriptUtils());
}
addApiUtilityToContext(executeCodeInput.getContext(), scriptRevision);
executeCodeInput.setCodeReference(new QCodeReference().withInlineCode(scriptRevision.getContents()).withCodeType(QCodeType.JAVA_SCRIPT)); // todo - code type as attribute of script!!
/////////////////////////////////////////////////////////////////////////////////////////////////
// let caller supply a logger, or by default use StoreScriptLogAndScriptLogLineExecutionLogger //
/////////////////////////////////////////////////////////////////////////////////////////////////
QCodeExecutionLoggerInterface executionLogger = Objects.requireNonNullElseGet(input.getLogger(), () -> new StoreScriptLogAndScriptLogLineExecutionLogger(scriptRevision.getScriptId(), scriptRevision.getId()));
executeCodeInput.setExecutionLogger(executionLogger);
if(executionLogger instanceof ScriptExecutionLoggerInterface scriptExecutionLoggerInterface)
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// if logger is aware of scripts (as opposed to a generic CodeExecution logger), give it the ids. //
////////////////////////////////////////////////////////////////////////////////////////////////////
scriptExecutionLoggerInterface.setScriptId(scriptRevision.getScriptId());
scriptExecutionLoggerInterface.setScriptRevisionId(scriptRevision.getId());
}
ExecuteCodeInput executeCodeInput = ExecuteCodeAction.setupExecuteCodeInput(input, scriptRevision);
executeCodeInput.getInput().put("records", getRecordsForScript(input, scriptRevision));
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
output.setOutput(executeCodeOutput.getOutput());
output.setLogger(executionLogger);
output.setLogger(executeCodeInput.getExecutionLogger());
}
catch(Exception e)
{
@ -161,17 +128,18 @@ public class RunAdHocRecordScriptAction
/*******************************************************************************
** Try to (dynamically) load the ApiScriptUtils object from the api middleware
** module -- in case the runtime doesn't have that module deployed (e.g, not in
** the project pom).
**
*******************************************************************************/
private void addApiUtilityToContext(Map<String, Serializable> context, ScriptRevision scriptRevision)
private static ArrayList<? extends Serializable> getRecordsForScript(RunAdHocRecordScriptInput input, ScriptRevision scriptRevision)
{
try
{
Class<?> apiScriptUtilsClass = Class.forName("com.kingsrook.qqq.api.utils.ApiScriptUtils");
Object apiScriptUtilsObject = apiScriptUtilsClass.getConstructor().newInstance();
context.put("api", (Serializable) apiScriptUtilsObject);
Class<?> apiScriptUtilsClass = Class.forName("com.kingsrook.qqq.api.utils.ApiScriptUtils");
Method qRecordListToApiRecordList = apiScriptUtilsClass.getMethod("qRecordListToApiRecordList", List.class, String.class, String.class, String.class);
Object apiRecordList = qRecordListToApiRecordList.invoke(null, input.getRecordList(), input.getTableName(), scriptRevision.getApiName(), scriptRevision.getApiVersion());
// noinspection unchecked
return (ArrayList<? extends Serializable>) apiRecordList;
}
catch(ClassNotFoundException e)
{
@ -182,8 +150,10 @@ public class RunAdHocRecordScriptAction
}
catch(Exception e)
{
LOG.warn("Error adding api utility to script context", e, logPair("scriptRevisionId", scriptRevision.getId()));
LOG.warn("Error converting QRecord list to api record list", e);
}
return (new ArrayList<>(input.getRecordList()));
}

View File

@ -25,11 +25,7 @@ package com.kingsrook.qqq.backend.core.actions.scripts;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.ScriptExecutionLoggerInterface;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.StoreScriptLogAndScriptLogLineExecutionLogger;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
@ -40,8 +36,6 @@ import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAssociatedScriptO
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
import com.kingsrook.qqq.backend.core.model.metadata.code.AssociatedScriptCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
import com.kingsrook.qqq.backend.core.model.scripts.Script;
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
@ -54,6 +48,7 @@ public class RunAssociatedScriptAction
private Map<AssociatedScriptCodeReference, ScriptRevision> scriptRevisionCache = new HashMap<>();
/*******************************************************************************
**
*******************************************************************************/
@ -61,36 +56,8 @@ public class RunAssociatedScriptAction
{
ActionHelper.validateSession(input);
ScriptRevision scriptRevision = getScriptRevision(input);
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput();
executeCodeInput.setInput(new HashMap<>(input.getInputValues()));
executeCodeInput.setContext(new HashMap<>());
if(input.getOutputObject() != null)
{
executeCodeInput.getContext().put("output", input.getOutputObject());
}
if(input.getScriptUtils() != null)
{
executeCodeInput.getContext().put("scriptUtils", input.getScriptUtils());
}
executeCodeInput.setCodeReference(new QCodeReference().withInlineCode(scriptRevision.getContents()).withCodeType(QCodeType.JAVA_SCRIPT)); // todo - code type as attribute of script!!
/////////////////////////////////////////////////////////////////////////////////////////////////
// let caller supply a logger, or by default use StoreScriptLogAndScriptLogLineExecutionLogger //
/////////////////////////////////////////////////////////////////////////////////////////////////
QCodeExecutionLoggerInterface executionLogger = Objects.requireNonNullElseGet(input.getLogger(), () -> new StoreScriptLogAndScriptLogLineExecutionLogger(scriptRevision.getScriptId(), scriptRevision.getId()));
executeCodeInput.setExecutionLogger(executionLogger);
if(executionLogger instanceof ScriptExecutionLoggerInterface scriptExecutionLoggerInterface)
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// if logger is aware of scripts (as opposed to a generic CodeExecution logger), give it the ids. //
////////////////////////////////////////////////////////////////////////////////////////////////////
scriptExecutionLoggerInterface.setScriptId(scriptRevision.getScriptId());
scriptExecutionLoggerInterface.setScriptRevisionId(scriptRevision.getId());
}
ScriptRevision scriptRevision = getScriptRevision(input);
ExecuteCodeInput executeCodeInput = ExecuteCodeAction.setupExecuteCodeInput(input, scriptRevision);
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);

View File

@ -47,6 +47,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
/*******************************************************************************
** Object made available to scripts for access to qqq api (e.g., query, insert,
** etc, plus object constructors).
**
** Before scripts knew about the API, this class made sense and was used.
** But, now that scripts do know about the API, it feels like this class could
** be deleted... but, what about, a QQQ deployment without the API module...
** In that case, we might still want this class... think about it.
*******************************************************************************/
public class ScriptApi implements Serializable
{

View File

@ -38,6 +38,12 @@ public class TableAutomationAction
private Integer priority = 500;
private QQueryFilter filter;
////////////////////////////////////////////////////////////////////////
// flag that will cause the records to cause their associations to be //
// fetched, when they are looked up for passing into the action //
////////////////////////////////////////////////////////////////////////
private boolean includeRecordAssociations = false;
private Map<String, Serializable> values;
////////////////////////////////
@ -292,4 +298,35 @@ public class TableAutomationAction
return (this);
}
/*******************************************************************************
** Getter for includeRecordAssociations
*******************************************************************************/
public boolean getIncludeRecordAssociations()
{
return (this.includeRecordAssociations);
}
/*******************************************************************************
** Setter for includeRecordAssociations
*******************************************************************************/
public void setIncludeRecordAssociations(boolean includeRecordAssociations)
{
this.includeRecordAssociations = includeRecordAssociations;
}
/*******************************************************************************
** Fluent setter for includeRecordAssociations
*******************************************************************************/
public TableAutomationAction withIncludeRecordAssociations(boolean includeRecordAssociations)
{
this.includeRecordAssociations = includeRecordAssociations;
return (this);
}
}

View File

@ -27,6 +27,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.data.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
/*******************************************************************************
@ -48,16 +49,22 @@ public class ScriptRevision extends QRecordEntity
@QField(possibleValueSourceName = "script")
private Integer scriptId;
@QField(possibleValueSourceName = "apiVersion", label = "API Version")
private String apiVersion;
@QField(possibleValueSourceName = "apiName", label = "API Name")
private String apiName;
@QField()
private String contents;
@QField()
private Integer sequenceNo;
@QField()
@QField(maxLength = 250, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String commitMessage;
@QField()
@QField(maxLength = 100, valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE_ELLIPSIS)
private String author;
@ -353,4 +360,66 @@ public class ScriptRevision extends QRecordEntity
return (this);
}
/*******************************************************************************
** Getter for apiVersion
*******************************************************************************/
public String getApiVersion()
{
return (this.apiVersion);
}
/*******************************************************************************
** Setter for apiVersion
*******************************************************************************/
public void setApiVersion(String apiVersion)
{
this.apiVersion = apiVersion;
}
/*******************************************************************************
** Fluent setter for apiVersion
*******************************************************************************/
public ScriptRevision withApiVersion(String apiVersion)
{
this.apiVersion = apiVersion;
return (this);
}
/*******************************************************************************
** Getter for apiName
*******************************************************************************/
public String getApiName()
{
return (this.apiName);
}
/*******************************************************************************
** Setter for apiName
*******************************************************************************/
public void setApiName(String apiName)
{
this.apiName = apiName;
}
/*******************************************************************************
** Fluent setter for apiName
*******************************************************************************/
public ScriptRevision withApiName(String apiName)
{
this.apiName = apiName;
return (this);
}
}

View File

@ -382,6 +382,7 @@ public class ScriptsMetaDataProvider
.withRecordLabelFormat("%s v%s")
.withRecordLabelFields(List.of("scriptId", "sequenceNo"))
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "scriptId", "sequenceNo")))
.withSection(new QFieldSection("api", "API", new QIcon().withName("code"), Tier.T2, List.of("apiName", "apiVersion")))
.withSection(new QFieldSection("code", new QIcon().withName("data_object"), Tier.T2, List.of("contents")))
.withSection(new QFieldSection("changeManagement", new QIcon().withName("history"), Tier.T2, List.of("commitMessage", "author")))
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));

View File

@ -83,6 +83,9 @@ public class ExtractViaQueryStep extends AbstractExtractStep
queryInput.setRecordPipe(getRecordPipe());
queryInput.setLimit(getLimit());
queryInput.setAsyncJobCallback(runBackendStepInput.getAsyncJobCallback());
customizeInputPreQuery(queryInput);
new QueryAction().execute(queryInput);
///////////////////////////////////////////////////////////////////
@ -92,6 +95,16 @@ public class ExtractViaQueryStep extends AbstractExtractStep
/*******************************************************************************
** chance for sub-classes to change things about the query input, if they want.
*******************************************************************************/
protected void customizeInputPreQuery(QueryInput queryInput)
{
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -28,6 +28,7 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInpu
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.scripts.Script;
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.ExtractViaQueryStep;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
@ -70,4 +71,16 @@ public class RunRecordScriptExtractStep extends ExtractViaQueryStep
super.preRun(runBackendStepInput, runBackendStepOutput);
}
/*******************************************************************************
** Make sure associations are fetched (so api records have children!)
*******************************************************************************/
@Override
protected void customizeInputPreQuery(QueryInput queryInput)
{
super.customizeInputPreQuery(queryInput);
queryInput.setIncludeAssociations(true);
}
}

View File

@ -112,6 +112,8 @@ public class StoreScriptRevisionProcessStep implements BackendStep
QRecord scriptRevision = new QRecord()
.withValue("scriptId", script.getValue("id"))
.withValue("contents", input.getValueString("contents"))
.withValue("apiName", input.getValueString("apiName"))
.withValue("apiVersion", input.getValueString("apiVersion"))
.withValue("commitMessage", commitMessage)
.withValue("sequenceNo", nextSequenceNo);

View File

@ -106,6 +106,7 @@ public class TestScriptProcessStep implements BackendStep
QueryInput queryInput = new QueryInput();
queryInput.setTableName(tableName);
queryInput.setFilter(new QQueryFilter(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, recordPrimaryKeyList.split(","))));
queryInput.setIncludeAssociations(true);
QueryOutput queryOutput = new QueryAction().execute(queryInput);
if(CollectionUtils.nullSafeIsEmpty(queryOutput.getRecords()))
{