diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/processes/RunBackendStepOutput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/processes/RunBackendStepOutput.java index 5cd13afb..fac4b6c4 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/processes/RunBackendStepOutput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/processes/RunBackendStepOutput.java @@ -42,7 +42,8 @@ public class RunBackendStepOutput extends AbstractActionOutput implements Serial private ProcessState processState; private Exception exception; // todo - make optional - private List auditInputList; + private List auditInputList = new ArrayList<>(); + /******************************************************************************* @@ -259,6 +260,7 @@ public class RunBackendStepOutput extends AbstractActionOutput implements Serial } + /******************************************************************************* ** Getter for auditInputList *******************************************************************************/ @@ -288,5 +290,4 @@ public class RunBackendStepOutput extends AbstractActionOutput implements Serial return (this); } - } 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 c310570c..d8e678eb 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 @@ -22,12 +22,13 @@ package com.kingsrook.qqq.backend.core.model.metadata; -import java.io.File; +import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import com.google.common.reflect.ClassPath; import com.kingsrook.qqq.backend.core.logging.QLogger; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; @@ -47,7 +48,7 @@ public class MetaDataProducerHelper ** ** Note - they'll be sorted by the sortOrder they provide. *******************************************************************************/ - public static void processAllMetaDataProducersInPackage(QInstance instance, String packageName) + public static void processAllMetaDataProducersInPackage(QInstance instance, String packageName) throws IOException { //////////////////////////////////////////////////////////// // find all the meta data producer classes in the package // @@ -111,40 +112,19 @@ public class MetaDataProducerHelper /******************************************************************************* - ** Thanks, Chat GPT. + ** from https://stackoverflow.com/questions/520328/can-you-find-all-classes-in-a-package-using-reflection + ** (since the original, from ChatGPT, didn't work in jars, despite GPT hallucinating that it would) *******************************************************************************/ - private static List> getClassesInPackage(String packageName) + private static List> getClassesInPackage(String packageName) throws IOException { List> classes = new ArrayList<>(); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); - String path = packageName.replace('.', '/'); - File directory = new File(Thread.currentThread().getContextClassLoader().getResource(path).getFile()); - - if(directory.exists()) + for(ClassPath.ClassInfo info : ClassPath.from(loader).getTopLevelClasses()) { - File[] files = directory.listFiles(); - if(files != null) + if(info.getName().startsWith(packageName)) { - for(File file : files) - { - if(file.isFile() && file.getName().endsWith(".class")) - { - String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6); - try - { - classes.add(Class.forName(className)); - } - catch(ClassNotFoundException e) - { - // Ignore, class not found - } - } - else if(file.isDirectory()) - { - List> subClasses = getClassesInPackage(packageName + "." + file.getName()); - classes.addAll(subClasses); - } - } + classes.add(info.load()); } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/tablesync/AbstractTableSyncTransformStep.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/tablesync/AbstractTableSyncTransformStep.java index cd8c45e4..a6acf84a 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/tablesync/AbstractTableSyncTransformStep.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/tablesync/AbstractTableSyncTransformStep.java @@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.core.processes.implementations.tablesync; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -216,6 +217,14 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt getTransaction().ifPresent(queryInput::setTransaction); QQueryFilter filter = getExistingRecordQueryFilter(runBackendStepInput, sourceKeyList); queryInput.setFilter(filter); + + Collection associationNamesToInclude = getAssociationNamesToInclude(); + if(CollectionUtils.nullSafeHasContents(associationNamesToInclude)) + { + queryInput.setIncludeAssociations(true); + queryInput.setAssociationNamesToInclude(associationNamesToInclude); + } + QueryOutput queryOutput = new QueryAction().execute(queryInput); existingRecordsByForeignKey = CollectionUtils.recordsToMap(queryOutput.getRecords(), destinationTableForeignKeyField); } @@ -296,6 +305,16 @@ public abstract class AbstractTableSyncTransformStep extends AbstractTransformSt + /******************************************************************************* + ** + *******************************************************************************/ + protected Collection getAssociationNamesToInclude() + { + return null; + } + + + /******************************************************************************* ** If needed, init a record lookup helper for this process. *******************************************************************************/ 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 9ee4dee7..8c96b8ab 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 @@ -22,6 +22,7 @@ package com.kingsrook.qqq.backend.core.model.metadata; +import java.io.IOException; import com.kingsrook.qqq.backend.core.model.metadata.producers.TestMetaDataProducer; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -37,7 +38,7 @@ class MetaDataProducerHelperTest ** *******************************************************************************/ @Test - void test() + void test() throws IOException { QInstance qInstance = new QInstance(); MetaDataProducerHelper.processAllMetaDataProducersInPackage(qInstance, "com.kingsrook.qqq.backend.core.model.metadata.producers"); diff --git a/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/model/OutboundAPILogMetaDataProvider.java b/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/model/OutboundAPILogMetaDataProvider.java index 7cb7e062..20c1c4ea 100644 --- a/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/model/OutboundAPILogMetaDataProvider.java +++ b/qqq-backend-module-api/src/main/java/com/kingsrook/qqq/backend/module/api/model/OutboundAPILogMetaDataProvider.java @@ -103,6 +103,7 @@ public class OutboundAPILogMetaDataProvider .withIcon(new QIcon().withName("data_object")) .withBackendName(backendName) .withRecordLabelFormat("%s") + .withRecordLabelFields("id") .withPrimaryKeyField("id") .withFieldsFromEntity(OutboundAPILog.class) .withSection(new QFieldSection("identity", new QIcon().withName("badge"), Tier.T1, List.of("id"))) @@ -142,6 +143,7 @@ public class OutboundAPILogMetaDataProvider // limit url to 250... // ///////////////////////// tableMetaData.getField("url").withMaxLength(250).withBehavior(ValueTooLongBehavior.TRUNCATE_ELLIPSIS); + tableMetaData.getField("url").withFieldAdornment(AdornmentType.Size.XLARGE.toAdornment()); if(backendDetailEnricher != null) { diff --git a/qqq-dev-tools/bin/createTableToRecordEntity.groovy b/qqq-dev-tools/bin/createTableToRecordEntity.groovy index a2afb2eb..8616a5d0 100755 --- a/qqq-dev-tools/bin/createTableToRecordEntity.groovy +++ b/qqq-dev-tools/bin/createTableToRecordEntity.groovy @@ -21,6 +21,7 @@ String allFieldNames = "" String dataFieldNames = "" List fieldNameList = new ArrayList<>(); List fieldTypeList = new ArrayList<>(); +Map fieldAttributesMap = new HashMap<>(); StringBuilder output = new StringBuilder(); if(writeWholeClass) @@ -58,8 +59,8 @@ while((line = reader.readLine()) != null) String columnType = words[1]; String fieldName = columNameToFieldName(columnName) - String fieldType = columTypeToFieldType(columnType) - String attributes = getFieldAttributes(fieldName); + String fieldType = columTypeToFieldType(fieldAttributesMap, fieldName, columnType) + String attributes = getFieldAttributes(fieldAttributesMap, fieldName); fieldNameList.add(fieldName); fieldTypeList.add(fieldType); @@ -235,13 +236,19 @@ private static String columNameToFieldName(String columnName) -private static String columTypeToFieldType(String columnType) +private static String columTypeToFieldType(Map fieldAttributesMap, String fieldName, String columnType) { if(columnType.toUpperCase().startsWith("INT")) { return ("Integer"); } - if(columnType.toUpperCase().startsWith("VARCHAR") || columnType.toUpperCase().startsWith("TEXT")) + if(columnType.toUpperCase().startsWith("VARCHAR")) + { + String length = columnType.toUpperCase().replaceAll(".*VARCHAR *\\( *", "").replaceAll(" *\\).*", ""); + fieldAttributesMap.put(fieldName, "maxLength = " + length + ", valueTooLongBehavior = ValueTooLongBehavior.TRUNCATE"); + return ("String"); + } + if(columnType.toUpperCase().startsWith("TEXT")) { return ("String"); } @@ -266,12 +273,22 @@ private static String columTypeToFieldType(String columnType) -private static String getFieldAttributes(String s) +private static String getFieldAttributes(Map fieldAttributesMap, String fieldName) { StringBuilder rs = new StringBuilder(""); - if(s.equals("id") || s.equals("createDate") || s.equals("modifyDate")) + if(fieldName.equals("id") || fieldName.equals("createDate") || fieldName.equals("modifyDate")) { rs.append("isEditable = false"); } + + if(fieldAttributesMap.containsKey(fieldName)) + { + if(rs.length() > 0) + { + rs.append(", "); + } + rs.append(fieldAttributesMap.get(fieldName)); + } + return (rs.toString()); } \ No newline at end of file