From 6f99111c52af409f14ae11bc5a048c9fe8e84d7a Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 28 Apr 2023 12:11:56 -0500 Subject: [PATCH] Move api name & version into ScriptRevision; make the records that go into record-scripts be api versions of records. --- .../PollingAutomationPerTableRunner.java | 3 + .../actions/scripts/ExecuteCodeAction.java | 102 +++++++++++++++++- .../scripts/RunAdHocRecordScriptAction.java | 64 +++-------- .../scripts/RunAssociatedScriptAction.java | 39 +------ .../core/actions/scripts/ScriptApi.java | 5 + .../automation/TableAutomationAction.java | 37 +++++++ .../core/model/scripts/ScriptRevision.java | 73 ++++++++++++- .../scripts/ScriptsMetaDataProvider.java | 1 + .../ExtractViaQueryStep.java | 13 +++ .../scripts/RunRecordScriptExtractStep.java | 13 +++ .../StoreScriptRevisionProcessStep.java | 2 + .../scripts/TestScriptProcessStep.java | 1 + .../metadata/ApiInstanceMetaDataProvider.java | 2 +- .../qqq/api/utils/ApiScriptUtils.java | 22 +++- .../qqq/api/utils/ApiScriptUtilsTest.java | 5 +- 15 files changed, 283 insertions(+), 99 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/polling/PollingAutomationPerTableRunner.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/polling/PollingAutomationPerTableRunner.java index 89eab8f2..0322a823 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/polling/PollingAutomationPerTableRunner.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/automation/polling/PollingAutomationPerTableRunner.java @@ -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()); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ExecuteCodeAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ExecuteCodeAction.java index 44db3df9..b04737df 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ExecuteCodeAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ExecuteCodeAction.java @@ -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 executorClass = (Class) 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 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()); + } + } + + + /******************************************************************************* ** *******************************************************************************/ diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java index 8313d8b0..f440e16f 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAdHocRecordScriptAction.java @@ -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 context, ScriptRevision scriptRevision) + private static ArrayList 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) 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())); } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAssociatedScriptAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAssociatedScriptAction.java index 3f1d2c8a..f8d9d511 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAssociatedScriptAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/RunAssociatedScriptAction.java @@ -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 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); diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java index c8fcd9dd..fa2f7154 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/scripts/ScriptApi.java @@ -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 { diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/automation/TableAutomationAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/automation/TableAutomationAction.java index d44fa9c1..aa043a8b 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/automation/TableAutomationAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/tables/automation/TableAutomationAction.java @@ -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 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); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptRevision.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptRevision.java index 0169c561..917ebfb2 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptRevision.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptRevision.java @@ -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); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java index d8235a2b..2e64aa29 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/scripts/ScriptsMetaDataProvider.java @@ -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"))); diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/ExtractViaQueryStep.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/ExtractViaQueryStep.java index 414b0c54..ee23b94f 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/ExtractViaQueryStep.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/etl/streamedwithfrontend/ExtractViaQueryStep.java @@ -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) + { + + } + + + /******************************************************************************* ** *******************************************************************************/ diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/RunRecordScriptExtractStep.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/RunRecordScriptExtractStep.java index 4599b0c8..6dda828d 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/RunRecordScriptExtractStep.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/RunRecordScriptExtractStep.java @@ -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); + } + } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/StoreScriptRevisionProcessStep.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/StoreScriptRevisionProcessStep.java index d1a0fb82..db523e40 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/StoreScriptRevisionProcessStep.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/StoreScriptRevisionProcessStep.java @@ -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); diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/TestScriptProcessStep.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/TestScriptProcessStep.java index 0abab72c..cf9df9df 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/TestScriptProcessStep.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/scripts/TestScriptProcessStep.java @@ -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())) { diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/ApiInstanceMetaDataProvider.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/ApiInstanceMetaDataProvider.java index 0d7779bc..e8ff2d9d 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/ApiInstanceMetaDataProvider.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/model/metadata/ApiInstanceMetaDataProvider.java @@ -118,7 +118,7 @@ public class ApiInstanceMetaDataProvider ApiInstanceMetaDataContainer apiInstanceMetaDataContainer = ApiInstanceMetaDataContainer.of(instance); for(Map.Entry entry : apiInstanceMetaDataContainer.getApis().entrySet()) { - apiNamePossibleValues.add(new QPossibleValue<>(entry.getKey())); + apiNamePossibleValues.add(new QPossibleValue<>(entry.getKey(), entry.getValue().getLabel())); ApiInstanceMetaData apiInstanceMetaData = entry.getValue(); allVersions.addAll(apiInstanceMetaData.getPastVersions()); diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/utils/ApiScriptUtils.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/utils/ApiScriptUtils.java index 5f01dd26..08586a41 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/utils/ApiScriptUtils.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/utils/ApiScriptUtils.java @@ -28,11 +28,13 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.kingsrook.qqq.api.actions.ApiImplementation; +import com.kingsrook.qqq.api.actions.QRecordApiAdapter; import com.kingsrook.qqq.api.model.APIVersion; import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData; import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer; import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.data.QRecord; /******************************************************************************* @@ -49,20 +51,30 @@ public class ApiScriptUtils implements Serializable ** Constructor ** *******************************************************************************/ - public ApiScriptUtils() + public ApiScriptUtils(String apiName, String apiVersion) { + setApiName(apiName); + setApiVersion(apiVersion); } /******************************************************************************* - ** Constructor ** *******************************************************************************/ - public ApiScriptUtils(String apiName, String apiVersion) + public static ArrayList> qRecordListToApiRecordList(List qRecordList, String tableName, String apiName, String apiVersion) throws QException { - setApiName(apiName); - setApiVersion(apiVersion); + if(qRecordList == null) + { + return (null); + } + + ArrayList> rs = new ArrayList<>(); + for(QRecord qRecord : qRecordList) + { + rs.add(QRecordApiAdapter.qRecordToApiMap(qRecord, tableName, apiName, apiVersion)); + } + return (rs); } diff --git a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/utils/ApiScriptUtilsTest.java b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/utils/ApiScriptUtilsTest.java index cd66985e..3d450744 100644 --- a/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/utils/ApiScriptUtilsTest.java +++ b/qqq-middleware-api/src/test/java/com/kingsrook/qqq/api/utils/ApiScriptUtilsTest.java @@ -267,10 +267,7 @@ class ApiScriptUtilsTest extends BaseTest *******************************************************************************/ private static ApiScriptUtils newDefaultApiScriptUtils() { - ApiScriptUtils apiScriptUtils = new ApiScriptUtils(); - apiScriptUtils.setApiName(TestUtils.API_NAME); - apiScriptUtils.setApiVersion(TestUtils.CURRENT_API_VERSION); - return apiScriptUtils; + return (new ApiScriptUtils(TestUtils.API_NAME, TestUtils.CURRENT_API_VERSION)); } } \ No newline at end of file