mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 20:50:44 +00:00
Merged feature/meta-data-producing-annotations into dev
This commit is contained in:
@ -70,6 +70,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.fields.FieldBehavior;
|
||||
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;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppChildMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
@ -780,14 +781,37 @@ public class QInstanceValidator
|
||||
if(assertCondition(StringUtils.hasContent(association.getName()), "missing a name for an Association on table " + table.getName()))
|
||||
{
|
||||
String messageSuffix = " for Association " + association.getName() + " on table " + table.getName();
|
||||
boolean recognizedTable = false;
|
||||
if(assertCondition(StringUtils.hasContent(association.getAssociatedTableName()), "missing associatedTableName" + messageSuffix))
|
||||
{
|
||||
assertCondition(qInstance.getTable(association.getAssociatedTableName()) != null, "unrecognized associatedTableName " + association.getAssociatedTableName() + messageSuffix);
|
||||
if(assertCondition(qInstance.getTable(association.getAssociatedTableName()) != null, "unrecognized associatedTableName " + association.getAssociatedTableName() + messageSuffix))
|
||||
{
|
||||
recognizedTable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(assertCondition(StringUtils.hasContent(association.getJoinName()), "missing joinName" + messageSuffix))
|
||||
{
|
||||
assertCondition(qInstance.getJoin(association.getJoinName()) != null, "unrecognized joinName " + association.getJoinName() + messageSuffix);
|
||||
QJoinMetaData join = qInstance.getJoin(association.getJoinName());
|
||||
if(assertCondition(join != null, "unrecognized joinName " + association.getJoinName() + messageSuffix))
|
||||
{
|
||||
assert join != null; // covered by the assertCondition
|
||||
|
||||
if(recognizedTable)
|
||||
{
|
||||
boolean isLeftToRight = join.getLeftTable().equals(table.getName()) && join.getRightTable().equals(association.getAssociatedTableName());
|
||||
boolean isRightToLeft = join.getRightTable().equals(table.getName()) && join.getLeftTable().equals(association.getAssociatedTableName());
|
||||
assertCondition(isLeftToRight || isRightToLeft, "join [" + association.getJoinName() + "] does not connect tables [" + table.getName() + "] and [" + association.getAssociatedTableName() + "]" + messageSuffix);
|
||||
if(isLeftToRight)
|
||||
{
|
||||
assertCondition(join.getType().equals(JoinType.ONE_TO_MANY) || join.getType().equals(JoinType.ONE_TO_ONE), "Join type does not have 'one' on this table's side side (left)" + messageSuffix);
|
||||
}
|
||||
else if(isRightToLeft)
|
||||
{
|
||||
assertCondition(join.getType().equals(JoinType.MANY_TO_ONE) || join.getType().equals(JoinType.ONE_TO_ONE), "Join type does not have 'one' on this table's side (right)" + messageSuffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ package com.kingsrook.qqq.backend.core.model.metadata;
|
||||
|
||||
/*******************************************************************************
|
||||
** Abstract class that knows how to produce meta data objects. Useful with
|
||||
** MetaDataProducerHelper, to put point at a package full of these, and populate
|
||||
** MetaDataProducerHelper, to point at a package full of these, and populate
|
||||
** your whole QInstance.
|
||||
*******************************************************************************/
|
||||
public abstract class MetaDataProducer<T extends MetaDataProducerOutput> implements MetaDataProducerInterface<T>
|
||||
|
@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata;
|
||||
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
@ -31,10 +32,23 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.ChildJoinFromRecordEntityGenericMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.PossibleValueSourceOfEnumGenericMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.PossibleValueSourceOfTableGenericMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildRecordListWidget;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildTable;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingPossibleValueEnum;
|
||||
import com.kingsrook.qqq.backend.core.utils.ClassPathUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||
|
||||
|
||||
@ -90,6 +104,9 @@ public class MetaDataProducerHelper
|
||||
}
|
||||
List<MetaDataProducerInterface<?>> producers = new ArrayList<>();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// loop over classes, processing them based on either their type or their annotations //
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
for(Class<?> aClass : classesInPackage)
|
||||
{
|
||||
try
|
||||
@ -101,23 +118,27 @@ public class MetaDataProducerHelper
|
||||
|
||||
if(MetaDataProducerInterface.class.isAssignableFrom(aClass))
|
||||
{
|
||||
boolean foundValidConstructor = false;
|
||||
for(Constructor<?> constructor : aClass.getConstructors())
|
||||
{
|
||||
if(constructor.getParameterCount() == 0)
|
||||
{
|
||||
Object o = constructor.newInstance();
|
||||
producers.add((MetaDataProducerInterface<?>) o);
|
||||
foundValidConstructor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CollectionUtils.addIfNotNull(producers, processMetaDataProducer(aClass));
|
||||
}
|
||||
|
||||
if(!foundValidConstructor)
|
||||
if(aClass.isAnnotationPresent(QMetaDataProducingEntity.class))
|
||||
{
|
||||
QMetaDataProducingEntity qMetaDataProducingEntity = aClass.getAnnotation(QMetaDataProducingEntity.class);
|
||||
if(qMetaDataProducingEntity.producePossibleValueSource())
|
||||
{
|
||||
LOG.warn("Found a class which implements MetaDataProducerInterface, but it does not have a no-arg constructor, so it cannot be used.", logPair("class", aClass.getSimpleName()));
|
||||
producers.addAll(processMetaDataProducingEntity(aClass));
|
||||
}
|
||||
}
|
||||
|
||||
if(aClass.isAnnotationPresent(QMetaDataProducingPossibleValueEnum.class))
|
||||
{
|
||||
QMetaDataProducingPossibleValueEnum qMetaDataProducingPossibleValueEnum = aClass.getAnnotation(QMetaDataProducingPossibleValueEnum.class);
|
||||
if(qMetaDataProducingPossibleValueEnum.producePossibleValueSource())
|
||||
{
|
||||
CollectionUtils.addIfNotNull(producers, processMetaDataProducingPossibleValueEnum(aClass));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
@ -168,7 +189,176 @@ public class MetaDataProducerHelper
|
||||
LOG.debug("Not using producer which is not enabled", logPair("producer", producer.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends PossibleValueEnum<T>> MetaDataProducerInterface<?> processMetaDataProducingPossibleValueEnum(Class<?> aClass)
|
||||
{
|
||||
String warningPrefix = "Found a class annotated as @" + QMetaDataProducingPossibleValueEnum.class.getSimpleName();
|
||||
if(!PossibleValueEnum.class.isAssignableFrom(aClass))
|
||||
{
|
||||
LOG.warn(warningPrefix + ", but which is not a " + PossibleValueEnum.class.getSimpleName() + ", so it will not be used.", logPair("class", aClass.getSimpleName()));
|
||||
return null;
|
||||
}
|
||||
|
||||
PossibleValueEnum<?>[] values = (PossibleValueEnum<?>[]) aClass.getEnumConstants();
|
||||
return (new PossibleValueSourceOfEnumGenericMetaDataProducer<T>(aClass.getSimpleName(), (PossibleValueEnum<T>[]) values));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static List<MetaDataProducerInterface<?>> processMetaDataProducingEntity(Class<?> aClass) throws Exception
|
||||
{
|
||||
List<MetaDataProducerInterface<?>> rs = new ArrayList<>();
|
||||
|
||||
String warningPrefix = "Found a class annotated as @" + QMetaDataProducingEntity.class.getSimpleName();
|
||||
if(!QRecordEntity.class.isAssignableFrom(aClass))
|
||||
{
|
||||
LOG.warn(warningPrefix + ", but which is not a " + QRecordEntity.class.getSimpleName() + ", so it will not be used.", logPair("class", aClass.getSimpleName()));
|
||||
return (rs);
|
||||
}
|
||||
|
||||
Field tableNameField = aClass.getDeclaredField("TABLE_NAME");
|
||||
if(!tableNameField.getType().equals(String.class))
|
||||
{
|
||||
LOG.warn(warningPrefix + ", but whose TABLE_NAME field is not a String, so it will not be used.", logPair("class", aClass.getSimpleName()));
|
||||
return (rs);
|
||||
}
|
||||
|
||||
String tableNameValue = (String) tableNameField.get(null);
|
||||
rs.add(new PossibleValueSourceOfTableGenericMetaDataProducer(tableNameValue));
|
||||
|
||||
//////////////////////////
|
||||
// process child tables //
|
||||
//////////////////////////
|
||||
QMetaDataProducingEntity qMetaDataProducingEntity = aClass.getAnnotation(QMetaDataProducingEntity.class);
|
||||
for(ChildTable childTable : qMetaDataProducingEntity.childTables())
|
||||
{
|
||||
Class<? extends QRecordEntity> childEntityClass = childTable.childTableEntityClass();
|
||||
if(childTable.childJoin().enabled())
|
||||
{
|
||||
CollectionUtils.addIfNotNull(rs, processChildJoin(aClass, childTable));
|
||||
|
||||
if(childTable.childRecordListWidget().enabled())
|
||||
{
|
||||
CollectionUtils.addIfNotNull(rs, processChildRecordListWidget(aClass, childTable));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(childTable.childRecordListWidget().enabled())
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// if not doing the join, can't do the child-widget, so warn about that //
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
LOG.warn(warningPrefix + " requested to produce a ChildRecordListWidget, but not produce a Join - which is not allowed (must do join to do widget). ", logPair("class", aClass.getSimpleName()), logPair("childEntityClass", childEntityClass.getSimpleName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static MetaDataProducerInterface<?> processChildRecordListWidget(Class<?> aClass, ChildTable childTable) throws Exception
|
||||
{
|
||||
Class<? extends QRecordEntity> childEntityClass = childTable.childTableEntityClass();
|
||||
String parentTableName = getTableNameStaticFieldValue(aClass);
|
||||
String childTableName = getTableNameStaticFieldValue(childEntityClass);
|
||||
|
||||
ChildRecordListWidget childRecordListWidget = childTable.childRecordListWidget();
|
||||
return (new ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer(childTableName, parentTableName, childRecordListWidget));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static String findPossibleValueField(Class<? extends QRecordEntity> entityClass, String possibleValueSourceName)
|
||||
{
|
||||
for(Field field : entityClass.getDeclaredFields())
|
||||
{
|
||||
if(field.isAnnotationPresent(QField.class))
|
||||
{
|
||||
QField qField = field.getAnnotation(QField.class);
|
||||
if(qField.possibleValueSourceName().equals(possibleValueSourceName))
|
||||
{
|
||||
return field.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static MetaDataProducerInterface<?> processChildJoin(Class<?> aClass, ChildTable childTable) throws Exception
|
||||
{
|
||||
Class<? extends QRecordEntity> childEntityClass = childTable.childTableEntityClass();
|
||||
|
||||
String parentTableName = getTableNameStaticFieldValue(aClass);
|
||||
String childTableName = getTableNameStaticFieldValue(childEntityClass);
|
||||
String possibleValueFieldName = findPossibleValueField(childEntityClass, parentTableName);
|
||||
if(!StringUtils.hasContent(possibleValueFieldName))
|
||||
{
|
||||
LOG.warn("Could not find field in [" + childEntityClass.getSimpleName() + "] with possibleValueSource referencing table [" + aClass.getSimpleName() + "]");
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (new ChildJoinFromRecordEntityGenericMetaDataProducer(childTableName, parentTableName, possibleValueFieldName));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static MetaDataProducerInterface<?> processMetaDataProducer(Class<?> aClass) throws Exception
|
||||
{
|
||||
for(Constructor<?> constructor : aClass.getConstructors())
|
||||
{
|
||||
if(constructor.getParameterCount() == 0)
|
||||
{
|
||||
Object o = constructor.newInstance();
|
||||
return (MetaDataProducerInterface<?>) o;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.warn("Found a class which implements MetaDataProducerInterface, but it does not have a no-arg constructor, so it cannot be used.", logPair("class", aClass.getSimpleName()));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private static String getTableNameStaticFieldValue(Class<?> aClass) throws NoSuchFieldException, IllegalAccessException
|
||||
{
|
||||
Field tableNameField = aClass.getDeclaredField("TABLE_NAME");
|
||||
if(!tableNameField.getType().equals(String.class))
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
String tableNameValue = (String) tableNameField.get(null);
|
||||
return (tableNameValue);
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,12 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
|
||||
/*******************************************************************************
|
||||
** Interface for classes that know how to produce meta data objects. Useful with
|
||||
** MetaDataProducerHelper, to put point at a package full of these, and populate
|
||||
** MetaDataProducerHelper, to point at a package full of these, and populate
|
||||
** your whole QInstance.
|
||||
**
|
||||
** See also MetaDataProducer - an implementer of this interface, which actually
|
||||
** came first, and is fine to extend if producing a meta-data class is all your
|
||||
** clas means to do (nice and "Single-responsibility principle").
|
||||
** class means to do (nice and "Single-responsibility principle").
|
||||
**
|
||||
** But, in some applications you may want to, for example, have one class that
|
||||
** defines a process step, and also produces the meta-data for that process, so
|
||||
|
@ -22,6 +22,9 @@
|
||||
package com.kingsrook.qqq.backend.core.model.metadata.possiblevalues;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** An actual possible value - an id and label.
|
||||
**
|
||||
@ -76,4 +79,37 @@ public class QPossibleValue<T>
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if(this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QPossibleValue<?> that = (QPossibleValue<?>) o;
|
||||
return Objects.equals(id, that.id) && Objects.equals(label, that.label);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(id, label);
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,10 @@ package com.kingsrook.qqq.backend.core.model.metadata.possiblevalues;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.TopLevelMetaDataInterface;
|
||||
@ -97,7 +100,7 @@ public class QPossibleValueSource implements TopLevelMetaDataInterface
|
||||
** Create a new possible value source, for an enum, with default settings.
|
||||
** e.g., type=ENUM; name from param values from the param; LABEL_ONLY format
|
||||
*******************************************************************************/
|
||||
public static <T extends PossibleValueEnum<?>> QPossibleValueSource newForEnum(String name, T[] values)
|
||||
public static <I, T extends PossibleValueEnum<I>> QPossibleValueSource newForEnum(String name, T[] values)
|
||||
{
|
||||
return new QPossibleValueSource()
|
||||
.withName(name)
|
||||
@ -553,11 +556,25 @@ public class QPossibleValueSource implements TopLevelMetaDataInterface
|
||||
** myPossibleValueSource.withValuesFromEnum(MyEnum.values()));
|
||||
**
|
||||
*******************************************************************************/
|
||||
public <T extends PossibleValueEnum<?>> QPossibleValueSource withValuesFromEnum(T[] values)
|
||||
public <I, T extends PossibleValueEnum<I>> QPossibleValueSource withValuesFromEnum(T[] values)
|
||||
{
|
||||
Set<I> usedIds = new HashSet<>();
|
||||
List<I> duplicatedIds = new ArrayList<>();
|
||||
|
||||
for(T t : values)
|
||||
{
|
||||
if(usedIds.contains(t.getPossibleValueId()))
|
||||
{
|
||||
duplicatedIds.add(t.getPossibleValueId());
|
||||
}
|
||||
|
||||
addEnumValue(new QPossibleValue<>(t.getPossibleValueId(), t.getPossibleValueLabel()));
|
||||
usedIds.add(t.getPossibleValueId());
|
||||
}
|
||||
|
||||
if(!duplicatedIds.isEmpty())
|
||||
{
|
||||
throw (new QRuntimeException("Error: Duplicated id(s) found in enum values: " + duplicatedIds));
|
||||
}
|
||||
|
||||
return (this);
|
||||
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinOn;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Generic meta-data-producer, which should be instantiated (e.g., by
|
||||
** MetaDataProducer Helper), to produce a QJoinMetaData, based on a
|
||||
** QRecordEntity and a ChildTable sub-annotation.
|
||||
**
|
||||
** e.g., Orders & LineItems - on the Order entity
|
||||
** <code>
|
||||
@QMetaDataProducingEntity(
|
||||
childTables = { @ChildTable(
|
||||
childTableEntityClass = LineItem.class,
|
||||
childJoin = @ChildJoin(enabled = true),
|
||||
childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Order Lines"))
|
||||
}
|
||||
)
|
||||
public class Order extends QRecordEntity
|
||||
** </code>
|
||||
**
|
||||
** A Join will be made:
|
||||
** - left: Order
|
||||
** - right: LineItem
|
||||
** - type: ONE_TO_MANY (one order (parent table) has mny lines (child table))
|
||||
** - joinOn: order's primary key, lineItem's orderId field
|
||||
** - name: inferred, based on the table names orderJoinLineItem)
|
||||
*******************************************************************************/
|
||||
public class ChildJoinFromRecordEntityGenericMetaDataProducer implements MetaDataProducerInterface<QJoinMetaData>
|
||||
{
|
||||
private String childTableName; // e.g., lineItem
|
||||
private String parentTableName; // e.g., order
|
||||
private String foreignKeyFieldName; // e.g., orderId
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public ChildJoinFromRecordEntityGenericMetaDataProducer(String childTableName, String parentTableName, String foreignKeyFieldName)
|
||||
{
|
||||
Objects.requireNonNull(childTableName, "childTableName cannot be null");
|
||||
Objects.requireNonNull(parentTableName, "parentTableName cannot be null");
|
||||
Objects.requireNonNull(foreignKeyFieldName, "foreignKeyFieldName cannot be null");
|
||||
|
||||
this.childTableName = childTableName;
|
||||
this.parentTableName = parentTableName;
|
||||
this.foreignKeyFieldName = foreignKeyFieldName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QJoinMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
QTableMetaData possibleValueTable = qInstance.getTable(parentTableName);
|
||||
if(possibleValueTable == null)
|
||||
{
|
||||
throw (new QException("Could not find tableMetaData " + parentTableName));
|
||||
}
|
||||
|
||||
QJoinMetaData join = new QJoinMetaData()
|
||||
.withLeftTable(parentTableName)
|
||||
.withRightTable(childTableName)
|
||||
.withInferredName()
|
||||
.withType(JoinType.ONE_TO_MANY)
|
||||
.withJoinOn(new JoinOn(possibleValueTable.getPrimaryKeyField(), foreignKeyFieldName));
|
||||
|
||||
return (join);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.ChildRecordListRenderer;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildRecordListWidget;
|
||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Generic meta-data-producer, which should be instantiated (e.g., by
|
||||
** MetaDataProducer Helper), to produce a ChildRecordList QWidgetMetaData, to
|
||||
** produce a QJoinMetaData, based on a QRecordEntity and a ChildTable sub-annotation.
|
||||
**
|
||||
** e.g., Orders & LineItems - on the Order entity
|
||||
** <code>
|
||||
@QMetaDataProducingEntity( childTables = { @ChildTable(
|
||||
childTableEntityClass = LineItem.class,
|
||||
childJoin = @ChildJoin(enabled = true),
|
||||
childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Order Lines"))
|
||||
})
|
||||
public class Order extends QRecordEntity
|
||||
** </code>
|
||||
**
|
||||
*******************************************************************************/
|
||||
public class ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer implements MetaDataProducerInterface<QWidgetMetaData>
|
||||
{
|
||||
private String childTableName; // e.g., lineItem
|
||||
private String parentTableName; // e.g., order
|
||||
|
||||
private ChildRecordListWidget childRecordListWidget;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer(String childTableName, String parentTableName, ChildRecordListWidget childRecordListWidget)
|
||||
{
|
||||
this.childTableName = childTableName;
|
||||
this.parentTableName = parentTableName;
|
||||
this.childRecordListWidget = childRecordListWidget;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QWidgetMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
String name = QJoinMetaData.makeInferredJoinName(parentTableName, childTableName);
|
||||
QJoinMetaData join = qInstance.getJoin(name);
|
||||
|
||||
QWidgetMetaData widget = ChildRecordListRenderer.widgetMetaDataBuilder(join)
|
||||
.withName(name)
|
||||
.withLabel(childRecordListWidget.label())
|
||||
.withCanAddChildRecord(childRecordListWidget.canAddChildRecords())
|
||||
.getWidgetMetaData();
|
||||
|
||||
if(StringUtils.hasContent(childRecordListWidget.manageAssociationName()))
|
||||
{
|
||||
widget.withDefaultValue("manageAssociationName", childRecordListWidget.manageAssociationName());
|
||||
}
|
||||
|
||||
if(childRecordListWidget.maxRows() > 0)
|
||||
{
|
||||
widget.withDefaultValue("maxRows", childRecordListWidget.maxRows());
|
||||
}
|
||||
|
||||
return (widget);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Generic meta-data-producer, which should be instantiated (e.g., by
|
||||
** MetaDataProducer Helper), to produce a QPossibleValueSource meta-data
|
||||
** based on a PossibleValueEnum
|
||||
**
|
||||
***************************************************************************/
|
||||
public class PossibleValueSourceOfEnumGenericMetaDataProducer<T extends PossibleValueEnum<T>> implements MetaDataProducerInterface<QPossibleValueSource>
|
||||
{
|
||||
private final String name;
|
||||
private final PossibleValueEnum<T>[] values;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public PossibleValueSourceOfEnumGenericMetaDataProducer(String name, PossibleValueEnum<T>[] values)
|
||||
{
|
||||
this.name = name;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QPossibleValueSource produce(QInstance qInstance)
|
||||
{
|
||||
return (QPossibleValueSource.newForEnum(name, values));
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Generic meta-data-producer, which should be instantiated (e.g., by
|
||||
** MetaDataProducer Helper), to produce a QPossibleValueSource meta-data
|
||||
** based on a QRecordEntity class (which has corresponding QTableMetaData).
|
||||
**
|
||||
***************************************************************************/
|
||||
public class PossibleValueSourceOfTableGenericMetaDataProducer implements MetaDataProducerInterface<QPossibleValueSource>
|
||||
{
|
||||
private final String tableName;
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor
|
||||
**
|
||||
*******************************************************************************/
|
||||
public PossibleValueSourceOfTableGenericMetaDataProducer(String tableName)
|
||||
{
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QPossibleValueSource produce(QInstance qInstance)
|
||||
{
|
||||
return (QPossibleValueSource.newForTable(tableName));
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers.annotations;
|
||||
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** value that goes inside a QMetadataProducingEntity annotation, to control
|
||||
** the generation of a QJoinMetaData
|
||||
***************************************************************************/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
||||
public @interface ChildJoin
|
||||
{
|
||||
boolean enabled();
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers.annotations;
|
||||
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** value that goes inside a QMetadataProducingEntity annotation, to control
|
||||
** the generation of a QWidgetMetaData - for a ChildRecordList widget.
|
||||
***************************************************************************/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
||||
public @interface ChildRecordListWidget
|
||||
{
|
||||
boolean enabled();
|
||||
|
||||
String label() default "";
|
||||
|
||||
int maxRows() default 20;
|
||||
|
||||
boolean canAddChildRecords() default false;
|
||||
|
||||
String manageAssociationName() default "";
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers.annotations;
|
||||
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** value that goes inside a QMetadataProducingEntity annotation, to define
|
||||
** child-tables, e.g., for producing joins and childRecordList widgets
|
||||
***************************************************************************/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
||||
public @interface ChildTable
|
||||
{
|
||||
Class<? extends QRecordEntity> childTableEntityClass();
|
||||
|
||||
String joinFieldName() default "";
|
||||
|
||||
ChildJoin childJoin() default @ChildJoin(enabled = false);
|
||||
|
||||
ChildRecordListWidget childRecordListWidget() default @ChildRecordListWidget(enabled = false);
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers.annotations;
|
||||
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** annotation to go on a QRecordEntity class, which you would like to be
|
||||
** processed by MetaDataProducerHelper, to automatically produce some meta-data
|
||||
** objects. Specifically supports:
|
||||
**
|
||||
** - Making a possible-value-source out of the table.
|
||||
** - Processing child tables to create joins and childRecordList widgets
|
||||
*******************************************************************************/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
||||
public @interface QMetaDataProducingEntity
|
||||
{
|
||||
boolean producePossibleValueSource() default true;
|
||||
|
||||
ChildTable[] childTables() default { };
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers.annotations;
|
||||
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** annotation to go on a PossibleValueEnum class, which you would like to be
|
||||
** processed by MetaDataProducerHelper, to automatically produce possible-value-
|
||||
** source meta-data based on the enum.
|
||||
*******************************************************************************/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@SuppressWarnings("checkstyle:MissingJavadocMethod")
|
||||
public @interface QMetaDataProducingPossibleValueEnum
|
||||
{
|
||||
boolean producePossibleValueSource() default true;
|
||||
}
|
@ -1329,6 +1329,21 @@ public class QTableMetaData implements QAppChildMetaData, Serializable, MetaData
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for an association by name
|
||||
*******************************************************************************/
|
||||
public Optional<Association> getAssociationByName(String name)
|
||||
{
|
||||
if(associations == null)
|
||||
{
|
||||
return (Optional.empty());
|
||||
}
|
||||
|
||||
return (getAssociations().stream().filter(a -> a.getName().equals(name)).findFirst());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for associations
|
||||
*******************************************************************************/
|
||||
|
@ -700,4 +700,16 @@ public class CollectionUtils
|
||||
return (map.containsKey(key) && map.get(key) != null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** add an element to a collection, but, only if the element isn't null
|
||||
***************************************************************************/
|
||||
public static <T, E extends T> void addIfNotNull(Collection<T> c, E element)
|
||||
{
|
||||
if(element != null)
|
||||
{
|
||||
c.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,4 +460,19 @@ public class StringUtils
|
||||
return (Pattern.matches("[a-f0-9]{8}(?:-[a-f0-9]{4}){4}[a-f0-9]{8}", s));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
public static String emptyToNull(String s)
|
||||
{
|
||||
if(!hasContent(s))
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2054,16 +2054,41 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
|
||||
assertValidationFailureReasons((qInstance -> qInstance.getTable(TestUtils.TABLE_NAME_ORDER).withAssociation(new Association().withName("myAssociation"))),
|
||||
"missing joinName for Association myAssociation on table " + TestUtils.TABLE_NAME_ORDER,
|
||||
"missing associatedTableName for Association myAssociation on table " + TestUtils.TABLE_NAME_ORDER
|
||||
);
|
||||
"missing associatedTableName for Association myAssociation on table " + TestUtils.TABLE_NAME_ORDER);
|
||||
|
||||
assertValidationFailureReasons((qInstance -> qInstance.getTable(TestUtils.TABLE_NAME_ORDER).withAssociation(new Association().withName("myAssociation").withJoinName("notAJoin").withAssociatedTableName(TestUtils.TABLE_NAME_LINE_ITEM))),
|
||||
"unrecognized joinName notAJoin for Association myAssociation on table " + TestUtils.TABLE_NAME_ORDER
|
||||
);
|
||||
"unrecognized joinName notAJoin for Association myAssociation on table " + TestUtils.TABLE_NAME_ORDER);
|
||||
|
||||
assertValidationFailureReasons((qInstance -> qInstance.getTable(TestUtils.TABLE_NAME_ORDER).withAssociation(new Association().withName("myAssociation").withJoinName("orderLineItem").withAssociatedTableName("notATable"))),
|
||||
"unrecognized associatedTableName notATable for Association myAssociation on table " + TestUtils.TABLE_NAME_ORDER
|
||||
);
|
||||
"unrecognized associatedTableName notATable for Association myAssociation on table " + TestUtils.TABLE_NAME_ORDER);
|
||||
|
||||
//////////////////////////////////
|
||||
// wrong join on an association //
|
||||
//////////////////////////////////
|
||||
assertValidationFailureReasons((qInstance ->
|
||||
{
|
||||
Association association = qInstance.getTable(TestUtils.TABLE_NAME_ORDER).getAssociationByName("orderLine").orElseThrow();
|
||||
association.setJoinName("orderOrderExtrinsic");
|
||||
}),
|
||||
"join [orderOrderExtrinsic] does not connect tables [order] and [orderLine]");
|
||||
|
||||
//////////////////////////////////////////
|
||||
// wrong table (doesn't match the join) //
|
||||
//////////////////////////////////////////
|
||||
assertValidationFailureReasons((qInstance ->
|
||||
{
|
||||
Association association = qInstance.getTable(TestUtils.TABLE_NAME_ORDER).getAssociationByName("orderLine").orElseThrow();
|
||||
association.setAssociatedTableName(TestUtils.TABLE_NAME_ORDER_EXTRINSIC);
|
||||
}),
|
||||
"join [orderLineItem] does not connect tables [order] and [orderExtrinsic]");
|
||||
|
||||
//////////////////////////////
|
||||
// invalid type on the join //
|
||||
//////////////////////////////
|
||||
assertValidationFailureReasons((qInstance -> qInstance.getJoin("orderLineItem").setType(JoinType.MANY_TO_MANY)),
|
||||
"Join type does not have 'one' on this table's side side (left)");
|
||||
assertValidationFailureReasons((qInstance -> qInstance.getJoin("orderLineItem").setType(JoinType.MANY_TO_ONE)),
|
||||
"Join type does not have 'one' on this table's side side (left)");
|
||||
}
|
||||
|
||||
|
||||
@ -2323,7 +2348,7 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
{
|
||||
int noOfReasons = actualReasons == null ? 0 : actualReasons.size();
|
||||
assertEquals(expectedReasons.length, noOfReasons, "Expected number of validation failure reasons.\nExpected reasons: " + String.join(",", expectedReasons)
|
||||
+ "\nActual reasons: " + (noOfReasons > 0 ? String.join("\n", actualReasons) : "--"));
|
||||
+ "\nActual reasons: " + (noOfReasons > 0 ? String.join("\n", actualReasons) : "--"));
|
||||
}
|
||||
|
||||
for(String reason : expectedReasons)
|
||||
@ -2451,6 +2476,7 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
public static class ValidAuthCustomizer implements QAuthenticationModuleCustomizerInterface {}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@ -2468,6 +2494,7 @@ public class QInstanceValidatorTest extends BaseTest
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
|
@ -23,14 +23,26 @@ package com.kingsrook.qqq.backend.core.model.metadata;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaDataInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.JoinType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.joins.QJoinMetaData;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValue;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSource;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.QPossibleValueSourceType;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestAbstractMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestDisabledMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestImplementsMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProducer;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProducingChildEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProducingEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProducingPossibleValueEnum;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestNoInterfacesExtendsObject;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestNoValidConstructorMetaDataProducer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
@ -54,6 +66,48 @@ class MetaDataProducerHelperTest
|
||||
assertFalse(qInstance.getTables().containsKey(TestNoInterfacesExtendsObject.NAME));
|
||||
assertFalse(qInstance.getTables().containsKey(TestAbstractMetaDataProducer.NAME));
|
||||
assertFalse(qInstance.getTables().containsKey(TestDisabledMetaDataProducer.NAME));
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// annotation on PVS enum -> PVS meta data //
|
||||
/////////////////////////////////////////////
|
||||
assertTrue(qInstance.getPossibleValueSources().containsKey(TestMetaDataProducingPossibleValueEnum.class.getSimpleName()));
|
||||
QPossibleValueSource enumPVS = qInstance.getPossibleValueSource(TestMetaDataProducingPossibleValueEnum.class.getSimpleName());
|
||||
assertEquals(QPossibleValueSourceType.ENUM, enumPVS.getType());
|
||||
assertEquals(2, enumPVS.getEnumValues().size());
|
||||
assertEquals(new QPossibleValue<>(1, "One"), enumPVS.getEnumValues().get(0));
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// annotation on PVS table -> PVS meta data //
|
||||
//////////////////////////////////////////////
|
||||
assertTrue(qInstance.getPossibleValueSources().containsKey(TestMetaDataProducingEntity.TABLE_NAME));
|
||||
QPossibleValueSource tablePVS = qInstance.getPossibleValueSource(TestMetaDataProducingEntity.TABLE_NAME);
|
||||
assertEquals(QPossibleValueSourceType.TABLE, tablePVS.getType());
|
||||
assertEquals(TestMetaDataProducingEntity.TABLE_NAME, tablePVS.getTableName());
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// annotation on parent table w/ joined child -> join meta data //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
String joinName = QJoinMetaData.makeInferredJoinName(TestMetaDataProducingEntity.TABLE_NAME, TestMetaDataProducingChildEntity.TABLE_NAME);
|
||||
assertTrue(qInstance.getJoins().containsKey(joinName));
|
||||
QJoinMetaData join = qInstance.getJoin(joinName);
|
||||
assertEquals(TestMetaDataProducingEntity.TABLE_NAME, join.getLeftTable());
|
||||
assertEquals(TestMetaDataProducingChildEntity.TABLE_NAME, join.getRightTable());
|
||||
assertEquals(JoinType.ONE_TO_MANY, join.getType());
|
||||
assertEquals("id", join.getJoinOns().get(0).getLeftField());
|
||||
assertEquals("parentId", join.getJoinOns().get(0).getRightField());
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// annotation on parent table w/ joined child -> child record list widget meta data //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
assertTrue(qInstance.getWidgets().containsKey(joinName));
|
||||
QWidgetMetaDataInterface widget = qInstance.getWidget(joinName);
|
||||
assertEquals(WidgetType.CHILD_RECORD_LIST.getType(), widget.getType());
|
||||
assertEquals("Test Children", widget.getLabel());
|
||||
assertEquals(joinName, widget.getDefaultValues().get("joinName"));
|
||||
assertEquals(false, widget.getDefaultValues().get("canAddChildRecord"));
|
||||
assertNull(widget.getDefaultValues().get("manageAssociationName"));
|
||||
assertEquals(15, widget.getDefaultValues().get("maxRows"));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.possiblevalues;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QRuntimeException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Unit test for QPossibleValueSource
|
||||
*******************************************************************************/
|
||||
class QPossibleValueSourceTest extends BaseTest
|
||||
{
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testWithValuesFromEnum()
|
||||
{
|
||||
assertThatThrownBy(() -> new QPossibleValueSource().withValuesFromEnum(DupeIds.values()))
|
||||
.isInstanceOf(QRuntimeException.class)
|
||||
.hasMessageContaining("Duplicated id(s)")
|
||||
.hasMessageMatching(".*: \\[1]$");
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
private enum DupeIds implements PossibleValueEnum<Integer>
|
||||
{
|
||||
ONE_A(1, "A"),
|
||||
TWO_B(2, "B"),
|
||||
ONE_C(1, "C");
|
||||
|
||||
|
||||
private final int id;
|
||||
private final String label;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
DupeIds(int id, String label)
|
||||
{
|
||||
this.id = id;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Integer getPossibleValueId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String getPossibleValueLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** QRecord Entity for TestMetaDataProducingEntity table
|
||||
*******************************************************************************/
|
||||
public class TestMetaDataProducingChildEntity extends QRecordEntity implements MetaDataProducerInterface<QTableMetaData>
|
||||
{
|
||||
public static final String TABLE_NAME = "testMetaDataProducingChildEntity";
|
||||
|
||||
@QField(isEditable = false, isPrimaryKey = true)
|
||||
private Integer id;
|
||||
|
||||
@QField(possibleValueSourceName = TestMetaDataProducingEntity.TABLE_NAME)
|
||||
private Integer parentId;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QTableMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME)
|
||||
.withFieldsFromEntity(TestMetaDataProducingChildEntity.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Default constructor
|
||||
*******************************************************************************/
|
||||
public TestMetaDataProducingChildEntity()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor that takes a QRecord
|
||||
*******************************************************************************/
|
||||
public TestMetaDataProducingChildEntity(QRecord record)
|
||||
{
|
||||
populateFromQRecord(record);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for id
|
||||
*******************************************************************************/
|
||||
public Integer getId()
|
||||
{
|
||||
return (this.id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for id
|
||||
*******************************************************************************/
|
||||
public void setId(Integer id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for id
|
||||
*******************************************************************************/
|
||||
public TestMetaDataProducingChildEntity withId(Integer id)
|
||||
{
|
||||
this.id = id;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for parentId
|
||||
*******************************************************************************/
|
||||
public Integer getParentId()
|
||||
{
|
||||
return (this.parentId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for parentId
|
||||
*******************************************************************************/
|
||||
public void setParentId(Integer parentId)
|
||||
{
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for parentId
|
||||
*******************************************************************************/
|
||||
public TestMetaDataProducingChildEntity withParentId(Integer parentId)
|
||||
{
|
||||
this.parentId = parentId;
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QField;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildJoin;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildRecordListWidget;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildTable;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** QRecord Entity for TestMetaDataProducingEntity table
|
||||
*******************************************************************************/
|
||||
@QMetaDataProducingEntity(producePossibleValueSource = true,
|
||||
childTables =
|
||||
{
|
||||
@ChildTable(childTableEntityClass = TestMetaDataProducingChildEntity.class,
|
||||
childJoin = @ChildJoin(enabled = true),
|
||||
childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Test Children", maxRows = 15))
|
||||
}
|
||||
)
|
||||
public class TestMetaDataProducingEntity extends QRecordEntity implements MetaDataProducerInterface<QTableMetaData>
|
||||
{
|
||||
public static final String TABLE_NAME = "testMetaDataProducingEntity";
|
||||
|
||||
@QField(isEditable = false, isPrimaryKey = true)
|
||||
private Integer id;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public QTableMetaData produce(QInstance qInstance) throws QException
|
||||
{
|
||||
return new QTableMetaData()
|
||||
.withName(TABLE_NAME)
|
||||
.withFieldsFromEntity(TestMetaDataProducingEntity.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Default constructor
|
||||
*******************************************************************************/
|
||||
public TestMetaDataProducingEntity()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Constructor that takes a QRecord
|
||||
*******************************************************************************/
|
||||
public TestMetaDataProducingEntity(QRecord record)
|
||||
{
|
||||
populateFromQRecord(record);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for id
|
||||
*******************************************************************************/
|
||||
public Integer getId()
|
||||
{
|
||||
return (this.id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for id
|
||||
*******************************************************************************/
|
||||
public void setId(Integer id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for id
|
||||
*******************************************************************************/
|
||||
public TestMetaDataProducingEntity withId(Integer id)
|
||||
{
|
||||
this.id = id;
|
||||
return (this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* QQQ - Low-code Application Framework for Engineers.
|
||||
* Copyright (C) 2021-2024. 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.producers;
|
||||
|
||||
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.possiblevalues.PossibleValueEnum;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingPossibleValueEnum;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@QMetaDataProducingPossibleValueEnum(producePossibleValueSource = true)
|
||||
public enum TestMetaDataProducingPossibleValueEnum implements PossibleValueEnum<Integer>
|
||||
{
|
||||
ONE(1, "One"),
|
||||
TWO(2, "Two");
|
||||
|
||||
|
||||
private final int id;
|
||||
private final String label;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
TestMetaDataProducingPossibleValueEnum(int id, String label)
|
||||
{
|
||||
this.id = id;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public String getPossibleValueLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@Override
|
||||
public Integer getPossibleValueId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
@ -26,10 +26,12 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@ -618,4 +620,23 @@ class CollectionUtilsTest extends BaseTest
|
||||
4, Map.of("B", "B4")), output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testAddIfNotNull()
|
||||
{
|
||||
HashSet<String> s = new HashSet<>();
|
||||
CollectionUtils.addIfNotNull(s, null);
|
||||
assertEquals(Set.of(), s);
|
||||
|
||||
CollectionUtils.addIfNotNull(s, "");
|
||||
assertEquals(Set.of(""), s);
|
||||
|
||||
CollectionUtils.addIfNotNull(s, "1");
|
||||
assertEquals(Set.of("", "1"), s);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -318,4 +318,19 @@ class StringUtilsTest extends BaseTest
|
||||
assertEquals("Apples were eaten", StringUtils.pluralFormat(2, "Apple{,s} {was,were} eaten"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testEmptyToNull()
|
||||
{
|
||||
assertNull(StringUtils.emptyToNull(null));
|
||||
assertNull(StringUtils.emptyToNull(""));
|
||||
assertNull(StringUtils.emptyToNull(" "));
|
||||
assertNull(StringUtils.emptyToNull(" "));
|
||||
assertEquals("a", StringUtils.emptyToNull("a"));
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user