mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Update QMetaDataProducingEntity to know how to produce table meta data; Add MetaDataCustomizers to work with producer helpers
This commit is contained in:
@ -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);
|
|
||||||
if(qMetaDataProducingEntity.producePossibleValueSource())
|
|
||||||
{
|
{
|
||||||
producers.addAll(processMetaDataProducingEntity(aClass));
|
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<>();
|
||||||
|
|
||||||
|
QMetaDataProducingEntity qMetaDataProducingEntity = aClass.getAnnotation(QMetaDataProducingEntity.class);
|
||||||
String warningPrefix = "Found a class annotated as @" + QMetaDataProducingEntity.class.getSimpleName();
|
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);
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// 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));
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 { };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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 //
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user