QQQ-21 starting to refactor process - 'steps' instead of 'functions'; more process meta-data

This commit is contained in:
2022-07-06 13:42:21 -05:00
parent dbaecfd879
commit c43f7a1edd
29 changed files with 923 additions and 335 deletions

View File

@ -59,7 +59,7 @@ public class MetaDataAction
Map<String, QFrontendProcessMetaData> processes = new LinkedHashMap<>();
for(Map.Entry<String, QProcessMetaData> entry : metaDataRequest.getInstance().getProcesses().entrySet())
{
processes.put(entry.getKey(), new QFrontendProcessMetaData(entry.getValue()));
processes.put(entry.getKey(), new QFrontendProcessMetaData(entry.getValue(), false));
}
metaDataResult.setProcesses(processes);

View File

@ -0,0 +1,60 @@
/*
* 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;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.model.actions.metadata.process.ProcessMetaDataRequest;
import com.kingsrook.qqq.backend.core.model.actions.metadata.process.ProcessMetaDataResult;
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
/*******************************************************************************
** Action to fetch meta-data for a process.
**
*******************************************************************************/
public class ProcessMetaDataAction
{
/*******************************************************************************
**
*******************************************************************************/
public ProcessMetaDataResult execute(ProcessMetaDataRequest processMetaDataRequest) throws QException
{
ActionHelper.validateSession(processMetaDataRequest);
// todo pre-customization - just get to modify the request?
ProcessMetaDataResult processMetaDataResult = new ProcessMetaDataResult();
QProcessMetaData process = processMetaDataRequest.getInstance().getProcess(processMetaDataRequest.getProcessName());
if(process == null)
{
throw (new QNotFoundException("Process [" + processMetaDataRequest.getProcessName() + "] was not found."));
}
processMetaDataResult.setProcess(new QFrontendProcessMetaData(process, true));
// todo post-customization - can do whatever w/ the result if you want
return processMetaDataResult;
}
}

View File

