Update QMetaDataProducingEntity to know how to produce table meta data; Add MetaDataCustomizers to work with producer helpers

This commit is contained in:
2025-01-31 14:29:51 -06:00
parent 38a17b2954
commit 2031e05117
8 changed files with 419 additions and 23 deletions

View File

@ -41,12 +41,15 @@ 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.possiblevalues.PossibleValueEnum;
import com.kingsrook.qqq.backend.core.model.metadata.producers.ChildJoinFromRecordEntityGenericMetaDataProducer; 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.ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer;
import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface;
import com.kingsrook.qqq.backend.core.model.metadata.producers.PossibleValueSourceOfEnumGenericMetaDataProducer; 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.PossibleValueSourceOfTableGenericMetaDataProducer;
import com.kingsrook.qqq.backend.core.model.metadata.producers.RecordEntityToTableGenericMetaDataProducer;
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildRecordListWidget; 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.ChildTable;
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity; 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.model.metadata.producers.annotations.QMetaDataProducingPossibleValueEnum;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.ClassPathUtils; import com.kingsrook.qqq.backend.core.utils.ClassPathUtils;
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;
@ -83,6 +86,27 @@ public class MetaDataProducerHelper
comparatorValuesByType.put(QAppMetaData.class, 23); comparatorValuesByType.put(QAppMetaData.class, 23);
} }
private static MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer = null;
/*******************************************************************************
** Recursively find all classes in the given package, that implement MetaDataProducerInterface
** run them, and add their output to the given qInstance - using the provided
** tableMetaDataCustomizer to help with all RecordEntity's that
** are configured to make tables.
**
** Note - they'll be sorted by the sortOrder they provide.
*******************************************************************************/
public static void processAllMetaDataProducersInPackage(QInstance instance, String packageName, MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer) throws QException
{
MetaDataProducerHelper.tableMetaDataCustomizer = tableMetaDataCustomizer;
processAllMetaDataProducersInPackage(instance, packageName);
MetaDataProducerHelper.tableMetaDataCustomizer = null;
}
/******************************************************************************* /*******************************************************************************
** Recursively find all classes in the given package, that implement MetaDataProducerInterface ** Recursively find all classes in the given package, that implement MetaDataProducerInterface
** run them, and add their output to the given qInstance. ** run them, and add their output to the given qInstance.
@ -117,20 +141,27 @@ public class MetaDataProducerHelper
continue; continue;
} }
/////////////////////////////////////////////////////////////////////
// handle classes which are themselves MetaDataProducerInterface's //
/////////////////////////////////////////////////////////////////////
if(MetaDataProducerInterface.class.isAssignableFrom(aClass)) if(MetaDataProducerInterface.class.isAssignableFrom(aClass))
{ {
CollectionUtils.addIfNotNull(producers, processMetaDataProducer(aClass)); CollectionUtils.addIfNotNull(producers, processMetaDataProducer(aClass));
} }
/////////////////////////////////////////////////////////////////////////
// handle classes that have the @QMetaDataProducingEntity annotation - //
// record entities that should produce meta-data //
/////////////////////////////////////////////////////////////////////////
if(aClass.isAnnotationPresent(QMetaDataProducingEntity.class)) if(aClass.isAnnotationPresent(QMetaDataProducingEntity.class))
{ {
QMetaDataProducingEntity qMetaDataProducingEntity = aClass.getAnnotation(QMetaDataProducingEntity.class); producers.addAll(processMetaDataProducingEntity(aClass));
if(qMetaDataProducingEntity.producePossibleValueSource())
{
producers.addAll(processMetaDataProducingEntity(aClass));
}
} }
//////////////////////////////////////////////////////////////////
// handle classes with the @QMetaDataProducingPossibleValueEnum //
// enums that are PVS's //
//////////////////////////////////////////////////////////////////
if(aClass.isAnnotationPresent(QMetaDataProducingPossibleValueEnum.class)) if(aClass.isAnnotationPresent(QMetaDataProducingPossibleValueEnum.class))
{ {
QMetaDataProducingPossibleValueEnum qMetaDataProducingPossibleValueEnum = aClass.getAnnotation(QMetaDataProducingPossibleValueEnum.class); QMetaDataProducingPossibleValueEnum qMetaDataProducingPossibleValueEnum = aClass.getAnnotation(QMetaDataProducingPossibleValueEnum.class);
@ -220,13 +251,24 @@ public class MetaDataProducerHelper
{ {
List<MetaDataProducerInterface<?>> rs = new ArrayList<>(); List<MetaDataProducerInterface<?>> rs = new ArrayList<>();
String warningPrefix = "Found a class annotated as @" + QMetaDataProducingEntity.class.getSimpleName(); QMetaDataProducingEntity qMetaDataProducingEntity = aClass.getAnnotation(QMetaDataProducingEntity.class);
String warningPrefix = "Found a class annotated as @" + QMetaDataProducingEntity.class.getSimpleName();
///////////////////////////////////////////////////////////
// make sures class is QRecordEntity and cast it as such //
///////////////////////////////////////////////////////////
if(!QRecordEntity.class.isAssignableFrom(aClass)) 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())); LOG.warn(warningPrefix + ", but which is not a " + QRecordEntity.class.getSimpleName() + ", so it will not be used.", logPair("class", aClass.getSimpleName()));
return (rs); return (rs);
} }
@SuppressWarnings("unchecked") // safe per the check above.
Class<? extends QRecordEntity> recordEntityClass = (Class<? extends QRecordEntity>) aClass;
////////////////////////////////////////////////
// get TABLE_NAME static field from the class //
////////////////////////////////////////////////
Field tableNameField = aClass.getDeclaredField("TABLE_NAME"); Field tableNameField = aClass.getDeclaredField("TABLE_NAME");
if(!tableNameField.getType().equals(String.class)) if(!tableNameField.getType().equals(String.class))
{ {
@ -235,12 +277,50 @@ public class MetaDataProducerHelper
} }
String tableNameValue = (String) tableNameField.get(null); String tableNameValue = (String) tableNameField.get(null);
rs.add(new PossibleValueSourceOfTableGenericMetaDataProducer(tableNameValue));
//////////////////////////////////////////
// add table producer, if so configured //
//////////////////////////////////////////
if(qMetaDataProducingEntity.produceTableMetaData())
{
try
{
////////////////////////////////////////////////////////
// todo - better to check the runtime type parameter? //
////////////////////////////////////////////////////////
Class<? extends MetaDataCustomizerInterface<?>> genericMetaProductionCustomizer = (Class<? extends MetaDataCustomizerInterface<?>>) qMetaDataProducingEntity.tableMetaDataCustomizer();
Class<? extends MetaDataCustomizerInterface<QTableMetaData>> tableMetaDataProductionCustomizer = null;
if(!genericMetaProductionCustomizer.equals(MetaDataCustomizerInterface.NoopMetaDataCustomizer.class))
{
tableMetaDataProductionCustomizer = (Class<? extends MetaDataCustomizerInterface<QTableMetaData>>) genericMetaProductionCustomizer;
}
RecordEntityToTableGenericMetaDataProducer producer = new RecordEntityToTableGenericMetaDataProducer(tableNameValue, recordEntityClass, tableMetaDataProductionCustomizer);
if(tableMetaDataCustomizer != null)
{
producer.addRecordEntityTableMetaDataProductionCustomizer(tableMetaDataCustomizer);
}
rs.add(producer);
}
catch(Exception e)
{
throw new QException("Error processing table meta data producer for entity class: " + recordEntityClass.getName(), e);
}
}
////////////////////////////////////////
// add PVS producer, if so configured //
////////////////////////////////////////
if(qMetaDataProducingEntity.producePossibleValueSource())
{
rs.add(new PossibleValueSourceOfTableGenericMetaDataProducer(tableNameValue));
}
////////////////////////// //////////////////////////
// process child tables // // process child tables //
////////////////////////// //////////////////////////
QMetaDataProducingEntity qMetaDataProducingEntity = aClass.getAnnotation(QMetaDataProducingEntity.class);
for(ChildTable childTable : qMetaDataProducingEntity.childTables()) for(ChildTable childTable : qMetaDataProducingEntity.childTables())
{ {
Class<? extends QRecordEntity> childEntityClass = childTable.childTableEntityClass(); Class<? extends QRecordEntity> childEntityClass = childTable.childTableEntityClass();
@ -362,4 +442,35 @@ public class MetaDataProducerHelper
String tableNameValue = (String) tableNameField.get(null); String tableNameValue = (String) tableNameField.get(null);
return (tableNameValue); return (tableNameValue);
} }
/*******************************************************************************
** Getter for tableMetaDataCustomizer
*******************************************************************************/
public MetaDataCustomizerInterface<QTableMetaData> getTableMetaDataCustomizer()
{
return (MetaDataProducerHelper.tableMetaDataCustomizer);
}
/*******************************************************************************
** Setter for tableMetaDataCustomizer
*******************************************************************************/
public void setTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
{
MetaDataProducerHelper.tableMetaDataCustomizer = tableMetaDataCustomizer;
}
/*******************************************************************************
** Fluent setter for tableMetaDataCustomizer
*******************************************************************************/
public void withTableMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> tableMetaDataCustomizer)
{
MetaDataProducerHelper.tableMetaDataCustomizer = tableMetaDataCustomizer;
}
} }

