add testScriptProcess

This commit is contained in:
2023-03-09 16:39:14 -06:00
parent 7956c8f455
commit 054c34918d
3 changed files with 233 additions and 13 deletions

View File

@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.fields;
import java.io.Serializable; import java.io.Serializable;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum; import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum;
import com.kingsrook.qqq.backend.core.utils.Pair; import com.kingsrook.qqq.backend.core.utils.Pair;
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
/******************************************************************************* /*******************************************************************************
@ -105,14 +106,20 @@ public enum AdornmentType
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public interface SizeValues public enum Size
{ {
String WIDTH = "width"; XSMALL,
String XSMALL = "xsmall"; SMALL,
String SMALL = "small"; MEDIUM,
String MEDIUM = "medium"; LARGE,
String LARGE = "large"; XLARGE;
String XLARGE = "xlarge";
public FieldAdornment toAdornment()
{
return (new FieldAdornment(AdornmentType.SIZE, MapBuilder.of("width", name().toLowerCase())));
}
} }

View File

@ -62,6 +62,7 @@ import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwith
import com.kingsrook.qqq.backend.core.processes.implementations.scripts.RunRecordScriptExtractStep; import com.kingsrook.qqq.backend.core.processes.implementations.scripts.RunRecordScriptExtractStep;
import com.kingsrook.qqq.backend.core.processes.implementations.scripts.RunRecordScriptLoadStep; import com.kingsrook.qqq.backend.core.processes.implementations.scripts.RunRecordScriptLoadStep;
import com.kingsrook.qqq.backend.core.processes.implementations.scripts.StoreScriptRevisionProcessStep; import com.kingsrook.qqq.backend.core.processes.implementations.scripts.StoreScriptRevisionProcessStep;
import com.kingsrook.qqq.backend.core.processes.implementations.scripts.TestScriptProcessStep;
/******************************************************************************* /*******************************************************************************
@ -71,6 +72,7 @@ public class ScriptsMetaDataProvider
{ {
public static final String RUN_RECORD_SCRIPT_PROCESS_NAME = "runRecordScript"; public static final String RUN_RECORD_SCRIPT_PROCESS_NAME = "runRecordScript";
public static final String STORE_SCRIPT_REVISION_PROCESS_NAME = "storeScriptRevision"; public static final String STORE_SCRIPT_REVISION_PROCESS_NAME = "storeScriptRevision";
public static final String TEST_SCRIPT_PROCESS_NAME = "testScript";
public static final String SCRIPT_TYPE_NAME_RECORD = "Record Script"; public static final String SCRIPT_TYPE_NAME_RECORD = "Record Script";
@ -87,6 +89,7 @@ public class ScriptsMetaDataProvider
defineStandardScriptsWidgets(instance); defineStandardScriptsWidgets(instance);
instance.addPossibleValueSource(TablesPossibleValueSourceMetaDataProvider.defineTablesPossibleValueSource(instance)); instance.addPossibleValueSource(TablesPossibleValueSourceMetaDataProvider.defineTablesPossibleValueSource(instance));
instance.addProcess(defineStoreScriptRevisionProcess()); instance.addProcess(defineStoreScriptRevisionProcess());
instance.addProcess(defineTestScriptProcess());
instance.addProcess(defineRunRecordScriptProcess()); instance.addProcess(defineRunRecordScriptProcess());
} }
@ -108,6 +111,22 @@ public class ScriptsMetaDataProvider
/*******************************************************************************
**
*******************************************************************************/
private QProcessMetaData defineTestScriptProcess()
{
return (new QProcessMetaData()
.withName(TEST_SCRIPT_PROCESS_NAME)
.withStepList(List.of(
new QBackendStepMetaData()
.withName("main")
.withCode(new QCodeReference(TestScriptProcessStep.class))
)));
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -303,10 +322,15 @@ public class ScriptsMetaDataProvider
*******************************************************************************/ *******************************************************************************/
private QTableMetaData defineScriptTable(String backendName) throws QException private QTableMetaData defineScriptTable(String backendName) throws QException
{ {
return (defineStandardTable(backendName, Script.TABLE_NAME, Script.class) QTableMetaData tableMetaData = defineStandardTable(backendName, Script.TABLE_NAME, Script.class)
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "name", "scriptTypeId", "tableName", "currentScriptRevisionId"))) .withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id", "name", "scriptTypeId", "tableName", "currentScriptRevisionId")))
.withSection(new QFieldSection("contents", new QIcon().withName("data_object"), Tier.T2).withWidgetName("scriptViewer")) .withSection(new QFieldSection("contents", new QIcon().withName("data_object"), Tier.T2).withWidgetName("scriptViewer"))
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")))); .withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));
tableMetaData.getField("name").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
tableMetaData.getField("currentScriptRevisionId").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
return (tableMetaData);
} }
@ -342,6 +366,8 @@ public class ScriptsMetaDataProvider
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate"))); .withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));
tableMetaData.getField("contents").withFieldAdornment(new FieldAdornment(AdornmentType.CODE_EDITOR)); tableMetaData.getField("contents").withFieldAdornment(new FieldAdornment(AdornmentType.CODE_EDITOR));
tableMetaData.getField("scriptId").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
return (tableMetaData); return (tableMetaData);
} }
@ -352,14 +378,21 @@ public class ScriptsMetaDataProvider
*******************************************************************************/ *******************************************************************************/
private QTableMetaData defineScriptLogTable(String backendName) throws QException private QTableMetaData defineScriptLogTable(String backendName) throws QException
{ {
return (defineStandardTable(backendName, ScriptLog.TABLE_NAME, ScriptLog.class) QTableMetaData tableMetaData = defineStandardTable(backendName, ScriptLog.TABLE_NAME, ScriptLog.class)
.withRecordLabelFields(List.of("id")) .withRecordLabelFields(List.of("id"))
.withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id"))) .withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id")))
.withSection(new QFieldSection("script", new QIcon().withName("data_object"), Tier.T2, List.of("scriptId", "scriptRevisionId"))) .withSection(new QFieldSection("script", new QIcon().withName("data_object"), Tier.T2, List.of("scriptId", "scriptRevisionId")))
.withSection(new QFieldSection("timing", new QIcon().withName("schedule"), Tier.T2, List.of("startTimestamp", "endTimestamp", "runTimeMillis", "createDate", "modifyDate"))) .withSection(new QFieldSection("timing", new QIcon().withName("schedule"), Tier.T2, List.of("startTimestamp", "endTimestamp", "runTimeMillis", "createDate", "modifyDate")))
.withSection(new QFieldSection("error", "Error", new QIcon().withName("error_outline"), Tier.T2, List.of("hadError", "error"))) .withSection(new QFieldSection("error", "Error", new QIcon().withName("error_outline"), Tier.T2, List.of("hadError", "error")))
.withSection(new QFieldSection("inputOutput", "Input/Output", new QIcon().withName("chat"), Tier.T2, List.of("input", "output"))) .withSection(new QFieldSection("inputOutput", "Input/Output", new QIcon().withName("chat"), Tier.T2, List.of("input", "output")))
.withSection(new QFieldSection("lines", new QIcon().withName("horizontal_rule"), Tier.T2).withWidgetName(QJoinMetaData.makeInferredJoinName(ScriptLog.TABLE_NAME, ScriptLogLine.TABLE_NAME)))); .withSection(new QFieldSection("lines", new QIcon().withName("horizontal_rule"), Tier.T2).withWidgetName(QJoinMetaData.makeInferredJoinName(ScriptLog.TABLE_NAME, ScriptLogLine.TABLE_NAME)));
tableMetaData.getField("scriptId").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
tableMetaData.getField("scriptRevisionId").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
tableMetaData.getField("input").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
tableMetaData.getField("output").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
return (tableMetaData);
} }
@ -369,8 +402,12 @@ public class ScriptsMetaDataProvider
*******************************************************************************/ *******************************************************************************/
private QTableMetaData defineScriptLogLineTable(String backendName) throws QException private QTableMetaData defineScriptLogLineTable(String backendName) throws QException
{ {
return (defineStandardTable(backendName, ScriptLogLine.TABLE_NAME, ScriptLogLine.class) QTableMetaData tableMetaData = defineStandardTable(backendName, ScriptLogLine.TABLE_NAME, ScriptLogLine.class)
.withRecordLabelFields(List.of("id"))); .withRecordLabelFields(List.of("id"));
tableMetaData.getField("text").withFieldAdornment(AdornmentType.Size.XLARGE.toAdornment());
return (tableMetaData);
} }
} }

