More api name & version with scripts (eg, running test scripts)

This commit is contained in:
2023-04-30 19:56:41 -05:00
parent 9ce45934a8
commit 15acaec523
11 changed files with 243 additions and 22 deletions

View File

@ -0,0 +1,41 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.actions.scripts;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
/*******************************************************************************
**
*******************************************************************************/
public interface AssociatedScriptContextPrimerInterface
{
/*******************************************************************************
**
*******************************************************************************/
void primeContext(ExecuteCodeInput executeCodeInput, ScriptRevision scriptRevision) throws QException;
}

View File

@ -127,19 +127,21 @@ public class ExecuteCodeAction
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput();
executeCodeInput.setInput(new HashMap<>(Objects.requireNonNullElseGet(input.getInputValues(), HashMap::new)));
executeCodeInput.setContext(new HashMap<>());
Map<String, Serializable> context = executeCodeInput.getContext();
if(input.getOutputObject() != null)
{
executeCodeInput.getContext().put("output", input.getOutputObject());
context.put("output", input.getOutputObject());
}
if(input.getScriptUtils() != null)
{
executeCodeInput.getContext().put("scriptUtils", input.getScriptUtils());
context.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.addApiUtilityToContext(context, scriptRevision);
ExecuteCodeAction.setExecutionLoggerInExecuteCodeInput(input, scriptRevision, executeCodeInput);
return (executeCodeInput);
@ -152,7 +154,7 @@ public class ExecuteCodeAction
** 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)
public static void addApiUtilityToContext(Map<String, Serializable> context, ScriptRevision scriptRevision)
{
if(!StringUtils.hasContent(scriptRevision.getApiName()) || !StringUtils.hasContent(scriptRevision.getApiVersion()))
{

View File

@ -59,6 +59,11 @@ public class RunAssociatedScriptAction
ScriptRevision scriptRevision = getScriptRevision(input);
ExecuteCodeInput executeCodeInput = ExecuteCodeAction.setupExecuteCodeInput(input, scriptRevision);
if(input.getAssociatedScriptContextPrimerInterface() != null)
{
input.getAssociatedScriptContextPrimerInterface().primeContext(executeCodeInput, scriptRevision);
}
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);

View File

@ -184,6 +184,8 @@ public class StoreAssociatedScriptAction
QRecord scriptRevision = new QRecord()
.withValue("scriptId", script.getValue("id"))
.withValue("contents", input.getCode())
.withValue("apiName", input.getApiName())
.withValue("apiVersion", input.getApiVersion())
.withValue("commitMessage", commitMessage)
.withValue("sequenceNo", nextSequenceNo);

View File

@ -32,6 +32,7 @@ import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeOutput;
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptInput;
import com.kingsrook.qqq.backend.core.model.actions.scripts.TestScriptOutput;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
/*******************************************************************************
@ -47,7 +48,7 @@ public interface TestScriptActionInterface
** Note - such a method may want or need to put an "output" object into the
** executeCodeInput's context map.
*******************************************************************************/
void setupTestScriptInput(TestScriptInput testScriptInput, ExecuteCodeInput executeCodeInput);
void setupTestScriptInput(TestScriptInput testScriptInput, ExecuteCodeInput executeCodeInput) throws QException;
/*******************************************************************************
@ -87,12 +88,21 @@ public interface TestScriptActionInterface
BuildScriptLogAndScriptLogLineExecutionLogger executionLogger = new BuildScriptLogAndScriptLogLineExecutionLogger(null, null);
executeCodeInput.setExecutionLogger(executionLogger);
try
{
setupTestScriptInput(input, executeCodeInput);
ScriptRevision scriptRevision = new ScriptRevision().withApiName(input.getApiName()).withApiVersion(input.getApiVersion());
if(this instanceof AssociatedScriptContextPrimerInterface associatedScriptContextPrimerInterface)
{
associatedScriptContextPrimerInterface.primeContext(executeCodeInput, scriptRevision);
}
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
try
{
ExecuteCodeAction.addApiUtilityToContext(executeCodeInput.getContext(), scriptRevision);
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
output.setOutputObject(processTestScriptOutput(executeCodeOutput));
}

View File

@ -22,6 +22,7 @@
package com.kingsrook.qqq.backend.core.model.actions.scripts;
import com.kingsrook.qqq.backend.core.actions.scripts.AssociatedScriptContextPrimerInterface;
import com.kingsrook.qqq.backend.core.model.metadata.code.AssociatedScriptCodeReference;
@ -30,5 +31,37 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.AssociatedScriptCodeRe
*******************************************************************************/
public class RunAssociatedScriptInput extends AbstractRunScriptInput<AssociatedScriptCodeReference>
{
private AssociatedScriptContextPrimerInterface associatedScriptContextPrimerInterface;
/*******************************************************************************
** Getter for associatedScriptContextPrimerInterface
*******************************************************************************/
public AssociatedScriptContextPrimerInterface getAssociatedScriptContextPrimerInterface()
{
return (this.associatedScriptContextPrimerInterface);
}
/*******************************************************************************
** Setter for associatedScriptContextPrimerInterface
*******************************************************************************/
public void setAssociatedScriptContextPrimerInterface(AssociatedScriptContextPrimerInterface associatedScriptContextPrimerInterface)
{
this.associatedScriptContextPrimerInterface = associatedScriptContextPrimerInterface;
}
/*******************************************************************************
** Fluent setter for associatedScriptContextPrimerInterface
*******************************************************************************/
public RunAssociatedScriptInput withAssociatedScriptContextPrimerInterface(AssociatedScriptContextPrimerInterface associatedScriptContextPrimerInterface)
{
this.associatedScriptContextPrimerInterface = associatedScriptContextPrimerInterface;
return (this);
}
}

View File

@ -35,6 +35,8 @@ public class StoreAssociatedScriptInput extends AbstractTableActionInput
private Serializable recordPrimaryKey;
private String code;
private String apiName;
private String apiVersion;
private String commitMessage;
@ -183,4 +185,66 @@ public class StoreAssociatedScriptInput extends AbstractTableActionInput
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 StoreAssociatedScriptInput withApiName(String apiName)
{
this.apiName = apiName;
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 StoreAssociatedScriptInput withApiVersion(String apiVersion)
{
this.apiVersion = apiVersion;
return (this);
}
}

View File

@ -36,6 +36,9 @@ public class TestScriptInput extends AbstractTableActionInput
private Map<String, Serializable> inputValues;
private QCodeReference codeReference;
private String apiName;
private String apiVersion;
/*******************************************************************************
@ -113,4 +116,66 @@ public class TestScriptInput extends AbstractTableActionInput
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 TestScriptInput withApiName(String apiName)
{
this.apiName = apiName;
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 TestScriptInput withApiVersion(String apiVersion)
{
this.apiVersion = apiVersion;
return (this);
}
}

View File

@ -150,12 +150,11 @@ public class ApiScriptUtils implements Serializable
/*******************************************************************************
**
*******************************************************************************/
public Map<String, Serializable> query(String urlPart) throws QException
public Map<String, Serializable> query(String tableName, String queryString) throws QException
{
validateApiNameAndVersion("query(" + urlPart + ")");
String[] urlParts = urlPart.split("\\?", 2);
Map<String, List<String>> paramMap = parseQueryString(urlParts.length > 1 ? urlParts[1] : null);
return (ApiImplementation.query(getApiInstanceMetaData(), apiVersion, urlParts[0], paramMap));
validateApiNameAndVersion("query(" + tableName + ")");
Map<String, List<String>> paramMap = parseQueryString(queryString);
return (ApiImplementation.query(getApiInstanceMetaData(), apiVersion, tableName, paramMap));
}

View File

@ -102,13 +102,13 @@ class ApiScriptUtilsTest extends BaseTest
{
ApiScriptUtils apiScriptUtils = newDefaultApiScriptUtils();
assertThatThrownBy(() -> apiScriptUtils.query(TestUtils.TABLE_NAME_PERSON + "?foo=bar"))
assertThatThrownBy(() -> apiScriptUtils.query(TestUtils.TABLE_NAME_PERSON, "foo=bar"))
.isInstanceOf(QBadRequestException.class)
.hasMessageContaining("Unrecognized filter criteria field: foo");
insertSimpsons();
Map<String, Serializable> result = apiScriptUtils.query(TestUtils.TABLE_NAME_PERSON + "?id=2");
Map<String, Serializable> result = apiScriptUtils.query(TestUtils.TABLE_NAME_PERSON, "id=2");
assertEquals(1, result.get("count"));
assertEquals(1, ((List<?>) result.get("records")).size());
assertEquals("Marge", ((Map<?, ?>) ((List<?>) result.get("records")).get(0)).get("firstName"));

View File

@ -395,18 +395,18 @@ public class QJavalinScriptsHandler
String key = entry.getKey();
String value = entry.getValue().get(0);
if(key.equals("code"))
switch(key)
{
input.setCodeReference(new QCodeReference().withInlineCode(value).withCodeType(QCodeType.JAVA_SCRIPT));
}
else
{
inputValues.put(key, value);
case "code" -> input.setCodeReference(new QCodeReference().withInlineCode(value).withCodeType(QCodeType.JAVA_SCRIPT));
case "apiName" -> input.setApiName(value);
case "apiVersion" -> input.setApiVersion(value);
default -> inputValues.put(key, value);
}
}
TestScriptActionInterface scriptTester = QCodeLoader.getAdHoc(TestScriptActionInterface.class, scriptTesterCodeRef);
TestScriptOutput output = new TestScriptOutput();
scriptTester.execute(input, output);
QJavalinAccessLogger.logEndSuccess();