View File

@ -38,14 +38,14 @@ import com.kingsrook.qqq.backend.core.utils.StringUtils;
** produce a QJoinMetaData, based on a QRecordEntity and a ChildTable sub-annotation. ** produce a QJoinMetaData, based on a QRecordEntity and a ChildTable sub-annotation.
** **
** e.g., Orders & LineItems - on the Order entity ** e.g., Orders & LineItems - on the Order entity
** <code> <code>
@QMetaDataProducingEntity( childTables = { @ChildTable( @QMetaDataProducingEntity( childTables = { @ChildTable(
childTableEntityClass = LineItem.class, childTableEntityClass = LineItem.class,
childJoin = @ChildJoin(enabled = true), childJoin = @ChildJoin(enabled = true),
childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Order Lines")) childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Order Lines"))
}) })
public class Order extends QRecordEntity public class Order extends QRecordEntity
** </code> </code>
** **
*******************************************************************************/ *******************************************************************************/
public class ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer implements MetaDataProducerInterface<QWidgetMetaData> public class ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer implements MetaDataProducerInterface<QWidgetMetaData>
@ -53,6 +53,8 @@ public class ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer implem
private String childTableName; // e.g., lineItem private String childTableName; // e.g., lineItem
private String parentTableName; // e.g., order private String parentTableName; // e.g., order
private MetaDataCustomizerInterface<QWidgetMetaData> widgetMetaDataProductionCustomizer = null;
private ChildRecordListWidget childRecordListWidget; private ChildRecordListWidget childRecordListWidget;
@ -60,11 +62,18 @@ public class ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer implem
/*************************************************************************** /***************************************************************************
** **
***************************************************************************/ ***************************************************************************/
public ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer(String childTableName, String parentTableName, ChildRecordListWidget childRecordListWidget) public ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer(String childTableName, String parentTableName, ChildRecordListWidget childRecordListWidget) throws Exception
{ {
this.childTableName = childTableName; this.childTableName = childTableName;
this.parentTableName = parentTableName; this.parentTableName = parentTableName;
this.childRecordListWidget = childRecordListWidget; this.childRecordListWidget = childRecordListWidget;
Class<? extends MetaDataCustomizerInterface<?>> genericMetaProductionCustomizer = (Class<? extends MetaDataCustomizerInterface<?>>) childRecordListWidget.widgetMetaDataCustomizer();
if(!genericMetaProductionCustomizer.equals(MetaDataCustomizerInterface.NoopMetaDataCustomizer.class))
{
Class<? extends MetaDataCustomizerInterface<QWidgetMetaData>> widgetMetaProductionCustomizerClass = (Class<? extends MetaDataCustomizerInterface<QWidgetMetaData>>) genericMetaProductionCustomizer;
this.widgetMetaDataProductionCustomizer = widgetMetaProductionCustomizerClass.getConstructor().newInstance();
}
} }
@ -94,6 +103,11 @@ public class ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer implem
widget.withDefaultValue("maxRows", childRecordListWidget.maxRows()); widget.withDefaultValue("maxRows", childRecordListWidget.maxRows());
} }
if(this.widgetMetaDataProductionCustomizer != null)
{
widget = this.widgetMetaDataProductionCustomizer.customizeMetaData(qInstance, widget);
}
return (widget); return (widget);
} }

