Merge branch 'integration/sprint-27' into feature/CTLE-509-support-sending-custom-data-fields-to-deposco

This commit is contained in:
2023-06-20 10:37:20 -05:00
committed by GitHub
61 changed files with 4854 additions and 195 deletions

View File

@ -39,6 +39,7 @@ import com.kingsrook.qqq.backend.core.state.InMemoryStateProvider;
import com.kingsrook.qqq.backend.core.state.StateProviderInterface;
import com.kingsrook.qqq.backend.core.state.StateType;
import com.kingsrook.qqq.backend.core.state.UUIDAndTypeStateKey;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import org.apache.logging.log4j.Level;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -50,6 +51,7 @@ public class AsyncJobManager
{
private static final QLogger LOG = QLogger.getLogger(AsyncJobManager.class);
private String forcedJobUUID = null;
/*******************************************************************************
@ -69,7 +71,8 @@ public class AsyncJobManager
*******************************************************************************/
public <T extends Serializable> T startJob(String jobName, long timeout, TimeUnit timeUnit, AsyncJob<T> asyncJob) throws JobGoingAsyncException, QException
{
UUIDAndTypeStateKey uuidAndTypeStateKey = new UUIDAndTypeStateKey(UUID.randomUUID(), StateType.ASYNC_JOB_STATUS);
UUID jobUUID = StringUtils.hasContent(forcedJobUUID) ? UUID.fromString(forcedJobUUID) : UUID.randomUUID();
UUIDAndTypeStateKey uuidAndTypeStateKey = new UUIDAndTypeStateKey(jobUUID, StateType.ASYNC_JOB_STATUS);
AsyncJobStatus asyncJobStatus = new AsyncJobStatus();
asyncJobStatus.setState(AsyncJobState.RUNNING);
getStateProvider().put(uuidAndTypeStateKey, asyncJobStatus);
@ -205,4 +208,35 @@ public class AsyncJobManager
jobStatus.ifPresent(asyncJobStatus -> asyncJobStatus.setCancelRequested(true));
}
/*******************************************************************************
** Getter for forcedJobUUID
*******************************************************************************/
public String getForcedJobUUID()
{
return (this.forcedJobUUID);
}
/*******************************************************************************
** Setter for forcedJobUUID
*******************************************************************************/
public void setForcedJobUUID(String forcedJobUUID)
{
this.forcedJobUUID = forcedJobUUID;
}
/*******************************************************************************
** Fluent setter for forcedJobUUID
*******************************************************************************/
public AsyncJobManager withForcedJobUUID(String forcedJobUUID)
{
this.forcedJobUUID = forcedJobUUID;
return (this);
}
}

View File

@ -57,12 +57,13 @@ 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;
import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QMiddlewareTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QSupplementalTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.Tier;
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.delete.BulkDeleteLoadStep;
@ -261,9 +262,9 @@ public class QInstanceEnricher
{
table.getFields().values().forEach(this::enrichField);
for(QMiddlewareTableMetaData middlewareTableMetaData : CollectionUtils.nonNullMap(table.getMiddlewareMetaData()).values())
for(QSupplementalTableMetaData supplementalTableMetaData : CollectionUtils.nonNullMap(table.getSupplementalMetaData()).values())
{
middlewareTableMetaData.enrich(table);
supplementalTableMetaData.enrich(table);
}
}
@ -367,6 +368,11 @@ public class QInstanceEnricher
process.getStepList().forEach(this::enrichStep);
}
for(QSupplementalProcessMetaData supplementalProcessMetaData : CollectionUtils.nonNullMap(process.getSupplementalMetaData()).values())
{
supplementalProcessMetaData.enrich(this, process);
}
enrichPermissionRules(process);
}

View File