@ -28,15 +28,16 @@ import java.util.List;
import java.util.Map;
import com.kingsrook.qqq.backend.core.callbacks.QProcessCallback;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.interfaces.FunctionBody;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.interfaces.BackendStep;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.actions.query.QueryRequest;
import com.kingsrook.qqq.backend.core.model.actions.query.QueryResult;
import com.kingsrook.qqq.backend.core.model.metadata.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import org.apache.logging.log4j.LogManager;
@ -44,54 +45,61 @@ import org.apache.logging.log4j.Logger;
/*******************************************************************************
** Action handler for running q-functions.
** Action handler for running backend steps as part of processes.
*
*******************************************************************************/
public class RunFunctionAction
public class RunBackendStepAction
{
private static final Logger LOG = LogManager.getLogger(RunFunctionAction.class);
private static final Logger LOG = LogManager.getLogger(RunBackendStepAction.class);
/*******************************************************************************
**
*******************************************************************************/
public RunFunctionResult execute(RunFunctionRequest runFunctionRequest) throws QException
public RunBackendStepResult execute(RunBackendStepRequest runBackendStepRequest) throws QException
{
ActionHelper.validateSession(runFunctionRequest);
ActionHelper.validateSession(runBackendStepRequest);
QProcessMetaData process = runFunctionRequest.getInstance().getProcess(runFunctionRequest.getProcessName());
QProcessMetaData process = runBackendStepRequest.getInstance().getProcess(runBackendStepRequest.getProcessName());
if(process == null)
{
throw new QException("Process [" + runFunctionRequest.getProcessName() + "] is not defined in this instance.");
throw new QException("Process [" + runBackendStepRequest.getProcessName() + "] is not defined in this instance.");
}
QFunctionMetaData function = process.getFunction(runFunctionRequest.getFunctionName());
if(function == null)
QStepMetaData stepMetaData = process.getStep(runBackendStepRequest.getStepName());
if(stepMetaData == null)
{
throw new QException("Function [" + runFunctionRequest.getFunctionName() + "] is not defined in the process [" + process.getName() + "]");
throw new QException("Step [" + runBackendStepRequest.getStepName() + "] is not defined in the process [" + process.getName() + "]");
}
if(!(stepMetaData instanceof QBackendStepMetaData backendStepMetaData))
{
throw new QException("Step [" + runBackendStepRequest.getStepName() + "] is not a backend step.");
}
//////////////////////////////////////////////////////////////////////////////////////
// ensure input data is set as needed - use callback object to get anything missing //
//////////////////////////////////////////////////////////////////////////////////////
ensureRecordsAreInRequest(runFunctionRequest, function);
ensureInputFieldsAreInRequest(runFunctionRequest, function);
ensureRecordsAreInRequest(runBackendStepRequest, backendStepMetaData);
ensureInputFieldsAreInRequest(runBackendStepRequest, backendStepMetaData);
////////////////////////////////////////////////////////////////////
// load and run the user-defined code that actually does the work //
////////////////////////////////////////////////////////////////////
return (runFunctionBodyCode(function.getCode(), runFunctionRequest));
return (runStepCode(backendStepMetaData.getCode(), runBackendStepRequest));
}
/*******************************************************************************
** check if this function needs any input fields - and if so, if we need to get one
** check if this step needs any input fields - and if so, if we need to get one
** via the callback
**
*******************************************************************************/
private void ensureInputFieldsAreInRequest(RunFunctionRequest runFunctionRequest, QFunctionMetaData function) throws QException
private void ensureInputFieldsAreInRequest(RunBackendStepRequest runBackendStepRequest, QBackendStepMetaData step) throws QException
{
QFunctionInputMetaData inputMetaData = function.getInputMetaData();
QFunctionInputMetaData inputMetaData = step.getInputMetaData();
if(inputMetaData == null)
{
return;
@ -100,12 +108,12 @@ public class RunFunctionAction
List<QFieldMetaData> fieldsToGet = new ArrayList<>();
for(QFieldMetaData field : inputMetaData.getFieldList())
{
Serializable value = runFunctionRequest.getValue(field.getName());
Serializable value = runBackendStepRequest.getValue(field.getName());
if(value == null)
{
if(field.getDefaultValue() != null)
{
runFunctionRequest.addValue(field.getName(), field.getDefaultValue());
runBackendStepRequest.addValue(field.getName(), field.getDefaultValue());
}
else
{
@ -117,7 +125,7 @@ public class RunFunctionAction
if(!fieldsToGet.isEmpty())
{
QProcessCallback callback = runFunctionRequest.getCallback();
QProcessCallback callback = runBackendStepRequest.getCallback();
if(callback == null)
{
throw (new QException("Function is missing values for fields, but no callback was present to request fields from a user"));
@ -126,7 +134,7 @@ public class RunFunctionAction
Map<String, Serializable> fieldValues = callback.getFieldValues(fieldsToGet);
for(Map.Entry<String, Serializable> entry : fieldValues.entrySet())
{
runFunctionRequest.addValue(entry.getKey(), entry.getValue());
runBackendStepRequest.addValue(entry.getKey(), entry.getValue());
// todo - check to make sure got values back?
}
}
@ -135,25 +143,25 @@ public class RunFunctionAction
/*******************************************************************************
** check if this function uses a record list - and if so, if we need to get one
** check if this step uses a record list - and if so, if we need to get one
** via the callback
*******************************************************************************/
private void ensureRecordsAreInRequest(RunFunctionRequest runFunctionRequest, QFunctionMetaData function) throws QException
private void ensureRecordsAreInRequest(RunBackendStepRequest runBackendStepRequest, QBackendStepMetaData step) throws QException
{
QFunctionInputMetaData inputMetaData = function.getInputMetaData();
QFunctionInputMetaData inputMetaData = step.getInputMetaData();
if(inputMetaData != null && inputMetaData.getRecordListMetaData() != null)
{
if(CollectionUtils.nullSafeIsEmpty(runFunctionRequest.getRecords()))
if(CollectionUtils.nullSafeIsEmpty(runBackendStepRequest.getRecords()))
{
QueryRequest queryRequest = new QueryRequest(runFunctionRequest.getInstance());
queryRequest.setSession(runFunctionRequest.getSession());
QueryRequest queryRequest = new QueryRequest(runBackendStepRequest.getInstance());
queryRequest.setSession(runBackendStepRequest.getSession());
queryRequest.setTableName(inputMetaData.getRecordListMetaData().getTableName());
// todo - handle this being async (e.g., http)
// seems like it just needs to throw, breaking this flow, and to send a response to the frontend, directing it to prompt the user for the needed data
// then this function can re-run, hopefully with the needed data.
// then this step can re-run, hopefully with the needed data.
QProcessCallback callback = runFunctionRequest.getCallback();
QProcessCallback callback = runBackendStepRequest.getCallback();
if(callback == null)
{
throw (new QException("Function is missing input records, but no callback was present to get a query filter from a user"));
@ -162,7 +170,7 @@ public class RunFunctionAction
queryRequest.setFilter(callback.getQueryFilter());
QueryResult queryResult = new QueryAction().execute(queryRequest);
runFunctionRequest.setRecords(queryResult.getRecords());
runBackendStepRequest.setRecords(queryResult.getRecords());
// todo - handle 0 results found?
}
}
@ -173,29 +181,29 @@ public class RunFunctionAction
/*******************************************************************************
**
*******************************************************************************/
private RunFunctionResult runFunctionBodyCode(QCodeReference code, RunFunctionRequest runFunctionRequest)
private RunBackendStepResult runStepCode(QCodeReference code, RunBackendStepRequest runBackendStepRequest)
{
RunFunctionResult runFunctionResult = new RunFunctionResult();
RunBackendStepResult runBackendStepResult = new RunBackendStepResult();
try
{
runFunctionResult.seedFromRequest(runFunctionRequest);
runBackendStepResult.seedFromRequest(runBackendStepRequest);
Class<?> codeClass = Class.forName(code.getName());
Object codeObject = codeClass.getConstructor().newInstance();
if(!(codeObject instanceof FunctionBody functionBodyCodeObject))
if(!(codeObject instanceof BackendStep backendStepCodeObject))
{
throw (new QException("The supplied code [" + codeClass.getName() + "] is not an instance of FunctionBody"));
}
functionBodyCodeObject.run(runFunctionRequest, runFunctionResult);
backendStepCodeObject.run(runBackendStepRequest, runBackendStepResult);
}
catch(Exception e)
{
runFunctionResult = new RunFunctionResult();
runFunctionResult.setError("Error running function code: " + e.getMessage());
LOG.info("Error running function code", e);
runBackendStepResult = new RunBackendStepResult();
runBackendStepResult.setError("Error running backend step code: " + e.getMessage());
LOG.info("Error running backend step code", e);
}
return (runFunctionResult);
return (runBackendStepResult);
}
}

View File

@ -26,12 +26,12 @@ import java.util.List;
import java.util.Optional;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessState;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessResult;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
import com.kingsrook.qqq.backend.core.state.InMemoryStateProvider;
import com.kingsrook.qqq.backend.core.state.StateProviderInterface;
import com.kingsrook.qqq.backend.core.state.UUIDStateKey;
@ -59,35 +59,35 @@ public class RunProcessAction
RunProcessResult runProcessResult = new RunProcessResult();
UUIDStateKey stateKey = new UUIDStateKey();
RunFunctionResult lastFunctionResult = null;
UUIDStateKey stateKey = new UUIDStateKey();
RunBackendStepResult lastFunctionResult = null;
// todo - custom routing?
List<QFunctionMetaData> functionList = process.getFunctionList();
for(QFunctionMetaData function : functionList)
List<QStepMetaData> functionList = process.getStepList();
for(QStepMetaData function : functionList)
{
RunFunctionRequest runFunctionRequest = new RunFunctionRequest(runProcessRequest.getInstance());
RunBackendStepRequest runBackendStepRequest = new RunBackendStepRequest(runProcessRequest.getInstance());
if(lastFunctionResult == null)
{
///////////////////////////////////////////////////////////////////////////////////////////////////////
// for the first request, load state from the run process request to prime the run function request. //
///////////////////////////////////////////////////////////////////////////////////////////////////////
primeFunction(runProcessRequest, runFunctionRequest);
primeFunction(runProcessRequest, runBackendStepRequest);
}
else
{
////////////////////////////////////////////////////////////////////////////////////////
// for functions after the first one, load from state management to prime the request //
////////////////////////////////////////////////////////////////////////////////////////
loadState(stateKey, runFunctionRequest);
loadState(stateKey, runBackendStepRequest);
}
runFunctionRequest.setProcessName(process.getName());
runFunctionRequest.setFunctionName(function.getName());
runFunctionRequest.setSession(runProcessRequest.getSession());
runFunctionRequest.setCallback(runProcessRequest.getCallback());
lastFunctionResult = new RunFunctionAction().execute(runFunctionRequest);
runBackendStepRequest.setProcessName(process.getName());
runBackendStepRequest.setStepName(function.getName());
runBackendStepRequest.setSession(runProcessRequest.getSession());
runBackendStepRequest.setCallback(runProcessRequest.getCallback());
lastFunctionResult = new RunBackendStepAction().execute(runBackendStepRequest);
if(lastFunctionResult.getError() != null)
{
runProcessResult.setError(lastFunctionResult.getError());
@ -116,7 +116,7 @@ public class RunProcessAction
// TODO - read this from somewhere in meta data eh?
return InMemoryStateProvider.getInstance();
// TODO - by using JSON serialization internally, this makes stupidly large payloads and crashes things.
// todo - by using JSON serialization internally, this makes stupidly large payloads and crashes things.
// return TempFileStateProvider.getInstance();
}
@ -126,9 +126,9 @@ public class RunProcessAction
** Store the process state from a function result to the state provider
**
*******************************************************************************/
private void storeState(UUIDStateKey stateKey, RunFunctionResult runFunctionResult)
private void storeState(UUIDStateKey stateKey, RunBackendStepResult runBackendStepResult)
{
getStateProvider().put(stateKey, runFunctionResult.getProcessState());
getStateProvider().put(stateKey, runBackendStepResult.getProcessState());
}
@ -137,9 +137,9 @@ public class RunProcessAction
** Copy data (the state) down from the run-process request, down into the run-
** function request.
*******************************************************************************/
private void primeFunction(RunProcessRequest runProcessRequest, RunFunctionRequest runFunctionRequest)
private void primeFunction(RunProcessRequest runProcessRequest, RunBackendStepRequest runBackendStepRequest)
{
runFunctionRequest.seedFromRunProcessRequest(runProcessRequest);
runBackendStepRequest.seedFromRunProcessRequest(runProcessRequest);
}
@ -148,10 +148,10 @@ public class RunProcessAction
** Load the process state into a function request from the state provider
**
*******************************************************************************/
private void loadState(UUIDStateKey stateKey, RunFunctionRequest runFunctionRequest) throws QException
private void loadState(UUIDStateKey stateKey, RunBackendStepRequest runBackendStepRequest) throws QException
{
Optional<ProcessState> processState = getStateProvider().get(ProcessState.class, stateKey);
runFunctionRequest.seedFromProcessState(processState
runBackendStepRequest.seedFromProcessState(processState
.orElseThrow(() -> new QException("Could not find process state in state provider.")));
}

View File

@ -23,7 +23,7 @@ package com.kingsrook.qqq.backend.core.actions;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.model.actions.metadata.table.TableMetaDataRequest;
import com.kingsrook.qqq.backend.core.model.actions.metadata.table.TableMetaDataResult;
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
@ -49,7 +49,7 @@ public class TableMetaDataAction
QTableMetaData table = tableMetaDataRequest.getInstance().getTable(tableMetaDataRequest.getTableName());
if(table == null)
{
throw (new QUserFacingException("Table [" + tableMetaDataRequest.getTableName() + "] was not found."));
throw (new QNotFoundException("Table [" + tableMetaDataRequest.getTableName() + "] was not found."));
}
tableMetaDataResult.setTable(new QFrontendTableMetaData(table, true));

View File

@ -0,0 +1,54 @@
/*
* 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.exceptions;
/*******************************************************************************
** User-facing exception for when something wasn't found (e.g., a named table or
** record-by-id).
**
*******************************************************************************/
public class QNotFoundException extends QUserFacingException
{
/*******************************************************************************
** Constructor of message
**
*******************************************************************************/
public QNotFoundException(String message)
{
super(message);
}
/*******************************************************************************
** Constructor of message & cause
**
*******************************************************************************/
public QNotFoundException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -27,7 +27,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
@ -100,9 +100,9 @@ public class QInstanceEnricher
process.setLabel(nameToLabel(process.getName()));
}
if(process.getFunctionList() != null)
if(process.getStepList() != null)
{
process.getFunctionList().forEach(this::enrich);
process.getStepList().forEach(this::enrich);
}
}
@ -111,7 +111,7 @@ public class QInstanceEnricher
/*******************************************************************************
**
*******************************************************************************/
private void enrich(QFunctionMetaData function)
private void enrich(QStepMetaData function)
{
if(!StringUtils.hasContent(function.getLabel()))
{

View File

@ -23,22 +23,22 @@ package com.kingsrook.qqq.backend.core.interfaces;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
/*******************************************************************************
** Simple interface that a "custom" function (as in, a component of a Process)
** must implement.
** Simple interface that Backend Steps (e.g., code within processes) must implement
**
*******************************************************************************/
public interface FunctionBody
public interface BackendStep
{
/*******************************************************************************
** Execute the function - using the request as input, and the result as output.
** Execute the backend step - using the request as input, and the result as output.
**
** TODO - think about - why take the Result object as a param, instead of return it?
** Is this way easier for inter-language operability maybe?
* Also - there's way too much "process-specific gunk" in the Request object - can we simplify it?
*******************************************************************************/
void run(RunFunctionRequest runFunctionRequest, RunFunctionResult runFunctionResult) throws QException;
void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult) throws QException;
}

View File

@ -22,9 +22,9 @@
package com.kingsrook.qqq.backend.core.interfaces.mock;
import com.kingsrook.qqq.backend.core.interfaces.FunctionBody;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.interfaces.BackendStep;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
/*******************************************************************************
@ -32,19 +32,22 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
**
** Basically just passes data from the request to the response.
*******************************************************************************/
public class MockFunctionBody implements FunctionBody
public class MockBackendStep implements BackendStep
{
@Override
public void run(RunFunctionRequest runFunctionRequest, RunFunctionResult runFunctionResult)
{
runFunctionResult.getRecords().forEach(r -> r.setValue("mockValue", "Ha ha!"));
public final static String FIELD_GREETING_PREFIX = "greetingPrefix";
public final static String FIELD_GREETING_SUFFIX = "greetingSuffix";
runFunctionResult.setValues(runFunctionRequest.getValues());
runFunctionResult.addValue("mockValue", "You so silly");
@Override
public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult)
{
runBackendStepResult.getRecords().forEach(r -> r.setValue("mockValue", "Ha ha!"));
runBackendStepResult.setValues(runBackendStepRequest.getValues());
runBackendStepResult.addValue("mockValue", "You so silly");
/////////////////////////////////
// mock the "greet" process... //
/////////////////////////////////
runFunctionResult.addValue("outputMessage", runFunctionRequest.getValueString("greetingPrefix") + " X " + runFunctionRequest.getValueString("greetingSuffix"));
runBackendStepResult.addValue("outputMessage", runBackendStepRequest.getValueString(FIELD_GREETING_PREFIX) + " X " + runBackendStepRequest.getValueString(FIELD_GREETING_SUFFIX));
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.model.actions.metadata.process;
import com.kingsrook.qqq.backend.core.model.actions.AbstractQRequest;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
/*******************************************************************************
** Request for meta-data for a process.
**
*******************************************************************************/
public class ProcessMetaDataRequest extends AbstractQRequest
{
private String processName;
/*******************************************************************************
**
*******************************************************************************/
public ProcessMetaDataRequest()
{
}
/*******************************************************************************
**
*******************************************************************************/
public ProcessMetaDataRequest(QInstance instance)
{
super(instance);
}
/*******************************************************************************
** Getter for processName
**
*******************************************************************************/
public String getProcessName()
{
return processName;
}
/*******************************************************************************
** Setter for processName
**
*******************************************************************************/
public void setProcessName(String processName)
{
this.processName = processName;
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.model.actions.metadata.process;
import com.kingsrook.qqq.backend.core.model.actions.AbstractQResult;
import com.kingsrook.qqq.backend.core.model.metadata.frontend.QFrontendProcessMetaData;
/*******************************************************************************
* Result for a process-metaData action
*
*******************************************************************************/
public class ProcessMetaDataResult extends AbstractQResult
{
QFrontendProcessMetaData process;
/*******************************************************************************
** Getter for process
**
*******************************************************************************/
public QFrontendProcessMetaData getProcess()
{
return process;
}
/*******************************************************************************
** Setter for process
**
*******************************************************************************/
public void setProcess(QFrontendProcessMetaData process)
{
this.process = process;
}
}

View File

@ -29,18 +29,18 @@ import com.kingsrook.qqq.backend.core.callbacks.QProcessCallback;
import com.kingsrook.qqq.backend.core.model.actions.AbstractQRequest;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
/*******************************************************************************
** Request data container for the RunFunction action
** Request data container for the RunBackendStep action
**
*******************************************************************************/
public class RunFunctionRequest extends AbstractQRequest
public class RunBackendStepRequest extends AbstractQRequest
{
private ProcessState processState;
private String processName;
private String functionName;
private String stepName;
private QProcessCallback callback;
@ -48,7 +48,7 @@ public class RunFunctionRequest extends AbstractQRequest
/*******************************************************************************
**
*******************************************************************************/
public RunFunctionRequest()
public RunBackendStepRequest()
{
processState = new ProcessState();
}
@ -58,7 +58,7 @@ public class RunFunctionRequest extends AbstractQRequest
/*******************************************************************************
**
*******************************************************************************/
public RunFunctionRequest(QInstance instance)
public RunBackendStepRequest(QInstance instance)
{
super(instance);
processState = new ProcessState();
@ -91,9 +91,9 @@ public class RunFunctionRequest extends AbstractQRequest
/*******************************************************************************
**
*******************************************************************************/
public QFunctionMetaData getFunctionMetaData()
public QStepMetaData getStepMetaData()
{
return (instance.getFunction(getProcessName(), getFunctionName()));
return (instance.getProcessStep(getProcessName(), getStepName()));
}
@ -124,7 +124,7 @@ public class RunFunctionRequest extends AbstractQRequest
** Setter for processName
**
*******************************************************************************/
public RunFunctionRequest withProcessName(String processName)
public RunBackendStepRequest withProcessName(String processName)
{
this.processName = processName;
return (this);
@ -136,9 +136,9 @@ public class RunFunctionRequest extends AbstractQRequest
** Getter for functionName
**
*******************************************************************************/
public String getFunctionName()
public String getStepName()
{
return functionName;
return stepName;
}
@ -147,9 +147,9 @@ public class RunFunctionRequest extends AbstractQRequest
** Setter for functionName
**
*******************************************************************************/
public void setFunctionName(String functionName)
public void setStepName(String stepName)
{
this.functionName = functionName;
this.stepName = stepName;
}
@ -158,9 +158,9 @@ public class RunFunctionRequest extends AbstractQRequest
** Setter for functionName
**
*******************************************************************************/
public RunFunctionRequest withFunctionName(String functionName)
public RunBackendStepRequest withFunctionName(String functionName)
{
this.functionName = functionName;
this.stepName = functionName;
return (this);
}
@ -192,7 +192,7 @@ public class RunFunctionRequest extends AbstractQRequest
** Setter for records
**
*******************************************************************************/
public RunFunctionRequest withRecords(List<QRecord> records)
public RunBackendStepRequest withRecords(List<QRecord> records)
{
this.processState.setRecords(records);
return (this);
@ -226,7 +226,7 @@ public class RunFunctionRequest extends AbstractQRequest
** Setter for values
**
*******************************************************************************/
public RunFunctionRequest withValues(Map<String, Serializable> values)
public RunBackendStepRequest withValues(Map<String, Serializable> values)
{
this.processState.setValues(values);
return (this);
@ -238,7 +238,7 @@ public class RunFunctionRequest extends AbstractQRequest
** Setter for values
**
*******************************************************************************/
public RunFunctionRequest addValue(String fieldName, Serializable value)
public RunBackendStepRequest addValue(String fieldName, Serializable value)
{
this.processState.getValues().put(fieldName, value);
return (this);
@ -272,7 +272,7 @@ public class RunFunctionRequest extends AbstractQRequest
** Setter for callback
**
*******************************************************************************/
public RunFunctionRequest withCallback(QProcessCallback callback)
public RunBackendStepRequest withCallback(QProcessCallback callback)
{
this.callback = callback;
return (this);

View File

@ -30,10 +30,10 @@ import com.kingsrook.qqq.backend.core.model.data.QRecord;
/*******************************************************************************
** Result data container for the RunFunction action
** Result data container for the RunBackendStep action
**
*******************************************************************************/
public class RunFunctionResult extends AbstractQResult
public class RunBackendStepResult extends AbstractQResult
{
private ProcessState processState;
private String error;
@ -46,7 +46,7 @@ public class RunFunctionResult extends AbstractQResult
@Override
public String toString()
{
return "RunFunctionResult{error='" + error
return "RunBackendStepResult{error='" + error
+ ",records.size()=" + (processState == null ? null : processState.getRecords().size())
+ ",values=" + (processState == null ? null : processState.getValues())
+ "}";
@ -57,7 +57,7 @@ public class RunFunctionResult extends AbstractQResult
/*******************************************************************************
**
*******************************************************************************/
public RunFunctionResult()
public RunBackendStepResult()
{
this.processState = new ProcessState();
}
@ -68,9 +68,9 @@ public class RunFunctionResult extends AbstractQResult
** e.g., populate the process state (records, values) in this result object.
**
*******************************************************************************/
public void seedFromRequest(RunFunctionRequest runFunctionRequest)
public void seedFromRequest(RunBackendStepRequest runBackendStepRequest)
{
this.processState = runFunctionRequest.getProcessState();
this.processState = runBackendStepRequest.getProcessState();
}
@ -101,7 +101,7 @@ public class RunFunctionResult extends AbstractQResult
** Setter for records
**
*******************************************************************************/
public RunFunctionResult withRecords(List<QRecord> records)
public RunBackendStepResult withRecords(List<QRecord> records)
{
this.processState.setRecords(records);
return (this);
@ -135,7 +135,7 @@ public class RunFunctionResult extends AbstractQResult
** Setter for values
**
*******************************************************************************/
public RunFunctionResult withValues(Map<String, Serializable> values)
public RunBackendStepResult withValues(Map<String, Serializable> values)
{
this.processState.setValues(values);
return (this);
@ -147,7 +147,7 @@ public class RunFunctionResult extends AbstractQResult
** Setter for values
**
*******************************************************************************/
public RunFunctionResult addValue(String fieldName, Serializable value)
public RunBackendStepResult addValue(String fieldName, Serializable value)
{
this.processState.getValues().put(fieldName, value);
return (this);

View File

@ -69,9 +69,9 @@ public class RunProcessResult extends AbstractQResult
** the final function result
**
*******************************************************************************/
public void seedFromLastFunctionResult(RunFunctionResult runFunctionResult)
public void seedFromLastFunctionResult(RunBackendStepResult runBackendStepResult)
{
this.processState = runFunctionResult.getProcessState();
this.processState = runBackendStepResult.getProcessState();
}

View File

@ -29,7 +29,7 @@ import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kingsrook.qqq.backend.core.instances.QInstanceValidationKey;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
@ -211,7 +211,7 @@ public class QInstance
/*******************************************************************************
**
*******************************************************************************/
public QFunctionMetaData getFunction(String processName, String functionName)
public QStepMetaData getProcessStep(String processName, String functionName)
{
QProcessMetaData qProcessMetaData = this.processes.get(processName);
if(qProcessMetaData == null)
@ -219,7 +219,7 @@ public class QInstance
return (null);
}
return (qProcessMetaData.getFunction(functionName));
return (qProcessMetaData.getStep(functionName));
}

View File

@ -22,10 +22,14 @@
package com.kingsrook.qqq.backend.core.model.metadata.frontend;
import java.util.Map;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
/*******************************************************************************
@ -39,7 +43,8 @@ public class QFrontendProcessMetaData
private String name;
private String label;
private String tableName;
private Map<String, QFrontendFieldMetaData> fields;
private List<QFrontendStepMetaData> frontendSteps;
//////////////////////////////////////////////////////////////////////////////////
// do not add setters. take values from the source-object in the constructor!! //
@ -50,11 +55,26 @@ public class QFrontendProcessMetaData
/*******************************************************************************
**
*******************************************************************************/
public QFrontendProcessMetaData(QProcessMetaData processMetaData)
public QFrontendProcessMetaData(QProcessMetaData processMetaData, boolean includeSteps)
{
this.name = processMetaData.getName();
this.label = processMetaData.getLabel();
this.tableName = processMetaData.getTableName();
if(includeSteps)
{
if(CollectionUtils.nullSafeHasContents(processMetaData.getStepList()))
{
this.frontendSteps = processMetaData.getStepList().stream()
.filter(QFrontendStepMetaData.class::isInstance)
.map(QFrontendStepMetaData.class::cast)
.collect(Collectors.toList());
}
else
{
frontendSteps = new ArrayList<>();
}
}
}
@ -93,11 +113,22 @@ public class QFrontendProcessMetaData
/*******************************************************************************
** Getter for fields
** Getter for frontendSteps
**
*******************************************************************************/
public Map<String, QFrontendFieldMetaData> getFields()
public List<QFrontendStepMetaData> getFrontendSteps()
{
return fields;
return frontendSteps;
}
/*******************************************************************************
** Setter for frontendSteps
**
*******************************************************************************/
public void setFrontendSteps(List<QFrontendStepMetaData> frontendSteps)
{
this.frontendSteps = frontendSteps;
}
}

View File

@ -24,67 +24,21 @@ package com.kingsrook.qqq.backend.core.model.metadata.processes;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kingsrook.qqq.backend.core.model.metadata.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
/*******************************************************************************
** Meta-Data to define a function in a QQQ instance.
** Meta-Data to define a backend-step in a process in a QQQ instance. e.g.,
** code that runs on a server/backend, to do something to some data.
**
*******************************************************************************/
public class QFunctionMetaData
public class QBackendStepMetaData extends QStepMetaData
{
private String name;
private String label;
private QFunctionInputMetaData inputMetaData;
private QFunctionOutputMetaData outputMetaData;
private QCodeReference code;
private QOutputView outputView;
/*******************************************************************************
** Getter for name
**
*******************************************************************************/
public String getName()
{
return name;
}
/*******************************************************************************
** Setter for name
**
*******************************************************************************/
public void setName(String name)
{
this.name = name;
}
/*******************************************************************************
** Setter for name
**
*******************************************************************************/
public QFunctionMetaData withName(String name)
{
this.name = name;
return (this);
}
/*******************************************************************************
** Getter for label
**
*******************************************************************************/
public String getLabel()
{
return label;
}
@ -92,20 +46,10 @@ public class QFunctionMetaData
** Setter for label
**
*******************************************************************************/
public void setLabel(String label)
@Override
public QBackendStepMetaData withName(String name)
{
this.label = label;
}
/*******************************************************************************
** Setter for label
**
*******************************************************************************/
public QFunctionMetaData withLabel(String label)
{
this.label = label;
setName(name);
return (this);
}
@ -137,7 +81,7 @@ public class QFunctionMetaData
** Setter for inputData
**
*******************************************************************************/
public QFunctionMetaData withInputData(QFunctionInputMetaData inputData)
public QBackendStepMetaData withInputData(QFunctionInputMetaData inputData)
{
this.inputMetaData = inputData;
return (this);
@ -171,7 +115,7 @@ public class QFunctionMetaData
** Setter for outputData
**
*******************************************************************************/
public QFunctionMetaData withOutputMetaData(QFunctionOutputMetaData outputMetaData)
public QBackendStepMetaData withOutputMetaData(QFunctionOutputMetaData outputMetaData)
{
this.outputMetaData = outputMetaData;
return (this);
@ -205,7 +149,7 @@ public class QFunctionMetaData
** Setter for code
**
*******************************************************************************/
public QFunctionMetaData withCode(QCodeReference code)
public QBackendStepMetaData withCode(QCodeReference code)
{
this.code = code;
return (this);
@ -213,43 +157,11 @@ public class QFunctionMetaData
/*******************************************************************************
** Getter for outputView
**
*******************************************************************************/
public QOutputView getOutputView()
{
return outputView;
}
/*******************************************************************************
** Setter for outputView
**
*******************************************************************************/
public void setOutputView(QOutputView outputView)
{
this.outputView = outputView;
}
/*******************************************************************************
** Setter for outputView
**
*******************************************************************************/
public QFunctionMetaData withOutputView(QOutputView outputView)
{
this.outputView = outputView;
return (this);
}
/*******************************************************************************
** Get a list of all of the input fields used by this function
*******************************************************************************/
@JsonIgnore
@Override
public List<QFieldMetaData> getInputFields()
{
List<QFieldMetaData> rs = new ArrayList<>();
@ -265,6 +177,8 @@ public class QFunctionMetaData
/*******************************************************************************
** Get a list of all of the output fields used by this function
*******************************************************************************/
@JsonIgnore
@Override
public List<QFieldMetaData> getOutputFields()
{
List<QFieldMetaData> rs = new ArrayList<>();

View File

@ -0,0 +1,115 @@
/*
* 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.model.metadata.processes;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
/*******************************************************************************
** Meta-Data to define a front-end step in a process in a QQQ instance (e.g.,
** a screen presented to a user).
**
*******************************************************************************/
public class QFrontendStepMetaData extends QStepMetaData
{
private List<QFieldMetaData> formFields;
/*******************************************************************************
** Getter for formFields
**
*******************************************************************************/
public List<QFieldMetaData> getFormFields()
{
return formFields;
}
/*******************************************************************************
** Setter for formFields
**
*******************************************************************************/
public void setFormFields(List<QFieldMetaData> formFields)
{
this.formFields = formFields;
}
/*******************************************************************************
** fluent setter to add a single form field
**
*******************************************************************************/
public QFrontendStepMetaData withFormField(QFieldMetaData formField)
{
if(this.formFields == null)
{
this.formFields = new ArrayList<>();
}
this.formFields.add(formField);
return (this);
}
/*******************************************************************************
** fluent setter for formFields
**
*******************************************************************************/
public QFrontendStepMetaData withFormFields(List<QFieldMetaData> formFields)
{
this.formFields = formFields;
return (this);
}
/*******************************************************************************
** fluent setter for name
**
*******************************************************************************/
@Override
public QFrontendStepMetaData withName(String name)
{
setName(name);
return (this);
}
/*******************************************************************************
** fluent setter for label
**
*******************************************************************************/
@Override
public QFrontendStepMetaData withLabel(String label)
{
setLabel(label);
return (this);
}
}

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.processes;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
@ -33,10 +34,10 @@ import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
*******************************************************************************/
public class QProcessMetaData
{
private String name;
private String label;
private String tableName;
private List<QFunctionMetaData> functionList;
private String name;
private String label;
private String tableName;
private List<QStepMetaData> stepList;
@ -143,51 +144,51 @@ public class QProcessMetaData
/*******************************************************************************
** Getter for functionList
** Getter for stepList
**
*******************************************************************************/
public List<QFunctionMetaData> getFunctionList()
public List<QStepMetaData> getStepList()
{
return functionList;
return stepList;
}
/*******************************************************************************
** Setter for functionList
** Setter for stepList
**
*******************************************************************************/
public QProcessMetaData withFunctionList(List<QFunctionMetaData> functionList)
public QProcessMetaData withStepList(List<QStepMetaData> stepList)
{
this.functionList = functionList;
this.stepList = stepList;
return (this);
}
/*******************************************************************************
** Setter for functionList
** Setter for stepList
**
*******************************************************************************/
public QProcessMetaData addFunction(QFunctionMetaData function)
public QProcessMetaData addStep(QStepMetaData step)
{
if(this.functionList == null)
if(this.stepList == null)
{
this.functionList = new ArrayList<>();
this.stepList = new ArrayList<>();
}
this.functionList.add(function);
this.stepList.add(step);
return (this);
}
/*******************************************************************************
** Setter for functionList
** Setter for stepList
**
*******************************************************************************/
public void setFunctionList(List<QFunctionMetaData> functionList)
public void setStepList(List<QStepMetaData> stepList)
{
this.functionList = functionList;
this.stepList = stepList;
}
@ -195,13 +196,13 @@ public class QProcessMetaData
/*******************************************************************************
**
*******************************************************************************/
public QFunctionMetaData getFunction(String functionName)
public QStepMetaData getStep(String stepName)
{
for(QFunctionMetaData function : functionList)
for(QStepMetaData step : stepList)
{
if(function.getName().equals(functionName))
if(step.getName().equals(stepName))
{
return (function);
return (step);
}
}
@ -211,16 +212,27 @@ public class QProcessMetaData
/*******************************************************************************
** Get a list of all of the input fields used by all the functions in this process.
** Wrapper to getStep, that internally casts t0 BackendStepMetaData
*******************************************************************************/
public QBackendStepMetaData getBackendStep(String name)
{
return (QBackendStepMetaData) getStep(name);
}
/*******************************************************************************
** Get a list of all of the input fields used by all the steps in this process.
*******************************************************************************/
@JsonIgnore
public List<QFieldMetaData> getInputFields()
{
List<QFieldMetaData> rs = new ArrayList<>();
if(functionList != null)
if(stepList != null)
{
for(QFunctionMetaData function : functionList)
for(QStepMetaData step : stepList)
{
rs.addAll(function.getInputFields());
rs.addAll(step.getInputFields());
}
}
return (rs);
@ -229,18 +241,20 @@ public class QProcessMetaData
/*******************************************************************************
** Get a list of all of the output fields used by all the functions in this process.
** Get a list of all of the output fields used by all the steps in this process.
*******************************************************************************/
@JsonIgnore
public List<QFieldMetaData> getOutputFields()
{
List<QFieldMetaData> rs = new ArrayList<>();
if(functionList != null)
if(stepList != null)
{
for(QFunctionMetaData function : functionList)
for(QStepMetaData step : stepList)
{
rs.addAll(function.getOutputFields());
rs.addAll(step.getOutputFields());
}
}
return (rs);
}
}

View File

@ -0,0 +1,130 @@
/*
* 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.model.metadata.processes;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
/*******************************************************************************
** Meta-Data to define a step in a process in a QQQ instance.
**
*******************************************************************************/
public class QStepMetaData
{
private String name;
private String label;
/*******************************************************************************
** Getter for name
**
*******************************************************************************/
public String getName()
{
return name;
}
/*******************************************************************************
** Setter for name
**
*******************************************************************************/
public void setName(String name)
{
this.name = name;
}
/*******************************************************************************
** Setter for name
**
*******************************************************************************/
public QStepMetaData withName(String name)
{
this.name = name;
return (this);
}
/*******************************************************************************
** Getter for label
**
*******************************************************************************/
public String getLabel()
{
return label;
}
/*******************************************************************************
** Setter for label
**
*******************************************************************************/
public void setLabel(String label)
{
this.label = label;
}
/*******************************************************************************
** Setter for label
**
*******************************************************************************/
public QStepMetaData withLabel(String label)
{
this.label = label;
return (this);
}
/*******************************************************************************
** Get a list of all of the input fields used by this function
*******************************************************************************/
@JsonIgnore
public List<QFieldMetaData> getInputFields()
{
return (new ArrayList<>());
}
/*******************************************************************************
** Get a list of all of the output fields used by this function
*******************************************************************************/
@JsonIgnore
public List<QFieldMetaData> getOutputFields()
{
return (new ArrayList<>());
}
}

View File

@ -24,9 +24,9 @@ package com.kingsrook.qqq.backend.core.processes.implementations.etl.basic;
import com.kingsrook.qqq.backend.core.actions.QueryAction;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.interfaces.FunctionBody;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.interfaces.BackendStep;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.actions.query.QueryRequest;
import com.kingsrook.qqq.backend.core.model.actions.query.QueryResult;
@ -34,14 +34,15 @@ import com.kingsrook.qqq.backend.core.model.actions.query.QueryResult;
/*******************************************************************************
** Function body for performing the Extract step of a basic ETL process.
*******************************************************************************/
public class BasicETLExtractFunction implements FunctionBody
public class BasicETLExtractFunction implements BackendStep
{
@Override
public void run(RunFunctionRequest runFunctionRequest, RunFunctionResult runFunctionResult) throws QException
public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult) throws QException
{
QueryRequest queryRequest = new QueryRequest(runFunctionRequest.getInstance());
queryRequest.setSession(runFunctionRequest.getSession());
queryRequest.setTableName(runFunctionRequest.getValueString(BasicETLProcess.FIELD_SOURCE_TABLE));
QueryRequest queryRequest = new QueryRequest(runBackendStepRequest.getInstance());
queryRequest.setSession(runBackendStepRequest.getSession());
queryRequest.setTableName(runBackendStepRequest.getValueString(BasicETLProcess.FIELD_SOURCE_TABLE));
// queryRequest.setSkip(integerQueryParam(context, "skip"));
// queryRequest.setLimit(integerQueryParam(context, "limit"));
@ -54,6 +55,6 @@ public class BasicETLExtractFunction implements FunctionBody
QueryAction queryAction = new QueryAction();
QueryResult queryResult = queryAction.execute(queryRequest);
runFunctionResult.setRecords(queryResult.getRecords());
runBackendStepResult.setRecords(queryResult.getRecords());
}
}

View File

@ -26,11 +26,11 @@ import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.actions.InsertAction;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.interfaces.FunctionBody;
import com.kingsrook.qqq.backend.core.interfaces.BackendStep;
import com.kingsrook.qqq.backend.core.model.actions.insert.InsertRequest;
import com.kingsrook.qqq.backend.core.model.actions.insert.InsertResult;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import org.apache.logging.log4j.LogManager;
@ -40,7 +40,7 @@ import org.apache.logging.log4j.Logger;
/*******************************************************************************
** Function body for performing the Load step of a basic ETL process.
*******************************************************************************/
public class BasicETLLoadFunction implements FunctionBody
public class BasicETLLoadFunction implements BackendStep
{
private static final Logger LOG = LogManager.getLogger(BasicETLLoadFunction.class);
@ -50,23 +50,23 @@ public class BasicETLLoadFunction implements FunctionBody
**
*******************************************************************************/
@Override
public void run(RunFunctionRequest runFunctionRequest, RunFunctionResult runFunctionResult) throws QException
public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult) throws QException
{
//////////////////////////////////////////////////////
// exit early with no-op if no records made it here //
//////////////////////////////////////////////////////
List<QRecord> inputRecords = runFunctionRequest.getRecords();
List<QRecord> inputRecords = runBackendStepRequest.getRecords();
LOG.info("Received [" + inputRecords.size() + "] records to load");
if(CollectionUtils.nullSafeIsEmpty(inputRecords))
{
runFunctionResult.addValue(BasicETLProcess.FIELD_RECORD_COUNT, 0);
runBackendStepResult.addValue(BasicETLProcess.FIELD_RECORD_COUNT, 0);
return;
}
//////////////////////////////////////////////////////////////////
// put the destination table name in all records being inserted //
//////////////////////////////////////////////////////////////////
String table = runFunctionRequest.getValueString(BasicETLProcess.FIELD_DESTINATION_TABLE);
String table = runBackendStepRequest.getValueString(BasicETLProcess.FIELD_DESTINATION_TABLE);
for(QRecord record : inputRecords)
{
record.setTableName(table);
@ -82,8 +82,8 @@ public class BasicETLLoadFunction implements FunctionBody
for(List<QRecord> page : CollectionUtils.getPages(inputRecords, pageSize))
{
LOG.info("Inserting a page of [" + page.size() + "] records. Progress: " + recordsInserted + " loaded out of " + inputRecords.size() + " total");
InsertRequest insertRequest = new InsertRequest(runFunctionRequest.getInstance());
insertRequest.setSession(runFunctionRequest.getSession());
InsertRequest insertRequest = new InsertRequest(runBackendStepRequest.getInstance());
insertRequest.setSession(runBackendStepRequest.getSession());
insertRequest.setTableName(table);
insertRequest.setRecords(page);
@ -93,8 +93,8 @@ public class BasicETLLoadFunction implements FunctionBody
recordsInserted += insertResult.getRecords().size();
}
runFunctionResult.setRecords(outputRecords);
runFunctionResult.addValue(BasicETLProcess.FIELD_RECORD_COUNT, recordsInserted);
runBackendStepResult.setRecords(outputRecords);
runBackendStepResult.addValue(BasicETLProcess.FIELD_RECORD_COUNT, recordsInserted);
}
}

View File

@ -27,10 +27,11 @@ import com.kingsrook.qqq.backend.core.model.metadata.QCodeType;
import com.kingsrook.qqq.backend.core.model.metadata.QCodeUsage;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
/*******************************************************************************
@ -54,7 +55,7 @@ public class BasicETLProcess
*******************************************************************************/
public QProcessMetaData defineProcessMetaData()
{
QFunctionMetaData extractFunction = new QFunctionMetaData()
QStepMetaData extractFunction = new QBackendStepMetaData()
.withName(FUNCTION_NAME_EXTRACT)
.withCode(new QCodeReference()
.withName(BasicETLExtractFunction.class.getName())
@ -63,7 +64,7 @@ public class BasicETLProcess
.withInputData(new QFunctionInputMetaData()
.addField(new QFieldMetaData(FIELD_SOURCE_TABLE, QFieldType.STRING)));
QFunctionMetaData transformFunction = new QFunctionMetaData()
QStepMetaData transformFunction = new QBackendStepMetaData()
.withName(FUNCTION_NAME_TRANSFORM)
.withCode(new QCodeReference()
.withName(BasicETLTransformFunction.class.getName())
@ -73,7 +74,7 @@ public class BasicETLProcess
.addField(new QFieldMetaData(FIELD_MAPPING_JSON, QFieldType.STRING))
.addField(new QFieldMetaData(FIELD_DESTINATION_TABLE, QFieldType.STRING)));
QFunctionMetaData loadFunction = new QFunctionMetaData()
QStepMetaData loadFunction = new QBackendStepMetaData()
.withName(FUNCTION_NAME_LOAD)
.withCode(new QCodeReference()
.withName(BasicETLLoadFunction.class.getName())
@ -86,8 +87,8 @@ public class BasicETLProcess
return new QProcessMetaData()
.withName(PROCESS_NAME)
.addFunction(extractFunction)
.addFunction(transformFunction)
.addFunction(loadFunction);
.addStep(extractFunction)
.addStep(transformFunction)
.addStep(loadFunction);
}
}

View File

@ -28,9 +28,9 @@ import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.adapters.JsonToQFieldMappingAdapter;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.interfaces.FunctionBody;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.interfaces.BackendStep;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.AbstractQFieldMapping;
import com.kingsrook.qqq.backend.core.model.actions.shared.mapping.QKeyBasedFieldMapping;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
@ -46,7 +46,7 @@ import org.apache.logging.log4j.Logger;
/*******************************************************************************
** Function body for performing the Extract step of a basic ETL process.
*******************************************************************************/
public class BasicETLTransformFunction implements FunctionBody
public class BasicETLTransformFunction implements BackendStep
{
private static final Logger LOG = LogManager.getLogger(BasicETLTransformFunction.class);
@ -56,17 +56,17 @@ public class BasicETLTransformFunction implements FunctionBody
**
*******************************************************************************/
@Override
public void run(RunFunctionRequest runFunctionRequest, RunFunctionResult runFunctionResult) throws QException
public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult) throws QException
{
////////////////////////////////////////////////////////////////////////////////////////////
// exit early with no-op if no records made it here, or if we don't have a mapping to use //
////////////////////////////////////////////////////////////////////////////////////////////
if(CollectionUtils.nullSafeIsEmpty(runFunctionRequest.getRecords()))
if(CollectionUtils.nullSafeIsEmpty(runBackendStepRequest.getRecords()))
{
return;
}
String mappingJSON = runFunctionRequest.getValueString(BasicETLProcess.FIELD_MAPPING_JSON);
String mappingJSON = runBackendStepRequest.getValueString(BasicETLProcess.FIELD_MAPPING_JSON);
if(!StringUtils.hasContent(mappingJSON))
{
return;
@ -81,16 +81,16 @@ public class BasicETLTransformFunction implements FunctionBody
throw (new QException("Mapping was not a Key-based mapping type. Was a : " + mapping.getClass().getName()));
}
String tableName = runFunctionRequest.getValueString(BasicETLProcess.FIELD_DESTINATION_TABLE);
QTableMetaData table = runFunctionRequest.getInstance().getTable(tableName);
List<QRecord> mappedRecords = applyMapping(runFunctionRequest.getRecords(), table, keyBasedFieldMapping);
String tableName = runBackendStepRequest.getValueString(BasicETLProcess.FIELD_DESTINATION_TABLE);
QTableMetaData table = runBackendStepRequest.getInstance().getTable(tableName);
List<QRecord> mappedRecords = applyMapping(runBackendStepRequest.getRecords(), table, keyBasedFieldMapping);
//////////////////////////////////////////////////////////////////////////////////////////////////////
// todo - should this be conditional, e.g., driven by a field, or an opt-in customization function? //
//////////////////////////////////////////////////////////////////////////////////////////////////////
removeNonNumericValuesFromMappedRecords(table, mappedRecords);
runFunctionResult.setRecords(mappedRecords);
runBackendStepResult.setRecords(mappedRecords);
}

View File

@ -0,0 +1,78 @@
/*
* 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;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.model.actions.metadata.process.ProcessMetaDataRequest;
import com.kingsrook.qqq.backend.core.model.actions.metadata.process.ProcessMetaDataResult;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
/*******************************************************************************
** Unit test for ProcessMetaDataAction
**
*******************************************************************************/
class ProcessMetaDataActionTest
{
/*******************************************************************************
** Test basic success case.
**
*******************************************************************************/
@Test
public void test() throws QException
{
ProcessMetaDataRequest request = new ProcessMetaDataRequest(TestUtils.defineInstance());
request.setSession(TestUtils.getMockSession());
request.setProcessName(TestUtils.PROCESS_NAME_GREET_PEOPLE_INTERACTIVE);
ProcessMetaDataResult result = new ProcessMetaDataAction().execute(request);
assertNotNull(result);
assertNotNull(result.getProcess());
assertEquals("greetInteractive", result.getProcess().getName());
assertEquals("Greet Interactive", result.getProcess().getLabel());
assertEquals(2, result.getProcess().getFrontendSteps().size());
}
/*******************************************************************************
** Test exception is thrown for the "not-found" case.
**
*******************************************************************************/
@Test
public void test_notFound()
{
assertThrows(QUserFacingException.class, () -> {
ProcessMetaDataRequest request = new ProcessMetaDataRequest(TestUtils.defineInstance());
request.setSession(TestUtils.getMockSession());
request.setProcessName("willNotBeFound");
new ProcessMetaDataAction().execute(request);
});
}
}

View File

@ -29,8 +29,8 @@ import java.util.List;
import java.util.Map;
import com.kingsrook.qqq.backend.core.callbacks.QProcessCallback;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.actions.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.metadata.QFieldMetaData;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
@ -44,7 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/*******************************************************************************
**
*******************************************************************************/
public class RunFunctionTest
public class RunBackendStepActionTest
{
/*******************************************************************************
@ -53,13 +53,13 @@ public class RunFunctionTest
@Test
public void test() throws QException
{
TestCallback callback = new TestCallback();
RunFunctionRequest request = new RunFunctionRequest(TestUtils.defineInstance());
TestCallback callback = new TestCallback();
RunBackendStepRequest request = new RunBackendStepRequest(TestUtils.defineInstance());
request.setSession(TestUtils.getMockSession());
request.setProcessName("greet");
request.setFunctionName("prepare");
request.setStepName("prepare");
request.setCallback(callback);
RunFunctionResult result = new RunFunctionAction().execute(request);
RunBackendStepResult result = new RunBackendStepAction().execute(request);
assertNotNull(result);
assertNull(result.getError());
assertTrue(result.getRecords().stream().allMatch(r -> r.getValues().containsKey("mockValue")), "records should have a mock value");

View File

@ -22,29 +22,29 @@
package com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage;
import com.kingsrook.qqq.backend.core.interfaces.FunctionBody;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.interfaces.BackendStep;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
/*******************************************************************************
**
*******************************************************************************/
public class AddAge implements FunctionBody
public class AddAge implements BackendStep
{
@Override
public void run(RunFunctionRequest runFunctionRequest, RunFunctionResult runFunctionResult)
public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult)
{
int totalYearsAdded = 0;
Integer yearsToAdd = runFunctionRequest.getValueInteger("yearsToAdd");
for(QRecord record : runFunctionRequest.getRecords())
Integer yearsToAdd = runBackendStepRequest.getValueInteger("yearsToAdd");
for(QRecord record : runBackendStepRequest.getRecords())
{
Integer age = record.getValueInteger("age");
age += yearsToAdd;
totalYearsAdded += yearsToAdd;
record.setValue("age", age);
}
runFunctionResult.addValue("totalYearsAdded", totalYearsAdded);
runBackendStepResult.addValue("totalYearsAdded", totalYearsAdded);
}
}

View File

@ -24,24 +24,24 @@ package com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage;
import java.time.LocalDate;
import java.time.Period;
import com.kingsrook.qqq.backend.core.interfaces.FunctionBody;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunFunctionResult;
import com.kingsrook.qqq.backend.core.interfaces.BackendStep;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepRequest;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepResult;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
/*******************************************************************************
**
*******************************************************************************/
public class GetAgeStatistics implements FunctionBody
public class GetAgeStatistics implements BackendStep
{
@Override
public void run(RunFunctionRequest runFunctionRequest, RunFunctionResult runFunctionResult)
public void run(RunBackendStepRequest runBackendStepRequest, RunBackendStepResult runBackendStepResult)
{
Integer min = null;
Integer max = null;
LocalDate now = LocalDate.now();
for(QRecord record : runFunctionRequest.getRecords())
for(QRecord record : runBackendStepRequest.getRecords())
{
LocalDate birthDate = record.getValueDate("birthDate");
Period until = birthDate.until(now);
@ -52,7 +52,7 @@ public class GetAgeStatistics implements FunctionBody
max = (max == null || age > max) ? age : max;
}
runFunctionResult.addValue("minAge", min);
runFunctionResult.addValue("maxAge", max);
runBackendStepResult.addValue("minAge", min);
runBackendStepResult.addValue("maxAge", max);
}
}

View File

@ -23,7 +23,8 @@ package com.kingsrook.qqq.backend.core.utils;
import java.util.List;
import com.kingsrook.qqq.backend.core.interfaces.mock.MockFunctionBody;
import com.kingsrook.qqq.backend.core.adapters.QInstanceAdapter;
import com.kingsrook.qqq.backend.core.interfaces.mock.MockBackendStep;
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QCodeReference;
@ -35,13 +36,12 @@ import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QOutputView;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListView;
import com.kingsrook.qqq.backend.core.model.session.QSession;
import com.kingsrook.qqq.backend.core.modules.mock.MockAuthenticationModule;
import com.kingsrook.qqq.backend.core.processes.implementations.etl.basic.BasicETLProcess;
@ -54,6 +54,8 @@ import com.kingsrook.qqq.backend.core.processes.implementations.etl.basic.BasicE
public class TestUtils
{
public static String DEFAULT_BACKEND_NAME = "default";
public static String PROCESS_NAME_GREET_PEOPLE = "greet";
public static String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
@ -71,8 +73,12 @@ public class TestUtils
qInstance.addTable(defineTableIdAndNameOnly());
qInstance.addPossibleValueSource(defineStatesPossibleValueSource());
qInstance.addProcess(defineProcessGreetPeople());
qInstance.addProcess(defineProcessGreetPeopleInteractive());
qInstance.addProcess(defineProcessAddToPeoplesAge());
qInstance.addProcess(new BasicETLProcess().defineProcessMetaData());
System.out.println(new QInstanceAdapter().qInstanceToJson(qInstance));
return (qInstance);
}
@ -176,12 +182,12 @@ public class TestUtils
private static QProcessMetaData defineProcessGreetPeople()
{
return new QProcessMetaData()
.withName("greet")
.withName(PROCESS_NAME_GREET_PEOPLE)
.withTableName("person")
.addFunction(new QFunctionMetaData()
.addStep(new QBackendStepMetaData()
.withName("prepare")
.withCode(new QCodeReference()
.withName(MockFunctionBody.class.getName())
.withName(MockBackendStep.class.getName())
.withCodeType(QCodeType.JAVA)
.withCodeUsage(QCodeUsage.FUNCTION)) // todo - needed, or implied in this context?
.withInputData(new QFunctionInputMetaData()
@ -196,9 +202,49 @@ public class TestUtils
.addField(new QFieldMetaData("fullGreeting", QFieldType.STRING))
)
.withFieldList(List.of(new QFieldMetaData("outputMessage", QFieldType.STRING))))
.withOutputView(new QOutputView()
.withMessageField("outputMessage")
.withRecordListView(new QRecordListView().withFieldNames(List.of("id", "firstName", "lastName", "fullGreeting"))))
);
}
/*******************************************************************************
** Define an interactive version of the 'greet people' process
*******************************************************************************/
private static QProcessMetaData defineProcessGreetPeopleInteractive()
{
return new QProcessMetaData()
.withName(PROCESS_NAME_GREET_PEOPLE_INTERACTIVE)
.withTableName("person")
.addStep(new QFrontendStepMetaData()
.withName("setup")
.withFormField(new QFieldMetaData("greetingPrefix", QFieldType.STRING))
.withFormField(new QFieldMetaData("greetingSuffix", QFieldType.STRING))
)
.addStep(new QBackendStepMetaData()
.withName("doWork")
.withCode(new QCodeReference()
.withName(MockBackendStep.class.getName())
.withCodeType(QCodeType.JAVA)
.withCodeUsage(QCodeUsage.FUNCTION)) // todo - needed, or implied in this context?
.withInputData(new QFunctionInputMetaData()
.withRecordListMetaData(new QRecordListMetaData().withTableName("person"))
.withFieldList(List.of(
new QFieldMetaData("greetingPrefix", QFieldType.STRING),
new QFieldMetaData("greetingSuffix", QFieldType.STRING)
)))
.withOutputMetaData(new QFunctionOutputMetaData()
.withRecordListMetaData(new QRecordListMetaData()
.withTableName("person")
.addField(new QFieldMetaData("fullGreeting", QFieldType.STRING))
)
.withFieldList(List.of(new QFieldMetaData("outputMessage", QFieldType.STRING))))
)
.addStep(new QFrontendStepMetaData()
.withName("results")
.withFormField(new QFieldMetaData("outputMessage", QFieldType.STRING))
);
}
@ -217,7 +263,7 @@ public class TestUtils
return new QProcessMetaData()
.withName("addToPeoplesAge")
.withTableName("person")
.addFunction(new QFunctionMetaData()
.addStep(new QBackendStepMetaData()
.withName("getAgeStatistics")
.withCode(new QCodeReference()
.withName("com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.GetAgeStatistics")
@ -231,10 +277,8 @@ public class TestUtils
.addField(new QFieldMetaData("age", QFieldType.INTEGER)))
.withFieldList(List.of(
new QFieldMetaData("minAge", QFieldType.INTEGER),
new QFieldMetaData("maxAge", QFieldType.INTEGER))))
.withOutputView(new QOutputView()
.withMessageField("outputMessage"))) // todo - wut?
.addFunction(new QFunctionMetaData()
new QFieldMetaData("maxAge", QFieldType.INTEGER)))))
.addStep(new QBackendStepMetaData()
.withName("addAge")
.withCode(new QCodeReference()
.withName("com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.AddAge")