mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Add field sections, record labels, display values being populated
This commit is contained in:
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.actions.tables;
|
|||||||
|
|
||||||
|
|
||||||
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
import com.kingsrook.qqq.backend.core.actions.ActionHelper;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
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.actions.tables.query.QueryOutput;
|
||||||
@ -48,6 +49,10 @@ public class QueryAction
|
|||||||
// todo pre-customization - just get to modify the request?
|
// todo pre-customization - just get to modify the request?
|
||||||
QueryOutput queryOutput = qModule.getQueryInterface().execute(queryInput);
|
QueryOutput queryOutput = qModule.getQueryInterface().execute(queryInput);
|
||||||
// todo post-customization - can do whatever w/ the result if you want
|
// todo post-customization - can do whatever w/ the result if you want
|
||||||
|
|
||||||
|
QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), queryOutput.getRecords());
|
||||||
|
|
||||||
return queryOutput;
|
return queryOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,10 @@ package com.kingsrook.qqq.backend.core.actions.values;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
@ -62,14 +65,114 @@ public class QValueFormatter
|
|||||||
return (field.getDisplayFormat().formatted(value));
|
return (field.getDisplayFormat().formatted(value));
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(e.getMessage().equals("f != java.lang.Integer"))
|
||||||
|
{
|
||||||
|
return formatValue(field, ValueUtils.getValueAsBigDecimal(value));
|
||||||
|
}
|
||||||
|
else if(e.getMessage().equals("d != java.math.BigDecimal"))
|
||||||
|
{
|
||||||
|
return formatValue(field, ValueUtils.getValueAsInteger(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
LOG.warn("Error formatting value [" + value + "] for field [" + field.getName() + "] with format [" + field.getDisplayFormat() + "]: " + e.getMessage());
|
LOG.warn("Error formatting value [" + value + "] for field [" + field.getName() + "] with format [" + field.getDisplayFormat() + "]: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch(Exception e2)
|
||||||
|
{
|
||||||
|
LOG.warn("Caught secondary exception trying to convert type on field [" + field.getName() + "] for formatting", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
// by default, just get back a string //
|
// by default, just get back a string //
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
return (ValueUtils.getValueAsString(value));
|
return (ValueUtils.getValueAsString(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Make a string from a table's recordLabelFormat and fields, for a given record.
|
||||||
|
*******************************************************************************/
|
||||||
|
public static String formatRecordLabel(QTableMetaData table, QRecord record)
|
||||||
|
{
|
||||||
|
if(!StringUtils.hasContent(table.getRecordLabelFormat()))
|
||||||
|
{
|
||||||
|
return (formatRecordLabelExceptionalCases(table, record));
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// get list of values, then pass them to the string formatter method //
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<Serializable> values = table.getRecordLabelFields().stream()
|
||||||
|
.map(record::getValue)
|
||||||
|
.map(v -> v == null ? "" : v)
|
||||||
|
.toList();
|
||||||
|
return (table.getRecordLabelFormat().formatted(values.toArray()));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
return (formatRecordLabelExceptionalCases(table, record));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Deal with non-happy-path cases for making a record label.
|
||||||
|
*******************************************************************************/
|
||||||
|
private static String formatRecordLabelExceptionalCases(QTableMetaData table, QRecord record)
|
||||||
|
{
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if there's no record label format, then just return the primary key display value //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
String pkeyDisplayValue = record.getDisplayValue(table.getPrimaryKeyField());
|
||||||
|
if(StringUtils.hasContent(pkeyDisplayValue))
|
||||||
|
{
|
||||||
|
return (pkeyDisplayValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
String pkeyRawValue = ValueUtils.getValueAsString(record.getValue(table.getPrimaryKeyField()));
|
||||||
|
if(StringUtils.hasContent(pkeyRawValue))
|
||||||
|
{
|
||||||
|
return (pkeyRawValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// worst case scenario, return empty string, but never null from this method //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
return ("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** For a list of records, set their recordLabels and display values
|
||||||
|
*******************************************************************************/
|
||||||
|
public static void setDisplayValuesInRecords(QTableMetaData table, List<QRecord> records)
|
||||||
|
{
|
||||||
|
if(records == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(QRecord record : records)
|
||||||
|
{
|
||||||
|
for(QFieldMetaData field : table.getFields().values())
|
||||||
|
{
|
||||||
|
String formattedValue = QValueFormatter.formatValue(field, record.getValue(field.getName()));
|
||||||
|
record.setDisplayValue(field.getName(), formattedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
record.setRecordLabel(QValueFormatter.formatRecordLabel(table, record));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,10 @@ package com.kingsrook.qqq.backend.core.instances;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
|
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.QInstance;
|
||||||
@ -32,6 +34,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QComponentType;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QComponentType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendComponentMetaData;
|
||||||
@ -41,13 +44,16 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMe
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
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.BulkDeleteStoreStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.delete.BulkDeleteStoreStep;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.edit.BulkEditReceiveValuesStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.edit.BulkEditReceiveValuesStep;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.edit.BulkEditStoreRecordsStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.edit.BulkEditStoreRecordsStep;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert.BulkInsertReceiveFileStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert.BulkInsertReceiveFileStep;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert.BulkInsertStoreRecordsStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.bulk.insert.BulkInsertStoreRecordsStep;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.general.LoadInitialRecordsStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.general.LoadInitialRecordsStep;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
@ -111,6 +117,11 @@ public class QInstanceEnricher
|
|||||||
{
|
{
|
||||||
table.getFields().values().forEach(this::enrich);
|
table.getFields().values().forEach(this::enrich);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeIsEmpty(table.getSections()))
|
||||||
|
{
|
||||||
|
generateTableFieldSections(table);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -196,13 +207,20 @@ public class QInstanceEnricher
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
private String nameToLabel(String name)
|
private String nameToLabel(String name)
|
||||||
{
|
{
|
||||||
if(name == null)
|
if(!StringUtils.hasContent(name))
|
||||||
{
|
{
|
||||||
return (null);
|
return (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(name.length() == 1)
|
||||||
|
{
|
||||||
|
return (name.substring(0, 1).toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return (name.substring(0, 1).toUpperCase(Locale.ROOT) + name.substring(1).replaceAll("([A-Z])", " $1"));
|
return (name.substring(0, 1).toUpperCase(Locale.ROOT) + name.substring(1).replaceAll("([A-Z])", " $1"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -422,4 +440,71 @@ public class QInstanceEnricher
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** If a table didn't have any sections, generate "sensible defaults"
|
||||||
|
*******************************************************************************/
|
||||||
|
private void generateTableFieldSections(QTableMetaData table)
|
||||||
|
{
|
||||||
|
if(CollectionUtils.nullSafeIsEmpty(table.getFields()))
|
||||||
|
{
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// assume this table is invalid if it has no fields, but surely it doesn't need any sections then. //
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// create an identity section for the id and any fields in the record label //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
QFieldSection identitySection = new QFieldSection("identity", "Identity", new QIcon("badge"), Tier.T1, new ArrayList<>());
|
||||||
|
|
||||||
|
Set<String> usedFieldNames = new HashSet<>();
|
||||||
|
|
||||||
|
if(StringUtils.hasContent(table.getPrimaryKeyField()))
|
||||||
|
{
|
||||||
|
identitySection.getFieldNames().add(table.getPrimaryKeyField());
|
||||||
|
usedFieldNames.add(table.getPrimaryKeyField());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeHasContents(table.getRecordLabelFields()))
|
||||||
|
{
|
||||||
|
for(String fieldName : table.getRecordLabelFields())
|
||||||
|
{
|
||||||
|
if(!usedFieldNames.contains(fieldName))
|
||||||
|
{
|
||||||
|
identitySection.getFieldNames().add(fieldName);
|
||||||
|
usedFieldNames.add(fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!identitySection.getFieldNames().isEmpty())
|
||||||
|
{
|
||||||
|
table.addSection(identitySection);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// if there are more fields, then add them in a default/Other Fields section //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
QFieldSection otherSection = new QFieldSection("otherFields", "Other Fields", new QIcon("dataset"), Tier.T2, new ArrayList<>());
|
||||||
|
if(CollectionUtils.nullSafeHasContents(table.getFields()))
|
||||||
|
{
|
||||||
|
for(String fieldName : table.getFields().keySet())
|
||||||
|
{
|
||||||
|
if(!usedFieldNames.contains(fieldName))
|
||||||
|
{
|
||||||
|
otherSection.getFieldNames().add(fieldName);
|
||||||
|
usedFieldNames.add(fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!otherSection.getFieldNames().isEmpty())
|
||||||
|
{
|
||||||
|
table.addSection(otherSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,9 @@ import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QStepMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||||
|
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.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
@ -160,12 +163,63 @@ public class QInstanceValidator
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// validate field sections in the table //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
Set<String> fieldNamesInSections = new HashSet<>();
|
||||||
|
QFieldSection tier1Section = null;
|
||||||
|
if(table.getSections() != null)
|
||||||
|
{
|
||||||
|
for(QFieldSection section : table.getSections())
|
||||||
|
{
|
||||||
|
validateSection(errors, table, section, fieldNamesInSections);
|
||||||
|
if(section.getTier().equals(Tier.T1))
|
||||||
|
{
|
||||||
|
assertCondition(errors, tier1Section == null, "Table " + tableName + " has more than 1 section listed as Tier 1");
|
||||||
|
tier1Section = section;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CollectionUtils.nullSafeHasContents(table.getFields()))
|
||||||
|
{
|
||||||
|
for(String fieldName : table.getFields().keySet())
|
||||||
|
{
|
||||||
|
assertCondition(errors, fieldNamesInSections.contains(fieldName), "Table " + tableName + " field " + fieldName + " is not listed in any field sections.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private void validateSection(List<String> errors, QTableMetaData table, QFieldSection section, Set<String> fieldNamesInSections)
|
||||||
|
{
|
||||||
|
assertCondition(errors, StringUtils.hasContent(section.getName()), "Missing a name for field section in table " + table.getName() + ".");
|
||||||
|
assertCondition(errors, StringUtils.hasContent(section.getLabel()), "Missing a label for field section in table " + table.getLabel() + ".");
|
||||||
|
if(assertCondition(errors, CollectionUtils.nullSafeHasContents(section.getFieldNames()), "Table " + table.getName() + " section " + section.getName() + " does not have any fields."))
|
||||||
|
{
|
||||||
|
if(table.getFields() != null)
|
||||||
|
{
|
||||||
|
for(String fieldName : section.getFieldNames())
|
||||||
|
{
|
||||||
|
assertCondition(errors, table.getFields().containsKey(fieldName), "Table " + table.getName() + " section " + section.getName() + " specifies fieldName " + fieldName + ", which is not a field on this table.");
|
||||||
|
assertCondition(errors, !fieldNamesInSections.contains(fieldName), "Table " + table.getName() + " has field " + fieldName + " listed more than once in its field sections.");
|
||||||
|
|
||||||
|
fieldNamesInSections.add(fieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -29,7 +29,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
|
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
@ -56,6 +55,8 @@ import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
|||||||
public class QRecord implements Serializable
|
public class QRecord implements Serializable
|
||||||
{
|
{
|
||||||
private String tableName;
|
private String tableName;
|
||||||
|
private String recordLabel;
|
||||||
|
|
||||||
private Map<String, Serializable> values = new LinkedHashMap<>();
|
private Map<String, Serializable> values = new LinkedHashMap<>();
|
||||||
private Map<String, String> displayValues = new LinkedHashMap<>();
|
private Map<String, String> displayValues = new LinkedHashMap<>();
|
||||||
private Map<String, Serializable> backendDetails = new LinkedHashMap<>();
|
private Map<String, Serializable> backendDetails = new LinkedHashMap<>();
|
||||||
@ -90,6 +91,7 @@ public class QRecord implements Serializable
|
|||||||
public QRecord(QRecord record)
|
public QRecord(QRecord record)
|
||||||
{
|
{
|
||||||
this.tableName = record.tableName;
|
this.tableName = record.tableName;
|
||||||
|
this.recordLabel = record.recordLabel;
|
||||||
this.values = record.values;
|
this.values = record.values;
|
||||||
this.displayValues = record.displayValues;
|
this.displayValues = record.displayValues;
|
||||||
this.backendDetails = record.backendDetails;
|
this.backendDetails = record.backendDetails;
|
||||||
@ -139,15 +141,6 @@ public class QRecord implements Serializable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public void setDisplayValue(QFieldMetaData field, Serializable rawValue)
|
|
||||||
{
|
|
||||||
displayValues.put(field.getName(), QValueFormatter.formatValue(field, rawValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
@ -160,17 +153,6 @@ public class QRecord implements Serializable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
**
|
|
||||||
*******************************************************************************/
|
|
||||||
public QRecord withDisplayValue(QFieldMetaData field, Serializable rawValue)
|
|
||||||
{
|
|
||||||
setDisplayValue(field, rawValue);
|
|
||||||
return (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for tableName
|
** Getter for tableName
|
||||||
**
|
**
|
||||||
@ -205,6 +187,39 @@ public class QRecord implements Serializable
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for recordLabel
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getRecordLabel()
|
||||||
|
{
|
||||||
|
return recordLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for recordLabel
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordLabel(String recordLabel)
|
||||||
|
{
|
||||||
|
this.recordLabel = recordLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for recordLabel
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QRecord withRecordLabel(String recordLabel)
|
||||||
|
{
|
||||||
|
this.recordLabel = recordLabel;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for values
|
** Getter for values
|
||||||
**
|
**
|
||||||
|
@ -61,10 +61,6 @@ public enum QFieldType
|
|||||||
{
|
{
|
||||||
return (INTEGER);
|
return (INTEGER);
|
||||||
}
|
}
|
||||||
if(c.equals(Boolean.class))
|
|
||||||
{
|
|
||||||
return (BOOLEAN);
|
|
||||||
}
|
|
||||||
if(c.equals(BigDecimal.class))
|
if(c.equals(BigDecimal.class))
|
||||||
{
|
{
|
||||||
return (DECIMAL);
|
return (DECIMAL);
|
||||||
|
@ -30,6 +30,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -45,6 +46,8 @@ public class QFrontendProcessMetaData
|
|||||||
private String tableName;
|
private String tableName;
|
||||||
private boolean isHidden;
|
private boolean isHidden;
|
||||||
|
|
||||||
|
private String iconName;
|
||||||
|
|
||||||
private List<QFrontendStepMetaData> frontendSteps;
|
private List<QFrontendStepMetaData> frontendSteps;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -77,6 +80,11 @@ public class QFrontendProcessMetaData
|
|||||||
frontendSteps = new ArrayList<>();
|
frontendSteps = new ArrayList<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(processMetaData.getIcon() != null && StringUtils.hasContent(processMetaData.getIcon().getName()))
|
||||||
|
{
|
||||||
|
this.iconName = processMetaData.getIcon().getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -148,12 +156,12 @@ public class QFrontendProcessMetaData
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Setter for isHidden
|
** Getter for iconName
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void setIsHidden(boolean isHidden)
|
public String getIconName()
|
||||||
{
|
{
|
||||||
this.isHidden = isHidden;
|
return iconName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,14 @@ package com.kingsrook.qqq.backend.core.model.metadata.frontend;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -43,7 +46,10 @@ public class QFrontendTableMetaData
|
|||||||
private boolean isHidden;
|
private boolean isHidden;
|
||||||
private String primaryKeyField;
|
private String primaryKeyField;
|
||||||
|
|
||||||
|
private String iconName;
|
||||||
|
|
||||||
private Map<String, QFrontendFieldMetaData> fields;
|
private Map<String, QFrontendFieldMetaData> fields;
|
||||||
|
private List<QFieldSection> sections;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////
|
||||||
// do not add setters. take values from the source-object in the constructor!! //
|
// do not add setters. take values from the source-object in the constructor!! //
|
||||||
@ -68,6 +74,13 @@ public class QFrontendTableMetaData
|
|||||||
{
|
{
|
||||||
this.fields.put(entry.getKey(), new QFrontendFieldMetaData(entry.getValue()));
|
this.fields.put(entry.getKey(), new QFrontendFieldMetaData(entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.sections = tableMetaData.getSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tableMetaData.getIcon() != null && StringUtils.hasContent(tableMetaData.getIcon().getName()))
|
||||||
|
{
|
||||||
|
this.iconName = tableMetaData.getIcon().getName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,6 +130,17 @@ public class QFrontendTableMetaData
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for sections
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QFieldSection> getSections()
|
||||||
|
{
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Getter for isHidden
|
** Getter for isHidden
|
||||||
**
|
**
|
||||||
@ -129,11 +153,11 @@ public class QFrontendTableMetaData
|
|||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Setter for isHidden
|
** Getter for iconName
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
public void setIsHidden(boolean isHidden)
|
public String getIconName()
|
||||||
{
|
{
|
||||||
this.isHidden = isHidden;
|
return iconName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import java.util.List;
|
|||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -44,6 +44,7 @@ public class QProcessMetaData implements QAppChildMetaData
|
|||||||
private List<QStepMetaData> stepList;
|
private List<QStepMetaData> stepList;
|
||||||
|
|
||||||
private String parentAppName;
|
private String parentAppName;
|
||||||
|
private QIcon icon;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -321,4 +322,38 @@ public class QProcessMetaData implements QAppChildMetaData
|
|||||||
this.parentAppName = parentAppName;
|
this.parentAppName = parentAppName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for icon
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QIcon getIcon()
|
||||||
|
{
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for icon
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIcon(QIcon icon)
|
||||||
|
{
|
||||||
|
this.icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for icon
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QProcessMetaData withIcon(QIcon icon)
|
||||||
|
{
|
||||||
|
this.icon = icon;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.metadata.tables;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** A section of fields - a logical grouping.
|
||||||
|
*******************************************************************************/
|
||||||
|
public class QFieldSection
|
||||||
|
{
|
||||||
|
private String name;
|
||||||
|
private String label;
|
||||||
|
private Tier tier;
|
||||||
|
|
||||||
|
private List<String> fieldNames;
|
||||||
|
private QIcon icon;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection(String name, String label, QIcon icon, Tier tier, List<String> fieldNames)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.label = label;
|
||||||
|
this.icon = icon;
|
||||||
|
this.tier = tier;
|
||||||
|
this.fieldNames = fieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for name
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection withName(String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for label
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getLabel()
|
||||||
|
{
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for label
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setLabel(String label)
|
||||||
|
{
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for label
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection withLabel(String label)
|
||||||
|
{
|
||||||
|
this.label = label;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for tier
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public Tier getTier()
|
||||||
|
{
|
||||||
|
return tier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for tier
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setTier(Tier tier)
|
||||||
|
{
|
||||||
|
this.tier = tier;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for tier
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection withTier(Tier tier)
|
||||||
|
{
|
||||||
|
this.tier = tier;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for fieldNames
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<String> getFieldNames()
|
||||||
|
{
|
||||||
|
return fieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for fieldNames
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setFieldNames(List<String> fieldNames)
|
||||||
|
{
|
||||||
|
this.fieldNames = fieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for fieldNames
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection withFieldNames(List<String> fieldNames)
|
||||||
|
{
|
||||||
|
this.fieldNames = fieldNames;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for icon
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QIcon getIcon()
|
||||||
|
{
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for icon
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setIcon(QIcon icon)
|
||||||
|
{
|
||||||
|
this.icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for icon
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QFieldSection withIcon(QIcon icon)
|
||||||
|
{
|
||||||
|
this.icon = icon;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.tables;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -64,6 +65,12 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
|||||||
private String parentAppName;
|
private String parentAppName;
|
||||||
private QIcon icon;
|
private QIcon icon;
|
||||||
|
|
||||||
|
private String recordLabelFormat;
|
||||||
|
private List<String> recordLabelFields;
|
||||||
|
|
||||||
|
private List<QFieldSection> sections;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Default constructor.
|
** Default constructor.
|
||||||
@ -496,6 +503,7 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Fluent setter for icon
|
** Fluent setter for icon
|
||||||
**
|
**
|
||||||
@ -506,4 +514,131 @@ public class QTableMetaData implements QAppChildMetaData, Serializable
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for recordLabelFormat
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getRecordLabelFormat()
|
||||||
|
{
|
||||||
|
return recordLabelFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for recordLabelFormat
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordLabelFormat(String recordLabelFormat)
|
||||||
|
{
|
||||||
|
this.recordLabelFormat = recordLabelFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for recordLabelFormat
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData withRecordLabelFormat(String recordLabelFormat)
|
||||||
|
{
|
||||||
|
this.recordLabelFormat = recordLabelFormat;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for recordLabelFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<String> getRecordLabelFields()
|
||||||
|
{
|
||||||
|
return recordLabelFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for recordLabelFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setRecordLabelFields(List<String> recordLabelFields)
|
||||||
|
{
|
||||||
|
this.recordLabelFields = recordLabelFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for recordLabelFields
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData withRecordLabelFields(List<String> recordLabelFields)
|
||||||
|
{
|
||||||
|
this.recordLabelFields = recordLabelFields;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for sections
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<QFieldSection> getSections()
|
||||||
|
{
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for sections
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setSections(List<QFieldSection> sections)
|
||||||
|
{
|
||||||
|
this.sections = sections;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for sections
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData withSections(List<QFieldSection> fieldSections)
|
||||||
|
{
|
||||||
|
this.sections = fieldSections;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public void addSection(QFieldSection fieldSection)
|
||||||
|
{
|
||||||
|
if(this.sections == null)
|
||||||
|
{
|
||||||
|
this.sections = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.sections.add(fieldSection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public QTableMetaData withSection(QFieldSection fieldSection)
|
||||||
|
{
|
||||||
|
addSection(fieldSection);
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.model.metadata.tables;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public enum Tier
|
||||||
|
{
|
||||||
|
T1,
|
||||||
|
T2,
|
||||||
|
T3
|
||||||
|
}
|
@ -65,7 +65,6 @@ public class MockQueryAction implements QueryInterface
|
|||||||
{
|
{
|
||||||
Serializable value = field.equals("id") ? (i + 1) : getValue(table, field);
|
Serializable value = field.equals("id") ? (i + 1) : getValue(table, field);
|
||||||
record.setValue(field, value);
|
record.setValue(field, value);
|
||||||
record.setDisplayValue(table.getField(field), value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queryOutput.addRecord(record);
|
queryOutput.addRecord(record);
|
||||||
|
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* QQQ - Low-code Application Framework for Engineers.
|
||||||
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
||||||
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
||||||
|
* contact@kingsrook.com
|
||||||
|
* https://github.com/Kingsrook/
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.kingsrook.qqq.backend.core.actions.values;
|
||||||
|
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Unit test for QValueFormatter
|
||||||
|
*******************************************************************************/
|
||||||
|
class QValueFormatterTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFormatValue()
|
||||||
|
{
|
||||||
|
assertNull(QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.COMMAS), null));
|
||||||
|
|
||||||
|
assertEquals("1", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.COMMAS), 1));
|
||||||
|
assertEquals("1,000", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.COMMAS), 1000));
|
||||||
|
assertEquals("1000", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(null), 1000));
|
||||||
|
assertEquals("$1,000.00", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.CURRENCY), 1000));
|
||||||
|
assertEquals("1,000.00", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.DECIMAL2_COMMAS), 1000));
|
||||||
|
assertEquals("1000.00", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.DECIMAL2), 1000));
|
||||||
|
|
||||||
|
assertEquals("1", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.COMMAS), new BigDecimal("1")));
|
||||||
|
assertEquals("1,000", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.COMMAS), new BigDecimal("1000")));
|
||||||
|
assertEquals("1000", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.STRING), new BigDecimal("1000")));
|
||||||
|
assertEquals("1000", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.STRING), 1000));
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// this one flows through the exceptional cases //
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
assertEquals("1000.01", QValueFormatter.formatValue(new QFieldMetaData().withDisplayFormat(DisplayFormat.COMMAS), new BigDecimal("1000.01")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFormatRecordLabel()
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData().withRecordLabelFormat("%s %s").withRecordLabelFields(List.of("firstName", "lastName"));
|
||||||
|
assertEquals("Darin Kelkhoff", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("firstName", "Darin").withValue("lastName", "Kelkhoff")));
|
||||||
|
assertEquals("Darin ", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("firstName", "Darin")));
|
||||||
|
assertEquals("Darin ", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("firstName", "Darin").withValue("lastName", null)));
|
||||||
|
|
||||||
|
table = new QTableMetaData().withRecordLabelFormat("%s " + DisplayFormat.CURRENCY).withRecordLabelFields(List.of("firstName", "price"));
|
||||||
|
assertEquals("Darin $10,000.00", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("firstName", "Darin").withValue("price", new BigDecimal(10000))));
|
||||||
|
|
||||||
|
table = new QTableMetaData().withRecordLabelFormat(DisplayFormat.DEFAULT).withRecordLabelFields(List.of("id"));
|
||||||
|
assertEquals("123456", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("id", "123456")));
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
// exceptional flow: no recordLabelFormat specified //
|
||||||
|
///////////////////////////////////////////////////////
|
||||||
|
table = new QTableMetaData().withPrimaryKeyField("id");
|
||||||
|
assertEquals("42", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("id", 42)));
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// exceptional flow: no fields for the format //
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
table = new QTableMetaData().withRecordLabelFormat("%s %s").withPrimaryKeyField("id");
|
||||||
|
assertEquals("128", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("id", 128)));
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
// exceptional flow: not enough fields for the format //
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
table = new QTableMetaData().withRecordLabelFormat("%s %s").withRecordLabelFields(List.of("a")).withPrimaryKeyField("id");
|
||||||
|
assertEquals("256", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("a", 47).withValue("id", 256)));
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// exceptional flow (kinda): too many fields for the format (just get the ones that are in the format) //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
table = new QTableMetaData().withRecordLabelFormat("%s %s").withRecordLabelFields(List.of("a", "b", "c")).withPrimaryKeyField("id");
|
||||||
|
assertEquals("47 48", QValueFormatter.formatRecordLabel(table, new QRecord().withValue("a", 47).withValue("b", 48).withValue("c", 49).withValue("id", 256)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSetDisplayValuesInRecords()
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData()
|
||||||
|
.withRecordLabelFormat("%s %s")
|
||||||
|
.withRecordLabelFields(List.of("firstName", "lastName"))
|
||||||
|
.withField(new QFieldMetaData("firstName", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("lastName", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("price", QFieldType.DECIMAL).withDisplayFormat(DisplayFormat.CURRENCY))
|
||||||
|
.withField(new QFieldMetaData("quantity", QFieldType.INTEGER).withDisplayFormat(DisplayFormat.COMMAS));
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// first, make sure it doesn't crash with null or empty inputs //
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
QValueFormatter.setDisplayValuesInRecords(table, null);
|
||||||
|
QValueFormatter.setDisplayValuesInRecords(table, Collections.emptyList());
|
||||||
|
|
||||||
|
List<QRecord> records = List.of(
|
||||||
|
new QRecord()
|
||||||
|
.withValue("firstName", "Tim")
|
||||||
|
.withValue("lastName", "Chamberlain")
|
||||||
|
.withValue("price", new BigDecimal("3.50"))
|
||||||
|
.withValue("quantity", 1701),
|
||||||
|
new QRecord()
|
||||||
|
.withValue("firstName", "Tyler")
|
||||||
|
.withValue("lastName", "Samples")
|
||||||
|
.withValue("price", new BigDecimal("174999.99"))
|
||||||
|
.withValue("quantity", 47)
|
||||||
|
);
|
||||||
|
|
||||||
|
QValueFormatter.setDisplayValuesInRecords(table, records);
|
||||||
|
|
||||||
|
assertEquals("Tim Chamberlain", records.get(0).getRecordLabel());
|
||||||
|
assertEquals("$3.50", records.get(0).getDisplayValue("price"));
|
||||||
|
assertEquals("1,701", records.get(0).getDisplayValue("quantity"));
|
||||||
|
|
||||||
|
assertEquals("Tyler Samples", records.get(1).getRecordLabel());
|
||||||
|
assertEquals("$174,999.99", records.get(1).getDisplayValue("price"));
|
||||||
|
assertEquals("47", records.get(1).getDisplayValue("quantity"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -24,10 +24,17 @@ package com.kingsrook.qqq.backend.core.instances;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
|
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.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||||
|
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.utils.TestUtils;
|
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@ -283,6 +290,124 @@ class QInstanceValidatorTest
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFieldSectionsMissingName()
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection(null, "Section 1", new QIcon("person"), Tier.T1, List.of("id")))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table), "Missing a name");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFieldSectionsMissingLabel()
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", null, new QIcon("person"), Tier.T1, List.of("id")))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table), "Missing a label");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFieldSectionsNoFields()
|
||||||
|
{
|
||||||
|
QTableMetaData table1 = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", "Section 1", new QIcon("person"), Tier.T1, List.of()))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table1), "section1 does not have any fields", "field id is not listed in any field sections");
|
||||||
|
|
||||||
|
QTableMetaData table2 = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", "Section 1", new QIcon("person"), Tier.T1, null))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table2), "section1 does not have any fields", "field id is not listed in any field sections");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFieldSectionsUnrecognizedFieldName()
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", "Section 1", new QIcon("person"), Tier.T1, List.of("id", "od")))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table), "not a field on this table");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFieldSectionsDuplicatedFieldName()
|
||||||
|
{
|
||||||
|
QTableMetaData table1 = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", "Section 1", new QIcon("person"), Tier.T1, List.of("id", "id")))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table1), "more than once");
|
||||||
|
|
||||||
|
QTableMetaData table2 = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", "Section 1", new QIcon("person"), Tier.T1, List.of("id")))
|
||||||
|
.withSection(new QFieldSection("section2", "Section 2", new QIcon("person"), Tier.T2, List.of("id")))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table2), "more than once");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFieldNotInAnySections()
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", "Section 1", new QIcon("person"), Tier.T1, List.of("id")))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
|
.withField(new QFieldMetaData("name", QFieldType.STRING));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table), "not listed in any field sections");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testFieldSectionsMultipleTier1()
|
||||||
|
{
|
||||||
|
QTableMetaData table = new QTableMetaData().withName("test")
|
||||||
|
.withBackendName(TestUtils.DEFAULT_BACKEND_NAME)
|
||||||
|
.withSection(new QFieldSection("section1", "Section 1", new QIcon("person"), Tier.T1, List.of("id")))
|
||||||
|
.withSection(new QFieldSection("section2", "Section 2", new QIcon("person"), Tier.T1, List.of("name")))
|
||||||
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
||||||
|
.withField(new QFieldMetaData("name", QFieldType.STRING));
|
||||||
|
assertValidationFailureReasons((qInstance) -> qInstance.addTable(table), "more than 1 section listed as Tier 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
** Run a little setup code on a qInstance; then validate it, and assert that it
|
** Run a little setup code on a qInstance; then validate it, and assert that it
|
||||||
** failed validation with reasons that match the supplied vararg-reasons (but allow
|
** failed validation with reasons that match the supplied vararg-reasons (but allow
|
||||||
|
@ -22,10 +22,12 @@
|
|||||||
package com.kingsrook.qqq.backend.module.rdbms;
|
package com.kingsrook.qqq.backend.module.rdbms;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.QAuthenticationType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
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.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
|
import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
|
||||||
|
|
||||||
@ -48,11 +50,25 @@ public class TestUtils
|
|||||||
QInstance qInstance = new QInstance();
|
QInstance qInstance = new QInstance();
|
||||||
qInstance.addBackend(defineBackend());
|
qInstance.addBackend(defineBackend());
|
||||||
qInstance.addTable(defineTablePerson());
|
qInstance.addTable(defineTablePerson());
|
||||||
|
qInstance.setAuthentication(defineAuthentication());
|
||||||
return (qInstance);
|
return (qInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Define the authentication used in standard tests - using 'mock' type.
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
public static QAuthenticationMetaData defineAuthentication()
|
||||||
|
{
|
||||||
|
return new QAuthenticationMetaData()
|
||||||
|
.withName("mock")
|
||||||
|
.withType(QAuthenticationType.MOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
@ -23,16 +23,20 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
|
|||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
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.QFilterCriteria;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
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.QueryInput;
|
||||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.session.QSession;
|
||||||
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
import com.kingsrook.qqq.backend.module.rdbms.TestUtils;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -416,7 +420,29 @@ public class RDBMSQueryActionTest extends RDBMSActionTest
|
|||||||
QueryInput queryInput = new QueryInput();
|
QueryInput queryInput = new QueryInput();
|
||||||
queryInput.setInstance(TestUtils.defineInstance());
|
queryInput.setInstance(TestUtils.defineInstance());
|
||||||
queryInput.setTableName(TestUtils.defineTablePerson().getName());
|
queryInput.setTableName(TestUtils.defineTablePerson().getName());
|
||||||
|
queryInput.setSession(new QSession());
|
||||||
return queryInput;
|
return queryInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** This doesn't really test any RDBMS code, but is a checkpoint that the core
|
||||||
|
** module is populating displayValues when it performs the system-level query action.
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
public void testThatDisplayValuesGetSetGoingThroughQueryAction() throws QException
|
||||||
|
{
|
||||||
|
QueryInput queryInput = initQueryRequest();
|
||||||
|
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||||
|
Assertions.assertEquals(5, queryOutput.getRecords().size(), "Unfiltered query should find all rows");
|
||||||
|
|
||||||
|
for(QRecord record : queryOutput.getRecords())
|
||||||
|
{
|
||||||
|
assertThat(record.getValues()).isNotEmpty();
|
||||||
|
assertThat(record.getDisplayValues()).isNotEmpty();
|
||||||
|
assertThat(record.getErrors()).isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -33,16 +33,20 @@ import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
|||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference;
|
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.code.QCodeType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeUsage;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.DisplayFormat;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFrontendStepMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
|
||||||
|
import com.kingsrook.qqq.backend.core.model.metadata.tables.QFieldSection;
|
||||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
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.modules.authentication.metadata.QAuthenticationMetaData;
|
import com.kingsrook.qqq.backend.core.modules.authentication.metadata.QAuthenticationMetaData;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.general.LoadInitialRecordsStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.general.LoadInitialRecordsStep;
|
||||||
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
import com.kingsrook.qqq.backend.core.processes.implementations.mock.MockBackendStep;
|
||||||
@ -123,18 +127,25 @@ public class SampleMetaDataProvider
|
|||||||
{
|
{
|
||||||
qInstance.addApp(new QAppMetaData()
|
qInstance.addApp(new QAppMetaData()
|
||||||
.withName(APP_NAME_GREETINGS)
|
.withName(APP_NAME_GREETINGS)
|
||||||
.withChild(qInstance.getProcess(PROCESS_NAME_GREET))
|
.withIcon(new QIcon().withName("emoji_people"))
|
||||||
.withChild(qInstance.getProcess(PROCESS_NAME_GREET_INTERACTIVE)));
|
.withChild(qInstance.getProcess(PROCESS_NAME_GREET)
|
||||||
|
.withIcon(new QIcon().withName("emoji_people")))
|
||||||
|
.withChild(qInstance.getTable(TABLE_NAME_PERSON)
|
||||||
|
.withIcon(new QIcon().withName("person")))
|
||||||
|
.withChild(qInstance.getTable(TABLE_NAME_CITY)
|
||||||
|
.withIcon(new QIcon().withName("location_city")))
|
||||||
|
.withChild(qInstance.getProcess(PROCESS_NAME_GREET_INTERACTIVE))
|
||||||
|
.withIcon(new QIcon().withName("waving_hand")));
|
||||||
|
|
||||||
qInstance.addApp(new QAppMetaData()
|
qInstance.addApp(new QAppMetaData()
|
||||||
.withName(APP_NAME_PEOPLE)
|
.withName(APP_NAME_PEOPLE)
|
||||||
.withChild(qInstance.getTable(TABLE_NAME_PERSON))
|
.withIcon(new QIcon().withName("person"))
|
||||||
.withChild(qInstance.getTable(TABLE_NAME_CITY))
|
|
||||||
.withChild(qInstance.getApp(APP_NAME_GREETINGS)));
|
.withChild(qInstance.getApp(APP_NAME_GREETINGS)));
|
||||||
|
|
||||||
qInstance.addApp(new QAppMetaData()
|
qInstance.addApp(new QAppMetaData()
|
||||||
.withName(APP_NAME_MISCELLANEOUS)
|
.withName(APP_NAME_MISCELLANEOUS)
|
||||||
.withChild(qInstance.getTable(TABLE_NAME_CARRIER))
|
.withIcon(new QIcon().withName("stars"))
|
||||||
|
.withChild(qInstance.getTable(TABLE_NAME_CARRIER).withIcon(new QIcon("local_shipping")))
|
||||||
.withChild(qInstance.getProcess(PROCESS_NAME_SIMPLE_SLEEP))
|
.withChild(qInstance.getProcess(PROCESS_NAME_SIMPLE_SLEEP))
|
||||||
.withChild(qInstance.getProcess(PROCESS_NAME_SLEEP_INTERACTIVE))
|
.withChild(qInstance.getProcess(PROCESS_NAME_SLEEP_INTERACTIVE))
|
||||||
.withChild(qInstance.getProcess(PROCESS_NAME_SIMPLE_THROW)));
|
.withChild(qInstance.getProcess(PROCESS_NAME_SIMPLE_THROW)));
|
||||||
@ -205,19 +216,25 @@ public class SampleMetaDataProvider
|
|||||||
table.setName(TABLE_NAME_CARRIER);
|
table.setName(TABLE_NAME_CARRIER);
|
||||||
table.setBackendName(RDBMS_BACKEND_NAME);
|
table.setBackendName(RDBMS_BACKEND_NAME);
|
||||||
table.setPrimaryKeyField("id");
|
table.setPrimaryKeyField("id");
|
||||||
|
table.setRecordLabelFormat("%s");
|
||||||
|
table.setRecordLabelFields(List.of("name"));
|
||||||
|
|
||||||
table.addField(new QFieldMetaData("id", QFieldType.INTEGER));
|
table.addField(new QFieldMetaData("id", QFieldType.INTEGER));
|
||||||
|
|
||||||
table.addField(new QFieldMetaData("name", QFieldType.STRING)
|
table.addField(new QFieldMetaData("name", QFieldType.STRING)
|
||||||
.withIsRequired(true));
|
.withIsRequired(true));
|
||||||
|
|
||||||
table.addField(new QFieldMetaData("company_code", QFieldType.STRING) // todo enum
|
table.addField(new QFieldMetaData("company_code", QFieldType.STRING) // todo PVS
|
||||||
.withLabel("Company")
|
.withLabel("Company")
|
||||||
.withIsRequired(true)
|
.withIsRequired(true)
|
||||||
.withBackendName("comp_code"));
|
.withBackendName("comp_code"));
|
||||||
|
|
||||||
table.addField(new QFieldMetaData("service_level", QFieldType.STRING)
|
table.addField(new QFieldMetaData("service_level", QFieldType.STRING) // todo PVS
|
||||||
.withIsRequired(true)); // todo enum
|
.withLabel("Service Level")
|
||||||
|
.withIsRequired(true));
|
||||||
|
|
||||||
|
table.addSection(new QFieldSection("identity", "Identity", new QIcon("badge"), Tier.T1, List.of("id", "name")));
|
||||||
|
table.addSection(new QFieldSection("basicInfo", "Basic Info", new QIcon("dataset"), Tier.T2, List.of("company_code", "service_level")));
|
||||||
|
|
||||||
return (table);
|
return (table);
|
||||||
}
|
}
|
||||||
@ -234,13 +251,24 @@ public class SampleMetaDataProvider
|
|||||||
.withLabel("Person")
|
.withLabel("Person")
|
||||||
.withBackendName(RDBMS_BACKEND_NAME)
|
.withBackendName(RDBMS_BACKEND_NAME)
|
||||||
.withPrimaryKeyField("id")
|
.withPrimaryKeyField("id")
|
||||||
.withField(new QFieldMetaData("id", QFieldType.INTEGER))
|
.withRecordLabelFormat("%s %s")
|
||||||
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withBackendName("create_date"))
|
.withRecordLabelFields(List.of("firstName", "lastName"))
|
||||||
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withBackendName("modify_date"))
|
.withField(new QFieldMetaData("id", QFieldType.INTEGER).withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("createDate", QFieldType.DATE_TIME).withBackendName("create_date").withIsEditable(false))
|
||||||
|
.withField(new QFieldMetaData("modifyDate", QFieldType.DATE_TIME).withBackendName("modify_date").withIsEditable(false))
|
||||||
.withField(new QFieldMetaData("firstName", QFieldType.STRING).withBackendName("first_name").withIsRequired(true))
|
.withField(new QFieldMetaData("firstName", QFieldType.STRING).withBackendName("first_name").withIsRequired(true))
|
||||||
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withBackendName("last_name").withIsRequired(true))
|
.withField(new QFieldMetaData("lastName", QFieldType.STRING).withBackendName("last_name").withIsRequired(true))
|
||||||
.withField(new QFieldMetaData("birthDate", QFieldType.DATE).withBackendName("birth_date"))
|
.withField(new QFieldMetaData("birthDate", QFieldType.DATE).withBackendName("birth_date"))
|
||||||
.withField(new QFieldMetaData("email", QFieldType.STRING));
|
.withField(new QFieldMetaData("email", QFieldType.STRING))
|
||||||
|
.withField(new QFieldMetaData("annualSalary", QFieldType.DECIMAL).withBackendName("annual_salary").withDisplayFormat(DisplayFormat.CURRENCY))
|
||||||
|
.withField(new QFieldMetaData("daysWorked", QFieldType.INTEGER).withBackendName("days_worked").withDisplayFormat(DisplayFormat.COMMAS))
|
||||||
|
|
||||||
|
.withSection(new QFieldSection("identity", "Identity", new QIcon("badge"), Tier.T1, List.of("id", "firstName", "lastName")))
|
||||||
|
.withSection(new QFieldSection("basicInfo", "Basic Info", new QIcon("dataset"), Tier.T2, List.of("email", "birthDate")))
|
||||||
|
.withSection(new QFieldSection("employmentInfo", "Employment Info", new QIcon("work"), Tier.T2, List.of("annualSalary", "daysWorked")))
|
||||||
|
.withSection(new QFieldSection("dates", "Dates", new QIcon("calendar_month"), Tier.T3, List.of("createDate", "modifyDate")))
|
||||||
|
|
||||||
|
.withInferredFieldBackendNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,14 +29,17 @@ CREATE TABLE person
|
|||||||
first_name VARCHAR(80) NOT NULL,
|
first_name VARCHAR(80) NOT NULL,
|
||||||
last_name VARCHAR(80) NOT NULL,
|
last_name VARCHAR(80) NOT NULL,
|
||||||
birth_date DATE,
|
birth_date DATE,
|
||||||
email VARCHAR(250) NOT NULL
|
email VARCHAR(250) NOT NULL,
|
||||||
|
|
||||||
|
annual_salary DECIMAL(12, 2),
|
||||||
|
days_worked INTEGER
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com');
|
INSERT INTO person (id, first_name, last_name, birth_date, email, annual_salary, days_worked) VALUES (1, 'Darin', 'Kelkhoff', '1980-05-31', 'darin.kelkhoff@gmail.com', 75003.50, 1001);
|
||||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (2, 'James', 'Maes', '1980-05-15', 'jmaes@mmltholdings.com');
|
INSERT INTO person (id, first_name, last_name, birth_date, email, annual_salary, days_worked) VALUES (2, 'James', 'Maes', '1980-05-15', 'jmaes@mmltholdings.com', 150000, 10100);
|
||||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (3, 'Tim', 'Chamberlain', '1976-05-28', 'tchamberlain@mmltholdings.com');
|
INSERT INTO person (id, first_name, last_name, birth_date, email, annual_salary, days_worked) VALUES (3, 'Tim', 'Chamberlain', '1976-05-28', 'tchamberlain@mmltholdings.com', 300000, 100100);
|
||||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (4, 'Tyler', 'Samples', NULL, 'tsamples@mmltholdings.com');
|
INSERT INTO person (id, first_name, last_name, birth_date, email, annual_salary, days_worked) VALUES (4, 'Tyler', 'Samples', NULL, 'tsamples@mmltholdings.com', 950000, 75);
|
||||||
INSERT INTO person (id, first_name, last_name, birth_date, email) VALUES (5, 'Garret', 'Richardson', '1981-01-01', 'grichardson@mmltholdings.com');
|
INSERT INTO person (id, first_name, last_name, birth_date, email, annual_salary, days_worked) VALUES (5, 'Garret', 'Richardson', '1981-01-01', 'grichardson@mmltholdings.com', 1500000, 1);
|
||||||
|
|
||||||
DROP TABLE IF EXISTS carrier;
|
DROP TABLE IF EXISTS carrier;
|
||||||
CREATE TABLE carrier
|
CREATE TABLE carrier
|
||||||
|
Reference in New Issue
Block a user