mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 21:20:45 +00:00
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -76,6 +76,21 @@ public class AuditAction extends AbstractQActionFunction<AuditInput, AuditOutput
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Execute to insert 1 audit, with a list of detail child records provided as just string messages
|
||||
*******************************************************************************/
|
||||
public static void executeWithStringDetails(String tableName, Integer recordId, Map<String, Serializable> securityKeyValues, String message, List<String> detailMessages)
|
||||
{
|
||||
List<QRecord> detailRecords = null;
|
||||
if(CollectionUtils.nullSafeHasContents(detailMessages))
|
||||
{
|
||||
detailRecords = detailMessages.stream().map(m -> new QRecord().withValue("message", m)).toList();
|
||||
}
|
||||
execute(tableName, recordId, securityKeyValues, message, detailRecords);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Execute to insert 1 audit, with a list of detail child records
|
||||
*******************************************************************************/
|
||||
|
@ -39,12 +39,15 @@ import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.QProcessCallback;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
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.RunProcessInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
@ -61,11 +64,14 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.Automatio
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.QTableAutomationDetails;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.TableAutomationAction;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.TriggerEvent;
|
||||
import com.kingsrook.qqq.backend.core.model.savedfilters.SavedFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -270,16 +276,39 @@ public class PollingAutomationPerTableRunner implements Runnable
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
for(QRecord record : queryOutput.getRecords())
|
||||
{
|
||||
// todo - get filter if there is/was one
|
||||
rs.add(new TableAutomationAction()
|
||||
.withName("Script:" + record.getValue("scriptId"))
|
||||
.withFilter(null)
|
||||
.withTriggerEvent(triggerEvent)
|
||||
.withPriority(record.getValueInteger("priority"))
|
||||
.withCodeReference(new QCodeReference(RunRecordScriptAutomationHandler.class))
|
||||
.withValues(MapBuilder.of("scriptId", record.getValue("scriptId")))
|
||||
.withIncludeRecordAssociations(true)
|
||||
);
|
||||
TableTrigger tableTrigger = new TableTrigger(record);
|
||||
|
||||
try
|
||||
{
|
||||
QQueryFilter filter = null;
|
||||
Integer filterId = tableTrigger.getFilterId();
|
||||
if(filterId != null)
|
||||
{
|
||||
GetInput getInput = new GetInput();
|
||||
getInput.setTableName(SavedFilter.TABLE_NAME);
|
||||
getInput.setPrimaryKey(filterId);
|
||||
GetOutput getOutput = new GetAction().execute(getInput);
|
||||
if(getOutput.getRecord() != null)
|
||||
{
|
||||
SavedFilter savedFilter = new SavedFilter(getOutput.getRecord());
|
||||
filter = JsonUtils.toObject(savedFilter.getFilterJson(), QQueryFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
rs.add(new TableAutomationAction()
|
||||
.withName("Script:" + tableTrigger.getScriptId())
|
||||
.withFilter(filter)
|
||||
.withTriggerEvent(triggerEvent)
|
||||
.withPriority(tableTrigger.getPriority())
|
||||
.withCodeReference(new QCodeReference(RunRecordScriptAutomationHandler.class))
|
||||
.withValues(MapBuilder.of("scriptId", tableTrigger.getScriptId()))
|
||||
.withIncludeRecordAssociations(true)
|
||||
);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.error("Error setting up table trigger", e, logPair("tableTriggerId", tableTrigger.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,17 @@ public class ExecuteCodeAction
|
||||
context.putAll(input.getInput());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// set the qCodeExecutor into any context objects which are QCodeExecutorAware //
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
for(Serializable value : context.values())
|
||||
{
|
||||
if(value instanceof QCodeExecutorAware qCodeExecutorAware)
|
||||
{
|
||||
qCodeExecutorAware.setQCodeExecutor(qCodeExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
Serializable codeOutput = qCodeExecutor.execute(codeReference, context, executionLogger);
|
||||
output.setOutput(codeOutput);
|
||||
executionLogger.acceptExecutionEnd(codeOutput);
|
||||
|
@ -41,4 +41,14 @@ public interface QCodeExecutor
|
||||
*******************************************************************************/
|
||||
Serializable execute(QCodeReference codeReference, Map<String, Serializable> inputContext, QCodeExecutionLoggerInterface executionLogger) throws QCodeException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Process an object from the script's language/runtime into a (more) native java object.
|
||||
** e.g., a Nashorn ScriptObjectMirror will end up as a "primitive", or a List or Map of such
|
||||
**
|
||||
*******************************************************************************/
|
||||
default Object convertObjectToJava(Object object)
|
||||
{
|
||||
return (object);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2023. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.actions.scripts;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for classes that can accept a QCodeExecutor object via a setter.
|
||||
*******************************************************************************/
|
||||
public interface QCodeExecutorAware
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
void setQCodeExecutor(QCodeExecutor qCodeExecutor);
|
||||
|
||||
}
|
@ -136,7 +136,7 @@ public class QValueFormatter
|
||||
{
|
||||
return formatValue(displayFormat, ValueUtils.getValueAsBigDecimal(value));
|
||||
}
|
||||
else if(e.getMessage().equals("d != java.math.BigDecimal"))
|
||||
else if(e.getMessage().equals("d != java.math.BigDecimal") || e.getMessage().equals("d != java.lang.String"))
|
||||
{
|
||||
return formatValue(displayFormat, ValueUtils.getValueAsInteger(value));
|
||||
}
|
||||
|
@ -22,12 +22,19 @@
|
||||
package com.kingsrook.qqq.backend.core.exceptions;
|
||||
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Base class for checked exceptions thrown in qqq.
|
||||
*
|
||||
*******************************************************************************/
|
||||
public class QException extends Exception
|
||||
{
|
||||
private boolean hasLoggedWarning;
|
||||
private boolean hasLoggedError;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor of message
|
||||
@ -59,4 +66,102 @@ public class QException extends Exception
|
||||
{
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for hasLoggedWarning
|
||||
*******************************************************************************/
|
||||
public boolean getHasLoggedWarning()
|
||||
{
|
||||
return (this.hasLoggedWarning);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for hasLoggedWarning
|
||||
*******************************************************************************/
|
||||
public void setHasLoggedWarning(boolean hasLoggedWarning)
|
||||
{
|
||||
this.hasLoggedWarning = hasLoggedWarning;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for hasLoggedWarning
|
||||
*******************************************************************************/
|
||||
public QException withHasLoggedWarning(boolean hasLoggedWarning)
|
||||
{
|
||||
this.hasLoggedWarning = hasLoggedWarning;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for hasLoggedError
|
||||
*******************************************************************************/
|
||||
public boolean getHasLoggedError()
|
||||
{
|
||||
return (this.hasLoggedError);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for hasLoggedError
|
||||
*******************************************************************************/
|
||||
public void setHasLoggedError(boolean hasLoggedError)
|
||||
{
|
||||
this.hasLoggedError = hasLoggedError;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for hasLoggedError
|
||||
*******************************************************************************/
|
||||
public QException withHasLoggedError(boolean hasLoggedError)
|
||||
{
|
||||
this.hasLoggedError = hasLoggedError;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** helper function for getting if level logged
|
||||
*******************************************************************************/
|
||||
public boolean hasLoggedLevel(Level level)
|
||||
{
|
||||
if(Level.WARN.equals(level))
|
||||
{
|
||||
return (hasLoggedWarning);
|
||||
}
|
||||
if(Level.ERROR.equals(level))
|
||||
{
|
||||
return (hasLoggedError);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** helper function for setting if level logged
|
||||
*******************************************************************************/
|
||||
public void setHasLoggedLevel(Level level)
|
||||
{
|
||||
if(Level.WARN.equals(level))
|
||||
{
|
||||
setHasLoggedWarning(true);
|
||||
}
|
||||
if(Level.ERROR.equals(level))
|
||||
{
|
||||
setHasLoggedError(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@ -57,12 +58,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;
|
||||
@ -96,6 +98,13 @@ public class QInstanceEnricher
|
||||
//////////////////////////////////////////////////////////
|
||||
private boolean configRemoveIdFromNameWhenCreatingPossibleValueFieldLabels = true;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// let an instance define mappings to be applied during name-to-label enrichments, //
|
||||
// e.g., to avoid ever incorrectly camel-casing an acronym (e.g., "Tla" shoudl always be "TLA") //
|
||||
// or to expand abbreviations in code (e.g., "Addr" should always be "Address" //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private static final Map<String, String> labelMappings = new LinkedHashMap<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -261,9 +270,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 +376,11 @@ public class QInstanceEnricher
|
||||
process.getStepList().forEach(this::enrichStep);
|
||||
}
|
||||
|
||||
for(QSupplementalProcessMetaData supplementalProcessMetaData : CollectionUtils.nonNullMap(process.getSupplementalMetaData()).values())
|
||||
{
|
||||
supplementalProcessMetaData.enrich(this, process);
|
||||
}
|
||||
|
||||
enrichPermissionRules(process);
|
||||
}
|
||||
|
||||
@ -641,7 +655,17 @@ public class QInstanceEnricher
|
||||
////////////////////////////////////////////////////////////////
|
||||
.replaceAll("([0-9])([A-Za-z])", "$1 $2");
|
||||
|
||||
return (name.substring(0, 1).toUpperCase(Locale.ROOT) + suffix);
|
||||
String label = name.substring(0, 1).toUpperCase(Locale.ROOT) + suffix;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// apply any label mappings - e.g., to force app-specific acronyms/initialisms to all-caps //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
for(Map.Entry<String, String> entry : labelMappings.entrySet())
|
||||
{
|
||||
label = label.replaceAll(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return (label);
|
||||
}
|
||||
|
||||
|
||||
@ -1105,4 +1129,35 @@ public class QInstanceEnricher
|
||||
{
|
||||
return (this.joinGraph);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void addLabelMapping(String from, String to)
|
||||
{
|
||||
labelMappings.put(from, to);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void removeLabelMapping(String from)
|
||||
{
|
||||
labelMappings.remove(from);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static void clearLabelMappings()
|
||||
{
|
||||
labelMappings.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -572,6 +573,11 @@ public class QInstanceValidator
|
||||
RECORD_SECURITY_LOCKS_LOOP:
|
||||
for(RecordSecurityLock recordSecurityLock : CollectionUtils.nonNullList(table.getRecordSecurityLocks()))
|
||||
{
|
||||
if(!assertCondition(recordSecurityLock != null, prefix + "has a null recordSecurityLock (did you mean to give it a null list of locks?)"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
String securityKeyTypeName = recordSecurityLock.getSecurityKeyType();
|
||||
if(assertCondition(StringUtils.hasContent(securityKeyTypeName), prefix + "has a recordSecurityLock that is missing a securityKeyType"))
|
||||
{
|
||||
@ -1226,6 +1232,11 @@ public class QInstanceValidator
|
||||
}
|
||||
}
|
||||
|
||||
for(QSupplementalProcessMetaData supplementalProcessMetaData : CollectionUtils.nonNullMap(process.getSupplementalMetaData()).values())
|
||||
{
|
||||
supplementalProcessMetaData.validate(qInstance, process, this);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1703,7 +1714,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 +1747,7 @@ public class QInstanceValidator
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void warn(String message)
|
||||
public void warn(String message)
|
||||
{
|
||||
if(printWarnings)
|
||||
{
|
||||
|
@ -29,10 +29,12 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.instances.QMetaDataVariableInterpreter;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ExceptionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -392,7 +394,7 @@ public class QLogger
|
||||
*******************************************************************************/
|
||||
public void warn(String message, Throwable t)
|
||||
{
|
||||
logger.warn(makeJsonString(message, t));
|
||||
logger.log(determineIfShouldDowngrade(t, Level.WARN), makeJsonString(message, t));
|
||||
}
|
||||
|
||||
|
||||
@ -402,7 +404,7 @@ public class QLogger
|
||||
*******************************************************************************/
|
||||
public void warn(String message, Throwable t, LogPair... logPairs)
|
||||
{
|
||||
logger.warn(makeJsonString(message, t, logPairs));
|
||||
logger.log(determineIfShouldDowngrade(t, Level.WARN), makeJsonString(message, t, logPairs));
|
||||
}
|
||||
|
||||
|
||||
@ -412,7 +414,7 @@ public class QLogger
|
||||
*******************************************************************************/
|
||||
public void warn(Throwable t)
|
||||
{
|
||||
logger.warn(makeJsonString(null, t));
|
||||
logger.log(determineIfShouldDowngrade(t, Level.WARN), makeJsonString(null, t));
|
||||
}
|
||||
|
||||
|
||||
@ -452,7 +454,7 @@ public class QLogger
|
||||
*******************************************************************************/
|
||||
public void error(String message, Throwable t)
|
||||
{
|
||||
logger.error(makeJsonString(message, t));
|
||||
logger.log(determineIfShouldDowngrade(t, Level.ERROR), makeJsonString(message, t));
|
||||
}
|
||||
|
||||
|
||||
@ -462,7 +464,7 @@ public class QLogger
|
||||
*******************************************************************************/
|
||||
public void error(String message, Throwable t, LogPair... logPairs)
|
||||
{
|
||||
logger.error(makeJsonString(message, t, logPairs));
|
||||
logger.log(determineIfShouldDowngrade(t, Level.ERROR), makeJsonString(message, t, logPairs));
|
||||
}
|
||||
|
||||
|
||||
@ -472,7 +474,7 @@ public class QLogger
|
||||
*******************************************************************************/
|
||||
public void error(Throwable t)
|
||||
{
|
||||
logger.error(makeJsonString(null, t));
|
||||
logger.log(determineIfShouldDowngrade(t, Level.ERROR), makeJsonString(null, t));
|
||||
}
|
||||
|
||||
|
||||
@ -532,7 +534,7 @@ public class QLogger
|
||||
|
||||
if(t != null)
|
||||
{
|
||||
logPairList.add(logPair("stackTrace", LogUtils.filterStackTrace(ExceptionUtils.getStackTrace(t))));
|
||||
logPairList.add(logPair("stackTrace", LogUtils.filterStackTrace(org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace(t))));
|
||||
}
|
||||
|
||||
return (LogUtils.jsonLog(logPairList));
|
||||
@ -582,4 +584,40 @@ public class QLogger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected Level determineIfShouldDowngrade(Throwable t, Level level)
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// look for QExceptions in the chain, if none found, return the log level passed in //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
List<QException> exceptionList = ExceptionUtils.getClassListFromRootChain(t, QException.class);
|
||||
if(CollectionUtils.nullSafeIsEmpty(exceptionList))
|
||||
{
|
||||
return (level);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// check if any QException in this chain to see if it has already //
|
||||
// logged this level, if so, downgrade to INFO //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
for(QException qException : exceptionList)
|
||||
{
|
||||
if(qException.hasLoggedLevel(level))
|
||||
{
|
||||
log(Level.DEBUG, "Downgrading log message from " + level.toString() + " to " + Level.INFO, t);
|
||||
return (Level.INFO);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if it has not logged at this level, set that it has in QException, and return passed in level //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
exceptionList.get(0).setHasLoggedLevel(level);
|
||||
return (level);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -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, ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -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;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -194,6 +199,17 @@ public class RunProcessInput extends AbstractActionInput
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public RunProcessInput withValue(String fieldName, Serializable value)
|
||||
{
|
||||
this.processState.getValues().put(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
@ -269,7 +285,7 @@ public class RunProcessInput extends AbstractActionInput
|
||||
*******************************************************************************/
|
||||
public String getValueString(String fieldName)
|
||||
{
|
||||
return ((String) getValue(fieldName));
|
||||
return (ValueUtils.getValueAsString(getValue(fieldName)));
|
||||
}
|
||||
|
||||
|
||||
@ -280,7 +296,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
|
||||
**
|
||||
|
@ -56,4 +56,14 @@ public enum AggregateOperator
|
||||
{
|
||||
return sqlPrefix;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Aggregate of(String fieldName)
|
||||
{
|
||||
return (new Aggregate(fieldName, this));
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.TablesPossibleValueSourceMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.model.savedfilters.SavedFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.scripts.Script;
|
||||
|
||||
|
||||
@ -50,7 +51,7 @@ public class TableTrigger extends QRecordEntity
|
||||
@QField(possibleValueSourceName = TablesPossibleValueSourceMetaDataProvider.NAME)
|
||||
private String tableName;
|
||||
|
||||
@QField(/* todo possibleValueSourceName = */)
|
||||
@QField(possibleValueSourceName = SavedFilter.TABLE_NAME)
|
||||
private Integer filterId;
|
||||
|
||||
@QField(possibleValueSourceName = Script.TABLE_NAME)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
@ -77,6 +77,21 @@ public class QPossibleValueSource implements TopLevelMetaDataInterface
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Create a new possible value source, for a table, with default settings.
|
||||
** e.g., name & table name from the tableName parameter; type=TABLE; and LABEL_ONLY format
|
||||
*******************************************************************************/
|
||||
public static QPossibleValueSource newForTable(String tableName)
|
||||
{
|
||||
return new QPossibleValueSource()
|
||||
.withName(tableName)
|
||||
.withType(QPossibleValueSourceType.TABLE)
|
||||
.withTableName(tableName)
|
||||
.withValueFormatAndFields(PVSValueFormatAndFields.LABEL_ONLY);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 //
|
||||
////////////////////////
|
||||
}
|
||||
}
|
@ -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);
|
@ -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;
|
||||
|
||||
@ -1203,60 +1203,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);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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.savedfilters;
|
||||
|
||||
|
||||
import java.time.Instant;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Entity bean for the saved filter table
|
||||
*******************************************************************************/
|
||||
public class SavedFilter extends QRecordEntity
|
||||
{
|
||||
public static final String TABLE_NAME = "savedFilter";
|
||||
|
||||
@QField(isEditable = false)
|
||||
private Integer id;
|
||||
|
||||
@QField(isEditable = false)
|
||||
private Instant createDate;
|
||||
|
||||
@QField(isEditable = false)
|
||||
private Instant modifyDate;
|
||||
|
||||
@QField(isRequired = true)
|
||||
private String label;
|
||||
|
||||
@QField(isEditable = false)
|
||||
private String tableName;
|
||||
|
||||
@QField(isEditable = false)
|
||||
private String userId;
|
||||
|
||||
@QField(isEditable = false)
|
||||
private String filterJson;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedFilter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedFilter(QRecord qRecord) throws QException
|
||||
{
|
||||
populateFromQRecord(qRecord);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for id
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Integer getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for id
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setId(Integer id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for createDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Instant getCreateDate()
|
||||
{
|
||||
return createDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for createDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCreateDate(Instant createDate)
|
||||
{
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for modifyDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public Instant getModifyDate()
|
||||
{
|
||||
return modifyDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for modifyDate
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setModifyDate(Instant modifyDate)
|
||||
{
|
||||
this.modifyDate = modifyDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for label
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedFilter withLabel(String label)
|
||||
{
|
||||
this.label = label;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getTableName()
|
||||
{
|
||||
return tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for tableName
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedFilter withTableName(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for userId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getUserId()
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for userId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setUserId(String userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for userId
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedFilter withUserId(String userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for filterJson
|
||||
**
|
||||
*******************************************************************************/
|
||||
public String getFilterJson()
|
||||
{
|
||||
return filterJson;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for filterJson
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setFilterJson(String filterJson)
|
||||
{
|
||||
this.filterJson = filterJson;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for filterJson
|
||||
**
|
||||
*******************************************************************************/
|
||||
public SavedFilter withFilterJson(String filterJson)
|
||||
{
|
||||
this.filterJson = filterJson;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||
* contact@kingsrook.com
|
||||
* https://github.com/Kingsrook/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.kingsrook.qqq.backend.core.model.savedfilters;
|
||||
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
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.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.savedfilters.DeleteSavedFilterProcess;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.savedfilters.QuerySavedFilterProcess;
|
||||
import com.kingsrook.qqq.backend.core.processes.implementations.savedfilters.StoreSavedFilterProcess;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class SavedFiltersMetaDataProvider
|
||||
{
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void defineAll(QInstance instance, String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
instance.addTable(defineSavedFilterTable(backendName, backendDetailEnricher));
|
||||
instance.addPossibleValueSource(defineSavedFilterPossibleValueSource());
|
||||
instance.addProcess(QuerySavedFilterProcess.getProcessMetaData());
|
||||
instance.addProcess(StoreSavedFilterProcess.getProcessMetaData());
|
||||
instance.addProcess(DeleteSavedFilterProcess.getProcessMetaData());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QTableMetaData defineSavedFilterTable(String backendName, Consumer<QTableMetaData> backendDetailEnricher) throws QException
|
||||
{
|
||||
QTableMetaData table = new QTableMetaData()
|
||||
.withName(SavedFilter.TABLE_NAME)
|
||||
.withLabel("Saved Filter")
|
||||
.withRecordLabelFormat("%s")
|
||||
.withRecordLabelFields("label")
|
||||
.withBackendName(backendName)
|
||||
.withPrimaryKeyField("id")
|
||||
.withFieldsFromEntity(SavedFilter.class);
|
||||
|
||||
if(backendDetailEnricher != null)
|
||||
{
|
||||
backendDetailEnricher.accept(table);
|
||||
}
|
||||
|
||||
return (table);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private QPossibleValueSource defineSavedFilterPossibleValueSource()
|
||||
{
|
||||
return new QPossibleValueSource()
|
||||
.withName(SavedFilter.TABLE_NAME)
|
||||
.withType(QPossibleValueSourceType.TABLE)
|
||||
.withTableName(SavedFilter.TABLE_NAME)
|
||||
.withValueFormatAndFields(PVSValueFormatAndFields.LABEL_ONLY);
|
||||
}
|
||||
|
||||
}
|
@ -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")
|
||||
@ -327,7 +331,12 @@ public class ScriptsMetaDataProvider
|
||||
.withSection(new QFieldSection("dates", new QIcon().withName("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")));
|
||||
|
||||
tableMetaData.getField("scriptId").withPossibleValueSourceFilter(new QQueryFilter(
|
||||
new QFilterCriteria("scriptType.name", QCriteriaOperator.EQUALS, SCRIPT_TYPE_NAME_RECORD)
|
||||
new QFilterCriteria("scriptType.name", QCriteriaOperator.EQUALS, SCRIPT_TYPE_NAME_RECORD),
|
||||
new QFilterCriteria("script.tableName", QCriteriaOperator.EQUALS, "${input.tableName}")
|
||||
));
|
||||
|
||||
tableMetaData.getField("filterId").withPossibleValueSourceFilter(new QQueryFilter(
|
||||
new QFilterCriteria("tableName", QCriteriaOperator.EQUALS, "${input.tableName}")
|
||||
));
|
||||
|
||||
return tableMetaData;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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."));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.savedfilters;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction;
|
||||
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;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
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.savedfilters.SavedFilter;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Process used by the delete filter dialog
|
||||
*******************************************************************************/
|
||||
public class DeleteSavedFilterProcess implements BackendStep
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(DeleteSavedFilterProcess.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QProcessMetaData getProcessMetaData()
|
||||
{
|
||||
return (new QProcessMetaData()
|
||||
.withName("deleteSavedFilter")
|
||||
.withStepList(List.of(
|
||||
new QBackendStepMetaData()
|
||||
.withCode(new QCodeReference(DeleteSavedFilterProcess.class))
|
||||
.withName("delete")
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(runBackendStepInput);
|
||||
|
||||
try
|
||||
{
|
||||
Integer savedFilterId = runBackendStepInput.getValueInteger("id");
|
||||
|
||||
DeleteInput input = new DeleteInput();
|
||||
input.setTableName(SavedFilter.TABLE_NAME);
|
||||
input.setPrimaryKeys(List.of(savedFilterId));
|
||||
new DeleteAction().execute(input);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error deleting saved filter", e);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.savedfilters;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
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;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
||||
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.savedfilters.SavedFilter;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Process used by the saved filter dialogs
|
||||
*******************************************************************************/
|
||||
public class QuerySavedFilterProcess implements BackendStep
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(QuerySavedFilterProcess.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QProcessMetaData getProcessMetaData()
|
||||
{
|
||||
return (new QProcessMetaData()
|
||||
.withName("querySavedFilter")
|
||||
.withStepList(List.of(
|
||||
new QBackendStepMetaData()
|
||||
.withCode(new QCodeReference(QuerySavedFilterProcess.class))
|
||||
.withName("query")
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(runBackendStepInput);
|
||||
|
||||
try
|
||||
{
|
||||
Integer savedFilterId = runBackendStepInput.getValueInteger("id");
|
||||
if(savedFilterId != null)
|
||||
{
|
||||
GetInput input = new GetInput();
|
||||
input.setTableName(SavedFilter.TABLE_NAME);
|
||||
input.setPrimaryKey(savedFilterId);
|
||||
|
||||
GetOutput output = new GetAction().execute(input);
|
||||
runBackendStepOutput.addRecord(output.getRecord());
|
||||
runBackendStepOutput.addValue("savedFilter", output.getRecord());
|
||||
runBackendStepOutput.addValue("savedFilterList", (Serializable) List.of(output.getRecord()));
|
||||
}
|
||||
else
|
||||
{
|
||||
String tableName = runBackendStepInput.getValueString("tableName");
|
||||
|
||||
QueryInput input = new QueryInput();
|
||||
input.setTableName(SavedFilter.TABLE_NAME);
|
||||
input.setFilter(new QQueryFilter()
|
||||
.withCriteria(new QFilterCriteria("tableName", QCriteriaOperator.EQUALS, tableName))
|
||||
.withOrderBy(new QFilterOrderBy("label")));
|
||||
|
||||
QueryOutput output = new QueryAction().execute(input);
|
||||
runBackendStepOutput.setRecords(output.getRecords());
|
||||
runBackendStepOutput.addValue("savedFilterList", (Serializable) output.getRecords());
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error deleting saved filter", e);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.savedfilters;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
|
||||
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;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.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.processes.QBackendStepMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.savedfilters.SavedFilter;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Process used by the saved filter dialog
|
||||
*******************************************************************************/
|
||||
public class StoreSavedFilterProcess implements BackendStep
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(StoreSavedFilterProcess.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static QProcessMetaData getProcessMetaData()
|
||||
{
|
||||
return (new QProcessMetaData()
|
||||
.withName("storeSavedFilter")
|
||||
.withStepList(List.of(
|
||||
new QBackendStepMetaData()
|
||||
.withCode(new QCodeReference(StoreSavedFilterProcess.class))
|
||||
.withName("store")
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
|
||||
{
|
||||
ActionHelper.validateSession(runBackendStepInput);
|
||||
|
||||
try
|
||||
{
|
||||
QRecord qRecord = new QRecord()
|
||||
.withValue("id", runBackendStepInput.getValueInteger("id"))
|
||||
.withValue("label", runBackendStepInput.getValueString("label"))
|
||||
.withValue("tableName", runBackendStepInput.getValueString("tableName"))
|
||||
.withValue("filterJson", runBackendStepInput.getValueString("filterJson"))
|
||||
.withValue("userId", runBackendStepInput.getSession().getUser().getIdReference());
|
||||
|
||||
List<QRecord> savedFilterList = new ArrayList<>();
|
||||
if(qRecord.getValueInteger("id") == null)
|
||||
{
|
||||
InsertInput input = new InsertInput();
|
||||
input.setTableName(SavedFilter.TABLE_NAME);
|
||||
input.setRecords(List.of(qRecord));
|
||||
|
||||
InsertOutput output = new InsertAction().execute(input);
|
||||
savedFilterList = output.getRecords();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateInput input = new UpdateInput();
|
||||
input.setTableName(SavedFilter.TABLE_NAME);
|
||||
input.setRecords(List.of(qRecord));
|
||||
|
||||
UpdateOutput output = new UpdateAction().execute(input);
|
||||
savedFilterList = output.getRecords();
|
||||
}
|
||||
|
||||
runBackendStepOutput.addValue("savedFilterList", (Serializable) savedFilterList);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error storing data saved filter", e);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
||||
@ -60,6 +62,45 @@ public class ExceptionUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Find a list of exceptions of the given class in an exception's caused-by chain.
|
||||
** Returns empty list if none found.
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static <T extends Throwable> List<T> getClassListFromRootChain(Throwable e, Class<T> targetClass)
|
||||
{
|
||||
List<T> throwableList = new ArrayList<>();
|
||||
if(targetClass.isInstance(e))
|
||||
{
|
||||
throwableList.add(targetClass.cast(e));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// iterate through the chain with a limit of 100 //
|
||||
///////////////////////////////////////////////////
|
||||
int counter = 0;
|
||||
while(counter++ < 100)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// look for the same class from the last throwable found of that type //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
e = findClassInRootChain(e.getCause(), targetClass);
|
||||
if(e == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// if we did not break, higher one must have been found, keep looking //
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
throwableList.add(targetClass.cast(e));
|
||||
}
|
||||
|
||||
return (throwableList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Get the root exception in a caused-by-chain.
|
||||
**
|
||||
@ -88,4 +129,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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||
import com.kingsrook.qqq.backend.core.model.session.QUser;
|
||||
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@ -47,7 +48,10 @@ public class BaseTest
|
||||
@BeforeEach
|
||||
void baseBeforeEach()
|
||||
{
|
||||
QContext.init(TestUtils.defineInstance(), new QSession());
|
||||
QContext.init(TestUtils.defineInstance(), new QSession()
|
||||
.withUser(new QUser()
|
||||
.withIdReference("001")
|
||||
.withFullName("Anonymous")));
|
||||
resetMemoryRecordStore();
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,16 @@ class QInstanceEnricherTest extends BaseTest
|
||||
assertEquals("Something USA", QInstanceEnricher.nameToLabel("somethingUSA"));
|
||||
assertEquals("Number 1 Dad", QInstanceEnricher.nameToLabel("number1Dad"));
|
||||
assertEquals("Number 417 Dad", QInstanceEnricher.nameToLabel("number417Dad"));
|
||||
|
||||
assertEquals("Default Wms System Id", QInstanceEnricher.nameToLabel("defaultWmsSystemId"));
|
||||
QInstanceEnricher.addLabelMapping("\\bWms\\b", "WMS");
|
||||
assertEquals("Default WMS System Id", QInstanceEnricher.nameToLabel("defaultWmsSystemId"));
|
||||
QInstanceEnricher.clearLabelMappings();
|
||||
|
||||
assertEquals("Api Client Id", QInstanceEnricher.nameToLabel("apiClientId"));
|
||||
QInstanceEnricher.addLabelMapping("\\bApi\\b", "API");
|
||||
assertEquals("API Client Id", QInstanceEnricher.nameToLabel("apiClientId"));
|
||||
QInstanceEnricher.clearLabelMappings();
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* 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.logging;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.Appender;
|
||||
import org.apache.logging.log4j.core.Core;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.Layout;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||
import org.apache.logging.log4j.core.config.Property;
|
||||
import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
|
||||
import org.apache.logging.log4j.core.filter.LevelRangeFilter;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for com.kingsrook.qqq.backend.core.logging.QLogger
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Disabled // disabled because could never get the custom appender class to receive logEvents that have their levels set (always null)
|
||||
class QLoggerTest extends BaseTest
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(QLoggerTest.class);
|
||||
private static final ListAppender listAppender = ListAppender.createAppender();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@BeforeEach
|
||||
void beforeAll() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testDowngradingWarnings() throws Exception
|
||||
{
|
||||
org.apache.logging.log4j.core.Logger logger = (org.apache.logging.log4j.core.Logger) LogManager.getLogger(QLoggerTest.class);
|
||||
logger.addAppender(listAppender);
|
||||
listAppender.start();
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
throw (new QException("Some deepest exception..."));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
String warning = "Less deep warning";
|
||||
LOG.warn(warning, e);
|
||||
throw (new QException(warning, e));
|
||||
}
|
||||
}
|
||||
catch(Exception e2)
|
||||
{
|
||||
String warning = "Middle warning";
|
||||
LOG.warn(warning, e2);
|
||||
throw (new QException(warning, e2));
|
||||
}
|
||||
}
|
||||
catch(Exception e2)
|
||||
{
|
||||
String warning = "Last warning";
|
||||
LOG.warn(warning, e2);
|
||||
throw (new QException(warning, e2));
|
||||
}
|
||||
}
|
||||
catch(Exception e3)
|
||||
{
|
||||
/////////////////////////
|
||||
// check results below //
|
||||
/////////////////////////
|
||||
}
|
||||
|
||||
assertThat(listAppender.getEventList()).isNotNull();
|
||||
assertThat(listAppender.getEventList().size()).isEqualTo(5);
|
||||
int counter = 0;
|
||||
for(LogEvent logEvent : listAppender.getEventList())
|
||||
{
|
||||
if(counter == 0)
|
||||
{
|
||||
assertThat(logEvent.getLevel()).isEqualTo(Level.WARN);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertThat(logEvent.getLevel()).isEqualTo(Level.INFO);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** appender to add to logger to keep a list of log events
|
||||
*******************************************************************************/
|
||||
@Plugin(name = "ListAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
|
||||
public static class ListAppender extends AbstractAppender
|
||||
{
|
||||
private List<LogEvent> eventList = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected ListAppender(final String name, final Filter filter, final Layout<? extends Serializable> layout, final boolean ignoreExceptions, final Property[] properties)
|
||||
{
|
||||
super(name, filter, layout, ignoreExceptions, properties);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@PluginFactory
|
||||
public static ListAppender createAppender()
|
||||
{
|
||||
LevelRangeFilter levelRangeFilter = LevelRangeFilter.createFilter(Level.TRACE, Level.ERROR, Filter.Result.ACCEPT, Filter.Result.ACCEPT);
|
||||
// return (new ListAppender("ListApppender", levelRangeFilter, null, true, null));
|
||||
return (new ListAppender("ListApppender", null, null, true, null));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public void append(LogEvent event)
|
||||
{
|
||||
eventList.add(event);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for eventList
|
||||
*******************************************************************************/
|
||||
public List<LogEvent> getEventList()
|
||||
{
|
||||
return (this.eventList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.savedfilters;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
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;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
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.savedfilters.SavedFiltersMetaDataProvider;
|
||||
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for all saved filter processes
|
||||
*******************************************************************************/
|
||||
class SavedFilterProcessTests extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void test() throws QException
|
||||
{
|
||||
QInstance qInstance = QContext.getQInstance();
|
||||
new SavedFiltersMetaDataProvider().defineAll(qInstance, TestUtils.MEMORY_BACKEND_NAME, null);
|
||||
String tableName = TestUtils.TABLE_NAME_PERSON_MEMORY;
|
||||
|
||||
{
|
||||
///////////////////////////////////////////
|
||||
// query - should be no filters to start //
|
||||
///////////////////////////////////////////
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(QuerySavedFilterProcess.getProcessMetaData().getName());
|
||||
runProcessInput.addValue("tableName", tableName);
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
assertEquals(0, ((List<?>) runProcessOutput.getValues().get("savedFilterList")).size());
|
||||
}
|
||||
|
||||
Integer savedFilterId;
|
||||
{
|
||||
////////////////////////
|
||||
// store a new filter //
|
||||
////////////////////////
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(StoreSavedFilterProcess.getProcessMetaData().getName());
|
||||
runProcessInput.addValue("label", "My Filter");
|
||||
runProcessInput.addValue("tableName", tableName);
|
||||
runProcessInput.addValue("filterJson", JsonUtils.toJson(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.EQUALS, 47))));
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
List<QRecord> savedFilterList = (List<QRecord>) runProcessOutput.getValues().get("savedFilterList");
|
||||
assertEquals(1, savedFilterList.size());
|
||||
savedFilterId = savedFilterList.get(0).getValueInteger("id");
|
||||
assertNotNull(savedFilterId);
|
||||
}
|
||||
|
||||
{
|
||||
////////////////////////////////////
|
||||
// query - should find our filter //
|
||||
////////////////////////////////////
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(QuerySavedFilterProcess.getProcessMetaData().getName());
|
||||
runProcessInput.addValue("tableName", tableName);
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
List<QRecord> savedFilterList = (List<QRecord>) runProcessOutput.getValues().get("savedFilterList");
|
||||
assertEquals(1, savedFilterList.size());
|
||||
assertEquals(1, savedFilterList.get(0).getValueInteger("id"));
|
||||
assertEquals("My Filter", savedFilterList.get(0).getValueString("label"));
|
||||
}
|
||||
|
||||
{
|
||||
///////////////////////
|
||||
// update our filter //
|
||||
///////////////////////
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(StoreSavedFilterProcess.getProcessMetaData().getName());
|
||||
runProcessInput.addValue("id", savedFilterId);
|
||||
runProcessInput.addValue("label", "My Updated Filter");
|
||||
runProcessInput.addValue("tableName", tableName);
|
||||
runProcessInput.addValue("filterJson", JsonUtils.toJson(new QQueryFilter(new QFilterCriteria("id", QCriteriaOperator.EQUALS, 47))));
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
List<QRecord> savedFilterList = (List<QRecord>) runProcessOutput.getValues().get("savedFilterList");
|
||||
assertEquals(1, savedFilterList.size());
|
||||
assertEquals(1, savedFilterList.get(0).getValueInteger("id"));
|
||||
assertEquals("My Updated Filter", savedFilterList.get(0).getValueString("label"));
|
||||
}
|
||||
|
||||
{
|
||||
///////////////////////
|
||||
// delete our filter //
|
||||
///////////////////////
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(DeleteSavedFilterProcess.getProcessMetaData().getName());
|
||||
runProcessInput.addValue("id", savedFilterId);
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
}
|
||||
|
||||
{
|
||||
////////////////////////////////////////
|
||||
// query - should be no filters again //
|
||||
////////////////////////////////////////
|
||||
RunProcessInput runProcessInput = new RunProcessInput();
|
||||
runProcessInput.setProcessName(QuerySavedFilterProcess.getProcessMetaData().getName());
|
||||
runProcessInput.addValue("tableName", tableName);
|
||||
RunProcessOutput runProcessOutput = new RunProcessAction().execute(runProcessInput);
|
||||
assertEquals(0, ((List<?>) runProcessOutput.getValues().get("savedFilterList")).size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -26,6 +26,7 @@ import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
@ -88,6 +89,33 @@ class ExceptionUtilsTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testConcatenateMessagesFromChain()
|
||||
{
|
||||
assertNull(ExceptionUtils.concatenateMessagesFromChain(null));
|
||||
assertEquals("QException", ExceptionUtils.concatenateMessagesFromChain(new QException((String) null)));
|
||||
assertEquals("QException", ExceptionUtils.concatenateMessagesFromChain(new QException("")));
|
||||
assertEquals("foo; bar", ExceptionUtils.concatenateMessagesFromChain(new QException("foo", new QException("bar"))));
|
||||
assertEquals("foo; QException; bar", ExceptionUtils.concatenateMessagesFromChain(new QException("foo", new QException(null, new QException("bar")))));
|
||||
|
||||
MyException selfCaused = new MyException("selfCaused");
|
||||
selfCaused.setCause(selfCaused);
|
||||
assertEquals("selfCaused", ExceptionUtils.concatenateMessagesFromChain(selfCaused));
|
||||
|
||||
MyException cycle1 = new MyException("cycle1");
|
||||
MyException cycle2 = new MyException("cycle2");
|
||||
cycle1.setCause(cycle2);
|
||||
cycle2.setCause(cycle1);
|
||||
|
||||
assertEquals("cycle1; cycle2", ExceptionUtils.concatenateMessagesFromChain(cycle1));
|
||||
assertEquals("cycle2; cycle1", ExceptionUtils.concatenateMessagesFromChain(cycle2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Test exception class - lets you set the cause, easier to create a loop.
|
||||
*******************************************************************************/
|
||||
@ -97,6 +125,9 @@ class ExceptionUtilsTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public MyException(String message)
|
||||
{
|
||||
super(message);
|
||||
@ -104,6 +135,9 @@ class ExceptionUtilsTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public MyException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
@ -111,6 +145,9 @@ class ExceptionUtilsTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void setCause(Throwable cause)
|
||||
{
|
||||
myCause = cause;
|
||||
|
@ -78,7 +78,7 @@ class MapBuilderTest
|
||||
@Test
|
||||
void testTypeYouRequest()
|
||||
{
|
||||
Map<String, Integer> myTreeMap = MapBuilder.<String, Integer>of(TreeMap::new).with("1", 1).with("2", 2).build();
|
||||
TreeMap<String, Integer> myTreeMap = MapBuilder.of(() -> new TreeMap<String, Integer>()).with("1", 1).with("2", 2).build();
|
||||
assertTrue(myTreeMap instanceof TreeMap);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user