View File

@ -0,0 +1,176 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.processes.implementations.scripts;
import java.util.ArrayList;
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.scripts.RunAdHocRecordScriptAction;
import com.kingsrook.qqq.backend.core.actions.scripts.logging.BuildScriptLogAndScriptLogLineExecutionLogger;
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;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAdHocRecordScriptInput;
import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAdHocRecordScriptOutput;
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.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.code.AdHocScriptCodeReference;
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.model.scripts.ScriptType;
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/*******************************************************************************
** Action to test a script!
**
*******************************************************************************/
public class TestScriptProcessStep implements BackendStep
{
/*******************************************************************************
**
*******************************************************************************/
@Override
public void run(RunBackendStepInput input, RunBackendStepOutput output) throws QException
{
try
{
ActionHelper.validateSession(input);
////////////////
// get inputs //
////////////////
Integer scriptId = input.getValueInteger("scriptId");
String code = input.getValueString("code");
ScriptRevision scriptRevision = new ScriptRevision();
scriptRevision.setScriptId(scriptId);
scriptRevision.setContents(code);
BuildScriptLogAndScriptLogLineExecutionLogger executionLogger = new BuildScriptLogAndScriptLogLineExecutionLogger(null, null);
/////////////////////////////////////////////////////////////////
// lookup the script - figure out how to proceed based on type //
/////////////////////////////////////////////////////////////////
QRecord script = getScript(scriptId);
String scriptTypeName = getScriptTypeName(script);
if(ScriptsMetaDataProvider.SCRIPT_TYPE_NAME_RECORD.equals(scriptTypeName))
{
String tableName = script.getValueString("tableName");
QTableMetaData table = QContext.getQInstance().getTable(tableName);
if(table == null)
{
throw (new QException("Could not find table [" + tableName + "] for script"));
}
String recordPrimaryKeyList = input.getValueString("recordPrimaryKeyList");
if(!StringUtils.hasContent(recordPrimaryKeyList))
{
throw (new QException("Record primary key list was not given."));
}
QueryInput queryInput = new QueryInput();
queryInput.setTableName(tableName);
queryInput.setFilter(new QQueryFilter(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, recordPrimaryKeyList.split(","))));
QueryOutput queryOutput = new QueryAction().execute(queryInput);
if(CollectionUtils.nullSafeIsEmpty(queryOutput.getRecords()))
{
throw (new QException("No records were found by the given primary keys."));
}
RunAdHocRecordScriptInput runAdHocRecordScriptInput = new RunAdHocRecordScriptInput();
runAdHocRecordScriptInput.setRecordList(queryOutput.getRecords());
runAdHocRecordScriptInput.setLogger(executionLogger);
runAdHocRecordScriptInput.setCodeReference(new AdHocScriptCodeReference().withScriptRevisionRecord(scriptRevision.toQRecord()));
RunAdHocRecordScriptOutput runAdHocRecordScriptOutput = new RunAdHocRecordScriptOutput();
new RunAdHocRecordScriptAction().run(runAdHocRecordScriptInput, runAdHocRecordScriptOutput);
}
else
{
throw new QException("This process does not know how to test a script of type: " + scriptTypeName);
}
output.addValue("scriptLogLines", new ArrayList<>(executionLogger.getScriptLogLines()));
}
catch(Exception e)
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// is this the kind of exception meant here? or is it more for one thrown by the script execution? or are those the same?? //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
output.addValue("exception", e);
}
}
/*******************************************************************************
**
*******************************************************************************/
private QRecord getScript(Integer scriptId) throws QException
{
GetInput getScriptInput = new GetInput();
getScriptInput.setTableName(Script.TABLE_NAME);
getScriptInput.setPrimaryKey(scriptId);
GetOutput getScriptOutput = new GetAction().execute(getScriptInput);
if(getScriptOutput.getRecord() == null)
{
throw (new QException("Script was not found by id " + scriptId));
}
return (getScriptOutput.getRecord());
}
/*******************************************************************************
**
*******************************************************************************/
private String getScriptTypeName(QRecord script) throws QException
{
GetInput getScriptTypeInput = new GetInput();
getScriptTypeInput.setTableName(ScriptType.TABLE_NAME);
getScriptTypeInput.setPrimaryKey(script.getValueInteger("scriptTypeId"));
GetOutput getScriptTypeOutput = new GetAction().execute(getScriptTypeInput);
if(getScriptTypeOutput.getRecord() == null)
{
throw (new QException("Script Type was not found for script " + script.getValue("id")));
}
return (getScriptTypeOutput.getRecord().getValueString("name"));
}
}