From ec74649c96e41b8cac89e390c27afe2312c48556 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 13 Dec 2024 11:23:38 -0600 Subject: [PATCH] Introduce annotations that can be found by MetaDataProducerHelper, to make more meta-data, with less code. Specifically: - PVS from PossibleValueEnum - PVS from RecordEntity - Joins from a parent-entity to child-entities - ChildRecordList Widgets from a parent-entity to child-entities --- .../metadata/MetaDataProducerHelper.java | 217 ++++++++++++++++-- .../possiblevalues/QPossibleValue.java | 36 +++ ...omRecordEntityGenericMetaDataProducer.java | 105 +++++++++ ...omRecordEntityGenericMetaDataProducer.java | 100 ++++++++ ...ueSourceOfEnumGenericMetaDataProducer.java | 64 ++++++ ...eSourceOfTableGenericMetaDataProducer.java | 61 +++++ .../producers/annotations/ChildJoin.java | 38 +++ .../annotations/ChildRecordListWidget.java | 46 ++++ .../producers/annotations/ChildTable.java | 45 ++++ .../annotations/QMetaDataProducingEntity.java | 48 ++++ .../QMetaDataProducingPossibleValueEnum.java | 42 ++++ .../metadata/MetaDataProducerHelperTest.java | 54 +++++ .../TestMetaDataProducingChildEntity.java | 140 +++++++++++ .../TestMetaDataProducingEntity.java | 119 ++++++++++ ...estMetaDataProducingPossibleValueEnum.java | 74 ++++++ 15 files changed, 1175 insertions(+), 14 deletions(-) create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildJoinFromRecordEntityGenericMetaDataProducer.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfEnumGenericMetaDataProducer.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfTableGenericMetaDataProducer.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildJoin.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildRecordListWidget.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildTable.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingEntity.java create mode 100644 qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingPossibleValueEnum.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingChildEntity.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingEntity.java create mode 100644 qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingPossibleValueEnum.java diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java index ac68cfd2..4fd45277 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelper.java @@ -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> 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,175 @@ public class MetaDataProducerHelper LOG.debug("Not using producer which is not enabled", logPair("producer", producer.getClass().getSimpleName())); } } - } + + + /*************************************************************************** + ** + ***************************************************************************/ + private static 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<>(aClass.getSimpleName(), values)); + } + + + + /*************************************************************************** + ** + ***************************************************************************/ + private static List> processMetaDataProducingEntity(Class aClass) throws Exception + { + List> 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 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 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 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 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); + } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValue.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValue.java index a36fb981..40a9dde2 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValue.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/possiblevalues/QPossibleValue.java @@ -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 { 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); + } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildJoinFromRecordEntityGenericMetaDataProducer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildJoinFromRecordEntityGenericMetaDataProducer.java new file mode 100644 index 00000000..76c892cd --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildJoinFromRecordEntityGenericMetaDataProducer.java @@ -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 . + */ + +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 + ** + @QMetaDataProducingEntity( + childTables = { @ChildTable( + childTableEntityClass = LineItem.class, + childJoin = @ChildJoin(enabled = true), + childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Order Lines")) + } + ) + public class Order extends QRecordEntity + ** + ** + ** 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 +{ + 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); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer.java new file mode 100644 index 00000000..cb8d451f --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer.java @@ -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 . + */ + +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 + ** + @QMetaDataProducingEntity( childTables = { @ChildTable( + childTableEntityClass = LineItem.class, + childJoin = @ChildJoin(enabled = true), + childRecordListWidget = @ChildRecordListWidget(enabled = true, label = "Order Lines")) + }) + public class Order extends QRecordEntity + ** + ** + *******************************************************************************/ +public class ChildRecordListWidgetFromRecordEntityGenericMetaDataProducer implements MetaDataProducerInterface +{ + 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); + } + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfEnumGenericMetaDataProducer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfEnumGenericMetaDataProducer.java new file mode 100644 index 00000000..9d617b4f --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfEnumGenericMetaDataProducer.java @@ -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 . + */ + +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> implements MetaDataProducerInterface +{ + private final String name; + private final PossibleValueEnum[] values; + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public PossibleValueSourceOfEnumGenericMetaDataProducer(String name, PossibleValueEnum[] values) + { + this.name = name; + this.values = values; + } + + + + /*************************************************************************** + ** + ***************************************************************************/ + @Override + public QPossibleValueSource produce(QInstance qInstance) + { + return (QPossibleValueSource.newForEnum(name, values)); + } +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfTableGenericMetaDataProducer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfTableGenericMetaDataProducer.java new file mode 100644 index 00000000..c1656f35 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/PossibleValueSourceOfTableGenericMetaDataProducer.java @@ -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 . + */ + +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 +{ + private final String tableName; + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public PossibleValueSourceOfTableGenericMetaDataProducer(String tableName) + { + this.tableName = tableName; + } + + + + /*************************************************************************** + ** + ***************************************************************************/ + @Override + public QPossibleValueSource produce(QInstance qInstance) + { + return (QPossibleValueSource.newForTable(tableName)); + } +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildJoin.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildJoin.java new file mode 100644 index 00000000..2266679e --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildJoin.java @@ -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 . + */ + +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(); +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildRecordListWidget.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildRecordListWidget.java new file mode 100644 index 00000000..9a5299c5 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildRecordListWidget.java @@ -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 . + */ + +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 ""; +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildTable.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildTable.java new file mode 100644 index 00000000..79a965ea --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/ChildTable.java @@ -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 . + */ + +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 childTableEntityClass(); + + String joinFieldName() default ""; + + ChildJoin childJoin() default @ChildJoin(enabled = false); + + ChildRecordListWidget childRecordListWidget() default @ChildRecordListWidget(enabled = false); +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingEntity.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingEntity.java new file mode 100644 index 00000000..4e755163 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingEntity.java @@ -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 . + */ + +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 { }; + +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingPossibleValueEnum.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingPossibleValueEnum.java new file mode 100644 index 00000000..7d7edc95 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/producers/annotations/QMetaDataProducingPossibleValueEnum.java @@ -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 . + */ + +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; +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java index 84f70562..61ba8d2b 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/MetaDataProducerHelperTest.java @@ -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")); + } } \ No newline at end of file diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingChildEntity.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingChildEntity.java new file mode 100644 index 00000000..7b1ce205 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingChildEntity.java @@ -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 . + */ + +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 +{ + 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); + } + + +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingEntity.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingEntity.java new file mode 100644 index 00000000..519d7946 --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingEntity.java @@ -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 . + */ + +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 +{ + 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); + } + +} diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingPossibleValueEnum.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingPossibleValueEnum.java new file mode 100644 index 00000000..05b32a9b --- /dev/null +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/model/metadata/producers/TestMetaDataProducingPossibleValueEnum.java @@ -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 . + */ + +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 +{ + 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; + } +}