mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Update to cache script and revision ids (could be better); new AccumulatingBuildScriptLogAndScriptLogLineExecutionLogger, to just do 2 inserts across multiple script runs; add child-log-lines to script log table
This commit is contained in:
@ -24,7 +24,11 @@ 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;
|
||||
@ -35,6 +39,7 @@ import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAssociatedScriptI
|
||||
import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAssociatedScriptOutput;
|
||||
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;
|
||||
@ -46,6 +51,8 @@ import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
|
||||
*******************************************************************************/
|
||||
public class RunAssociatedScriptAction
|
||||
{
|
||||
private Map<AssociatedScriptCodeReference, ScriptRevision> scriptRevisionCache = new HashMap<>();
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@ -54,6 +61,46 @@ 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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||
|
||||
output.setOutput(executeCodeOutput.getOutput());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private ScriptRevision getScriptRevision(RunAssociatedScriptInput input) throws QException
|
||||
{
|
||||
if(!scriptRevisionCache.containsKey(input.getCodeReference()))
|
||||
{
|
||||
Serializable scriptId = getScriptId(input);
|
||||
if(scriptId == null)
|
||||
{
|
||||
@ -69,20 +116,10 @@ public class RunAssociatedScriptAction
|
||||
}
|
||||
|
||||
ScriptRevision scriptRevision = getCurrentScriptRevision(input, script.getCurrentScriptRevisionId());
|
||||
|
||||
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput();
|
||||
executeCodeInput.setInput(new HashMap<>(input.getInputValues()));
|
||||
executeCodeInput.setContext(new HashMap<>());
|
||||
if(input.getOutputObject() != null)
|
||||
{
|
||||
executeCodeInput.getContext().put("output", input.getOutputObject());
|
||||
scriptRevisionCache.put(input.getCodeReference(), scriptRevision);
|
||||
}
|
||||
executeCodeInput.setCodeReference(new QCodeReference().withInlineCode(scriptRevision.getContents()).withCodeType(QCodeType.JAVA_SCRIPT)); // todo - code type as attribute of script!!
|
||||
executeCodeInput.setExecutionLogger(new StoreScriptLogAndScriptLogLineExecutionLogger(scriptRevision.getScriptId(), scriptRevision.getId()));
|
||||
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||
|
||||
output.setOutput(executeCodeOutput.getOutput());
|
||||
return scriptRevisionCache.get(input.getCodeReference());
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.actions.scripts.logging;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class AccumulatingBuildScriptLogAndScriptLogLineExecutionLogger extends BuildScriptLogAndScriptLogLineExecutionLogger implements ScriptExecutionLoggerInterface
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(AccumulatingBuildScriptLogAndScriptLogLineExecutionLogger.class);
|
||||
|
||||
private List<QRecord> scriptLogs = new ArrayList<>();
|
||||
private List<List<QRecord>> scriptLogLines = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AccumulatingBuildScriptLogAndScriptLogLineExecutionLogger()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void acceptExecutionStart(ExecuteCodeInput executeCodeInput)
|
||||
{
|
||||
super.acceptExecutionStart(executeCodeInput);
|
||||
super.setScriptLogLines(new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void acceptException(Exception exception)
|
||||
{
|
||||
accumulate(null, exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void acceptExecutionEnd(Serializable output)
|
||||
{
|
||||
accumulate(output, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void accumulate(Serializable output, Exception exception)
|
||||
{
|
||||
super.updateHeaderAtEnd(output, exception);
|
||||
scriptLogs.add(super.getScriptLog());
|
||||
scriptLogLines.add(new ArrayList<>(super.getScriptLogLines()));
|
||||
super.getScriptLogLines().clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void storeAndClear()
|
||||
{
|
||||
try
|
||||
{
|
||||
InsertInput insertInput = new InsertInput();
|
||||
insertInput.setTableName("scriptLog");
|
||||
insertInput.setRecords(scriptLogs);
|
||||
InsertOutput insertOutput = new InsertAction().execute(insertInput);
|
||||
|
||||
List<QRecord> flatScriptLogLines = new ArrayList<>();
|
||||
for(int i = 0; i < insertOutput.getRecords().size(); i++)
|
||||
{
|
||||
QRecord insertedScriptLog = insertOutput.getRecords().get(i);
|
||||
List<QRecord> subScriptLogLines = scriptLogLines.get(i);
|
||||
subScriptLogLines.forEach(r -> r.setValue("scriptLogId", insertedScriptLog.getValueInteger("id")));
|
||||
flatScriptLogLines.addAll(subScriptLogLines);
|
||||
}
|
||||
|
||||
insertInput = new InsertInput();
|
||||
insertInput.setTableName("scriptLogLine");
|
||||
insertInput.setRecords(flatScriptLogLines);
|
||||
new InsertAction().execute(insertInput);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error storing script logs", e);
|
||||
}
|
||||
|
||||
scriptLogs.clear();
|
||||
scriptLogLines.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setScriptId(Integer scriptId)
|
||||
{
|
||||
super.setScriptId(scriptId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setScriptRevisionId(Integer scriptRevisionId)
|
||||
{
|
||||
super.setScriptRevisionId(scriptRevisionId);
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
** scriptLogLine records - but doesn't insert them. e.g., useful for testing
|
||||
** (both in junit, and for users in-app).
|
||||
*******************************************************************************/
|
||||
public class BuildScriptLogAndScriptLogLineExecutionLogger implements QCodeExecutionLoggerInterface
|
||||
public class BuildScriptLogAndScriptLogLineExecutionLogger implements QCodeExecutionLoggerInterface, ScriptExecutionLoggerInterface
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(BuildScriptLogAndScriptLogLineExecutionLogger.class);
|
||||
|
||||
@ -217,4 +217,37 @@ public class BuildScriptLogAndScriptLogLineExecutionLogger implements QCodeExecu
|
||||
{
|
||||
this.scriptLog = scriptLog;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for scriptLogLines
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected void setScriptLogLines(List<QRecord> scriptLogLines)
|
||||
{
|
||||
this.scriptLogLines = scriptLogLines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setScriptId(Integer scriptId)
|
||||
{
|
||||
this.scriptId = scriptId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void setScriptRevisionId(Integer scriptRevisionId)
|
||||
{
|
||||
this.scriptRevisionId = scriptRevisionId;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.actions.scripts.logging;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface ScriptExecutionLoggerInterface
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
void setScriptId(Integer scriptId);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
void setScriptRevisionId(Integer scriptRevisionId);
|
||||
}
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.AssociatedScriptCodeReference;
|
||||
|
||||
@ -35,6 +36,7 @@ public class RunAssociatedScriptInput extends AbstractTableActionInput
|
||||
{
|
||||
private AssociatedScriptCodeReference codeReference;
|
||||
private Map<String, Serializable> inputValues;
|
||||
private QCodeExecutionLoggerInterface logger;
|
||||
|
||||
private Serializable outputObject;
|
||||
|
||||
@ -149,4 +151,35 @@ public class RunAssociatedScriptInput extends AbstractTableActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for logger
|
||||
*******************************************************************************/
|
||||
public QCodeExecutionLoggerInterface getLogger()
|
||||
{
|
||||
return (this.logger);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for logger
|
||||
*******************************************************************************/
|
||||
public void setLogger(QCodeExecutionLoggerInterface logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for logger
|
||||
*******************************************************************************/
|
||||
public RunAssociatedScriptInput withLogger(QCodeExecutionLoggerInterface logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.code;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -136,4 +137,34 @@ public class AssociatedScriptCodeReference extends QCodeReference
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if(this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
AssociatedScriptCodeReference that = (AssociatedScriptCodeReference) o;
|
||||
return Objects.equals(recordTable, that.recordTable) && Objects.equals(recordPrimaryKey, that.recordPrimaryKey) && Objects.equals(fieldName, that.fieldName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(recordTable, recordPrimaryKey, fieldName);
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,16 @@ package com.kingsrook.qqq.backend.core.model.scripts;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.ChildRecordListRenderer;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability;
|
||||
@ -51,6 +56,35 @@ public class ScriptsMetaDataProvider
|
||||
{
|
||||
defineStandardScriptsTables(instance, backendName, backendDetailEnricher);
|
||||
defineStandardScriptsPossibleValueSources(instance);
|
||||
defineStandardScriptsJoins(instance);
|
||||
defineStandardScriptsWidgets(instance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineStandardScriptsWidgets(QInstance instance)
|
||||
{
|
||||
instance.addWidget(ChildRecordListRenderer.widgetMetaDataBuilder(instance.getJoin(QJoinMetaData.makeInferredJoinName(ScriptLog.TABLE_NAME, ScriptLogLine.TABLE_NAME)))
|
||||
.withLabel("Log Lines")
|
||||
.getWidgetMetaData());
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineStandardScriptsJoins(QInstance instance)
|
||||
{
|
||||
instance.addJoin(new QJoinMetaData()
|
||||
.withType(JoinType.ONE_TO_MANY)
|
||||
.withLeftTable(ScriptLog.TABLE_NAME)
|
||||
.withRightTable(ScriptLogLine.TABLE_NAME)
|
||||
.withJoinOn(new JoinOn("id", "scriptLogId"))
|
||||
.withOrderBy(new QFilterOrderBy("id"))
|
||||
.withInferredName());
|
||||
}
|
||||
|
||||
|
||||
@ -201,7 +235,8 @@ public class ScriptsMetaDataProvider
|
||||
.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("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))));
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,6 +56,7 @@ public class MemoryRecordStore
|
||||
private static boolean collectStatistics = false;
|
||||
|
||||
public static final String STAT_QUERIES_RAN = "queriesRan";
|
||||
public static final String STAT_INSERTS_RAN = "insertsRan";
|
||||
|
||||
private static final Map<String, Integer> statistics = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
@ -173,6 +174,8 @@ public class MemoryRecordStore
|
||||
*******************************************************************************/
|
||||
public List<QRecord> insert(InsertInput input, boolean returnInsertedRecords)
|
||||
{
|
||||
incrementStatistic(input);
|
||||
|
||||
if(input.getRecords() == null)
|
||||
{
|
||||
return (new ArrayList<>());
|
||||
@ -324,6 +327,10 @@ public class MemoryRecordStore
|
||||
{
|
||||
incrementStatistic(STAT_QUERIES_RAN);
|
||||
}
|
||||
else if(input instanceof InsertInput)
|
||||
{
|
||||
incrementStatistic(STAT_INSERTS_RAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.AccumulatingBuildScriptLogAndScriptLogLineExecutionLogger;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
@ -45,10 +46,16 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.AssociatedScript;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.scripts.ScriptLog;
|
||||
import com.kingsrook.qqq.backend.core.model.scripts.ScriptsMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -57,15 +64,28 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
class RunAssociatedScriptActionTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void beforeAndAfterEach()
|
||||
{
|
||||
MemoryRecordStore.getInstance().reset();
|
||||
MemoryRecordStore.resetStatistics();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
QInstance instance = setupInstance();
|
||||
setupInstance();
|
||||
|
||||
insertScript(instance, 1, """
|
||||
insertScript(1, """
|
||||
return "Hello";
|
||||
""");
|
||||
|
||||
@ -86,6 +106,11 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
.isInstanceOf(QException.class)
|
||||
.hasRootCauseInstanceOf(ClassNotFoundException.class)
|
||||
.hasRootCauseMessage("com.kingsrook.qqq.languages.javascript.QJavaScriptExecutor");
|
||||
|
||||
/////////////////////////////////////
|
||||
// assert that a log was generated //
|
||||
/////////////////////////////////////
|
||||
assertEquals(1, TestUtils.queryTable(ScriptLog.TABLE_NAME).size());
|
||||
}
|
||||
|
||||
|
||||
@ -93,7 +118,61 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QInstance setupInstance() throws QException
|
||||
@Test
|
||||
void testOverridingLoggerAndCachingScriptLookups() throws QException
|
||||
{
|
||||
setupInstance();
|
||||
|
||||
insertScript(1, """
|
||||
return "Hello";
|
||||
""");
|
||||
|
||||
AccumulatingBuildScriptLogAndScriptLogLineExecutionLogger scriptLogger = new AccumulatingBuildScriptLogAndScriptLogLineExecutionLogger();
|
||||
|
||||
RunAssociatedScriptInput runAssociatedScriptInput = new RunAssociatedScriptInput();
|
||||
runAssociatedScriptInput.setInputValues(Map.of());
|
||||
runAssociatedScriptInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||
runAssociatedScriptInput.setLogger(scriptLogger);
|
||||
runAssociatedScriptInput.setCodeReference(new AssociatedScriptCodeReference()
|
||||
.withRecordTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
|
||||
.withRecordPrimaryKey(1)
|
||||
.withFieldName("testScriptId")
|
||||
);
|
||||
RunAssociatedScriptOutput runAssociatedScriptOutput = new RunAssociatedScriptOutput();
|
||||
|
||||
MemoryRecordStore.setCollectStatistics(true);
|
||||
RunAssociatedScriptAction runAssociatedScriptAction = new RunAssociatedScriptAction();
|
||||
|
||||
int N = 10;
|
||||
for(int i = 0; i < N; i++)
|
||||
{
|
||||
assertThatThrownBy(() -> runAssociatedScriptAction.run(runAssociatedScriptInput, runAssociatedScriptOutput));
|
||||
}
|
||||
|
||||
scriptLogger.storeAndClear();
|
||||
|
||||
/////////////////////////////////////
|
||||
// assert that logs were generated //
|
||||
/////////////////////////////////////
|
||||
assertEquals(N, TestUtils.queryTable(ScriptLog.TABLE_NAME).size());
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// and we should have just ran 2 inserts - for the log & logLines (even though empty) //
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertEquals(2, MemoryRecordStore.getStatistics().get(MemoryRecordStore.STAT_INSERTS_RAN));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// and we shouldn't have run N queries (which we would have (at least), if we would have built a new Action object inside the loop) //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assertThat(MemoryRecordStore.getStatistics().get(MemoryRecordStore.STAT_QUERIES_RAN)).isLessThan(N);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void setupInstance() throws QException
|
||||
{
|
||||
QInstance instance = QContext.getQInstance();
|
||||
QTableMetaData table = instance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
|
||||
@ -113,7 +192,6 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
TestUtils.insertRecords(instance, instance.getTable("scriptType"), List.of(
|
||||
new QRecord().withValue("id", 1).withValue("name", "Test Script Type")
|
||||
));
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +202,7 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
@Test
|
||||
void testRecordNotFound() throws QException
|
||||
{
|
||||
QInstance instance = setupInstance();
|
||||
setupInstance();
|
||||
|
||||
RunAssociatedScriptInput runAssociatedScriptInput = new RunAssociatedScriptInput();
|
||||
runAssociatedScriptInput.setInputValues(Map.of());
|
||||
@ -149,7 +227,7 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
@Test
|
||||
void testNoScriptInRecord() throws QException
|
||||
{
|
||||
QInstance instance = setupInstance();
|
||||
setupInstance();
|
||||
|
||||
RunAssociatedScriptInput runAssociatedScriptInput = new RunAssociatedScriptInput();
|
||||
runAssociatedScriptInput.setInputValues(Map.of());
|
||||
@ -174,7 +252,7 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
@Test
|
||||
void testBadScriptIdInRecord() throws QException
|
||||
{
|
||||
QInstance instance = setupInstance();
|
||||
setupInstance();
|
||||
|
||||
UpdateInput updateInput = new UpdateInput();
|
||||
updateInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||
@ -204,9 +282,9 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
@Test
|
||||
void testNoCurrentScriptRevisionOnScript() throws QException
|
||||
{
|
||||
QInstance instance = setupInstance();
|
||||
setupInstance();
|
||||
|
||||
insertScript(instance, 1, """
|
||||
insertScript(1, """
|
||||
return "Hello";
|
||||
""");
|
||||
|
||||
@ -244,9 +322,9 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
@Test
|
||||
void testBadCurrentScriptRevisionOnScript() throws QException
|
||||
{
|
||||
QInstance instance = setupInstance();
|
||||
setupInstance();
|
||||
|
||||
insertScript(instance, 1, """
|
||||
insertScript(1, """
|
||||
return "Hello";
|
||||
""");
|
||||
|
||||
@ -281,7 +359,7 @@ class RunAssociatedScriptActionTest extends BaseTest
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void insertScript(QInstance instance, Serializable recordId, String code) throws QException
|
||||
private void insertScript(Serializable recordId, String code) throws QException
|
||||
{
|
||||
StoreAssociatedScriptInput storeAssociatedScriptInput = new StoreAssociatedScriptInput();
|
||||
storeAssociatedScriptInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
|
||||
|
Reference in New Issue
Block a user