View File

@ -0,0 +1,56 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2025. 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.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.TopLevelMetaDataInterface;
/*******************************************************************************
**
*******************************************************************************/
public interface MetaDataCustomizerInterface<T extends TopLevelMetaDataInterface>
{
/***************************************************************************
**
***************************************************************************/
T customizeMetaData(QInstance qInstance, T metaData) throws QException;
/***************************************************************************
** noop version of this interface - used as default value in annotation
**
***************************************************************************/
class NoopMetaDataCustomizer<T extends TopLevelMetaDataInterface> implements MetaDataCustomizerInterface<T>
{
/***************************************************************************
**
***************************************************************************/
@Override
public T customizeMetaData(QInstance qInstance, T metaData) throws QException
{
return (metaData);
}
}
}

View File

@ -0,0 +1,157 @@
/*
* 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.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.exceptions.QException;
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;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
/***************************************************************************
** Generic meta-data-producer, which should be instantiated (e.g., by
** MetaDataProducerHelper), to produce a QPossibleValueSource meta-data
** based on a QRecordEntity class (which has corresponding QTableMetaData).
**
***************************************************************************/
public class RecordEntityToTableGenericMetaDataProducer implements MetaDataProducerInterface<QTableMetaData>
{
private final String tableName;
private final Class<? extends QRecordEntity> entityClass;
private final List<MetaDataCustomizerInterface<QTableMetaData>> metaDataCustomizers = new ArrayList<>();
private static MetaDataCustomizerInterface<QTableMetaData> defaultMetaDataCustomizer = null;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public RecordEntityToTableGenericMetaDataProducer(String tableName, Class<? extends QRecordEntity> entityClass, Class<? extends MetaDataCustomizerInterface<QTableMetaData>> metaDataProductionCustomizerClass) throws QException
{
this.tableName = tableName;
this.entityClass = entityClass;
if(metaDataProductionCustomizerClass != null)
{
metaDataCustomizers.add(getMetaDataProductionCustomizer(metaDataProductionCustomizerClass));
}
}
/***************************************************************************
**
***************************************************************************/
@Override
public QTableMetaData produce(QInstance qInstance) throws QException
{
QTableMetaData qTableMetaData = new QTableMetaData();
qTableMetaData.setName(tableName);
qTableMetaData.setRecordLabelFormat("%s");
qTableMetaData.withFieldsFromEntity(entityClass);
////////////////////////////////////////////////////////////////////
// use the productionCustomizers to fill in more of the meta data //
////////////////////////////////////////////////////////////////////
for(MetaDataCustomizerInterface<QTableMetaData> metaDataMetaDataCustomizer : metaDataCustomizers)
{
qTableMetaData = metaDataMetaDataCustomizer.customizeMetaData(qInstance, qTableMetaData);
}
///////////////////////////////////////////////////////////////////////////////////
// now if there's a default customizer, call it too - for generic, common things //
// you might want on all of your tables, or defaults if not set otherwise //
///////////////////////////////////////////////////////////////////////////////////
if(defaultMetaDataCustomizer != null)
{
qTableMetaData = defaultMetaDataCustomizer.customizeMetaData(qInstance, qTableMetaData);
}
/////////////////////////////////////////////////////////////////////////
// use primary key as record label field, if it hasn't been set so far //
// todo - does this belong in the enricher?? //
/////////////////////////////////////////////////////////////////////////
if(CollectionUtils.nullSafeIsEmpty(qTableMetaData.getRecordLabelFields()) && StringUtils.hasContent(qTableMetaData.getPrimaryKeyField()))
{
qTableMetaData.setRecordLabelFields(List.of(qTableMetaData.getPrimaryKeyField()));
}
return qTableMetaData;
}
/***************************************************************************
**
***************************************************************************/
private MetaDataCustomizerInterface<QTableMetaData> getMetaDataProductionCustomizer(Class<? extends MetaDataCustomizerInterface<QTableMetaData>> metaDataCustomizerClass) throws QException
{
try
{
return metaDataCustomizerClass.getConstructor().newInstance();
}
catch(Exception e)
{
throw (new QException("Error constructing table metadata production customizer class [" + metaDataCustomizerClass + "]: ", e));
}
}
/***************************************************************************
**
***************************************************************************/
public void addRecordEntityTableMetaDataProductionCustomizer(MetaDataCustomizerInterface<QTableMetaData> metaDataMetaDataCustomizer)
{
metaDataCustomizers.add(metaDataMetaDataCustomizer);
}
/*******************************************************************************
** Getter for defaultMetaDataCustomizer
*******************************************************************************/
public static MetaDataCustomizerInterface<QTableMetaData> getDefaultMetaDataCustomizer()
{
return (RecordEntityToTableGenericMetaDataProducer.defaultMetaDataCustomizer);
}
/*******************************************************************************
** Setter for defaultMetaDataCustomizer
*******************************************************************************/
public static void setDefaultMetaDataCustomizer(MetaDataCustomizerInterface<QTableMetaData> defaultMetaDataCustomizer)
{
RecordEntityToTableGenericMetaDataProducer.defaultMetaDataCustomizer = defaultMetaDataCustomizer;
}
}

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.producers.annotations;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface;
/*************************************************************************** /***************************************************************************
@ -43,4 +44,6 @@ public @interface ChildRecordListWidget
boolean canAddChildRecords() default false; boolean canAddChildRecords() default false;
String manageAssociationName() default ""; String manageAssociationName() default "";
Class<? extends MetaDataCustomizerInterface> widgetMetaDataCustomizer() default MetaDataCustomizerInterface.NoopMetaDataCustomizer.class;
} }

View File

@ -26,6 +26,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import com.kingsrook.qqq.backend.core.model.metadata.producers.MetaDataCustomizerInterface;
/******************************************************************************* /*******************************************************************************
@ -41,8 +42,10 @@ import java.lang.annotation.Target;
@SuppressWarnings("checkstyle:MissingJavadocMethod") @SuppressWarnings("checkstyle:MissingJavadocMethod")
public @interface QMetaDataProducingEntity public @interface QMetaDataProducingEntity
{ {
boolean producePossibleValueSource() default true; boolean produceTableMetaData() default false;
Class<? extends MetaDataCustomizerInterface> tableMetaDataCustomizer() default MetaDataCustomizerInterface.NoopMetaDataCustomizer.class;
boolean producePossibleValueSource() default false;
ChildTable[] childTables() default { }; ChildTable[] childTables() default { };
} }

View File

@ -39,6 +39,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProdu
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProducingPossibleValueEnum; 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.TestNoInterfacesExtendsObject;
import com.kingsrook.qqq.backend.core.model.metadata.producers.TestNoValidConstructorMetaDataProducer; import com.kingsrook.qqq.backend.core.model.metadata.producers.TestNoValidConstructorMetaDataProducer;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
@ -76,6 +77,17 @@ class MetaDataProducerHelperTest
assertEquals(2, enumPVS.getEnumValues().size()); assertEquals(2, enumPVS.getEnumValues().size());
assertEquals(new QPossibleValue<>(1, "One"), enumPVS.getEnumValues().get(0)); assertEquals(new QPossibleValue<>(1, "One"), enumPVS.getEnumValues().get(0));
////////////////////////////////////////////
// annotation on table -> table meta data //
////////////////////////////////////////////
assertTrue(qInstance.getTables().containsKey(TestMetaDataProducingEntity.TABLE_NAME));
QTableMetaData table = qInstance.getTables().get(TestMetaDataProducingEntity.TABLE_NAME);
assertEquals(TestMetaDataProducingEntity.TABLE_NAME, table.getName());
assertEquals("id", table.getPrimaryKeyField());
assertEquals(2, table.getFields().size());
assertTrue(table.getField("name").getIsRequired());
assertEquals("Customized Label", table.getLabel());
////////////////////////////////////////////// //////////////////////////////////////////////
// annotation on PVS table -> PVS meta data // // annotation on PVS table -> PVS meta data //
////////////////////////////////////////////// //////////////////////////////////////////////

View File

@ -26,7 +26,6 @@ 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.QField;
import com.kingsrook.qqq.backend.core.model.data.QRecord; 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.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.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.ChildJoin; 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.ChildRecordListWidget;
@ -38,7 +37,10 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
/******************************************************************************* /*******************************************************************************
** QRecord Entity for TestMetaDataProducingEntity table ** QRecord Entity for TestMetaDataProducingEntity table
*******************************************************************************/ *******************************************************************************/
@QMetaDataProducingEntity(producePossibleValueSource = true, @QMetaDataProducingEntity(
produceTableMetaData = true,
tableMetaDataCustomizer = TestMetaDataProducingEntity.TableMetaDataCustomizer.class,
producePossibleValueSource = true,
childTables = childTables =
{ {
@ChildTable(childTableEntityClass = TestMetaDataProducingChildEntity.class, @ChildTable(childTableEntityClass = TestMetaDataProducingChildEntity.class,
@ -46,24 +48,31 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Test Children", maxRows = 15)) childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Test Children", maxRows = 15))
} }
) )
public class TestMetaDataProducingEntity extends QRecordEntity implements MetaDataProducerInterface<QTableMetaData> public class TestMetaDataProducingEntity extends QRecordEntity
{ {
public static final String TABLE_NAME = "testMetaDataProducingEntity"; public static final String TABLE_NAME = "testMetaDataProducingEntity";
@QField(isEditable = false, isPrimaryKey = true) @QField(isEditable = false, isPrimaryKey = true)
private Integer id; private Integer id;
@QField(isRequired = true)
private String name;
/*************************************************************************** /***************************************************************************
** **
***************************************************************************/ ***************************************************************************/
@Override public static class TableMetaDataCustomizer implements MetaDataCustomizerInterface<QTableMetaData>
public QTableMetaData produce(QInstance qInstance) throws QException
{ {
return new QTableMetaData() /***************************************************************************
.withName(TABLE_NAME) **
.withFieldsFromEntity(TestMetaDataProducingEntity.class); ***************************************************************************/
@Override
public QTableMetaData customizeMetaData(QInstance qInstance, QTableMetaData table) throws QException
{
table.withLabel("Customized Label");
return table;
}
} }
@ -116,4 +125,35 @@ public class TestMetaDataProducingEntity extends QRecordEntity implements MetaDa
return (this); return (this);
} }
/*******************************************************************************
** Getter for name
*******************************************************************************/
public String getName()
{
return (this.name);
}
/*******************************************************************************
** Setter for name
*******************************************************************************/
public void setName(String name)
{
this.name = name;
}
/*******************************************************************************
** Fluent setter for name
*******************************************************************************/
public TestMetaDataProducingEntity withName(String name)
{
this.name = name;
return (this);
}
} }