diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostQueryCustomizer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostQueryCustomizer.java new file mode 100644 index 00000000..d1beaa4c --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/AbstractPostQueryCustomizer.java @@ -0,0 +1,65 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2022. 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.actions.customizers; + + +import java.util.List; +import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; +import com.kingsrook.qqq.backend.core.model.data.QRecord; + + +/******************************************************************************* + ** + *******************************************************************************/ +public abstract class AbstractPostQueryCustomizer +{ + protected AbstractTableActionInput input; + + + + /******************************************************************************* + ** + *******************************************************************************/ + public abstract List apply(List records); + + + + /******************************************************************************* + ** Getter for input + ** + *******************************************************************************/ + public AbstractTableActionInput getInput() + { + return (input); + } + + + + /******************************************************************************* + ** Setter for input + ** + *******************************************************************************/ + public void setInput(AbstractTableActionInput input) + { + this.input = input; + } +} diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/TableCustomizers.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/TableCustomizers.java index 36e467df..2d2d6621 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/TableCustomizers.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/TableCustomizers.java @@ -22,10 +22,6 @@ package com.kingsrook.qqq.backend.core.actions.customizers; -import java.util.function.Function; -import com.kingsrook.qqq.backend.core.model.data.QRecord; - - /******************************************************************************* ** Enum definition of possible table customizers - "roles" for custom code that ** can be applied to tables. @@ -43,13 +39,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecord; *******************************************************************************/ public enum TableCustomizers { - POST_QUERY_RECORD(new TableCustomizer("postQueryRecord", Function.class, ((Object x) -> - { - @SuppressWarnings("unchecked") - Function function = (Function) x; - QRecord output = function.apply(new QRecord()); - }))), - + POST_QUERY_RECORD(new TableCustomizer("postQueryRecord", AbstractPostQueryCustomizer.class)), POST_INSERT_RECORD(new TableCustomizer("postInsertRecord", AbstractPostInsertCustomizer.class)); diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/ProcessWidgetRenderer.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/ProcessWidgetRenderer.java index f13fbbc6..bdbf8382 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/ProcessWidgetRenderer.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/dashboard/widgets/ProcessWidgetRenderer.java @@ -55,7 +55,6 @@ public class ProcessWidgetRenderer extends AbstractWidgetRenderer if(input.getWidgetMetaData() instanceof QWidgetMetaData widgetMetaData) { setupDropdowns(input, widgetMetaData, data); - // todo - something about an error-like screen if dropdowns aren't valid? String processName = (String) widgetMetaData.getDefaultValues().get(WIDGET_PROCESS_NAME); QProcessMetaData processMetaData = input.getInstance().getProcess(processName); diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/GetAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/GetAction.java index f6162271..e6b2329b 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/GetAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/GetAction.java @@ -28,8 +28,8 @@ import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Function; import com.kingsrook.qqq.backend.core.actions.ActionHelper; +import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer; import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.actions.interfaces.GetInterface; @@ -64,7 +64,7 @@ import org.apache.commons.lang.NotImplementedException; *******************************************************************************/ public class GetAction { - private Optional> postGetRecordCustomizer; + private Optional postGetRecordCustomizer; private GetInput getInput; private QValueFormatter qValueFormatter; @@ -80,7 +80,7 @@ public class GetAction ActionHelper.validateSession(getInput); QTableMetaData table = getInput.getTable(); - postGetRecordCustomizer = QCodeLoader.getTableCustomizerFunction(table, TableCustomizers.POST_QUERY_RECORD.getRole()); + postGetRecordCustomizer = QCodeLoader.getTableCustomizer(AbstractPostQueryCustomizer.class, table, TableCustomizers.POST_QUERY_RECORD.getRole()); this.getInput = getInput; QBackendModuleDispatcher qBackendModuleDispatcher = new QBackendModuleDispatcher(); @@ -325,7 +325,7 @@ public class GetAction QRecord returnRecord = record; if(this.postGetRecordCustomizer.isPresent()) { - returnRecord = postGetRecordCustomizer.get().apply(record); + returnRecord = postGetRecordCustomizer.get().apply(List.of(record)).get(0); } if(getInput.getShouldTranslatePossibleValues()) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/QueryAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/QueryAction.java index 845a49b3..e757a4ae 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/QueryAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/QueryAction.java @@ -24,8 +24,8 @@ package com.kingsrook.qqq.backend.core.actions.tables; import java.util.List; import java.util.Optional; -import java.util.function.Function; import com.kingsrook.qqq.backend.core.actions.ActionHelper; +import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer; import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator; @@ -44,10 +44,9 @@ import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; *******************************************************************************/ public class QueryAction { - private Optional> postQueryRecordCustomizer; + private Optional postQueryRecordCustomizer; private QueryInput queryInput; - private QValueFormatter qValueFormatter; private QPossibleValueTranslator qPossibleValueTranslator; @@ -59,7 +58,7 @@ public class QueryAction { ActionHelper.validateSession(queryInput); - postQueryRecordCustomizer = QCodeLoader.getTableCustomizerFunction(queryInput.getTable(), TableCustomizers.POST_QUERY_RECORD.getRole()); + postQueryRecordCustomizer = QCodeLoader.getTableCustomizer(AbstractPostQueryCustomizer.class, queryInput.getTable(), TableCustomizers.POST_QUERY_RECORD.getRole()); this.queryInput = queryInput; if(queryInput.getRecordPipe() != null) @@ -92,7 +91,7 @@ public class QueryAction { if(this.postQueryRecordCustomizer.isPresent()) { - records.replaceAll(t -> postQueryRecordCustomizer.get().apply(t)); + records = postQueryRecordCustomizer.get().apply(records); } if(queryInput.getShouldTranslatePossibleValues()) @@ -106,11 +105,7 @@ public class QueryAction if(queryInput.getShouldGenerateDisplayValues()) { - if(qValueFormatter == null) - { - qValueFormatter = new QValueFormatter(); - } - qValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), records); + QValueFormatter.setDisplayValuesInRecords(queryInput.getTable(), records); } } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java index 6d1c1834..4e2271d0 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidator.java @@ -784,6 +784,9 @@ public class QInstanceValidator } else if(!Modifier.isPublic(clazz.getModifiers())) { + ////////////////////////////////////////////////////////////// + // seems like this doesn't get hit, for private classses... // + ////////////////////////////////////////////////////////////// errors.add(prefix + " because it is not public"); } else @@ -794,7 +797,7 @@ public class QInstanceValidator boolean hasNoArgConstructor = Stream.of(clazz.getConstructors()).anyMatch(c -> c.getParameterCount() == 0); if(!hasNoArgConstructor) { - errors.add(prefix + " because it does not have a parameterless constructor"); + errors.add(prefix + " because it does not have a public parameterless constructor"); } else { diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/WidgetDropdownData.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/WidgetDropdownData.java index da2af156..54cdf91f 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/WidgetDropdownData.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/metadata/dashboard/WidgetDropdownData.java @@ -23,7 +23,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.dashboard; /******************************************************************************* - ** inner class for specifying details about dropdown fields on a parent widget + ** Details about dropdown fields on a widget ** *******************************************************************************/ public class WidgetDropdownData diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java index 11ae63ff..14e1d2c8 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/instances/QInstanceValidatorTest.java @@ -27,7 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.function.Consumer; -import java.util.function.Function; +import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.actions.processes.BackendStep; import com.kingsrook.qqq.backend.core.exceptions.QException; @@ -387,17 +387,17 @@ class QInstanceValidatorTest assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerWithNoVoidConstructor.class, QCodeUsage.CUSTOMIZER)), "Instance of " + CustomizerWithNoVoidConstructor.class.getSimpleName() + " could not be created"); - assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerThatIsNotAFunction.class, QCodeUsage.CUSTOMIZER)), + assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerThatIsNotOfTheRightBaseClass.class, QCodeUsage.CUSTOMIZER)), "CodeReference is not of the expected type"); - assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerFunctionWithIncorrectTypeParameters.class, QCodeUsage.CUSTOMIZER)), - "Error validating customizer type parameters"); + assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerWithOnlyPrivateConstructor.class, QCodeUsage.CUSTOMIZER)), + "it does not have a public parameterless constructor"); - assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerFunctionWithIncorrectTypeParameter1.class, QCodeUsage.CUSTOMIZER)), - "Error validating customizer type parameters"); - - assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerFunctionWithIncorrectTypeParameter2.class, QCodeUsage.CUSTOMIZER)), - "Error validating customizer type parameters"); + ///////////////////////////////////////////// + // this class actually works, so, :shrug:? // + ///////////////////////////////////////////// + // assertValidationFailureReasons((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerWithPrivateVisibility.class, QCodeUsage.CUSTOMIZER)), + // "it does not have a public parameterless constructor"); assertValidationSuccess((qInstance) -> qInstance.getTable("person").withCustomizer(TableCustomizers.POST_QUERY_RECORD.getRole(), new QCodeReference(CustomizerValid.class, QCodeUsage.CUSTOMIZER))); } @@ -417,6 +417,30 @@ class QInstanceValidatorTest + /******************************************************************************* + ** + *******************************************************************************/ + private static class CustomizerWithPrivateVisibility extends AbstractPostQueryCustomizer + { + public CustomizerWithPrivateVisibility() + { + System.out.println("eh?"); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + public List apply(List records) + { + return (records); + } + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -433,7 +457,7 @@ class QInstanceValidatorTest /******************************************************************************* ** *******************************************************************************/ - public static class CustomizerThatIsNotAFunction + public static class CustomizerThatIsNotOfTheRightBaseClass { } @@ -442,54 +466,12 @@ class QInstanceValidatorTest /******************************************************************************* ** *******************************************************************************/ - public static class CustomizerFunctionWithIncorrectTypeParameters implements Function + public static class CustomizerValid extends AbstractPostQueryCustomizer { @Override - public String apply(String s) + public List apply(List records) { - return null; - } - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public static class CustomizerFunctionWithIncorrectTypeParameter1 implements Function - { - @Override - public QRecord apply(String s) - { - return null; - } - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public static class CustomizerFunctionWithIncorrectTypeParameter2 implements Function - { - @Override - public String apply(QRecord s) - { - return "Test"; - } - } - - - - /******************************************************************************* - ** - *******************************************************************************/ - public static class CustomizerValid implements Function - { - @Override - public QRecord apply(QRecord record) - { - return null; + return (records); } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/modules/backend/implementations/memory/MemoryBackendModuleTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/modules/backend/implementations/memory/MemoryBackendModuleTest.java index 21e00c65..d2f70281 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/modules/backend/implementations/memory/MemoryBackendModuleTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/modules/backend/implementations/memory/MemoryBackendModuleTest.java @@ -25,7 +25,7 @@ package com.kingsrook.qqq.backend.core.modules.backend.implementations.memory; import java.time.LocalDate; import java.time.Month; import java.util.List; -import java.util.function.Function; +import com.kingsrook.qqq.backend.core.actions.customizers.AbstractPostQueryCustomizer; import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers; import com.kingsrook.qqq.backend.core.actions.tables.CountAction; import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; @@ -472,13 +472,15 @@ class MemoryBackendModuleTest /////////////////////////////////////////////////////// // do a query - assert that the customizer did stuff // /////////////////////////////////////////////////////// - ShapeTestCustomizer.executionCount = 0; + ShapeTestCustomizer.invocationCount = 0; + ShapeTestCustomizer.recordsCustomizedCount = 0; QueryInput queryInput = new QueryInput(qInstance); queryInput.setSession(session); queryInput.setTableName(table.getName()); QueryOutput queryOutput = new QueryAction().execute(queryInput); assertEquals(3, queryOutput.getRecords().size()); - assertEquals(3, ShapeTestCustomizer.executionCount); + assertEquals(1, ShapeTestCustomizer.invocationCount); + assertEquals(3, ShapeTestCustomizer.recordsCustomizedCount); assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(1) && r.getValueInteger("tenTimesId").equals(10))); assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(2) && r.getValueInteger("tenTimesId").equals(20))); assertTrue(queryOutput.getRecords().stream().anyMatch(r -> r.getValueInteger("id").equals(3) && r.getValueInteger("tenTimesId").equals(30))); @@ -489,18 +491,26 @@ class MemoryBackendModuleTest /******************************************************************************* ** *******************************************************************************/ - public static class ShapeTestCustomizer implements Function + public static class ShapeTestCustomizer extends AbstractPostQueryCustomizer { - static int executionCount = 0; + static int invocationCount = 0; + static int recordsCustomizedCount = 0; + /******************************************************************************* + ** + *******************************************************************************/ @Override - public QRecord apply(QRecord record) + public List apply(List records) { - executionCount++; - record.setValue("tenTimesId", record.getValueInteger("id") * 10); - return (record); + invocationCount++; + for(QRecord record : records) + { + recordsCustomizedCount++; + record.setValue("tenTimesId", record.getValueInteger("id") * 10); + } + return (records); } } } \ No newline at end of file