@ -48,7 +48,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
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.QMiddlewareInstanceMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QSupplementalInstanceMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
@ -63,6 +63,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
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.queues.SQSQueueProviderMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportDataSource;
import com.kingsrook.qqq.backend.core.model.metadata.reporting.QReportField;
@ -158,7 +159,7 @@ public class QInstanceValidator
validateQueuesAndProviders(qInstance);
validateJoins(qInstance);
validateSecurityKeyTypes(qInstance);
validateMiddlewareMetaData(qInstance);
validateSupplementalMetaData(qInstance);
validateUniqueTopLevelNames(qInstance);
}
@ -182,11 +183,11 @@ public class QInstanceValidator
/*******************************************************************************
**
*******************************************************************************/
private void validateMiddlewareMetaData(QInstance qInstance)
private void validateSupplementalMetaData(QInstance qInstance)
{
for(QMiddlewareInstanceMetaData middlewareInstanceMetaData : CollectionUtils.nonNullMap(qInstance.getMiddlewareMetaData()).values())
for(QSupplementalInstanceMetaData supplementalInstanceMetaData : CollectionUtils.nonNullMap(qInstance.getSupplementalMetaData()).values())
{
middlewareInstanceMetaData.validate(qInstance, this);
supplementalInstanceMetaData.validate(qInstance, this);
}
}
@ -1226,6 +1227,11 @@ public class QInstanceValidator
}
}
for(QSupplementalProcessMetaData supplementalProcessMetaData : CollectionUtils.nonNullMap(process.getSupplementalMetaData()).values())
{
supplementalProcessMetaData.validate(qInstance, process, this);
}
});
}
}
@ -1703,7 +1709,7 @@ public class QInstanceValidator
** But if it throws, add the provided message to the list of errors (and return false,
** e.g., in case you need to stop evaluating rules to avoid exceptions).
*******************************************************************************/
private boolean assertNoException(UnsafeLambda unsafeLambda, String message)
public boolean assertNoException(UnsafeLambda unsafeLambda, String message)
{
try
{
@ -1736,7 +1742,7 @@ public class QInstanceValidator
/*******************************************************************************
**
*******************************************************************************/
private void warn(String message)
public void warn(String message)
{
if(printWarnings)
{

View File

@ -22,8 +22,10 @@
package com.kingsrook.qqq.backend.core.model.actions.processes;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kingsrook.qqq.backend.core.logging.LogPair;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -76,6 +78,35 @@ public class ProcessSummaryFilterLink implements ProcessSummaryLineInterface
/*******************************************************************************
**
*******************************************************************************/
@JsonIgnore
public String getFullText()
{
StringBuilder rs = new StringBuilder();
if(StringUtils.hasContent(linkPreText))
{
rs.append(linkPreText).append(" ");
}
if(StringUtils.hasContent(linkText))
{
rs.append(linkText).append(" ");
}
if(StringUtils.hasContent(linkPostText))
{
rs.append(linkPostText).append(" ");
}
rs.deleteCharAt(rs.length() - 1);
return (rs.toString());
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -26,6 +26,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.logging.LogPair;
import com.kingsrook.qqq.backend.core.utils.ObjectUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -395,15 +396,19 @@ public class ProcessSummaryLine implements ProcessSummaryLineInterface
{
if(count != null)
{
String baseMessage;
if(count.equals(1))
{
setMessage((isPast ? getSingularPastMessage() : getSingularFutureMessage())
+ (messageSuffix == null ? "" : messageSuffix));
baseMessage = isPast ? getSingularPastMessage() : getSingularFutureMessage();
}
else
{
setMessage((isPast ? getPluralPastMessage() : getPluralFutureMessage())
+ (messageSuffix == null ? "" : messageSuffix));
baseMessage = isPast ? getPluralPastMessage() : getPluralFutureMessage();
}
if(StringUtils.hasContent(baseMessage))
{
setMessage(baseMessage + ObjectUtils.requireConditionElse(messageSuffix, StringUtils::hasContent, ""));
}
}
}

View File

@ -23,7 +23,9 @@ package com.kingsrook.qqq.backend.core.model.actions.processes;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kingsrook.qqq.backend.core.logging.LogPair;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
@ -64,6 +66,35 @@ public class ProcessSummaryRecordLink implements ProcessSummaryLineInterface
/*******************************************************************************
**
*******************************************************************************/
@JsonIgnore
public String getFullText()
{
StringBuilder rs = new StringBuilder();
if(StringUtils.hasContent(linkPreText))
{
rs.append(linkPreText).append(" ");
}
if(StringUtils.hasContent(linkText))
{
rs.append(linkText).append(" ");
}
if(StringUtils.hasContent(linkPostText))
{
rs.append(linkPostText).append(" ");
}
rs.deleteCharAt(rs.length() - 1);
return (rs.toString());
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -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)));
}

View File

@ -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
**

View File

@ -91,7 +91,7 @@ public class QInstance
private Map<String, QQueueProviderMetaData> queueProviders = new LinkedHashMap<>();
private Map<String, QQueueMetaData> queues = new LinkedHashMap<>();
private Map<String, QMiddlewareInstanceMetaData> middlewareMetaData = new LinkedHashMap<>();
private Map<String, QSupplementalInstanceMetaData> supplementalMetaData = new LinkedHashMap<>();
private Map<String, String> environmentValues = new LinkedHashMap<>();
private String defaultTimeZoneId = "UTC";
@ -1083,60 +1083,60 @@ public class QInstance
/*******************************************************************************
** Getter for middlewareMetaData
** Getter for supplementalMetaData
*******************************************************************************/
public Map<String, QMiddlewareInstanceMetaData> getMiddlewareMetaData()
public Map<String, QSupplementalInstanceMetaData> getSupplementalMetaData()
{
return (this.middlewareMetaData);
return (this.supplementalMetaData);
}
/*******************************************************************************
** Getter for middlewareMetaData
** Getter for supplementalMetaData
*******************************************************************************/
public QMiddlewareInstanceMetaData getMiddlewareMetaData(String type)
public QSupplementalInstanceMetaData getSupplementalMetaData(String type)
{
if(this.middlewareMetaData == null)
if(this.supplementalMetaData == null)
{
return (null);
}
return this.middlewareMetaData.get(type);
return this.supplementalMetaData.get(type);
}
/*******************************************************************************
** Setter for middlewareMetaData
** Setter for supplementalMetaData
*******************************************************************************/
public void setMiddlewareMetaData(Map<String, QMiddlewareInstanceMetaData> middlewareMetaData)
public void setSupplementalMetaData(Map<String, QSupplementalInstanceMetaData> supplementalMetaData)
{
this.middlewareMetaData = middlewareMetaData;
this.supplementalMetaData = supplementalMetaData;
}
/*******************************************************************************
** Fluent setter for middlewareMetaData
** Fluent setter for supplementalMetaData
*******************************************************************************/
public QInstance withMiddlewareMetaData(Map<String, QMiddlewareInstanceMetaData> middlewareMetaData)
public QInstance withSupplementalMetaData(Map<String, QSupplementalInstanceMetaData> supplementalMetaData)
{
this.middlewareMetaData = middlewareMetaData;
this.supplementalMetaData = supplementalMetaData;
return (this);
}
/*******************************************************************************
** Fluent setter for middlewareMetaData
** Fluent setter for supplementalMetaData
*******************************************************************************/
public QInstance withMiddlewareMetaData(QMiddlewareInstanceMetaData middlewareMetaData)
public QInstance withSupplementalMetaData(QSupplementalInstanceMetaData supplementalMetaData)
{
if(this.middlewareMetaData == null)
if(this.supplementalMetaData == null)
{
this.middlewareMetaData = new HashMap<>();
this.supplementalMetaData = new HashMap<>();
}
this.middlewareMetaData.put(middlewareMetaData.getType(), middlewareMetaData);
this.supplementalMetaData.put(supplementalMetaData.getType(), supplementalMetaData);
return (this);
}

View File

@ -27,9 +27,10 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
/*******************************************************************************
** Base-class for instance-level meta-data defined for a specific middleware.
** Base-class for instance-level meta-data defined by some supplemental module, etc,
** outside of qqq core
*******************************************************************************/
public abstract class QMiddlewareInstanceMetaData
public abstract class QSupplementalInstanceMetaData
{
protected String type;
@ -58,7 +59,7 @@ public abstract class QMiddlewareInstanceMetaData
/*******************************************************************************
** Fluent setter for type
*******************************************************************************/
public QMiddlewareInstanceMetaData withType(String type)
public QSupplementalInstanceMetaData withType(String type)
{
this.type = type;
return (this);

View File

@ -85,7 +85,7 @@ public class QFieldMetaData implements Cloneable
private List<FieldAdornment> adornments;
private Map<String, QMiddlewareFieldMetaData> middlewareMetaData;
private Map<String, QSupplementalFieldMetaData> supplementalMetaData;
@ -840,60 +840,60 @@ public class QFieldMetaData implements Cloneable
/*******************************************************************************
** Getter for middlewareMetaData
** Getter for supplementalMetaData
*******************************************************************************/
public Map<String, QMiddlewareFieldMetaData> getMiddlewareMetaData()
public Map<String, QSupplementalFieldMetaData> getSupplementalMetaData()
{
return (this.middlewareMetaData);
return (this.supplementalMetaData);
}
/*******************************************************************************
** Getter for middlewareMetaData
** Getter for supplementalMetaData
*******************************************************************************/
public QMiddlewareFieldMetaData getMiddlewareMetaData(String type)
public QSupplementalFieldMetaData getSupplementalMetaData(String type)
{
if(this.middlewareMetaData == null)
if(this.supplementalMetaData == null)
{
return (null);
}
return this.middlewareMetaData.get(type);
return this.supplementalMetaData.get(type);
}
/*******************************************************************************
** Setter for middlewareMetaData
** Setter for supplementalMetaData
*******************************************************************************/
public void setMiddlewareMetaData(Map<String, QMiddlewareFieldMetaData> middlewareMetaData)
public void setSupplementalMetaData(Map<String, QSupplementalFieldMetaData> supplementalMetaData)
{
this.middlewareMetaData = middlewareMetaData;
this.supplementalMetaData = supplementalMetaData;
}
/*******************************************************************************
** Fluent setter for middlewareMetaData
** Fluent setter for supplementalMetaData
*******************************************************************************/
public QFieldMetaData withMiddlewareMetaData(Map<String, QMiddlewareFieldMetaData> middlewareMetaData)
public QFieldMetaData withSupplementalMetaData(Map<String, QSupplementalFieldMetaData> supplementalMetaData)
{
this.middlewareMetaData = middlewareMetaData;
this.supplementalMetaData = supplementalMetaData;
return (this);
}
/*******************************************************************************
** Fluent setter for middlewareMetaData
** Fluent setter for supplementalMetaData
*******************************************************************************/
public QFieldMetaData withMiddlewareMetaData(QMiddlewareFieldMetaData middlewareMetaData)
public QFieldMetaData withSupplementalMetaData(QSupplementalFieldMetaData supplementalMetaData)
{
if(this.middlewareMetaData == null)
if(this.supplementalMetaData == null)
{
this.middlewareMetaData = new HashMap<>();
this.supplementalMetaData = new HashMap<>();
}
this.middlewareMetaData.put(middlewareMetaData.getType(), middlewareMetaData);
this.supplementalMetaData.put(supplementalMetaData.getType(), supplementalMetaData);
return (this);
}

View File

@ -23,9 +23,10 @@ package com.kingsrook.qqq.backend.core.model.metadata.fields;
/*******************************************************************************
** Base-class for field-level meta-data defined for a specific middleware.
** Base-class for field-level meta-data defined by some supplemental module, etc,
** outside of qqq core
*******************************************************************************/
public abstract class QMiddlewareFieldMetaData
public abstract class QSupplementalFieldMetaData
{
protected String type;
@ -54,7 +55,7 @@ public abstract class QMiddlewareFieldMetaData
/*******************************************************************************
** Fluent setter for type
*******************************************************************************/
public QMiddlewareFieldMetaData withType(String type)
public QSupplementalFieldMetaData withType(String type)
{
this.type = type;
return (this);

View File

@ -54,6 +54,9 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
private BasepullConfiguration basepullConfiguration;
private QPermissionRules permissionRules;
private Integer minInputRecords = null;
private Integer maxInputRecords = null;
private List<QStepMetaData> stepList; // these are the steps that are ran, by-default, in the order they are ran in
private Map<String, QStepMetaData> steps; // this is the full map of possible steps
@ -61,6 +64,8 @@ public class QProcessMetaData implements QAppChildMetaData, MetaDataWithPermissi
private QScheduleMetaData schedule;
private Map<String, QSupplementalProcessMetaData> supplementalMetaData;
/*******************************************************************************
@ -544,4 +549,126 @@ 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);
}
/*******************************************************************************
** Getter for minInputRecords
*******************************************************************************/
public Integer getMinInputRecords()
{
return (this.minInputRecords);
}
/*******************************************************************************
** Setter for minInputRecords
*******************************************************************************/
public void setMinInputRecords(Integer minInputRecords)
{
this.minInputRecords = minInputRecords;
}
/*******************************************************************************
** Fluent setter for minInputRecords
*******************************************************************************/
public QProcessMetaData withMinInputRecords(Integer minInputRecords)
{
this.minInputRecords = minInputRecords;
return (this);
}
/*******************************************************************************
** Getter for maxInputRecords
*******************************************************************************/
public Integer getMaxInputRecords()
{
return (this.maxInputRecords);
}
/*******************************************************************************
** Setter for maxInputRecords
*******************************************************************************/
public void setMaxInputRecords(Integer maxInputRecords)
{
this.maxInputRecords = maxInputRecords;
}
/*******************************************************************************
** Fluent setter for maxInputRecords
*******************************************************************************/
public QProcessMetaData withMaxInputRecords(Integer maxInputRecords)
{
this.maxInputRecords = maxInputRecords;
return (this);
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.instances.QInstanceEnricher;
import com.kingsrook.qqq.backend.core.instances.QInstanceValidator;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
/*******************************************************************************
** 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(QInstanceEnricher qInstanceEnricher, QProcessMetaData process)
{
////////////////////////
// noop in base class //
////////////////////////
}
/*******************************************************************************
**
*******************************************************************************/
public void validate(QInstance qInstance, QProcessMetaData process, QInstanceValidator qInstanceValidator)
{
////////////////////////
// noop in base class //
////////////////////////
}
}

View File

@ -23,9 +23,10 @@ package com.kingsrook.qqq.backend.core.model.metadata.tables;
/*******************************************************************************
** Base-class for table-level meta-data defined for a specific middleware.
** Base-class for table-level meta-data defined by some supplemental module, etc,
** outside of qqq core
*******************************************************************************/
public abstract class QMiddlewareTableMetaData
public abstract class QSupplementalTableMetaData
{
protected String type;
@ -54,7 +55,7 @@ public abstract class QMiddlewareTableMetaData
/*******************************************************************************
** Fluent setter for type
*******************************************************************************/
public QMiddlewareTableMetaData withType(String type)
public QSupplementalTableMetaData withType(String type)
{
this.type = type;
return (this);

View File

@ -99,7 +99,7 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
private CacheOf cacheOf;
private Map<String, QMiddlewareTableMetaData> middlewareMetaData;
private Map<String, QSupplementalTableMetaData> supplementalMetaData;
private List<ExposedJoin> exposedJoins;
@ -1189,60 +1189,60 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
/*******************************************************************************
** Getter for middlewareMetaData
** Getter for supplementalMetaData
*******************************************************************************/
public Map<String, QMiddlewareTableMetaData> getMiddlewareMetaData()
public Map<String, QSupplementalTableMetaData> getSupplementalMetaData()
{
return (this.middlewareMetaData);
return (this.supplementalMetaData);
}
/*******************************************************************************
** Getter for middlewareMetaData
** Getter for supplementalMetaData
*******************************************************************************/
public QMiddlewareTableMetaData getMiddlewareMetaData(String type)
public QSupplementalTableMetaData getSupplementalMetaData(String type)
{
if(this.middlewareMetaData == null)
if(this.supplementalMetaData == null)
{
return (null);
}
return this.middlewareMetaData.get(type);
return this.supplementalMetaData.get(type);
}
/*******************************************************************************
** Setter for middlewareMetaData
** Setter for supplementalMetaData
*******************************************************************************/
public void setMiddlewareMetaData(Map<String, QMiddlewareTableMetaData> middlewareMetaData)
public void setSupplementalMetaData(Map<String, QSupplementalTableMetaData> supplementalMetaData)
{
this.middlewareMetaData = middlewareMetaData;
this.supplementalMetaData = supplementalMetaData;
}
/*******************************************************************************
** Fluent setter for middlewareMetaData
** Fluent setter for supplementalMetaData
*******************************************************************************/
public QTableMetaData withMiddlewareMetaData(Map<String, QMiddlewareTableMetaData> middlewareMetaData)
public QTableMetaData withSupplementalMetaData(Map<String, QSupplementalTableMetaData> supplementalMetaData)
{
this.middlewareMetaData = middlewareMetaData;
this.supplementalMetaData = supplementalMetaData;
return (this);
}
/*******************************************************************************
** Fluent setter for middlewareMetaData
** Fluent setter for supplementalMetaData
*******************************************************************************/
public QTableMetaData withMiddlewareMetaData(QMiddlewareTableMetaData middlewareMetaData)
public QTableMetaData withSupplementalMetaData(QSupplementalTableMetaData supplementalMetaData)
{
if(this.middlewareMetaData == null)
if(this.supplementalMetaData == null)
{
this.middlewareMetaData = new HashMap<>();
this.supplementalMetaData = new HashMap<>();
}
this.middlewareMetaData.put(middlewareMetaData.getType(), middlewareMetaData);
this.supplementalMetaData.put(supplementalMetaData.getType(), supplementalMetaData);
return (this);
}

View File

@ -102,6 +102,8 @@ public class ScriptsMetaDataProvider
{
return (new QProcessMetaData()
.withName(STORE_SCRIPT_REVISION_PROCESS_NAME)
.withTableName(Script.TABLE_NAME)
.withIsHidden(true)
.withStepList(List.of(
new QBackendStepMetaData()
.withName("main")
@ -118,6 +120,8 @@ public class ScriptsMetaDataProvider
{
return (new QProcessMetaData()
.withName(TEST_SCRIPT_PROCESS_NAME)
.withTableName(Script.TABLE_NAME)
.withIsHidden(true)
.withStepList(List.of(
new QBackendStepMetaData()
.withName("main")

View File

@ -0,0 +1,40 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend;
import com.kingsrook.qqq.backend.core.exceptions.QException;
/*******************************************************************************
**
*******************************************************************************/
public class CouldNotFindQueryFilterForExtractStepException extends QException
{
/*******************************************************************************
**
*******************************************************************************/
public CouldNotFindQueryFilterForExtractStepException(String message)
{
super(message);
}
}

View File

@ -223,7 +223,7 @@ public class ExtractViaQueryStep extends AbstractExtractStep
return (new QQueryFilter().withCriteria(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, idStrings)));
}
throw (new QException("Could not find query filter for Extract step."));
throw (new CouldNotFindQueryFilterForExtractStepException("Could not find query filter for Extract step."));
}

View File

@ -27,6 +27,7 @@ import java.util.List;
import com.kingsrook.qqq.backend.core.actions.async.AsyncRecordPipeLoop;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
@ -71,11 +72,14 @@ public class StreamedETLPreviewStep extends BaseStreamedETLStep implements Backe
return;
}
if(runBackendStepInput.getFrontendStepBehavior() != null && runBackendStepInput.getFrontendStepBehavior().equals(RunProcessInput.FrontendStepBehavior.SKIP))
{
LOG.debug("Skipping preview because frontend behavior is [" + RunProcessInput.FrontendStepBehavior.SKIP + "].");
return;
}
//////////////////////////////
// set up the extract steps //
//////////////////////////////
AbstractExtractStep extractStep = getExtractStep(runBackendStepInput);
RecordPipe recordPipe = new RecordPipe();
extractStep.setLimit(limit);
extractStep.setRecordPipe(recordPipe);
extractStep.preRun(runBackendStepInput, runBackendStepOutput);
/////////////////////////////////////////////////////////////////
// if we're running inside an automation, then skip this step. //
@ -86,17 +90,26 @@ public class StreamedETLPreviewStep extends BaseStreamedETLStep implements Backe
return;
}
//////////////////////////////////////////
// set up the extract & transform steps //
//////////////////////////////////////////
AbstractExtractStep extractStep = getExtractStep(runBackendStepInput);
RecordPipe recordPipe = new RecordPipe();
extractStep.setLimit(limit);
extractStep.setRecordPipe(recordPipe);
extractStep.preRun(runBackendStepInput, runBackendStepOutput);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if skipping frontend steps, skip this action - //
// but, if inside an (ideally, only async) API call, at least do the count, so status calls can get x of y status //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(RunProcessInput.FrontendStepBehavior.SKIP.equals(runBackendStepInput.getFrontendStepBehavior()))
{
if(QContext.getQSession().getValue("apiVersion") != null)
{
countRecords(runBackendStepInput, runBackendStepOutput, extractStep);
}
LOG.debug("Skipping preview because frontend behavior is [" + RunProcessInput.FrontendStepBehavior.SKIP + "].");
return;
}
countRecords(runBackendStepInput, runBackendStepOutput, extractStep);
//////////////////////////////
// setup the transform step //
//////////////////////////////
AbstractTransformStep transformStep = getTransformStep(runBackendStepInput);
transformStep.preRun(runBackendStepInput, runBackendStepOutput);

View File

@ -407,6 +407,30 @@ public class StreamedETLWithFrontendProcess
/*******************************************************************************
** Fluent setter for minInputRecords
**
*******************************************************************************/
public Builder withMinInputRecords(Integer minInputRecords)
{
processMetaData.setMinInputRecords(minInputRecords);
return (this);
}
/*******************************************************************************
** Fluent setter for maxInputRecords
**
*******************************************************************************/
public Builder withMaxInputRecords(Integer maxInputRecords)
{
processMetaData.setMaxInputRecords(maxInputRecords);
return (this);
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -22,7 +22,9 @@
package com.kingsrook.qqq.backend.core.utils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -88,4 +90,39 @@ public class ExceptionUtils
return (root);
}
/*******************************************************************************
**
*******************************************************************************/
public static String concatenateMessagesFromChain(Exception exception)
{
if(exception == null)
{
return (null);
}
List<String> messages = new ArrayList<>();
Throwable root = exception;
Set<Throwable> seen = new HashSet<>();
do
{
if(StringUtils.hasContent(root.getMessage()))
{
messages.add(root.getMessage());
}
else
{
messages.add(root.getClass().getSimpleName());
}
seen.add(root);
root = root.getCause();
}
while(root != null && !seen.contains(root));
return (StringUtils.join("; ", messages));
}
}

View File

@ -22,6 +22,9 @@
package com.kingsrook.qqq.backend.core.utils;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeConsumer;
import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeSupplier;
@ -96,4 +99,44 @@ public class ObjectUtils
return (defaultIfThrew);
}
/*******************************************************************************
**
*******************************************************************************/
public static <T> void ifNotNull(T object, Consumer<T> consumer)
{
if(object != null)
{
consumer.accept(object);
}
}
/*******************************************************************************
**
*******************************************************************************/
public static <T, E extends Exception> void ifNotNullUnsafe(T object, UnsafeConsumer<T, E> consumer) throws E
{
if(object != null)
{
consumer.run(object);
}
}
/*******************************************************************************
**
*******************************************************************************/
public static <T> T requireConditionElse(T a, Predicate<T> condition, T b)
{
if(condition.test(a))
{
return (a);
}
return (b);
}
}

View File

@ -35,18 +35,18 @@ import java.util.function.Supplier;
**
** Can use it 2 ways:
** MapBuilder.of(key, value, key2, value2, ...) => Map (a HashMap)
** MapBuilder.<KeyType ValueType>of(SomeMap::new).with(key, value).with(key2, value2)...build() => SomeMap (the type you specify)
** MapBuilder.of(() -> new SomeMap<SomeKeyType, SomeValueType>()).with(key, value).with(key2, value2)...build() => SomeMap (the type you specify)
*******************************************************************************/
public class MapBuilder<K, V>
public class MapBuilder<K, V, M extends Map<K, V>>
{
private Map<K, V> map;
private M map;
/*******************************************************************************
**
*******************************************************************************/
private MapBuilder(Map<K, V> map)
private MapBuilder(M map)
{
this.map = map;
}
@ -56,7 +56,7 @@ public class MapBuilder<K, V>
/*******************************************************************************
**
*******************************************************************************/
public static <K, V> MapBuilder<K, V> of(Supplier<Map<K, V>> mapSupplier)
public static <K, V, M extends Map<K, V>> MapBuilder<K, V, M> of(Supplier<M> mapSupplier)
{
return (new MapBuilder<>(mapSupplier.get()));
}
@ -66,7 +66,7 @@ public class MapBuilder<K, V>
/*******************************************************************************
**
*******************************************************************************/
public MapBuilder<K, V> with(K key, V value)
public MapBuilder<K, V, M> with(K key, V value)
{
map.put(key, value);
return (this);
@ -77,7 +77,7 @@ public class MapBuilder<K, V>
/*******************************************************************************
**
*******************************************************************************/
public Map<K, V> build()
public M build()
{
return (this.map);
}