mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-19 13:40:44 +00:00
Merge branch 'feature/CTLE-153-default-ct-live-packing-slips-to-deposco' into integration/sprint-26
# Conflicts: # qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java # qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java # qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java # qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java # qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/TestUtils.java
This commit is contained in:
@ -194,32 +194,57 @@ public class DMLAuditAction extends AbstractQActionFunction<DMLAuditInput, DMLAu
|
||||
continue;
|
||||
}
|
||||
|
||||
String formattedValue = getFormattedValueForAuditDetail(record, fieldName, field, value);
|
||||
detailRecord = new QRecord().withValue("message", "Set " + field.getLabel() + " to " + formattedValue);
|
||||
detailRecord.withValue("newValue", formattedValue);
|
||||
if(field.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Set " + field.getLabel());
|
||||
}
|
||||
else
|
||||
{
|
||||
String formattedValue = getFormattedValueForAuditDetail(record, fieldName, field, value);
|
||||
detailRecord = new QRecord().withValue("message", "Set " + field.getLabel() + " to " + formattedValue);
|
||||
detailRecord.withValue("newValue", formattedValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!Objects.equals(oldValue, value))
|
||||
{
|
||||
String formattedValue = getFormattedValueForAuditDetail(record, fieldName, field, value);
|
||||
String formattedOldValue = getFormattedValueForAuditDetail(oldRecord, fieldName, field, oldValue);
|
||||
|
||||
if(oldValue == null)
|
||||
if(field.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Set " + field.getLabel() + " to " + formatFormattedValueForDetailMessage(field, formattedValue));
|
||||
detailRecord.withValue("newValue", formattedValue);
|
||||
}
|
||||
else if(value == null)
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Removed " + formatFormattedValueForDetailMessage(field, formattedOldValue) + " from " + field.getLabel());
|
||||
detailRecord.withValue("oldValue", formattedOldValue);
|
||||
if(oldValue == null)
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Set " + field.getLabel());
|
||||
}
|
||||
else if(value == null)
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Removed " + field.getLabel());
|
||||
}
|
||||
else
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Changed " + field.getLabel());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Changed " + field.getLabel() + " from " + formatFormattedValueForDetailMessage(field, formattedOldValue) + " to " + formatFormattedValueForDetailMessage(field, formattedValue));
|
||||
detailRecord.withValue("oldValue", formattedOldValue);
|
||||
detailRecord.withValue("newValue", formattedValue);
|
||||
String formattedValue = getFormattedValueForAuditDetail(record, fieldName, field, value);
|
||||
String formattedOldValue = getFormattedValueForAuditDetail(oldRecord, fieldName, field, oldValue);
|
||||
|
||||
if(oldValue == null)
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Set " + field.getLabel() + " to " + formatFormattedValueForDetailMessage(field, formattedValue));
|
||||
detailRecord.withValue("newValue", formattedValue);
|
||||
}
|
||||
else if(value == null)
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Removed " + formatFormattedValueForDetailMessage(field, formattedOldValue) + " from " + field.getLabel());
|
||||
detailRecord.withValue("oldValue", formattedOldValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
detailRecord = new QRecord().withValue("message", "Changed " + field.getLabel() + " from " + formatFormattedValueForDetailMessage(field, formattedOldValue) + " to " + formatFormattedValueForDetailMessage(field, formattedValue));
|
||||
detailRecord.withValue("oldValue", formattedOldValue);
|
||||
detailRecord.withValue("newValue", formattedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import java.util.Set;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||
@ -160,10 +161,12 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
|
||||
@Override
|
||||
public RenderWidgetOutput render(RenderWidgetInput input) throws QException
|
||||
{
|
||||
String widgetLabel = input.getQueryParams().get("widgetLabel");
|
||||
String joinName = input.getQueryParams().get("joinName");
|
||||
QJoinMetaData join = input.getInstance().getJoin(joinName);
|
||||
String id = input.getQueryParams().get("id");
|
||||
String widgetLabel = input.getQueryParams().get("widgetLabel");
|
||||
String joinName = input.getQueryParams().get("joinName");
|
||||
QJoinMetaData join = input.getInstance().getJoin(joinName);
|
||||
String id = input.getQueryParams().get("id");
|
||||
QTableMetaData leftTable = input.getInstance().getTable(join.getLeftTable());
|
||||
QTableMetaData rightTable = input.getInstance().getTable(join.getRightTable());
|
||||
|
||||
Integer maxRows = null;
|
||||
if(StringUtils.hasContent(input.getQueryParams().get("maxRows")))
|
||||
@ -187,8 +190,7 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
|
||||
|
||||
if(record == null)
|
||||
{
|
||||
QTableMetaData table = input.getInstance().getTable(join.getLeftTable());
|
||||
throw (new QNotFoundException("Could not find " + (table == null ? "" : table.getLabel()) + " with primary key " + id));
|
||||
throw (new QNotFoundException("Could not find " + (leftTable == null ? "" : leftTable.getLabel()) + " with primary key " + id));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -209,6 +211,8 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
|
||||
queryInput.setFilter(filter);
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
|
||||
QValueFormatter.setBlobValuesToDownloadUrls(rightTable, queryOutput.getRecords());
|
||||
|
||||
int totalRows = queryOutput.getRecords().size();
|
||||
if(maxRows != null && (queryOutput.getRecords().size() == maxRows))
|
||||
{
|
||||
@ -222,11 +226,10 @@ public class ChildRecordListRenderer extends AbstractWidgetRenderer
|
||||
totalRows = new CountAction().execute(countInput).getCount();
|
||||
}
|
||||
|
||||
QTableMetaData table = input.getInstance().getTable(join.getRightTable());
|
||||
String tablePath = input.getInstance().getTablePath(table.getName());
|
||||
String viewAllLink = tablePath == null ? null : (tablePath + "?filter=" + URLEncoder.encode(JsonUtils.toJson(filter), Charset.defaultCharset()));
|
||||
String tablePath = input.getInstance().getTablePath(rightTable.getName());
|
||||
String viewAllLink = tablePath == null ? null : (tablePath + "?filter=" + URLEncoder.encode(JsonUtils.toJson(filter), Charset.defaultCharset()));
|
||||
|
||||
ChildRecordListData widgetData = new ChildRecordListData(widgetLabel, queryOutput, table, tablePath, viewAllLink, totalRows);
|
||||
ChildRecordListData widgetData = new ChildRecordListData(widgetLabel, queryOutput, rightTable, tablePath, viewAllLink, totalRows);
|
||||
|
||||
if(BooleanUtils.isTrue(ValueUtils.getValueAsBoolean(input.getQueryParams().get("canAddChildRecord"))))
|
||||
{
|
||||
|
@ -386,13 +386,22 @@ public class ExportAction
|
||||
fieldList = new ArrayList<>(table.getFields().values());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// add fields for possible value labels //
|
||||
//////////////////////////////////////////
|
||||
List<QFieldMetaData> returnList = new ArrayList<>();
|
||||
for(QFieldMetaData field : fieldList)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// skip heavy fields. they aren't fetched, and we generally think we don't want them. //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(field.getIsHeavy())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
returnList.add(field);
|
||||
|
||||
//////////////////////////////////////////
|
||||
// add fields for possible value labels //
|
||||
//////////////////////////////////////////
|
||||
if(StringUtils.hasContent(field.getPossibleValueSourceName()))
|
||||
{
|
||||
returnList.add(new QFieldMetaData(field.getName() + ":possibleValueLabel", QFieldType.STRING).withLabel(field.getLabel() + " Name"));
|
||||
|
@ -81,6 +81,16 @@ public class QueryAction
|
||||
{
|
||||
ActionHelper.validateSession(queryInput);
|
||||
|
||||
if(queryInput.getTableName() == null)
|
||||
{
|
||||
throw (new QException("Table name was not specified in query input"));
|
||||
}
|
||||
|
||||
if(queryInput.getTable() == null)
|
||||
{
|
||||
throw (new QException("A table named [" + queryInput.getTableName() + "] was not found in the active QInstance"));
|
||||
}
|
||||
|
||||
postQueryRecordCustomizer = QCodeLoader.getTableCustomizer(AbstractPostQueryCustomizer.class, queryInput.getTable(), TableCustomizers.POST_QUERY_RECORD.getRole());
|
||||
this.queryInput = queryInput;
|
||||
|
||||
|
@ -26,20 +26,30 @@ import java.io.StringWriter;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateInput;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.RenderTemplateOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.templates.TemplateType;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
import org.apache.velocity.app.Velocity;
|
||||
import org.apache.velocity.app.event.EventCartridge;
|
||||
import org.apache.velocity.app.event.MethodExceptionEventHandler;
|
||||
import org.apache.velocity.context.Context;
|
||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Basic action to render a template!
|
||||
**
|
||||
** hard-coded built to only assume Velocity right now. could expand (and refactor) in future.
|
||||
*******************************************************************************/
|
||||
public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplateInput, RenderTemplateOutput>
|
||||
{
|
||||
private static final QLogger LOG = QLogger.getLogger(RenderTemplateAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
@ -52,9 +62,12 @@ public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplate
|
||||
if(TemplateType.VELOCITY.equals(input.getTemplateType()))
|
||||
{
|
||||
Velocity.init();
|
||||
Context context = new VelocityContext(input.getContext());
|
||||
Context context = new VelocityContext(input.getContext());
|
||||
|
||||
setupEventHandlers(context);
|
||||
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
Velocity.evaluate(context, stringWriter, "logTag", input.getCode());
|
||||
Velocity.evaluate(context, stringWriter, StringUtils.hasContent(input.getTemplateIdentifier()) ? input.getTemplateIdentifier() : "anonymous", input.getCode());
|
||||
output.setResult(stringWriter.getBuffer().toString());
|
||||
}
|
||||
else
|
||||
@ -67,12 +80,28 @@ public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplate
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static void setupEventHandlers(Context context)
|
||||
{
|
||||
EventCartridge eventCartridge = new EventCartridge();
|
||||
eventCartridge.addEventHandler((MethodExceptionEventHandler) (ctx, aClass, method, exception, info) ->
|
||||
{
|
||||
LOG.info("Exception in velocity template", exception, logPair("at", info.toString()));
|
||||
return (null);
|
||||
});
|
||||
eventCartridge.attachToContext(context);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Most convenient static wrapper to render a Velocity template.
|
||||
*******************************************************************************/
|
||||
public static String renderVelocity(AbstractActionInput parentActionInput, Map<String, Object> context, String code) throws QException
|
||||
{
|
||||
return (render(parentActionInput, TemplateType.VELOCITY, context, code));
|
||||
return (render(TemplateType.VELOCITY, context, code));
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +109,7 @@ public class RenderTemplateAction extends AbstractQActionFunction<RenderTemplate
|
||||
/*******************************************************************************
|
||||
** Convenient static wrapper to render a template of an arbitrary type (language).
|
||||
*******************************************************************************/
|
||||
public static String render(AbstractActionInput parentActionInput, TemplateType templateType, Map<String, Object> context, String code) throws QException
|
||||
public static String render(TemplateType templateType, Map<String, Object> context, String code) throws QException
|
||||
{
|
||||
RenderTemplateInput renderTemplateInput = new RenderTemplateInput();
|
||||
renderTemplateInput.setCode(code);
|
||||
|
@ -29,13 +29,18 @@ import java.time.LocalTime;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.ExposedJoin;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
@ -434,4 +439,127 @@ public class QValueFormatter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** For any BLOB type fields in the list of records, change their value to
|
||||
** the URL where they can be downloaded, and set their display value to a file name.
|
||||
*******************************************************************************/
|
||||
public static void setBlobValuesToDownloadUrls(QTableMetaData table, List<QRecord> records)
|
||||
{
|
||||
for(QFieldMetaData field : table.getFields().values())
|
||||
{
|
||||
if(field.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// file name comes from: //
|
||||
// if there's a FILE_DOWNLOAD adornment, with a FILE_NAME_FIELD value, then the full filename comes from that field //
|
||||
// - unless it was empty - then we do the "default thing": //
|
||||
// else - the "default thing" is: //
|
||||
// - tableLabel primaryKey fieldLabel //
|
||||
// - and - if the FILE_DOWNLOAD adornment had a DEFAULT_EXTENSION, then it gets added (preceded by a dot) //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Optional<FieldAdornment> fileDownloadAdornment = field.getAdornment(AdornmentType.FILE_DOWNLOAD);
|
||||
Map<String, Serializable> adornmentValues = Collections.emptyMap();
|
||||
|
||||
if(fileDownloadAdornment.isPresent())
|
||||
{
|
||||
adornmentValues = fileDownloadAdornment.get().getValues();
|
||||
}
|
||||
|
||||
String fileNameField = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FIELD));
|
||||
String fileNameFormat = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT));
|
||||
String defaultExtension = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.DEFAULT_EXTENSION));
|
||||
|
||||
for(QRecord record : records)
|
||||
{
|
||||
if(!doesFieldHaveValue(field, record))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Serializable primaryKey = record.getValue(table.getPrimaryKeyField());
|
||||
String fileName = null;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// try to make file name from the fileNameField //
|
||||
//////////////////////////////////////////////////
|
||||
if(StringUtils.hasContent(fileNameField))
|
||||
{
|
||||
fileName = record.getValueString(fileNameField);
|
||||
}
|
||||
|
||||
if(!StringUtils.hasContent(fileName))
|
||||
{
|
||||
if(StringUtils.hasContent(fileNameFormat))
|
||||
{
|
||||
@SuppressWarnings("unchecked") // instance validation should make this safe!
|
||||
List<String> fileNameFormatFields = (List<String>) adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT_FIELDS);
|
||||
List<String> values = fileNameFormatFields.stream().map(f -> ValueUtils.getValueAsString(record.getValue(f))).toList();
|
||||
fileName = QValueFormatter.formatStringWithValues(fileNameFormat, values);
|
||||
}
|
||||
}
|
||||
|
||||
if(!StringUtils.hasContent(fileName))
|
||||
{
|
||||
//////////////////////////////////
|
||||
// make default name if missing //
|
||||
//////////////////////////////////
|
||||
fileName = table.getLabel() + " " + primaryKey + " " + field.getLabel();
|
||||
|
||||
if(StringUtils.hasContent(defaultExtension))
|
||||
{
|
||||
//////////////////////////////////////////
|
||||
// add default extension if we have one //
|
||||
//////////////////////////////////////////
|
||||
fileName += "." + defaultExtension;
|
||||
}
|
||||
}
|
||||
|
||||
record.setValue(field.getName(), "/data/" + table.getName() + "/" + primaryKey + "/" + field.getName() + "/" + fileName);
|
||||
record.setDisplayValue(field.getName(), fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static boolean doesFieldHaveValue(QFieldMetaData field, QRecord record)
|
||||
{
|
||||
boolean fieldHasValue = false;
|
||||
|
||||
try
|
||||
{
|
||||
if(record.getValue(field.getName()) != null)
|
||||
{
|
||||
fieldHasValue = true;
|
||||
}
|
||||
else if(field.getIsHeavy())
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// heavy fields that weren't fetched - they should have a backend-detail specifying their length (or null if null) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
Map<String, Serializable> heavyFieldLengths = (Map<String, Serializable>) record.getBackendDetail(QRecord.BACKEND_DETAILS_TYPE_HEAVY_FIELD_LENGTHS);
|
||||
if(heavyFieldLengths != null)
|
||||
{
|
||||
Integer fieldLength = ValueUtils.getValueAsInteger(heavyFieldLengths.get(field.getName()));
|
||||
if(fieldLength != null && fieldLength > 0)
|
||||
{
|
||||
fieldHasValue = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.info("Error checking if field has value", e, logPair("fieldName", field.getName()), logPair("record", record));
|
||||
}
|
||||
|
||||
return fieldHasValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -715,7 +715,7 @@ public class QInstanceEnricher
|
||||
try
|
||||
{
|
||||
QFieldMetaData field = table.getField(fieldName);
|
||||
if(field.getIsEditable())
|
||||
if(field.getIsEditable() && !field.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
editableFields.add(field);
|
||||
}
|
||||
@ -734,7 +734,7 @@ public class QInstanceEnricher
|
||||
QFrontendStepMetaData uploadScreen = new QFrontendStepMetaData()
|
||||
.withName("upload")
|
||||
.withLabel("Upload File")
|
||||
.withFormField(new QFieldMetaData("theFile", QFieldType.BLOB).withIsRequired(true))
|
||||
.withFormField(new QFieldMetaData("theFile", QFieldType.BLOB).withLabel(table.getLabel() + " File").withIsRequired(true))
|
||||
.withComponent(new QFrontendComponentMetaData()
|
||||
.withType(QComponentType.HELP_TEXT)
|
||||
.withValue("previewText", "file upload instructions")
|
||||
@ -773,6 +773,7 @@ public class QInstanceEnricher
|
||||
|
||||
List<QFieldMetaData> editableFields = table.getFields().values().stream()
|
||||
.filter(QFieldMetaData::getIsEditable)
|
||||
.filter(f -> !f.getType().equals(QFieldType.BLOB))
|
||||
.toList();
|
||||
|
||||
QFrontendStepMetaData editScreen = new QFrontendStepMetaData()
|
||||
|
@ -22,6 +22,7 @@
|
||||
package com.kingsrook.qqq.backend.core.instances;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
@ -50,6 +51,8 @@ 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.code.QCodeReference;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.AdornmentType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldAdornment;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.ValueTooLongBehavior;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||
@ -80,6 +83,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheOf;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheUseCase;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -416,7 +420,7 @@ public class QInstanceValidator
|
||||
{
|
||||
table.getFields().forEach((fieldName, field) ->
|
||||
{
|
||||
validateTableField(qInstance, tableName, fieldName, field);
|
||||
validateTableField(qInstance, tableName, fieldName, table, field);
|
||||
});
|
||||
}
|
||||
|
||||
@ -657,7 +661,7 @@ public class QInstanceValidator
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
private void validateTableField(QInstance qInstance, String tableName, String fieldName, QFieldMetaData field)
|
||||
private void validateTableField(QInstance qInstance, String tableName, String fieldName, QTableMetaData table, QFieldMetaData field)
|
||||
{
|
||||
assertCondition(Objects.equals(fieldName, field.getName()),
|
||||
"Inconsistent naming in table " + tableName + " for field " + fieldName + "/" + field.getName() + ".");
|
||||
@ -699,6 +703,55 @@ public class QInstanceValidator
|
||||
assertCondition(fieldSecurityLock.getDefaultBehavior() != null, prefix + "has a fieldSecurityLock that is missing a defaultBehavior");
|
||||
assertCondition(CollectionUtils.nullSafeHasContents(fieldSecurityLock.getOverrideValues()), prefix + "has a fieldSecurityLock that is missing overrideValues");
|
||||
}
|
||||
|
||||
for(FieldAdornment adornment : CollectionUtils.nonNullList(field.getAdornments()))
|
||||
{
|
||||
Map<String, Serializable> adornmentValues = CollectionUtils.nonNullMap(adornment.getValues());
|
||||
if(assertCondition(adornment.getType() != null, prefix + "has an adornment that is missing a type"))
|
||||
{
|
||||
String adornmentPrefix = prefix.trim() + ", " + adornment.getType() + " adornment ";
|
||||
switch(adornment.getType())
|
||||
{
|
||||
case SIZE ->
|
||||
{
|
||||
String width = ValueUtils.getValueAsString(adornmentValues.get("width"));
|
||||
if(assertCondition(StringUtils.hasContent(width), adornmentPrefix + "is missing a width value"))
|
||||
{
|
||||
assertNoException(() -> AdornmentType.Size.valueOf(width.toUpperCase()), adornmentPrefix + "has an unrecognized width value [" + width + "]");
|
||||
}
|
||||
}
|
||||
case FILE_DOWNLOAD ->
|
||||
{
|
||||
String fileNameField = ValueUtils.getValueAsString(adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FIELD));
|
||||
if(StringUtils.hasContent(fileNameField)) // file name isn't required - but if given, must be a field on the table.
|
||||
{
|
||||
assertNoException(() -> table.getField(fileNameField), adornmentPrefix + "specifies an unrecognized fileNameField [" + fileNameField + "]");
|
||||
}
|
||||
|
||||
if(adornmentValues.containsKey(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT_FIELDS))
|
||||
{
|
||||
try
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> formatFieldNames = (List<String>) adornmentValues.get(AdornmentType.FileDownloadValues.FILE_NAME_FORMAT_FIELDS);
|
||||
for(String formatFieldName : CollectionUtils.nonNullList(formatFieldNames))
|
||||
{
|
||||
assertNoException(() -> table.getField(formatFieldName), adornmentPrefix + "specifies an unrecognized field name in fileNameFormatFields [" + formatFieldName + "]");
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
errors.add(adornmentPrefix + "fileNameFormatFields could not be accessed (is it a List<String>?)");
|
||||
}
|
||||
}
|
||||
}
|
||||
default ->
|
||||
{
|
||||
// no validations by default
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.audits.AuditInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.audits.AuditSingleInput;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||
|
||||
@ -290,4 +291,25 @@ public class RunBackendStepOutput extends AbstractActionOutput implements Serial
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public void addAuditSingleInput(AuditSingleInput auditSingleInput)
|
||||
{
|
||||
if(getAuditInputList() == null)
|
||||
{
|
||||
setAuditInputList(new ArrayList<>());
|
||||
}
|
||||
|
||||
if(getAuditInputList().isEmpty())
|
||||
{
|
||||
getAuditInputList().add(new AuditInput());
|
||||
}
|
||||
|
||||
AuditInput auditInput = getAuditInputList().get(0);
|
||||
auditInput.addAuditSingleInput(auditSingleInput);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -73,7 +73,11 @@ public class QRecord implements Serializable
|
||||
|
||||
private Map<String, List<QRecord>> associatedRecords = new HashMap<>();
|
||||
|
||||
public static final String BACKEND_DETAILS_TYPE_JSON_SOURCE_OBJECT = "jsonSourceObject";
|
||||
////////////////////////////////////////////////
|
||||
// well-known keys for the backendDetails map //
|
||||
////////////////////////////////////////////////
|
||||
public static final String BACKEND_DETAILS_TYPE_JSON_SOURCE_OBJECT = "jsonSourceObject"; // String of JSON
|
||||
public static final String BACKEND_DETAILS_TYPE_HEAVY_FIELD_LENGTHS = "heavyFieldLengths"; // Map<fieldName, length>
|
||||
|
||||
|
||||
|
||||
|
@ -295,7 +295,8 @@ public abstract class QRecordEntity
|
||||
|| returnType.equals(BigDecimal.class)
|
||||
|| returnType.equals(Instant.class)
|
||||
|| returnType.equals(LocalDate.class)
|
||||
|| returnType.equals(LocalTime.class));
|
||||
|| returnType.equals(LocalTime.class)
|
||||
|| returnType.equals(byte[].class));
|
||||
/////////////////////////////////////////////
|
||||
// note - this list has implications upon: //
|
||||
// - QFieldType.fromClass //
|
||||
|
@ -165,6 +165,11 @@ public class QRecordEntityField
|
||||
{
|
||||
return (ValueUtils.getValueAsLocalTime(value));
|
||||
}
|
||||
|
||||
if(type.equals(byte[].class))
|
||||
{
|
||||
return (ValueUtils.getValueAsByteArray(value));
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
@ -167,7 +167,8 @@ public interface QRecordEnum
|
||||
|| returnType.equals(BigDecimal.class)
|
||||
|| returnType.equals(Instant.class)
|
||||
|| returnType.equals(LocalDate.class)
|
||||
|| returnType.equals(LocalTime.class));
|
||||
|| returnType.equals(LocalTime.class)
|
||||
|| returnType.equals(byte[].class));
|
||||
/////////////////////////////////////////////
|
||||
// note - this list has implications upon: //
|
||||
// - QFieldType.fromClass //
|
||||
|
@ -40,6 +40,7 @@ public enum AdornmentType
|
||||
CODE_EDITOR,
|
||||
RENDER_HTML,
|
||||
REVEAL,
|
||||
FILE_DOWNLOAD,
|
||||
ERROR;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// keep these values in sync with AdornmentType.ts in qqq-frontend-core //
|
||||
@ -58,6 +59,26 @@ public enum AdornmentType
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public interface FileDownloadValues
|
||||
{
|
||||
String FILE_NAME_FIELD = "fileNameField";
|
||||
String DEFAULT_EXTENSION = "defaultExtension";
|
||||
String DEFAULT_MIME_TYPE = "defaultMimeType";
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// use these two together, as in: //
|
||||
// FILE_NAME_FORMAT = "Order %s Packing Slip.pdf" //
|
||||
// FILE_NAME_FORMAT_FIELDS = "orderId" //
|
||||
////////////////////////////////////////////////////
|
||||
String FILE_NAME_FORMAT = "fileNameFormat";
|
||||
String FILE_NAME_FORMAT_FIELDS = "fileNameFormatFields";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -112,6 +133,7 @@ public enum AdornmentType
|
||||
XSMALL,
|
||||
SMALL,
|
||||
MEDIUM,
|
||||
MEDLARGE,
|
||||
LARGE,
|
||||
XLARGE;
|
||||
|
||||
|
@ -25,6 +25,8 @@ package com.kingsrook.qqq.backend.core.model.metadata.fields;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.kingsrook.qqq.backend.core.utils.Pair;
|
||||
|
||||
|
||||
@ -116,6 +118,22 @@ public class FieldAdornment
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@JsonIgnore
|
||||
public Optional<Serializable> getValue(String key)
|
||||
{
|
||||
if(key != null && values != null)
|
||||
{
|
||||
return (Optional.ofNullable(values.get(key)));
|
||||
}
|
||||
|
||||
return (Optional.empty());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for values
|
||||
**
|
||||
|
@ -31,6 +31,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.github.hervian.reflection.Fun;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
@ -534,6 +535,29 @@ public class QFieldMetaData implements Cloneable
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for adornments
|
||||
**
|
||||
*******************************************************************************/
|
||||
@JsonIgnore
|
||||
public Optional<FieldAdornment> getAdornment(AdornmentType adornmentType)
|
||||
{
|
||||
if(adornmentType != null && adornments != null)
|
||||
{
|
||||
for(FieldAdornment adornment : adornments)
|
||||
{
|
||||
if(adornmentType.equals(adornment.getType()))
|
||||
{
|
||||
return Optional.of((adornment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (Optional.empty());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for adornments
|
||||
**
|
||||
|
@ -85,6 +85,10 @@ public enum QFieldType
|
||||
{
|
||||
return (BOOLEAN);
|
||||
}
|
||||
if(c.equals(byte[].class))
|
||||
{
|
||||
return (BLOB);
|
||||
}
|
||||
|
||||
throw (new QException("Unrecognized class [" + c + "]"));
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ public class QFrontendFieldMetaData
|
||||
private QFieldType type;
|
||||
private boolean isRequired;
|
||||
private boolean isEditable;
|
||||
private boolean isHeavy;
|
||||
private String possibleValueSourceName;
|
||||
private String displayFormat;
|
||||
|
||||
@ -64,6 +65,7 @@ public class QFrontendFieldMetaData
|
||||
this.type = fieldMetaData.getType();
|
||||
this.isRequired = fieldMetaData.getIsRequired();
|
||||
this.isEditable = fieldMetaData.getIsEditable();
|
||||
this.isHeavy = fieldMetaData.getIsHeavy();
|
||||
this.possibleValueSourceName = fieldMetaData.getPossibleValueSourceName();
|
||||
this.displayFormat = fieldMetaData.getDisplayFormat();
|
||||
this.adornments = fieldMetaData.getAdornments();
|
||||
@ -126,6 +128,17 @@ public class QFrontendFieldMetaData
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for isHeavy
|
||||
**
|
||||
*******************************************************************************/
|
||||
public boolean getIsHeavy()
|
||||
{
|
||||
return isHeavy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for displayFormat
|
||||
**
|
||||
|
@ -70,6 +70,17 @@ public class AbstractProcessMetaDataBuilder
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public AbstractProcessMetaDataBuilder withInputFieldDefaultValue(String fieldName, Serializable value)
|
||||
{
|
||||
setInputFieldDefaultValue(fieldName, value);
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -31,6 +31,7 @@ import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
|
||||
*******************************************************************************/
|
||||
public class RenderTemplateInput extends AbstractActionInput
|
||||
{
|
||||
private String templateIdentifier;
|
||||
private String code; // todo - TemplateReference, like CodeReference??
|
||||
private TemplateType templateType;
|
||||
|
||||
@ -147,4 +148,35 @@ public class RenderTemplateInput extends AbstractActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for templateIdentifier
|
||||
*******************************************************************************/
|
||||
public String getTemplateIdentifier()
|
||||
{
|
||||
return (this.templateIdentifier);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for templateIdentifier
|
||||
*******************************************************************************/
|
||||
public void setTemplateIdentifier(String templateIdentifier)
|
||||
{
|
||||
this.templateIdentifier = templateIdentifier;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for templateIdentifier
|
||||
*******************************************************************************/
|
||||
public RenderTemplateInput withTemplateIdentifier(String templateIdentifier)
|
||||
{
|
||||
this.templateIdentifier = templateIdentifier;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -140,6 +140,11 @@ public class ColumnStatsStep implements BackendStep
|
||||
throw (new QException("Could not find field by name: " + fieldName));
|
||||
}
|
||||
|
||||
if(field.getType().equals(QFieldType.BLOB))
|
||||
{
|
||||
throw (new QException("Column stats are not supported for this field's data type."));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
// do a count query grouped by this field //
|
||||
////////////////////////////////////////////
|
||||
|
@ -47,6 +47,8 @@ public abstract class AbstractLoadStep implements BackendStep
|
||||
private Optional<QBackendTransaction> transaction = Optional.empty();
|
||||
protected QSession session;
|
||||
|
||||
private AbstractTransformStep transformStep;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -122,4 +124,35 @@ public abstract class AbstractLoadStep implements BackendStep
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for transformStep
|
||||
*******************************************************************************/
|
||||
public AbstractTransformStep getTransformStep()
|
||||
{
|
||||
return (this.transformStep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for transformStep
|
||||
*******************************************************************************/
|
||||
public void setTransformStep(AbstractTransformStep transformStep)
|
||||
{
|
||||
this.transformStep = transformStep;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for transformStep
|
||||
*******************************************************************************/
|
||||
public AbstractLoadStep withTransformStep(AbstractTransformStep transformStep)
|
||||
{
|
||||
this.transformStep = transformStep;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -109,6 +109,11 @@ public class ExtractViaQueryStep extends AbstractExtractStep
|
||||
queryInput.setRecordPipe(getRecordPipe());
|
||||
queryInput.setAsyncJobCallback(runBackendStepInput.getAsyncJobCallback());
|
||||
|
||||
if(runBackendStepInput.getValuePrimitiveBoolean(StreamedETLWithFrontendProcess.FIELD_FETCH_HEAVY_FIELDS))
|
||||
{
|
||||
queryInput.setShouldFetchHeavyFields(true);
|
||||
}
|
||||
|
||||
customizeInputPreQuery(queryInput);
|
||||
|
||||
new QueryAction().execute(queryInput);
|
||||
|
@ -34,6 +34,8 @@ import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.audits.AuditInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLine;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface;
|
||||
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.data.QRecord;
|
||||
@ -73,6 +75,8 @@ public class StreamedETLExecuteStep extends BaseStreamedETLStep implements Backe
|
||||
AbstractTransformStep transformStep = getTransformStep(runBackendStepInput);
|
||||
AbstractLoadStep loadStep = getLoadStep(runBackendStepInput);
|
||||
|
||||
loadStep.setTransformStep(transformStep);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// let the load step override the capacity for the record pipe. //
|
||||
// this is useful for slower load steps - so that the extract step doesn't //
|
||||
@ -140,13 +144,17 @@ public class StreamedETLExecuteStep extends BaseStreamedETLStep implements Backe
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get the process summary from the load step, if it's a summary-provider -- else, use the transform step (which is always a provider) //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
ArrayList<ProcessSummaryLineInterface> processSummaryLines = null;
|
||||
if(loadStep instanceof ProcessSummaryProviderInterface provider)
|
||||
{
|
||||
runBackendStepOutput.addValue(StreamedETLWithFrontendProcess.FIELD_PROCESS_SUMMARY, provider.doGetProcessSummary(runBackendStepOutput, true));
|
||||
processSummaryLines = provider.doGetProcessSummary(runBackendStepOutput, true);
|
||||
runBackendStepOutput.addValue(StreamedETLWithFrontendProcess.FIELD_PROCESS_SUMMARY, processSummaryLines);
|
||||
}
|
||||
else
|
||||
|
||||
if(CollectionUtils.nullSafeIsEmpty(processSummaryLines))
|
||||
{
|
||||
runBackendStepOutput.addValue(StreamedETLWithFrontendProcess.FIELD_PROCESS_SUMMARY, transformStep.doGetProcessSummary(runBackendStepOutput, true));
|
||||
processSummaryLines = transformStep.doGetProcessSummary(runBackendStepOutput, true);
|
||||
runBackendStepOutput.addValue(StreamedETLWithFrontendProcess.FIELD_PROCESS_SUMMARY, processSummaryLines);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -81,6 +81,7 @@ public class StreamedETLWithFrontendProcess
|
||||
public static final String FIELD_DESTINATION_TABLE = "destinationTable"; // String
|
||||
public static final String FIELD_RECORD_COUNT = "recordCount"; // Integer
|
||||
public static final String FIELD_DEFAULT_QUERY_FILTER = "defaultQueryFilter"; // QQueryFilter or String (json, of q QQueryFilter)
|
||||
public static final String FIELD_FETCH_HEAVY_FIELDS = "fetchHeavyFields"; // Boolean
|
||||
|
||||
public static final String FIELD_SUPPORTS_FULL_VALIDATION = "supportsFullValidation"; // Boolean
|
||||
public static final String FIELD_DO_FULL_VALIDATION = "doFullValidation"; // Boolean
|
||||
@ -142,6 +143,7 @@ public class StreamedETLWithFrontendProcess
|
||||
.withCode(new QCodeReference(StreamedETLPreviewStep.class))
|
||||
.withInputData(new QFunctionInputMetaData()
|
||||
.withField(new QFieldMetaData(FIELD_SOURCE_TABLE, QFieldType.STRING).withDefaultValue(defaultFieldValues.get(FIELD_SOURCE_TABLE)))
|
||||
.withField(new QFieldMetaData(FIELD_FETCH_HEAVY_FIELDS, QFieldType.BOOLEAN).withDefaultValue(defaultFieldValues.getOrDefault(FIELD_FETCH_HEAVY_FIELDS, false)))
|
||||
.withField(new QFieldMetaData(FIELD_DESTINATION_TABLE, QFieldType.STRING).withDefaultValue(defaultFieldValues.get(FIELD_DESTINATION_TABLE)))
|
||||
.withField(new QFieldMetaData(FIELD_SUPPORTS_FULL_VALIDATION, QFieldType.BOOLEAN).withDefaultValue(defaultFieldValues.getOrDefault(FIELD_SUPPORTS_FULL_VALIDATION, true)))
|
||||
.withField(new QFieldMetaData(FIELD_DO_FULL_VALIDATION, QFieldType.BOOLEAN).withDefaultValue(defaultFieldValues.get(FIELD_DO_FULL_VALIDATION)))
|
||||
|
@ -28,6 +28,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.CountAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
@ -394,9 +395,25 @@ public class GeneralProcessUtils
|
||||
** Note - null values from the key field are NOT put in the map.
|
||||
*******************************************************************************/
|
||||
public static <T extends QRecordEntity> Map<Serializable, T> loadTableToMap(AbstractActionInput parentActionInput, String tableName, String keyFieldName, Class<T> entityClass) throws QException
|
||||
{
|
||||
return (loadTableToMap(tableName, keyFieldName, entityClass, null));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Note - null values from the key field are NOT put in the map.
|
||||
*******************************************************************************/
|
||||
public static <T extends QRecordEntity> Map<Serializable, T> loadTableToMap(String tableName, String keyFieldName, Class<T> entityClass, Consumer<QueryInput> queryInputCustomizer) throws QException
|
||||
{
|
||||
QueryInput queryInput = new QueryInput();
|
||||
queryInput.setTableName(tableName);
|
||||
|
||||
if(queryInputCustomizer != null)
|
||||
{
|
||||
queryInputCustomizer.accept(queryInput);
|
||||
}
|
||||
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
List<QRecord> records = queryOutput.getRecords();
|
||||
|
||||
|
Reference in New Issue
Block a user