mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-20 14:10:44 +00:00
Merge branch 'feature/CTLE-422-api-for-scripts' into integration/sprint-25
# Conflicts: # qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/QueryAction.java
This commit is contained in:
@ -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());
|
||||
}
|
||||
|
||||
|
@ -50,4 +50,13 @@ public interface DeleteInterface
|
||||
return (false);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
** Specify whether this particular module's delete action can & should fetch
|
||||
** records before deleting them, e.g., for audits or "not-found-checks"
|
||||
*******************************************************************************/
|
||||
default boolean supportsPreFetchQuery()
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -37,4 +37,14 @@ public interface UpdateInterface
|
||||
**
|
||||
*******************************************************************************/
|
||||
UpdateOutput execute(UpdateInput updateInput) throws QException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Specify whether this particular module's update action can & should fetch
|
||||
** records before updating them, e.g., for audits or "not-found-checks"
|
||||
*******************************************************************************/
|
||||
default boolean supportsPreFetchQuery()
|
||||
{
|
||||
return (true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.actions.reporting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
@ -63,7 +64,7 @@ public class BufferedRecordPipe extends RecordPipe
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecord(QRecord record)
|
||||
public void addRecord(QRecord record) throws QException
|
||||
{
|
||||
buffer.add(record);
|
||||
if(buffer.size() >= bufferSize)
|
||||
@ -78,7 +79,7 @@ public class BufferedRecordPipe extends RecordPipe
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void finalFlush()
|
||||
public void finalFlush() throws QException
|
||||
{
|
||||
if(!buffer.isEmpty())
|
||||
{
|
||||
|
@ -26,10 +26,11 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.utils.SleepUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeConsumer;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -47,7 +48,7 @@ public class RecordPipe
|
||||
|
||||
private boolean isTerminated = false;
|
||||
|
||||
private Consumer<List<QRecord>> postRecordActions = null;
|
||||
private UnsafeConsumer<List<QRecord>, QException> postRecordActions = null;
|
||||
|
||||
/////////////////////////////////////
|
||||
// See usage below for explanation //
|
||||
@ -93,7 +94,7 @@ public class RecordPipe
|
||||
/*******************************************************************************
|
||||
** Add a record to the pipe. Will block if the pipe is full. Will noop if pipe is terminated.
|
||||
*******************************************************************************/
|
||||
public void addRecord(QRecord record)
|
||||
public void addRecord(QRecord record) throws QException
|
||||
{
|
||||
if(isTerminated)
|
||||
{
|
||||
@ -109,7 +110,7 @@ public class RecordPipe
|
||||
// (which we'll create as a field in this class, to avoid always re-constructing) //
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
singleRecordListForPostRecordActions.add(record);
|
||||
postRecordActions.accept(singleRecordListForPostRecordActions);
|
||||
postRecordActions.run(singleRecordListForPostRecordActions);
|
||||
record = singleRecordListForPostRecordActions.remove(0);
|
||||
}
|
||||
|
||||
@ -152,11 +153,11 @@ public class RecordPipe
|
||||
/*******************************************************************************
|
||||
** Add a list of records to the pipe. Will block if the pipe is full. Will noop if pipe is terminated.
|
||||
*******************************************************************************/
|
||||
public void addRecords(List<QRecord> records)
|
||||
public void addRecords(List<QRecord> records) throws QException
|
||||
{
|
||||
if(postRecordActions != null)
|
||||
{
|
||||
postRecordActions.accept(records);
|
||||
postRecordActions.run(records);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -207,7 +208,7 @@ public class RecordPipe
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setPostRecordActions(Consumer<List<QRecord>> postRecordActions)
|
||||
public void setPostRecordActions(UnsafeConsumer<List<QRecord>, QException> postRecordActions)
|
||||
{
|
||||
this.postRecordActions = postRecordActions;
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.reporting;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Subclass of BufferedRecordPipe, which ultimately sends records down to an
|
||||
** original RecordPipe.
|
||||
**
|
||||
** Meant to be used where: someone passed in a RecordPipe (so they have a reference
|
||||
** to it, and they are waiting to read from it), but the producer knows that
|
||||
** it will be better to buffer the records, so they want to use a buffered pipe
|
||||
** (but they still need the records to end up in the original pipe - thus -
|
||||
** it gets wrapped by an object of this class).
|
||||
*******************************************************************************/
|
||||
public class RecordPipeBufferedWrapper extends BufferedRecordPipe
|
||||
{
|
||||
private RecordPipe wrappedPipe;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor - uses default buffer size
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RecordPipeBufferedWrapper(RecordPipe wrappedPipe)
|
||||
{
|
||||
this.wrappedPipe = wrappedPipe;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor - customize buffer size.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RecordPipeBufferedWrapper(Integer bufferSize, RecordPipe wrappedPipe)
|
||||
{
|
||||
super(bufferSize);
|
||||
this.wrappedPipe = wrappedPipe;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** when it's time to actually add records into the pipe, actually add them
|
||||
** into the wrapped pipe!
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecords(List<QRecord> records) throws QException
|
||||
{
|
||||
wrappedPipe.addRecords(records);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
@ -25,13 +25,21 @@ package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.Log4jCodeExecutionLogger;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.ScriptExecutionLoggerInterface;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.StoreScriptLogAndScriptLogLineExecutionLogger;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QCodeException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.scripts.AbstractRunScriptInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.scripts.ExecuteCodeOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -49,6 +57,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
*******************************************************************************/
|
||||
public class ExecuteCodeAction
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ExecuteCodeAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@ -68,10 +79,10 @@ public class ExecuteCodeAction
|
||||
try
|
||||
{
|
||||
String languageExecutor = switch(codeReference.getCodeType())
|
||||
{
|
||||
case JAVA -> "com.kingsrook.qqq.backend.core.actions.scripts.QJavaExecutor";
|
||||
case JAVA_SCRIPT -> "com.kingsrook.qqq.languages.javascript.QJavaScriptExecutor";
|
||||
};
|
||||
{
|
||||
case JAVA -> "com.kingsrook.qqq.backend.core.actions.scripts.QJavaExecutor";
|
||||
case JAVA_SCRIPT -> "com.kingsrook.qqq.languages.javascript.QJavaScriptExecutor";
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends QCodeExecutor> executorClass = (Class<? extends QCodeExecutor>) Class.forName(languageExecutor);
|
||||
@ -108,6 +119,91 @@ 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<>());
|
||||
|
||||
Map<String, Serializable> context = executeCodeInput.getContext();
|
||||
if(input.getOutputObject() != null)
|
||||
{
|
||||
context.put("output", input.getOutputObject());
|
||||
}
|
||||
|
||||
if(input.getScriptUtils() != null)
|
||||
{
|
||||
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(context, 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).
|
||||
*******************************************************************************/
|
||||
public static void addApiUtilityToContext(Map<String, Serializable> context, ScriptRevision scriptRevision)
|
||||
{
|
||||
if(!StringUtils.hasContent(scriptRevision.getApiName()) || !StringUtils.hasContent(scriptRevision.getApiVersion()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Class<?> apiScriptUtilsClass = Class.forName("com.kingsrook.qqq.api.utils.ApiScriptUtils");
|
||||
Object apiScriptUtilsObject = apiScriptUtilsClass.getConstructor(String.class, String.class).newInstance(scriptRevision.getApiName(), scriptRevision.getApiVersion());
|
||||
context.put("api", (Serializable) apiScriptUtilsObject);
|
||||
}
|
||||
catch(ClassNotFoundException e)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// this is the only exception we're kinda expecting here - so catch for it specifically, and just log.trace - others, warn //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
LOG.trace("Couldn't load ApiScriptUtils class - qqq-middleware-api not on the classpath?");
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error adding api utility to script context", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void setExecutionLoggerInExecuteCodeInput(AbstractRunScriptInput<?> input, ScriptRevision scriptRevision, ExecuteCodeInput executeCodeInput)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// let caller supply a logger, or by default use StoreScriptLogAndScriptLogLineExecutionLogger //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
QCodeExecutionLoggerInterface executionLogger = Objects.requireNonNullElseGet(input.getLogger(), () -> new StoreScriptLogAndScriptLogLineExecutionLogger(scriptRevision.getScriptId(), scriptRevision.getId()));
|
||||
executeCodeInput.setExecutionLogger(executionLogger);
|
||||
if(executionLogger instanceof ScriptExecutionLoggerInterface scriptExecutionLoggerInterface)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if logger is aware of scripts (as opposed to a generic CodeExecution logger), give it the ids. //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
scriptExecutionLoggerInterface.setScriptId(scriptRevision.getScriptId());
|
||||
scriptExecutionLoggerInterface.setScriptRevisionId(scriptRevision.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -22,15 +22,14 @@
|
||||
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;
|
||||
@ -49,8 +48,6 @@ 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;
|
||||
@ -96,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());
|
||||
}
|
||||
@ -112,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());
|
||||
}
|
||||
|
||||
executeCodeInput.getContext().put("api", new ScriptApi());
|
||||
|
||||
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)
|
||||
{
|
||||
@ -158,6 +127,37 @@ public class RunAdHocRecordScriptAction
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static ArrayList<? extends Serializable> getRecordsForScript(RunAdHocRecordScriptInput input, ScriptRevision scriptRevision)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> apiScriptUtilsClass = Class.forName("com.kingsrook.qqq.api.utils.ApiScriptUtils");
|
||||
Method qRecordListToApiRecordList = apiScriptUtilsClass.getMethod("qRecordListToApiRecordList", List.class, String.class, String.class, String.class);
|
||||
Object apiRecordList = qRecordListToApiRecordList.invoke(null, input.getRecordList(), input.getTableName(), scriptRevision.getApiName(), scriptRevision.getApiVersion());
|
||||
|
||||
// noinspection unchecked
|
||||
return (ArrayList<? extends Serializable>) apiRecordList;
|
||||
}
|
||||
catch(ClassNotFoundException e)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 converting QRecord list to api record list", e);
|
||||
}
|
||||
|
||||
return (new ArrayList<>(input.getRecordList()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -25,11 +25,7 @@ package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.QCodeExecutionLoggerInterface;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.ScriptExecutionLoggerInterface;
|
||||
import com.kingsrook.qqq.backend.core.actions.scripts.logging.StoreScriptLogAndScriptLogLineExecutionLogger;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
@ -40,8 +36,6 @@ import com.kingsrook.qqq.backend.core.model.actions.scripts.RunAssociatedScriptO
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.AssociatedScriptCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||
import com.kingsrook.qqq.backend.core.model.scripts.Script;
|
||||
import com.kingsrook.qqq.backend.core.model.scripts.ScriptRevision;
|
||||
|
||||
@ -54,6 +48,7 @@ public class RunAssociatedScriptAction
|
||||
private Map<AssociatedScriptCodeReference, ScriptRevision> scriptRevisionCache = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -61,35 +56,12 @@ public class RunAssociatedScriptAction
|
||||
{
|
||||
ActionHelper.validateSession(input);
|
||||
|
||||
ScriptRevision scriptRevision = getScriptRevision(input);
|
||||
ScriptRevision scriptRevision = getScriptRevision(input);
|
||||
ExecuteCodeInput executeCodeInput = ExecuteCodeAction.setupExecuteCodeInput(input, scriptRevision);
|
||||
|
||||
ExecuteCodeInput executeCodeInput = new ExecuteCodeInput();
|
||||
executeCodeInput.setInput(new HashMap<>(input.getInputValues()));
|
||||
executeCodeInput.setContext(new HashMap<>());
|
||||
if(input.getOutputObject() != null)
|
||||
if(input.getAssociatedScriptContextPrimerInterface() != 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());
|
||||
input.getAssociatedScriptContextPrimerInterface().primeContext(executeCodeInput, scriptRevision);
|
||||
}
|
||||
|
||||
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
setupTestScriptInput(input, executeCodeInput);
|
||||
|
||||
ExecuteCodeOutput executeCodeOutput = new ExecuteCodeOutput();
|
||||
|
||||
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();
|
||||
|
||||
ExecuteCodeAction.addApiUtilityToContext(executeCodeInput.getContext(), scriptRevision);
|
||||
|
||||
new ExecuteCodeAction().run(executeCodeInput, executeCodeOutput);
|
||||
output.setOutputObject(processTestScriptOutput(executeCodeOutput));
|
||||
}
|
||||
|
@ -76,13 +76,13 @@ public class DeleteAction
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(deleteInput.getBackend());
|
||||
DeleteInterface deleteInterface = qModule.getDeleteInterface();
|
||||
|
||||
if(CollectionUtils.nullSafeHasContents(deleteInput.getPrimaryKeys()) && deleteInput.getQueryFilter() != null)
|
||||
{
|
||||
throw (new QException("A delete request may not contain both a list of primary keys and a query filter."));
|
||||
}
|
||||
|
||||
DeleteInterface deleteInterface = qModule.getDeleteInterface();
|
||||
if(deleteInput.getQueryFilter() != null && !deleteInterface.supportsQueryFilterInput())
|
||||
{
|
||||
LOG.info("Querying for primary keys, for backend module " + qModule.getBackendType() + " which does not support queryFilter input for deletes");
|
||||
@ -99,8 +99,8 @@ public class DeleteAction
|
||||
}
|
||||
}
|
||||
|
||||
List<QRecord> recordListForAudit = getRecordListForAuditIfNeeded(deleteInput);
|
||||
List<QRecord> recordsWithValidationErrors = validateRecordsExistAndCanBeAccessed(deleteInput, recordListForAudit);
|
||||
List<QRecord> recordListForAudit = deleteInterface.supportsPreFetchQuery() ? getRecordListForAuditIfNeeded(deleteInput) : new ArrayList<>();
|
||||
List<QRecord> recordsWithValidationErrors = deleteInterface.supportsPreFetchQuery() ? validateRecordsExistAndCanBeAccessed(deleteInput, recordListForAudit) : new ArrayList<>();
|
||||
|
||||
DeleteOutput deleteOutput = deleteInterface.execute(deleteInput);
|
||||
|
||||
|
@ -35,6 +35,7 @@ import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCusto
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.BufferedRecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipeBufferedWrapper;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
@ -85,14 +86,15 @@ public class QueryAction
|
||||
if(queryInput.getRecordPipe() != null)
|
||||
{
|
||||
queryInput.getRecordPipe().setPostRecordActions(this::postRecordActions);
|
||||
}
|
||||
|
||||
if(queryInput.getIncludeAssociations() && queryInput.getRecordPipe() != null)
|
||||
{
|
||||
//////////////////////////////////////////////
|
||||
// todo - support this in the future maybe? //
|
||||
//////////////////////////////////////////////
|
||||
throw (new QException("Associations may not be fetched into a RecordPipe."));
|
||||
if(queryInput.getIncludeAssociations())
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the user requested to include associations, it's important that that is buffered, //
|
||||
// (for performance reasons), so, wrap the user's pipe with a buffer //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
queryInput.setRecordPipe(new RecordPipeBufferedWrapper(queryInput.getRecordPipe()));
|
||||
}
|
||||
}
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
@ -111,11 +113,6 @@ public class QueryAction
|
||||
postRecordActions(queryOutput.getRecords());
|
||||
}
|
||||
|
||||
if(queryInput.getIncludeAssociations())
|
||||
{
|
||||
manageAssociations(queryInput, queryOutput);
|
||||
}
|
||||
|
||||
return queryOutput;
|
||||
}
|
||||
|
||||
@ -124,8 +121,9 @@ public class QueryAction
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void manageAssociations(QueryInput queryInput, QueryOutput queryOutput) throws QException
|
||||
private void manageAssociations(QueryInput queryInput, List<QRecord> queryOutputRecords) throws QException
|
||||
{
|
||||
LOG.info("In manageAssociations for " + queryInput.getTableName() + " with " + queryOutputRecords.size() + " records");
|
||||
QTableMetaData table = queryInput.getTable();
|
||||
for(Association association : CollectionUtils.nonNullList(table.getAssociations()))
|
||||
{
|
||||
@ -149,7 +147,7 @@ public class QueryAction
|
||||
{
|
||||
JoinOn joinOn = join.getJoinOns().get(0);
|
||||
Set<Serializable> values = new HashSet<>();
|
||||
for(QRecord record : queryOutput.getRecords())
|
||||
for(QRecord record : queryOutputRecords)
|
||||
{
|
||||
Serializable value = record.getValue(joinOn.getLeftField());
|
||||
values.add(value);
|
||||
@ -161,7 +159,7 @@ public class QueryAction
|
||||
{
|
||||
filter.setBooleanOperator(QQueryFilter.BooleanOperator.OR);
|
||||
|
||||
for(QRecord record : queryOutput.getRecords())
|
||||
for(QRecord record : queryOutputRecords)
|
||||
{
|
||||
QQueryFilter subFilter = new QQueryFilter();
|
||||
filter.addSubFilter(subFilter);
|
||||
@ -229,7 +227,7 @@ public class QueryAction
|
||||
** not one created via List.of()). This may include setting display values,
|
||||
** translating possible values, and running post-record customizations.
|
||||
*******************************************************************************/
|
||||
public void postRecordActions(List<QRecord> records)
|
||||
public void postRecordActions(List<QRecord> records) throws QException
|
||||
{
|
||||
if(this.postQueryRecordCustomizer.isPresent())
|
||||
{
|
||||
@ -250,6 +248,11 @@ public class QueryAction
|
||||
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), records);
|
||||
}
|
||||
|
||||
if(queryInput.getIncludeAssociations())
|
||||
{
|
||||
manageAssociations(queryInput, records);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
// mask any password fields //
|
||||
//////////////////////////////
|
||||
|
@ -33,6 +33,7 @@ import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.audits.DMLAuditAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
|
||||
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationStatusUpdater;
|
||||
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.helpers.ValidateRecordSecurityLockHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.ValueBehaviorApplier;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
@ -87,18 +88,24 @@ public class UpdateAction
|
||||
ValueBehaviorApplier.applyFieldBehaviors(updateInput.getInstance(), updateInput.getTable(), updateInput.getRecords());
|
||||
// todo - need to handle records with errors coming out of here...
|
||||
|
||||
List<QRecord> oldRecordList = getOldRecordListForAuditIfNeeded(updateInput);
|
||||
|
||||
QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher();
|
||||
QBackendModuleInterface qModule = qBackendModuleDispatcher.getQBackendModule(updateInput.getBackend());
|
||||
UpdateInterface updateInterface = qModule.getUpdateInterface();
|
||||
|
||||
List<QRecord> oldRecordList = updateInterface.supportsPreFetchQuery() ? getOldRecordListForAuditIfNeeded(updateInput) : new ArrayList<>();
|
||||
|
||||
validatePrimaryKeysAreGiven(updateInput);
|
||||
validateRecordsExistAndCanBeAccessed(updateInput, oldRecordList);
|
||||
|
||||
if(updateInterface.supportsPreFetchQuery())
|
||||
{
|
||||
validateRecordsExistAndCanBeAccessed(updateInput, oldRecordList);
|
||||
}
|
||||
|
||||
validateRequiredFields(updateInput);
|
||||
ValidateRecordSecurityLockHelper.validateSecurityFields(updateInput.getTable(), updateInput.getRecords(), ValidateRecordSecurityLockHelper.Action.UPDATE);
|
||||
|
||||
// todo pre-customization - just get to modify the request?
|
||||
UpdateOutput updateOutput = qModule.getUpdateInterface().execute(updateInput);
|
||||
UpdateOutput updateOutput = updateInterface.execute(updateInput);
|
||||
// todo post-customization - can do whatever w/ the result if you want
|
||||
|
||||
List<String> errors = updateOutput.getRecords().stream().flatMap(r -> r.getErrors().stream()).toList();
|
||||
|
@ -261,7 +261,7 @@ public class ValidateRecordSecurityLockHelper
|
||||
QSecurityKeyType securityKeyType = QContext.getQInstance().getSecurityKeyType(recordSecurityLock.getSecurityKeyType());
|
||||
if(StringUtils.hasContent(securityKeyType.getAllAccessKeyName()) && QContext.getQSession().hasSecurityKeyValue(securityKeyType.getAllAccessKeyName(), true, QFieldType.BOOLEAN))
|
||||
{
|
||||
LOG.debug("Session has " + securityKeyType.getAllAccessKeyName() + " - not checking this lock.");
|
||||
LOG.trace("Session has " + securityKeyType.getAllAccessKeyName() + " - not checking this lock.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -31,6 +31,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.AbstractQFieldMapping;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
@ -61,7 +62,7 @@ public class CsvToQRecordAdapter
|
||||
** using a given mapping.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void buildRecordsFromCsv(RecordPipe recordPipe, String csv, QTableMetaData table, AbstractQFieldMapping<?> mapping, Consumer<QRecord> recordCustomizer)
|
||||
public void buildRecordsFromCsv(RecordPipe recordPipe, String csv, QTableMetaData table, AbstractQFieldMapping<?> mapping, Consumer<QRecord> recordCustomizer) throws QException
|
||||
{
|
||||
buildRecordsFromCsv(new InputWrapper().withRecordPipe(recordPipe).withCsv(csv).withTable(table).withMapping(mapping).withRecordCustomizer(recordCustomizer));
|
||||
}
|
||||
@ -73,7 +74,7 @@ public class CsvToQRecordAdapter
|
||||
** using a given mapping.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public List<QRecord> buildRecordsFromCsv(String csv, QTableMetaData table, AbstractQFieldMapping<?> mapping)
|
||||
public List<QRecord> buildRecordsFromCsv(String csv, QTableMetaData table, AbstractQFieldMapping<?> mapping) throws QException
|
||||
{
|
||||
buildRecordsFromCsv(new InputWrapper().withCsv(csv).withTable(table).withMapping(mapping));
|
||||
return (recordList);
|
||||
@ -87,7 +88,7 @@ public class CsvToQRecordAdapter
|
||||
**
|
||||
** todo - meta-data validation, type handling
|
||||
*******************************************************************************/
|
||||
public void buildRecordsFromCsv(InputWrapper inputWrapper)
|
||||
public void buildRecordsFromCsv(InputWrapper inputWrapper) throws QException
|
||||
{
|
||||
String csv = inputWrapper.getCsv();
|
||||
AbstractQFieldMapping<?> mapping = inputWrapper.getMapping();
|
||||
@ -297,7 +298,7 @@ public class CsvToQRecordAdapter
|
||||
/*******************************************************************************
|
||||
** Add a record - either to the pipe, or list, whichever we're building.
|
||||
*******************************************************************************/
|
||||
private void addRecord(QRecord record)
|
||||
private void addRecord(QRecord record) throws QException
|
||||
{
|
||||
if(recordPipe != null)
|
||||
{
|
||||
|
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.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.QCodeReference;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Base class for input wrappers that end up running scripts (ExecuteCodeAction)
|
||||
*******************************************************************************/
|
||||
public class AbstractRunScriptInput<C extends QCodeReference> extends AbstractTableActionInput
|
||||
{
|
||||
private C codeReference;
|
||||
private Map<String, Serializable> inputValues;
|
||||
private QCodeExecutionLoggerInterface logger;
|
||||
private Serializable outputObject;
|
||||
private Serializable scriptUtils;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for codeReference
|
||||
*******************************************************************************/
|
||||
public C getCodeReference()
|
||||
{
|
||||
return (this.codeReference);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for codeReference
|
||||
*******************************************************************************/
|
||||
public void setCodeReference(C codeReference)
|
||||
{
|
||||
this.codeReference = codeReference;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for codeReference
|
||||
*******************************************************************************/
|
||||
public AbstractRunScriptInput<C> withCodeReference(C codeReference)
|
||||
{
|
||||
this.codeReference = codeReference;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for inputValues
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getInputValues()
|
||||
{
|
||||
return (this.inputValues);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for inputValues
|
||||
*******************************************************************************/
|
||||
public void setInputValues(Map<String, Serializable> inputValues)
|
||||
{
|
||||
this.inputValues = inputValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for inputValues
|
||||
*******************************************************************************/
|
||||
public AbstractRunScriptInput<C> withInputValues(Map<String, Serializable> inputValues)
|
||||
{
|
||||
this.inputValues = inputValues;
|
||||
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 AbstractRunScriptInput<C> withLogger(QCodeExecutionLoggerInterface logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for outputObject
|
||||
*******************************************************************************/
|
||||
public Serializable getOutputObject()
|
||||
{
|
||||
return (this.outputObject);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for outputObject
|
||||
*******************************************************************************/
|
||||
public void setOutputObject(Serializable outputObject)
|
||||
{
|
||||
this.outputObject = outputObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for outputObject
|
||||
*******************************************************************************/
|
||||
public AbstractRunScriptInput<C> withOutputObject(Serializable outputObject)
|
||||
{
|
||||
this.outputObject = outputObject;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for scriptUtils
|
||||
*******************************************************************************/
|
||||
public Serializable getScriptUtils()
|
||||
{
|
||||
return (this.scriptUtils);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for scriptUtils
|
||||
*******************************************************************************/
|
||||
public void setScriptUtils(Serializable scriptUtils)
|
||||
{
|
||||
this.scriptUtils = scriptUtils;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for scriptUtils
|
||||
*******************************************************************************/
|
||||
public AbstractRunScriptInput<C> withScriptUtils(Serializable scriptUtils)
|
||||
{
|
||||
this.scriptUtils = scriptUtils;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -24,9 +24,6 @@ package com.kingsrook.qqq.backend.core.model.actions.scripts;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
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.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.AdHocScriptCodeReference;
|
||||
|
||||
@ -34,18 +31,10 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.AdHocScriptCodeReferen
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RunAdHocRecordScriptInput extends AbstractTableActionInput
|
||||
public class RunAdHocRecordScriptInput extends AbstractRunScriptInput<AdHocScriptCodeReference>
|
||||
{
|
||||
private AdHocScriptCodeReference codeReference;
|
||||
private Map<String, Serializable> inputValues;
|
||||
private List<Serializable> recordPrimaryKeyList; // can either supply recordList, or recordPrimaryKeyList
|
||||
private List<QRecord> recordList;
|
||||
private String tableName;
|
||||
private QCodeExecutionLoggerInterface logger;
|
||||
|
||||
private Serializable outputObject;
|
||||
|
||||
private Serializable scriptUtils;
|
||||
private List<Serializable> recordPrimaryKeyList; // can either supply recordList, or recordPrimaryKeyList
|
||||
private List<QRecord> recordList;
|
||||
|
||||
|
||||
|
||||
@ -58,189 +47,6 @@ public class RunAdHocRecordScriptInput extends AbstractTableActionInput
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for inputValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getInputValues()
|
||||
{
|
||||
return inputValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for inputValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setInputValues(Map<String, Serializable> inputValues)
|
||||
{
|
||||
this.inputValues = inputValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for inputValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunAdHocRecordScriptInput withInputValues(Map<String, Serializable> inputValues)
|
||||
{
|
||||
this.inputValues = inputValues;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for outputObject
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getOutputObject()
|
||||
{
|
||||
return outputObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for outputObject
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setOutputObject(Serializable outputObject)
|
||||
{
|
||||
this.outputObject = outputObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for outputObject
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunAdHocRecordScriptInput withOutputObject(Serializable outputObject)
|
||||
{
|
||||
this.outputObject = outputObject;
|
||||
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 RunAdHocRecordScriptInput withLogger(QCodeExecutionLoggerInterface logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for scriptUtils
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getScriptUtils()
|
||||
{
|
||||
return scriptUtils;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for scriptUtils
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setScriptUtils(Serializable scriptUtils)
|
||||
{
|
||||
this.scriptUtils = scriptUtils;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for codeReference
|
||||
*******************************************************************************/
|
||||
public AdHocScriptCodeReference getCodeReference()
|
||||
{
|
||||
return (this.codeReference);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for codeReference
|
||||
*******************************************************************************/
|
||||
public void setCodeReference(AdHocScriptCodeReference codeReference)
|
||||
{
|
||||
this.codeReference = codeReference;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for codeReference
|
||||
*******************************************************************************/
|
||||
public RunAdHocRecordScriptInput withCodeReference(AdHocScriptCodeReference codeReference)
|
||||
{
|
||||
this.codeReference = codeReference;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return (this.tableName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
*******************************************************************************/
|
||||
public RunAdHocRecordScriptInput withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for recordList
|
||||
*******************************************************************************/
|
||||
|
@ -22,187 +22,46 @@
|
||||
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.actions.scripts.AssociatedScriptContextPrimerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.AssociatedScriptCodeReference;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class RunAssociatedScriptInput extends AbstractTableActionInput
|
||||
public class RunAssociatedScriptInput extends AbstractRunScriptInput<AssociatedScriptCodeReference>
|
||||
{
|
||||
private AssociatedScriptCodeReference codeReference;
|
||||
private Map<String, Serializable> inputValues;
|
||||
private QCodeExecutionLoggerInterface logger;
|
||||
|
||||
private Serializable outputObject;
|
||||
|
||||
private Serializable scriptUtils;
|
||||
private AssociatedScriptContextPrimerInterface associatedScriptContextPrimerInterface;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
** Getter for associatedScriptContextPrimerInterface
|
||||
*******************************************************************************/
|
||||
public RunAssociatedScriptInput()
|
||||
public AssociatedScriptContextPrimerInterface getAssociatedScriptContextPrimerInterface()
|
||||
{
|
||||
return (this.associatedScriptContextPrimerInterface);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for codeReference
|
||||
**
|
||||
** Setter for associatedScriptContextPrimerInterface
|
||||
*******************************************************************************/
|
||||
public AssociatedScriptCodeReference getCodeReference()
|
||||
public void setAssociatedScriptContextPrimerInterface(AssociatedScriptContextPrimerInterface associatedScriptContextPrimerInterface)
|
||||
{
|
||||
return codeReference;
|
||||
this.associatedScriptContextPrimerInterface = associatedScriptContextPrimerInterface;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for codeReference
|
||||
**
|
||||
** Fluent setter for associatedScriptContextPrimerInterface
|
||||
*******************************************************************************/
|
||||
public void setCodeReference(AssociatedScriptCodeReference codeReference)
|
||||
public RunAssociatedScriptInput withAssociatedScriptContextPrimerInterface(AssociatedScriptContextPrimerInterface associatedScriptContextPrimerInterface)
|
||||
{
|
||||
this.codeReference = codeReference;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for codeReference
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunAssociatedScriptInput withCodeReference(AssociatedScriptCodeReference codeReference)
|
||||
{
|
||||
this.codeReference = codeReference;
|
||||
this.associatedScriptContextPrimerInterface = associatedScriptContextPrimerInterface;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for inputValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Map<String, Serializable> getInputValues()
|
||||
{
|
||||
return inputValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for inputValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setInputValues(Map<String, Serializable> inputValues)
|
||||
{
|
||||
this.inputValues = inputValues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for inputValues
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunAssociatedScriptInput withInputValues(Map<String, Serializable> inputValues)
|
||||
{
|
||||
this.inputValues = inputValues;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for outputObject
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getOutputObject()
|
||||
{
|
||||
return outputObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for outputObject
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setOutputObject(Serializable outputObject)
|
||||
{
|
||||
this.outputObject = outputObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for outputObject
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunAssociatedScriptInput withOutputObject(Serializable outputObject)
|
||||
{
|
||||
this.outputObject = outputObject;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for scriptUtils
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getScriptUtils()
|
||||
{
|
||||
return scriptUtils;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for scriptUtils
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setScriptUtils(Serializable scriptUtils)
|
||||
{
|
||||
this.scriptUtils = scriptUtils;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
@ -63,7 +64,7 @@ public class QueryOutput extends AbstractActionOutput implements Serializable
|
||||
** that could be read asynchronously, at any time, by another thread - SO - only
|
||||
** completely populated records should be passed into this method.
|
||||
*******************************************************************************/
|
||||
public void addRecord(QRecord record)
|
||||
public void addRecord(QRecord record) throws QException
|
||||
{
|
||||
storage.addRecord(record);
|
||||
}
|
||||
@ -73,7 +74,7 @@ public class QueryOutput extends AbstractActionOutput implements Serializable
|
||||
/*******************************************************************************
|
||||
** add a list of records to this output
|
||||
*******************************************************************************/
|
||||
public void addRecords(List<QRecord> records)
|
||||
public void addRecords(List<QRecord> records) throws QException
|
||||
{
|
||||
storage.addRecords(records);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query;
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
@ -53,7 +54,7 @@ class QueryOutputRecordPipe implements QueryOutputStorageInterface
|
||||
** add a record to this output
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecord(QRecord record)
|
||||
public void addRecord(QRecord record) throws QException
|
||||
{
|
||||
recordPipe.addRecord(record);
|
||||
}
|
||||
@ -64,7 +65,7 @@ class QueryOutputRecordPipe implements QueryOutputStorageInterface
|
||||
** add a list of records to this output
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void addRecords(List<QRecord> records)
|
||||
public void addRecords(List<QRecord> records) throws QException
|
||||
{
|
||||
recordPipe.addRecords(records);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.query;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
|
||||
|
||||
@ -36,13 +37,13 @@ interface QueryOutputStorageInterface
|
||||
/*******************************************************************************
|
||||
** add a records to this output
|
||||
*******************************************************************************/
|
||||
void addRecord(QRecord record);
|
||||
void addRecord(QRecord record) throws QException;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** add a list of records to this output
|
||||
*******************************************************************************/
|
||||
void addRecords(List<QRecord> records);
|
||||
void addRecords(List<QRecord> records) throws QException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Get all stored records
|
||||
|
@ -38,6 +38,12 @@ public class TableAutomationAction
|
||||
private Integer priority = 500;
|
||||
private QQueryFilter filter;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// flag that will cause the records to cause their associations to be //
|
||||
// fetched, when they are looked up for passing into the action //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
private boolean includeRecordAssociations = false;
|
||||
|
||||
private Map<String, Serializable> values;
|
||||
|
||||
////////////////////////////////
|
||||
@ -292,4 +298,35 @@ public class TableAutomationAction
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for includeRecordAssociations
|
||||
*******************************************************************************/
|
||||
public boolean getIncludeRecordAssociations()
|
||||
{
|
||||
return (this.includeRecordAssociations);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for includeRecordAssociations
|
||||
*******************************************************************************/
|
||||
public void setIncludeRecordAssociations(boolean includeRecordAssociations)
|
||||
{
|
||||
this.includeRecordAssociations = includeRecordAssociations;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for includeRecordAssociations
|
||||
*******************************************************************************/
|
||||
public TableAutomationAction withIncludeRecordAssociations(boolean includeRecordAssociations)
|
||||
{
|
||||
this.includeRecordAssociations = includeRecordAssociations;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -389,6 +389,23 @@ public class ScriptsMetaDataProvider
|
||||
tableMetaData.getField("contents").withFieldAdornment(new FieldAdornment(AdornmentType.CODE_EDITOR).withValue(AdornmentType.CodeEditorValues.languageMode("javascript")));
|
||||
tableMetaData.getField("scriptId").withFieldAdornment(AdornmentType.Size.LARGE.toAdornment());
|
||||
|
||||
try
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the api module is loaded, then add a section to the table for the api name & version fields //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Class.forName("com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataProvider");
|
||||
tableMetaData.getSections().add(1, new QFieldSection("api", "API", new QIcon().withName("code"), Tier.T2, List.of("apiName", "apiVersion")));
|
||||
}
|
||||
catch(ClassNotFoundException e)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if the api module is not loaded, then make sure we don't have these fields in our scripts table //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
tableMetaData.getFields().remove("apiName");
|
||||
tableMetaData.getFields().remove("apiVersion");
|
||||
}
|
||||
|
||||
return (tableMetaData);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
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;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -43,7 +44,16 @@ public class MemoryQueryAction implements QueryInterface
|
||||
try
|
||||
{
|
||||
QueryOutput queryOutput = new QueryOutput(queryInput);
|
||||
queryOutput.addRecords(MemoryRecordStore.getInstance().query(queryInput));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// add the records to the output one-by-one -- this more closely matches how "real" backends perform //
|
||||
// and works better w/ pipes //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
for(QRecord qRecord : MemoryRecordStore.getInstance().query(queryInput))
|
||||
{
|
||||
queryOutput.addRecord(qRecord);
|
||||
}
|
||||
|
||||
return (queryOutput);
|
||||
}
|
||||
catch(Exception e)
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -74,11 +74,12 @@ public class TestScriptProcessStep implements BackendStep
|
||||
// get inputs //
|
||||
////////////////
|
||||
Integer scriptId = input.getValueInteger("scriptId");
|
||||
String code = input.getValueString("code");
|
||||
|
||||
ScriptRevision scriptRevision = new ScriptRevision();
|
||||
scriptRevision.setScriptId(scriptId);
|
||||
scriptRevision.setContents(code);
|
||||
scriptRevision.setContents(input.getValueString("code"));
|
||||
scriptRevision.setApiName(input.getValueString("apiName"));
|
||||
scriptRevision.setApiVersion(input.getValueString("apiVersion"));
|
||||
|
||||
BuildScriptLogAndScriptLogLineExecutionLogger executionLogger = new BuildScriptLogAndScriptLogLineExecutionLogger(null, null);
|
||||
|
||||
@ -106,6 +107,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()))
|
||||
{
|
||||
|
Reference in New Issue
Block a user