mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Initial implementation of api processes
This commit is contained in:
@ -57,6 +57,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponen
|
||||
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.model.metadata.processes.QStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QSupplementalProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportDataSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportView;
|
||||
@ -367,6 +368,11 @@ public class QInstanceEnricher
|
||||
process.getStepList().forEach(this::enrichStep);
|
||||
}
|
||||
|
||||
for(QSupplementalProcessMetaData supplementalProcessMetaData : CollectionUtils.nonNullMap(process.getSupplementalMetaData()).values())
|
||||
{
|
||||
supplementalProcessMetaData.enrich(process);
|
||||
}
|
||||
|
||||
enrichPermissionRules(process);
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,10 @@ package com.kingsrook.qqq.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.async.AsyncJobCallback;
|
||||
@ -31,6 +35,7 @@ import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -183,6 +188,17 @@ public class RunProcessInput extends AbstractActionInput
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput withValue(String fieldName, Serializable value)
|
||||
{
|
||||
this.processState.getValues().put(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
@ -258,7 +274,7 @@ public class RunProcessInput extends AbstractActionInput
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return ((String) getValue(fieldName));
|
||||
return (ValueUtils.getValueAsString(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
@ -269,7 +285,67 @@ public class RunProcessInput extends AbstractActionInput
|
||||
*******************************************************************************/
|
||||
public Integer getValueInteger(String fieldName)
|
||||
{
|
||||
return ((Integer) getValue(fieldName));
|
||||
return (ValueUtils.getValueAsInteger(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BigDecimal getValueBigDecimal(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBigDecimal(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Boolean getValueBoolean(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBoolean(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public LocalTime getValueLocalTime(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsLocalTime(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public LocalDate getValueLocalDate(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsLocalDate(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public byte[] getValueByteArray(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsByteArray(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Instant getValueInstant(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsInstant(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,11 +23,16 @@ package com.kingsrook.qqq.backend.core.model.actions.processes;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -122,6 +127,99 @@ public class RunProcessOutput extends AbstractActionOutput implements Serializab
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Serializable getValue(String fieldName)
|
||||
{
|
||||
return (this.processState.getValues().get(fieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsString(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for a single field's value
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getValueInteger(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsInteger(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public BigDecimal getValueBigDecimal(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBigDecimal(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Boolean getValueBoolean(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsBoolean(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public LocalTime getValueLocalTime(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsLocalTime(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public LocalDate getValueLocalDate(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsLocalDate(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public byte[] getValueByteArray(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsByteArray(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Instant getValueInstant(String fieldName)
|
||||
{
|
||||
return (ValueUtils.getValueAsInstant(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
@ -133,6 +231,17 @@ public class RunProcessOutput extends AbstractActionOutput implements Serializab
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessOutput withValue(String fieldName, Serializable value)
|
||||
{
|
||||
this.processState.getValues().put(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
|
@ -61,6 +61,7 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
|
||||
|
||||
private QScheduleMetaData schedule;
|
||||
|
||||
private Map<String, QSupplementalProcessMetaData> supplementalMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -544,4 +545,64 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
|
||||
qInstance.addProcess(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for supplementalMetaData
|
||||
*******************************************************************************/
|
||||
public Map<String, QSupplementalProcessMetaData> getSupplementalMetaData()
|
||||
{
|
||||
return (this.supplementalMetaData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for supplementalMetaData
|
||||
*******************************************************************************/
|
||||
public QSupplementalProcessMetaData getSupplementalMetaData(String type)
|
||||
{
|
||||
if(this.supplementalMetaData == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
return this.supplementalMetaData.get(type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for supplementalMetaData
|
||||
*******************************************************************************/
|
||||
public void setSupplementalMetaData(Map<String, QSupplementalProcessMetaData> supplementalMetaData)
|
||||
{
|
||||
this.supplementalMetaData = supplementalMetaData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for supplementalMetaData
|
||||
*******************************************************************************/
|
||||
public QProcessMetaData withSupplementalMetaData(Map<String, QSupplementalProcessMetaData> supplementalMetaData)
|
||||
{
|
||||
this.supplementalMetaData = supplementalMetaData;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for supplementalMetaData
|
||||
*******************************************************************************/
|
||||
public QProcessMetaData withSupplementalMetaData(QSupplementalProcessMetaData supplementalMetaData)
|
||||
{
|
||||
if(this.supplementalMetaData == null)
|
||||
{
|
||||
this.supplementalMetaData = new HashMap<>();
|
||||
}
|
||||
this.supplementalMetaData.put(supplementalMetaData.getType(), supplementalMetaData);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.metadata.processes;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Base-class for process-level meta-data defined by some supplemental module, etc,
|
||||
** outside of qqq core
|
||||
*******************************************************************************/
|
||||
public abstract class QSupplementalProcessMetaData
|
||||
{
|
||||
protected String type;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for type
|
||||
*******************************************************************************/
|
||||
public String getType()
|
||||
{
|
||||
return (this.type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for type
|
||||
*******************************************************************************/
|
||||
public void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for type
|
||||
*******************************************************************************/
|
||||
public QSupplementalProcessMetaData withType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void enrich(QProcessMetaData process)
|
||||
{
|
||||
////////////////////////
|
||||
// noop in base class //
|
||||
////////////////////////
|
||||
}
|
||||
}
|
@ -30,14 +30,23 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import com.kingsrook.qqq.api.javalin.QBadRequestException;
|
||||
import com.kingsrook.qqq.api.model.APIVersion;
|
||||
import com.kingsrook.qqq.api.model.APIVersionRange;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiOperation;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessCustomizers;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.PostRunApiProcessCustomizer;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.PreRunApiProcessCustomizer;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
@ -49,6 +58,8 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.logging.LogPair;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.QInputSource;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||
@ -67,8 +78,10 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.BadInputStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.NotFoundStatusMessage;
|
||||
@ -96,10 +109,11 @@ public class ApiImplementation
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(ApiImplementation.class);
|
||||
|
||||
/////////////////////////////////////
|
||||
// key: Pair<apiName, apiVersion> //
|
||||
/////////////////////////////////////
|
||||
private static Map<Pair<String, String>, Map<String, QTableMetaData>> tableApiNameMap = new HashMap<>();
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// key: Pair<apiName, apiVersion>, value: Map<name => metaData> //
|
||||
///////////////////////////////////////////////////////////////////
|
||||
private static Map<Pair<String, String>, Map<String, QTableMetaData>> tableApiNameMap = new HashMap<>();
|
||||
private static Map<Pair<String, String>, Map<String, QProcessMetaData>> processApiNameMap = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
@ -896,6 +910,99 @@ public class ApiImplementation
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static Map<String, Serializable> runProcess(ApiInstanceMetaData apiInstanceMetaData, String version, String processApiName, Map<String, String> paramMap) throws QException
|
||||
{
|
||||
QProcessMetaData process = validateProcessAndVersion(apiInstanceMetaData, version, processApiName);
|
||||
String processName = process.getName();
|
||||
ApiProcessMetaData apiProcessMetaData = getApiProcessMetaDataIfProcessIsInApi(apiInstanceMetaData, process);
|
||||
|
||||
List<String> badRequestMessages = new ArrayList<>();
|
||||
Map<String, Serializable> output = new LinkedHashMap<>();
|
||||
|
||||
String processUUID = UUID.randomUUID().toString();
|
||||
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(processName);
|
||||
runProcessInput.setFrontendStepBehavior(RunProcessInput.FrontendStepBehavior.SKIP);
|
||||
runProcessInput.setProcessUUID(processUUID);
|
||||
// todo i don't think runProcessInput.setCallback();
|
||||
// todo i don't think runProcessInput.setAsyncJobCallback();
|
||||
|
||||
//////////////////////
|
||||
// map input values //
|
||||
//////////////////////
|
||||
for(QFieldMetaData inputField : CollectionUtils.nonNullList(apiProcessMetaData.getInputFields()))
|
||||
{
|
||||
String value = paramMap.get(inputField.getName());
|
||||
if(!StringUtils.hasContent(value) && inputField.getIsRequired())
|
||||
{
|
||||
badRequestMessages.add("Missing value for required input field " + inputField.getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
// todo - types?
|
||||
|
||||
runProcessInput.addValue(inputField.getName(), value);
|
||||
}
|
||||
|
||||
// todo! runProcessInput.setRecords(records);
|
||||
|
||||
/////////////////////////////////////////
|
||||
// throw if bad inputs have been noted //
|
||||
/////////////////////////////////////////
|
||||
if(!badRequestMessages.isEmpty())
|
||||
{
|
||||
if(badRequestMessages.size() == 1)
|
||||
{
|
||||
throw (new QBadRequestException(badRequestMessages.get(0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw (new QBadRequestException("Request failed with " + badRequestMessages.size() + " reasons: " + StringUtils.join(" \n", badRequestMessages)));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// run pre-customizer, if there is one //
|
||||
/////////////////////////////////////////
|
||||
Map<String, QCodeReference> customizers = apiProcessMetaData.getCustomizers();
|
||||
if(customizers != null && customizers.containsKey(ApiProcessCustomizers.PRE_RUN.getRole()))
|
||||
{
|
||||
PreRunApiProcessCustomizer preRunCustomizer = QCodeLoader.getAdHoc(PreRunApiProcessCustomizer.class, customizers.get(ApiProcessCustomizers.PRE_RUN.getRole()));
|
||||
preRunCustomizer.preApiRun(runProcessInput);
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
// run the process //
|
||||
/////////////////////
|
||||
RunProcessAction runProcessAction = new RunProcessAction();
|
||||
RunProcessOutput runProcessOutput = runProcessAction.execute(runProcessInput);
|
||||
|
||||
/////////////////////////////////////////
|
||||
// run post-customizer, if there is one //
|
||||
/////////////////////////////////////////
|
||||
if(customizers != null && customizers.containsKey(ApiProcessCustomizers.POST_RUN.getRole()))
|
||||
{
|
||||
PostRunApiProcessCustomizer postRunCustomizer = QCodeLoader.getAdHoc(PostRunApiProcessCustomizer.class, customizers.get(ApiProcessCustomizers.POST_RUN.getRole()));
|
||||
postRunCustomizer.postApiRun(runProcessInput, runProcessOutput);
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// map output values //
|
||||
///////////////////////
|
||||
for(QFieldMetaData outputField : apiProcessMetaData.getOutputFields())
|
||||
{
|
||||
output.put(outputField.getName(), runProcessOutput.getValues().get(outputField.getName()));
|
||||
}
|
||||
|
||||
return (output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -1078,14 +1185,14 @@ public class ApiImplementation
|
||||
ApiTableMetaDataContainer apiTableMetaDataContainer = ApiTableMetaDataContainer.of(table);
|
||||
if(apiTableMetaDataContainer == null)
|
||||
{
|
||||
LOG.info("404 because table apiMetaDataContainer is null", logPairs);
|
||||
LOG.info("404 because table apiTableMetaDataContainer is null", logPairs);
|
||||
throw (new QNotFoundException("Could not find a table named " + tableApiName + " in this api."));
|
||||
}
|
||||
|
||||
ApiTableMetaData apiTableMetaData = apiTableMetaDataContainer.getApiTableMetaData(apiInstanceMetaData.getName());
|
||||
if(apiTableMetaData == null)
|
||||
{
|
||||
LOG.info("404 because table apiMetaData is null", logPairs);
|
||||
LOG.info("404 because table apiTableMetaData is null", logPairs);
|
||||
throw (new QNotFoundException("Could not find a table named " + tableApiName + " in this api."));
|
||||
}
|
||||
|
||||
@ -1126,6 +1233,65 @@ public class ApiImplementation
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QProcessMetaData validateProcessAndVersion(ApiInstanceMetaData apiInstanceMetaData, String version, String processApiName) throws QNotFoundException
|
||||
{
|
||||
QProcessMetaData process = getProcessByApiName(apiInstanceMetaData.getName(), version, processApiName);
|
||||
LogPair[] logPairs = new LogPair[] { logPair("apiName", apiInstanceMetaData.getName()), logPair("version", version), logPair("processApiName", processApiName) };
|
||||
|
||||
if(process == null)
|
||||
{
|
||||
LOG.info("404 because process is null (processApiName=" + processApiName + ")", logPairs);
|
||||
throw (new QNotFoundException("Could not find a process named " + processApiName + " in this api."));
|
||||
}
|
||||
|
||||
if(BooleanUtils.isTrue(process.getIsHidden()))
|
||||
{
|
||||
LOG.info("404 because process isHidden", logPairs);
|
||||
throw (new QNotFoundException("Could not find a process named " + processApiName + " in this api."));
|
||||
}
|
||||
|
||||
ApiProcessMetaDataContainer apiProcessMetaDataContainer = ApiProcessMetaDataContainer.of(process);
|
||||
if(apiProcessMetaDataContainer == null)
|
||||
{
|
||||
LOG.info("404 because process apiProcessMetaDataContainer is null", logPairs);
|
||||
throw (new QNotFoundException("Could not find a process named " + processApiName + " in this api."));
|
||||
}
|
||||
|
||||
ApiProcessMetaData apiProcessMetaData = apiProcessMetaDataContainer.getApiProcessMetaData(apiInstanceMetaData.getName());
|
||||
if(apiProcessMetaData == null)
|
||||
{
|
||||
LOG.info("404 because process apiProcessMetaData is null", logPairs);
|
||||
throw (new QNotFoundException("Could not find a process named " + processApiName + " in this api."));
|
||||
}
|
||||
|
||||
if(BooleanUtils.isTrue(apiProcessMetaData.getIsExcluded()))
|
||||
{
|
||||
LOG.info("404 because process is excluded", logPairs);
|
||||
throw (new QNotFoundException("Could not find a process named " + processApiName + " in this api."));
|
||||
}
|
||||
|
||||
APIVersion requestApiVersion = new APIVersion(version);
|
||||
List<APIVersion> supportedVersions = apiInstanceMetaData.getSupportedVersions();
|
||||
if(CollectionUtils.nullSafeIsEmpty(supportedVersions) || !supportedVersions.contains(requestApiVersion))
|
||||
{
|
||||
LOG.info("404 because requested version is not supported", logPairs);
|
||||
throw (new QNotFoundException(version + " is not a supported version in this api."));
|
||||
}
|
||||
|
||||
if(!apiProcessMetaData.getApiVersionRange().includes(requestApiVersion))
|
||||
{
|
||||
LOG.info("404 because process version range does not include requested version", logPairs);
|
||||
throw (new QNotFoundException(version + " is not a supported version for process " + processApiName + " in this api."));
|
||||
}
|
||||
|
||||
return (process);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -1167,6 +1333,100 @@ public class ApiImplementation
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static QProcessMetaData getProcessByApiName(String apiName, String version, String processApiName)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// processApiNameMap is a map of (apiName,apiVersion) => Map<String, QProcessMetaData>. //
|
||||
// that is to say, a 2-level map. The first level is keyed by (apiName,apiVersion) pairs. //
|
||||
// the second level is keyed by processApiNames. //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Pair<String, String> key = new Pair<>(apiName, version);
|
||||
if(processApiNameMap.get(key) == null)
|
||||
{
|
||||
Map<String, QProcessMetaData> map = new HashMap<>();
|
||||
|
||||
for(QProcessMetaData process : QContext.getQInstance().getProcesses().values())
|
||||
{
|
||||
ApiProcessMetaDataContainer apiProcessMetaDataContainer = ApiProcessMetaDataContainer.of(process);
|
||||
if(apiProcessMetaDataContainer != null)
|
||||
{
|
||||
ApiProcessMetaData apiProcessMetaData = apiProcessMetaDataContainer.getApiProcessMetaData(apiName);
|
||||
if(apiProcessMetaData != null)
|
||||
{
|
||||
String name = process.getName();
|
||||
if(StringUtils.hasContent(apiProcessMetaData.getApiProcessName()))
|
||||
{
|
||||
name = apiProcessMetaData.getApiProcessName();
|
||||
}
|
||||
map.put(name, process);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processApiNameMap.put(key, map);
|
||||
}
|
||||
|
||||
return (processApiNameMap.get(key).get(processApiName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiProcessMetaData getApiProcessMetaDataIfProcessIsInApi(ApiInstanceMetaData apiInstanceMetaData, QProcessMetaData process)
|
||||
{
|
||||
if(BooleanUtils.isTrue(process.getIsHidden()))
|
||||
{
|
||||
LOG.trace("excluding process because it is hidden (process=" + process.getName() + ")");
|
||||
return (null);
|
||||
}
|
||||
|
||||
ApiProcessMetaDataContainer apiProcessMetaDataContainer = ApiProcessMetaDataContainer.of(process);
|
||||
if(apiProcessMetaDataContainer == null)
|
||||
{
|
||||
LOG.trace("excluding process because apiProcessMetaDataContainer is null (process=" + process.getName() + ")");
|
||||
return (null);
|
||||
}
|
||||
|
||||
ApiProcessMetaData apiProcessMetaData = apiProcessMetaDataContainer.getApiProcessMetaData(apiInstanceMetaData.getName());
|
||||
if(apiProcessMetaData == null)
|
||||
{
|
||||
LOG.trace("excluding process because apiProcessMetaData is null (process=" + process.getName() + ")");
|
||||
return (null);
|
||||
}
|
||||
|
||||
if(BooleanUtils.isTrue(apiProcessMetaData.getIsExcluded()))
|
||||
{
|
||||
LOG.trace("excluding process because is excluded (process=" + process.getName() + ")");
|
||||
return (null);
|
||||
}
|
||||
|
||||
boolean isProcessInAnySupportedVersions = false;
|
||||
List<APIVersion> supportedVersions = apiInstanceMetaData.getSupportedVersions();
|
||||
APIVersionRange apiVersionRange = apiProcessMetaData.getApiVersionRange();
|
||||
for(APIVersion supportedVersion : supportedVersions)
|
||||
{
|
||||
if(apiVersionRange.includes(supportedVersion))
|
||||
{
|
||||
isProcessInAnySupportedVersions = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isProcessInAnySupportedVersions)
|
||||
{
|
||||
LOG.trace("excluding process because it is not in any supported versions (process=" + process.getName() + ")");
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (apiProcessMetaData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -29,6 +29,7 @@ import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -43,8 +44,10 @@ import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataProvider;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.openapi.HttpMethod;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
@ -54,6 +57,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
@ -66,6 +70,8 @@ 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.authentication.Auth0AuthenticationMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.branding.QBrandingMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
||||
@ -156,10 +162,43 @@ public class QJavalinApiHandler
|
||||
////////////////////////////////////////////
|
||||
ApiBuilder.get("/", context -> doSpecHtml(context, apiInstanceMetaData));
|
||||
|
||||
///////////////////////////////////////////
|
||||
// add known paths for specs & docs page //
|
||||
///////////////////////////////////////////
|
||||
ApiBuilder.get("/openapi.yaml", context -> doSpecYaml(context, apiInstanceMetaData));
|
||||
ApiBuilder.get("/openapi.json", context -> doSpecJson(context, apiInstanceMetaData));
|
||||
ApiBuilder.get("/openapi.html", context -> doSpecHtml(context, apiInstanceMetaData));
|
||||
|
||||
///////////////////
|
||||
// add processes //
|
||||
///////////////////
|
||||
for(QProcessMetaData process : qInstance.getProcesses().values())
|
||||
{
|
||||
ApiProcessMetaData apiProcessMetaData = ApiImplementation.getApiProcessMetaDataIfProcessIsInApi(apiInstanceMetaData, process);
|
||||
if(apiProcessMetaData != null)
|
||||
{
|
||||
String path = getProcessApiPath(process, apiProcessMetaData, apiInstanceMetaData);
|
||||
HttpMethod method = apiProcessMetaData.getMethod();
|
||||
switch(method)
|
||||
{
|
||||
case GET -> ApiBuilder.get(path, context -> runProcess(context, process, apiProcessMetaData, apiInstanceMetaData));
|
||||
case POST -> ApiBuilder.post(path, context -> runProcess(context, process, apiProcessMetaData, apiInstanceMetaData));
|
||||
case PUT -> ApiBuilder.put(path, context -> runProcess(context, process, apiProcessMetaData, apiInstanceMetaData));
|
||||
case PATCH -> ApiBuilder.patch(path, context -> runProcess(context, process, apiProcessMetaData, apiInstanceMetaData));
|
||||
case DELETE -> ApiBuilder.delete(path, context -> runProcess(context, process, apiProcessMetaData, apiInstanceMetaData));
|
||||
default -> throw (new QRuntimeException("Unrecognized http method [" + method + "] for process [" + process.getName() + "]"));
|
||||
}
|
||||
|
||||
if(doesProcessSupportAsync(apiInstanceMetaData, process))
|
||||
{
|
||||
ApiBuilder.get(path + "/status/{processId}", context -> getProcessStatus(context, apiInstanceMetaData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
// add wildcard paths for tables //
|
||||
///////////////////////////////////
|
||||
ApiBuilder.path("/{tableName}", () ->
|
||||
{
|
||||
ApiBuilder.get("/openapi.yaml", context -> doSpecYaml(context, apiInstanceMetaData));
|
||||
@ -208,6 +247,104 @@ public class QJavalinApiHandler
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void getProcessStatus(Context context, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
// todo!
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("checkstyle:indentation")
|
||||
private void runProcess(Context context, QProcessMetaData processMetaData, ApiProcessMetaData apiProcessMetaData, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
String version = context.pathParam("version");
|
||||
APILog apiLog = newAPILog(context);
|
||||
|
||||
try
|
||||
{
|
||||
setupSession(context, null, version, apiInstanceMetaData);
|
||||
QJavalinAccessLogger.logStart("apiRunProcess", logPair("process", processMetaData.getName()));
|
||||
|
||||
Map<String, String> parameters = new LinkedHashMap<>();
|
||||
for(QFieldMetaData inputField : CollectionUtils.nonNullList(apiProcessMetaData.getInputFields()))
|
||||
{
|
||||
String value = switch(apiProcessMetaData.getMethod())
|
||||
{
|
||||
case GET -> context.queryParam(inputField.getName());
|
||||
// todo - other methods (all from a JSON body??)
|
||||
default -> throw new QException("Http method " + apiLog.getMethod() + " is not yet implemented for reading parameters");
|
||||
};
|
||||
parameters.put(inputField.getName(), value);
|
||||
}
|
||||
|
||||
Map<String, Serializable> outputRecord = ApiImplementation.runProcess(apiInstanceMetaData, version, apiProcessMetaData.getApiProcessName(), parameters);
|
||||
|
||||
QJavalinAccessLogger.logEndSuccess();
|
||||
String resultString = toJson(outputRecord);
|
||||
context.result(resultString);
|
||||
storeApiLog(apiLog.withStatusCode(context.statusCode()).withResponseBody(resultString));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
QJavalinAccessLogger.logEndFail(e);
|
||||
handleException(context, e, apiLog);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private boolean doesProcessSupportAsync(ApiInstanceMetaData apiInstanceMetaData, QProcessMetaData process)
|
||||
{
|
||||
// todo - implement
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private String getProcessApiPath(QProcessMetaData process, ApiProcessMetaData apiProcessMetaData, ApiInstanceMetaData apiInstanceMetaData)
|
||||
{
|
||||
if(StringUtils.hasContent(apiProcessMetaData.getPath()))
|
||||
{
|
||||
return apiProcessMetaData.getPath() + "/" + apiProcessMetaData.getApiProcessName();
|
||||
}
|
||||
else if(StringUtils.hasContent(process.getTableName()))
|
||||
{
|
||||
QTableMetaData table = qInstance.getTable(process.getTableName());
|
||||
String tablePathPart = table.getName();
|
||||
ApiTableMetaDataContainer apiTableMetaDataContainer = ApiTableMetaDataContainer.of(table);
|
||||
if(apiTableMetaDataContainer != null)
|
||||
{
|
||||
ApiTableMetaData apiTableMetaData = apiTableMetaDataContainer.getApis().get(apiInstanceMetaData.getName());
|
||||
if(apiTableMetaData != null)
|
||||
{
|
||||
if(StringUtils.hasContent(apiTableMetaData.getApiTableName()))
|
||||
{
|
||||
tablePathPart = apiTableMetaData.getApiTableName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return tablePathPart + "/" + apiProcessMetaData.getApiProcessName();
|
||||
}
|
||||
else
|
||||
{
|
||||
return apiProcessMetaData.getApiProcessName();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.api.model.metadata.processes;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum ApiProcessCustomizers
|
||||
{
|
||||
PRE_RUN("preRun", PreRunApiProcessCustomizer.class),
|
||||
POST_RUN("postRun", PreRunApiProcessCustomizer.class);
|
||||
|
||||
private final String role;
|
||||
private final Class<?> expectedType;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
ApiProcessCustomizers(String role, Class<?> expectedType)
|
||||
{
|
||||
this.role = role;
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the FilesystemTableCustomer for a given role (e.g., the role used in meta-data, not
|
||||
** the enum-constant name).
|
||||
*******************************************************************************/
|
||||
public static ApiProcessCustomizers forRole(String name)
|
||||
{
|
||||
for(ApiProcessCustomizers value : values())
|
||||
{
|
||||
if(value.role.equals(name))
|
||||
{
|
||||
return (value);
|
||||
}
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for role
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getRole()
|
||||
{
|
||||
return role;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for expectedType
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Class<?> getExpectedType()
|
||||
{
|
||||
return expectedType;
|
||||
}
|
||||
}
|
@ -0,0 +1,496 @@
|
||||
/*
|
||||
* 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.api.model.metadata.processes;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.api.ApiSupplementType;
|
||||
import com.kingsrook.qqq.api.model.APIVersionRange;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.openapi.HttpMethod;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
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.model.metadata.processes.QStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiProcessMetaData
|
||||
{
|
||||
private String initialVersion;
|
||||
private String finalVersion;
|
||||
|
||||
private String apiProcessName;
|
||||
private Boolean isExcluded;
|
||||
|
||||
private String path;
|
||||
private HttpMethod method;
|
||||
|
||||
private List<QFieldMetaData> inputFields;
|
||||
private List<QFieldMetaData> outputFields;
|
||||
|
||||
private Map<String, QCodeReference> customizers;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withInferredInputFields(QProcessMetaData processMetaData)
|
||||
{
|
||||
inputFields = new ArrayList<>();
|
||||
for(QStepMetaData stepMetaData : CollectionUtils.nonNullList(processMetaData.getStepList()))
|
||||
{
|
||||
if(stepMetaData instanceof QFrontendStepMetaData frontendStep)
|
||||
{
|
||||
inputFields.addAll(frontendStep.getInputFields());
|
||||
}
|
||||
}
|
||||
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withInferredOutputFields(QProcessMetaData processMetaData)
|
||||
{
|
||||
outputFields = new ArrayList<>();
|
||||
for(QStepMetaData stepMetaData : CollectionUtils.nonNullList(processMetaData.getStepList()))
|
||||
{
|
||||
if(stepMetaData instanceof QFrontendStepMetaData frontendStep)
|
||||
{
|
||||
outputFields.addAll(frontendStep.getOutputFields());
|
||||
}
|
||||
}
|
||||
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public APIVersionRange getApiVersionRange()
|
||||
{
|
||||
if(getInitialVersion() == null)
|
||||
{
|
||||
return APIVersionRange.none();
|
||||
}
|
||||
|
||||
return (getFinalVersion() != null
|
||||
? APIVersionRange.betweenAndIncluding(getInitialVersion(), getFinalVersion())
|
||||
: APIVersionRange.afterAndIncluding(getInitialVersion()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void enrich(String apiName, QProcessMetaData process)
|
||||
{
|
||||
if(!StringUtils.hasContent(getApiProcessName()))
|
||||
{
|
||||
setApiProcessName(process.getName());
|
||||
}
|
||||
|
||||
if(initialVersion != null)
|
||||
{
|
||||
///////////////////////////////////////////////////////////////
|
||||
// make sure all fields have at least an initial version set //
|
||||
///////////////////////////////////////////////////////////////
|
||||
for(QFieldMetaData field : CollectionUtils.mergeLists(getInputFields(), getOutputFields()))
|
||||
{
|
||||
ApiFieldMetaData apiFieldMetaData = ensureFieldHasApiSupplementalMetaData(apiName, field);
|
||||
if(apiFieldMetaData.getInitialVersion() == null)
|
||||
{
|
||||
apiFieldMetaData.setInitialVersion(initialVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static ApiFieldMetaData ensureFieldHasApiSupplementalMetaData(String apiName, QFieldMetaData field)
|
||||
{
|
||||
if(field.getSupplementalMetaData(ApiSupplementType.NAME) == null)
|
||||
{
|
||||
field.withSupplementalMetaData(new ApiFieldMetaDataContainer());
|
||||
}
|
||||
|
||||
ApiFieldMetaDataContainer apiFieldMetaDataContainer = ApiFieldMetaDataContainer.of(field);
|
||||
if(apiFieldMetaDataContainer.getApiFieldMetaData(apiName) == null)
|
||||
{
|
||||
apiFieldMetaDataContainer.withApiFieldMetaData(apiName, new ApiFieldMetaData());
|
||||
}
|
||||
|
||||
return (apiFieldMetaDataContainer.getApiFieldMetaData(apiName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for a single outputField
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withOutputField(QFieldMetaData outputField)
|
||||
{
|
||||
if(this.outputFields == null)
|
||||
{
|
||||
this.outputFields = new ArrayList<>();
|
||||
}
|
||||
this.outputFields.add(outputField);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for a single inputField
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withInputField(QFieldMetaData inputField)
|
||||
{
|
||||
if(this.inputFields == null)
|
||||
{
|
||||
this.inputFields = new ArrayList<>();
|
||||
}
|
||||
this.inputFields.add(inputField);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for initialVersion
|
||||
*******************************************************************************/
|
||||
public String getInitialVersion()
|
||||
{
|
||||
return (this.initialVersion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for initialVersion
|
||||
*******************************************************************************/
|
||||
public void setInitialVersion(String initialVersion)
|
||||
{
|
||||
this.initialVersion = initialVersion;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for initialVersion
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withInitialVersion(String initialVersion)
|
||||
{
|
||||
this.initialVersion = initialVersion;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for finalVersion
|
||||
*******************************************************************************/
|
||||
public String getFinalVersion()
|
||||
{
|
||||
return (this.finalVersion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for finalVersion
|
||||
*******************************************************************************/
|
||||
public void setFinalVersion(String finalVersion)
|
||||
{
|
||||
this.finalVersion = finalVersion;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for finalVersion
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withFinalVersion(String finalVersion)
|
||||
{
|
||||
this.finalVersion = finalVersion;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apiProcessName
|
||||
*******************************************************************************/
|
||||
public String getApiProcessName()
|
||||
{
|
||||
return (this.apiProcessName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for apiProcessName
|
||||
*******************************************************************************/
|
||||
public void setApiProcessName(String apiProcessName)
|
||||
{
|
||||
this.apiProcessName = apiProcessName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apiProcessName
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withApiProcessName(String apiProcessName)
|
||||
{
|
||||
this.apiProcessName = apiProcessName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isExcluded
|
||||
*******************************************************************************/
|
||||
public Boolean getIsExcluded()
|
||||
{
|
||||
return (this.isExcluded);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for isExcluded
|
||||
*******************************************************************************/
|
||||
public void setIsExcluded(Boolean isExcluded)
|
||||
{
|
||||
this.isExcluded = isExcluded;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for isExcluded
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withIsExcluded(Boolean isExcluded)
|
||||
{
|
||||
this.isExcluded = isExcluded;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for method
|
||||
*******************************************************************************/
|
||||
public HttpMethod getMethod()
|
||||
{
|
||||
return (this.method);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for method
|
||||
*******************************************************************************/
|
||||
public void setMethod(HttpMethod method)
|
||||
{
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for method
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withMethod(HttpMethod method)
|
||||
{
|
||||
this.method = method;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for path
|
||||
*******************************************************************************/
|
||||
public String getPath()
|
||||
{
|
||||
return (this.path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for path
|
||||
*******************************************************************************/
|
||||
public void setPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for path
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for inputFields
|
||||
*******************************************************************************/
|
||||
public List<QFieldMetaData> getInputFields()
|
||||
{
|
||||
return (this.inputFields);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for inputFields
|
||||
*******************************************************************************/
|
||||
public void setInputFields(List<QFieldMetaData> inputFields)
|
||||
{
|
||||
this.inputFields = inputFields;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for inputFields
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withInputFields(List<QFieldMetaData> inputFields)
|
||||
{
|
||||
this.inputFields = inputFields;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for outputFields
|
||||
*******************************************************************************/
|
||||
public List<QFieldMetaData> getOutputFields()
|
||||
{
|
||||
return (this.outputFields);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for outputFields
|
||||
*******************************************************************************/
|
||||
public void setOutputFields(List<QFieldMetaData> outputFields)
|
||||
{
|
||||
this.outputFields = outputFields;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for outputFields
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withOutputFields(List<QFieldMetaData> outputFields)
|
||||
{
|
||||
this.outputFields = outputFields;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for customizers
|
||||
*******************************************************************************/
|
||||
public Map<String, QCodeReference> getCustomizers()
|
||||
{
|
||||
return (this.customizers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for customizers
|
||||
*******************************************************************************/
|
||||
public void setCustomizers(Map<String, QCodeReference> customizers)
|
||||
{
|
||||
this.customizers = customizers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for customizers
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withCustomizers(Map<String, QCodeReference> customizers)
|
||||
{
|
||||
this.customizers = customizers;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData withCustomizer(String role, QCodeReference customizer)
|
||||
{
|
||||
if(this.customizers == null)
|
||||
{
|
||||
this.customizers = new HashMap<>();
|
||||
}
|
||||
|
||||
if(this.customizers.containsKey(role))
|
||||
{
|
||||
throw (new IllegalArgumentException("Attempt to add a second customizer with role [" + role + "] to apiProcess [" + apiProcessName + "]."));
|
||||
}
|
||||
this.customizers.put(role, customizer);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.api.model.metadata.processes;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.api.ApiSupplementType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QSupplementalProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ApiProcessMetaDataContainer extends QSupplementalProcessMetaData
|
||||
{
|
||||
private Map<String, ApiProcessMetaData> apis;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaDataContainer()
|
||||
{
|
||||
setType("api");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static ApiProcessMetaDataContainer of(QProcessMetaData process)
|
||||
{
|
||||
return ((ApiProcessMetaDataContainer) process.getSupplementalMetaData(ApiSupplementType.NAME));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void enrich(QProcessMetaData process)
|
||||
{
|
||||
super.enrich(process);
|
||||
|
||||
for(Map.Entry<String, ApiProcessMetaData> entry : CollectionUtils.nonNullMap(apis).entrySet())
|
||||
{
|
||||
entry.getValue().enrich(entry.getKey(), process);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public Map<String, ApiProcessMetaData> getApis()
|
||||
{
|
||||
return (this.apis);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for apis
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaData getApiProcessMetaData(String apiName)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (this.apis.get(apiName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for apis
|
||||
*******************************************************************************/
|
||||
public void setApis(Map<String, ApiProcessMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaDataContainer withApis(Map<String, ApiProcessMetaData> apis)
|
||||
{
|
||||
this.apis = apis;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for apis
|
||||
*******************************************************************************/
|
||||
public ApiProcessMetaDataContainer withApiProcessMetaData(String apiName, ApiProcessMetaData apiProcessMetaData)
|
||||
{
|
||||
if(this.apis == null)
|
||||
{
|
||||
this.apis = new LinkedHashMap<>();
|
||||
}
|
||||
this.apis.put(apiName, apiProcessMetaData);
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.kingsrook.qqq.api.model.metadata.processes;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface PostRunApiProcessCustomizer
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
void postApiRun(RunProcessInput runProcessInput, RunProcessOutput runProcessOutput) throws QException;
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.kingsrook.qqq.api.model.metadata.processes;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface PreRunApiProcessCustomizer
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
void preApiRun(RunProcessInput runProcessInput) throws QException;
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.kingsrook.qqq.api.model.openapi;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public enum HttpMethod
|
||||
{
|
||||
GET,
|
||||
POST,
|
||||
PUT,
|
||||
PATCH,
|
||||
DELETE
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.kingsrook.qqq.api;
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class GetPersonInfoStep implements BackendStep
|
||||
{
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||
{
|
||||
runBackendStepOutput.addValue("density", new BigDecimal("3.50"));
|
||||
runBackendStepOutput.addValue("daysOld", runBackendStepInput.getValueInteger("age") * 365);
|
||||
runBackendStepOutput.addValue("nickname", "Guy from " + runBackendStepInput.getValueString("homeTown"));
|
||||
}
|
||||
|
||||
}
|
@ -29,8 +29,11 @@ import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.processes.ApiProcessMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
|
||||
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaDataContainer;
|
||||
import com.kingsrook.qqq.api.model.openapi.HttpMethod;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPreDeleteCustomizer;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPreInsertCustomizer;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPreUpdateCustomizer;
|
||||
@ -45,12 +48,23 @@ import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.authentication.Auth0AuthenticationMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.HtmlWrapper;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.nocode.WidgetHtmlLine;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PVSValueFormatAndFields;
|
||||
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.NoCodeWidgetFrontendComponentMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QComponentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
|
||||
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.model.metadata.tables.Association;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
|
||||
@ -59,6 +73,7 @@ import com.kingsrook.qqq.backend.core.model.statusmessages.QWarningMessage;
|
||||
import com.kingsrook.qqq.backend.core.model.statusmessages.SystemErrorStatusMessage;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryBackendModule;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.ListBuilder;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -74,6 +89,8 @@ public class TestUtils
|
||||
public static final String TABLE_NAME_LINE_ITEM_EXTRINSIC = "orderLineExtrinsic";
|
||||
public static final String TABLE_NAME_ORDER_EXTRINSIC = "orderExtrinsic";
|
||||
|
||||
public static final String PROCESS_NAME_GET_PERSON_INFO = "getPersonInfo";
|
||||
|
||||
public static final String API_NAME = "test-api";
|
||||
public static final String ALTERNATIVE_API_NAME = "person-api";
|
||||
|
||||
@ -103,6 +120,9 @@ public class TestUtils
|
||||
qInstance.addJoin(defineJoinLineItemLineItemExtrinsic());
|
||||
qInstance.addJoin(defineJoinOrderOrderExtrinsic());
|
||||
|
||||
qInstance.addPossibleValueSource(definePersonPossibleValueSource());
|
||||
qInstance.addProcess(defineProcessGetPersonInfo());
|
||||
|
||||
qInstance.setAuthentication(new Auth0AuthenticationMetaData().withType(QAuthenticationType.FULLY_ANONYMOUS).withName("anonymous"));
|
||||
|
||||
qInstance.withSupplementalMetaData(new ApiInstanceMetaDataContainer()
|
||||
@ -133,6 +153,80 @@ public class TestUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static QPossibleValueSource definePersonPossibleValueSource()
|
||||
{
|
||||
return new QPossibleValueSource()
|
||||
.withName(TABLE_NAME_PERSON)
|
||||
.withType(QPossibleValueSourceType.TABLE)
|
||||
.withTableName(TABLE_NAME_PERSON)
|
||||
.withValueFormatAndFields(PVSValueFormatAndFields.LABEL_ONLY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static QProcessMetaData defineProcessGetPersonInfo()
|
||||
{
|
||||
QProcessMetaData process = new QProcessMetaData()
|
||||
.withName(PROCESS_NAME_GET_PERSON_INFO)
|
||||
.withLabel("Get Person Info")
|
||||
.withTableName(TABLE_NAME_PERSON)
|
||||
.addStep(new QFrontendStepMetaData()
|
||||
.withName("enterInputs")
|
||||
.withLabel("Person Info Input")
|
||||
.withComponent(new QFrontendComponentMetaData().withType(QComponentType.EDIT_FORM))
|
||||
|
||||
.withFormField(new QFieldMetaData("age", QFieldType.INTEGER))
|
||||
.withFormField(new QFieldMetaData("partnerPersonId", QFieldType.INTEGER).withPossibleValueSourceName(TABLE_NAME_PERSON))
|
||||
.withFormField(new QFieldMetaData("heightInches", QFieldType.DECIMAL))
|
||||
.withFormField(new QFieldMetaData("weightPounds", QFieldType.INTEGER))
|
||||
.withFormField(new QFieldMetaData("homeTown", QFieldType.STRING))
|
||||
|
||||
.withComponent(new NoCodeWidgetFrontendComponentMetaData()
|
||||
|
||||
.withOutput(new WidgetHtmlLine()
|
||||
.withWrapper(HtmlWrapper.divWithStyles(HtmlWrapper.STYLE_FLOAT_RIGHT, HtmlWrapper.STYLE_MEDIUM_CENTERED, HtmlWrapper.styleWidth("50%")))
|
||||
.withVelocityTemplate("""
|
||||
<b>Density:</b><br />$density<br/>
|
||||
"""))
|
||||
|
||||
.withOutput(new WidgetHtmlLine()
|
||||
.withVelocityTemplate("""
|
||||
<b>Days old:</b> $daysOld<br/>
|
||||
<b>Nickname:</b> $nickname<br/>
|
||||
"""))
|
||||
))
|
||||
|
||||
.addStep(new QBackendStepMetaData()
|
||||
.withName("execute")
|
||||
.withCode(new QCodeReference(GetPersonInfoStep.class)))
|
||||
|
||||
.addStep(new QFrontendStepMetaData()
|
||||
.withName("dummyStep")
|
||||
);
|
||||
|
||||
process.withSupplementalMetaData(new ApiProcessMetaDataContainer()
|
||||
.withApiProcessMetaData(API_NAME, new ApiProcessMetaData()
|
||||
.withInitialVersion(CURRENT_API_VERSION)
|
||||
.withMethod(HttpMethod.GET)
|
||||
.withInferredInputFields(process)
|
||||
.withOutputFields(ListBuilder.of(
|
||||
new QFieldMetaData("density", QFieldType.DECIMAL),
|
||||
new QFieldMetaData("daysOld", QFieldType.INTEGER),
|
||||
new QFieldMetaData("nickname", QFieldType.STRING)
|
||||
))
|
||||
));
|
||||
|
||||
return (process);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Define the in-memory backend used in standard tests
|
||||
*******************************************************************************/
|
||||
|
@ -1439,6 +1439,20 @@ class QJavalinApiHandlerTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testProcess() throws QException
|
||||
{
|
||||
HttpResponse<String> response = Unirest.get(BASE_URL + "/api/" + VERSION + "/person/getPersonInfo?age=43&partnerPersonId=1&heightInches=72&weightPounds=220&homeTown=Chester").asString();
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
JSONObject jsonObject = new JSONObject(response.getBody());
|
||||
System.out.println(jsonObject.toString(3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user