diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java index 44b8984a..9cb17a0c 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java @@ -260,9 +260,6 @@ public class SearchPossibleValueSourceAction } } - // todo - skip & limit as params - queryFilter.setLimit(250); - /////////////////////////////////////////////////////////////////////////////////////////////////////// // if given a default filter, make it the 'top level' filter and the one we just created a subfilter // /////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -272,6 +269,9 @@ public class SearchPossibleValueSourceAction queryFilter = input.getDefaultQueryFilter(); } + // todo - skip & limit as params + queryFilter.setLimit(250); + queryFilter.setOrderBys(possibleValueSource.getOrderByFields()); queryInput.setFilter(queryFilter); diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java index 33c2b5ad..cca918ab 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementation.java @@ -1279,6 +1279,11 @@ public class QJavalinImplementation queryInput.getFilter().setLimit(limit); } + if(queryInput.getFilter() == null || queryInput.getFilter().getLimit() == null) + { + handleQueryNullLimit(context, queryInput); + } + List queryJoins = processQueryJoinsParam(context); queryInput.setQueryJoins(queryJoins); @@ -1299,6 +1304,28 @@ public class QJavalinImplementation + /*************************************************************************** + ** + ***************************************************************************/ + private static void handleQueryNullLimit(Context context, QueryInput queryInput) + { + boolean allowed = javalinMetaData.getQueryWithoutLimitAllowed(); + if(!allowed) + { + if(queryInput.getFilter() == null) + { + queryInput.setFilter(new QQueryFilter()); + } + + queryInput.getFilter().setLimit(javalinMetaData.getQueryWithoutLimitDefault()); + LOG.log(javalinMetaData.getQueryWithoutLimitLogLevel(), "Query request did not specify a limit, which is not allowed. Using default instead", null, + logPair("defaultLimit", javalinMetaData.getQueryWithoutLimitDefault()), + logPair("path", context.path())); + } + } + + + /******************************************************************************* ** *******************************************************************************/ diff --git a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinMetaData.java b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinMetaData.java index e55db75c..89f422b2 100644 --- a/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinMetaData.java +++ b/qqq-middleware-javalin/src/main/java/com/kingsrook/qqq/backend/javalin/QJavalinMetaData.java @@ -23,6 +23,7 @@ package com.kingsrook.qqq.backend.javalin; import java.util.function.Function; +import org.apache.logging.log4j.Level; /******************************************************************************* @@ -36,6 +37,10 @@ public class QJavalinMetaData private Function logFilter; + private boolean queryWithoutLimitAllowed = false; + private Integer queryWithoutLimitDefault = 1000; + private Level queryWithoutLimitLogLevel = Level.INFO; + /******************************************************************************* @@ -143,4 +148,97 @@ public class QJavalinMetaData return (this); } + + + /******************************************************************************* + ** Getter for queryWithoutLimitAllowed + *******************************************************************************/ + public boolean getQueryWithoutLimitAllowed() + { + return (this.queryWithoutLimitAllowed); + } + + + + /******************************************************************************* + ** Setter for queryWithoutLimitAllowed + *******************************************************************************/ + public void setQueryWithoutLimitAllowed(boolean queryWithoutLimitAllowed) + { + this.queryWithoutLimitAllowed = queryWithoutLimitAllowed; + } + + + + /******************************************************************************* + ** Fluent setter for queryWithoutLimitAllowed + *******************************************************************************/ + public QJavalinMetaData withQueryWithoutLimitAllowed(boolean queryWithoutLimitAllowed) + { + this.queryWithoutLimitAllowed = queryWithoutLimitAllowed; + return (this); + } + + + + /******************************************************************************* + ** Getter for queryWithoutLimitDefault + *******************************************************************************/ + public Integer getQueryWithoutLimitDefault() + { + return (this.queryWithoutLimitDefault); + } + + + + /******************************************************************************* + ** Setter for queryWithoutLimitDefault + *******************************************************************************/ + public void setQueryWithoutLimitDefault(Integer queryWithoutLimitDefault) + { + this.queryWithoutLimitDefault = queryWithoutLimitDefault; + } + + + + /******************************************************************************* + ** Fluent setter for queryWithoutLimitDefault + *******************************************************************************/ + public QJavalinMetaData withQueryWithoutLimitDefault(Integer queryWithoutLimitDefault) + { + this.queryWithoutLimitDefault = queryWithoutLimitDefault; + return (this); + } + + + + /******************************************************************************* + ** Getter for queryWithoutLimitLogLevel + *******************************************************************************/ + public Level getQueryWithoutLimitLogLevel() + { + return (this.queryWithoutLimitLogLevel); + } + + + + /******************************************************************************* + ** Setter for queryWithoutLimitLogLevel + *******************************************************************************/ + public void setQueryWithoutLimitLogLevel(Level queryWithoutLimitLogLevel) + { + this.queryWithoutLimitLogLevel = queryWithoutLimitLogLevel; + } + + + + /******************************************************************************* + ** Fluent setter for queryWithoutLimitLogLevel + *******************************************************************************/ + public QJavalinMetaData withQueryWithoutLimitLogLevel(Level queryWithoutLimitLogLevel) + { + this.queryWithoutLimitLogLevel = queryWithoutLimitLogLevel; + return (this); + } + } diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java index 9f59d373..df633b30 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinImplementationTest.java @@ -33,6 +33,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QInstanceValidationException; +import com.kingsrook.qqq.backend.core.logging.QCollectingLogger; +import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat; import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType; import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; @@ -45,6 +47,7 @@ import com.kingsrook.qqq.backend.core.utils.JsonUtils; import com.kingsrook.qqq.backend.core.utils.SleepUtils; import kong.unirest.HttpResponse; import kong.unirest.Unirest; +import org.apache.logging.log4j.Level; import org.eclipse.jetty.http.HttpStatus; import org.json.JSONArray; import org.json.JSONObject; @@ -469,6 +472,101 @@ class QJavalinImplementationTest extends QJavalinTestBase + /******************************************************************************* + ** test a table query using an actual filter via POST, with no limit specified, + ** and with that not being allowed. + ** + *******************************************************************************/ + @Test + public void test_dataQueryWithFilterPOSTWithoutLimitNotAllowed() throws QInstanceValidationException + { + try + { + qJavalinImplementation.getJavalinMetaData() + .withQueryWithoutLimitAllowed(false) + .withQueryWithoutLimitDefault(3) + .withQueryWithoutLimitLogLevel(Level.WARN); + + QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(QJavalinImplementation.class); + + String filterJson = """ + {"criteria":[]}"""; + + HttpResponse response = Unirest.post(BASE_URL + "/data/person/query") + .field("filter", filterJson) + .asString(); + + assertEquals(200, response.getStatus()); + JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody()); + assertTrue(jsonObject.has("records")); + JSONArray records = jsonObject.getJSONArray("records"); + assertEquals(3, records.length()); + + assertThat(collectingLogger.getCollectedMessages()) + .anyMatch(m -> m.getLevel().equals(Level.WARN) && m.getMessage().contains("Query request did not specify a limit")); + } + finally + { + QLogger.activateCollectingLoggerForClass(QJavalinImplementation.class); + resetMetaDataQueryWithoutLimitSettings(); + } + } + + + + /******************************************************************************* + ** test a table query using an actual filter via POST, with no limit specified, + ** but with that being allowed. + ** + *******************************************************************************/ + @Test + public void test_dataQueryWithFilterPOSTWithoutLimitAllowed() throws QInstanceValidationException + { + try + { + qJavalinImplementation.getJavalinMetaData() + .withQueryWithoutLimitAllowed(true); + + QCollectingLogger collectingLogger = QLogger.activateCollectingLoggerForClass(QJavalinImplementation.class); + + String filterJson = """ + {"criteria":[]}"""; + + HttpResponse response = Unirest.post(BASE_URL + "/data/person/query") + .field("filter", filterJson) + .asString(); + + assertEquals(200, response.getStatus()); + JSONObject jsonObject = JsonUtils.toJSONObject(response.getBody()); + assertTrue(jsonObject.has("records")); + JSONArray records = jsonObject.getJSONArray("records"); + assertEquals(6, records.length()); + + assertThat(collectingLogger.getCollectedMessages()) + .noneMatch(m -> m.getMessage().contains("Query request did not specify a limit")); + } + finally + { + QLogger.activateCollectingLoggerForClass(QJavalinImplementation.class); + resetMetaDataQueryWithoutLimitSettings(); + } + } + + + + /*************************************************************************** + ** + ***************************************************************************/ + private void resetMetaDataQueryWithoutLimitSettings() + { + qJavalinImplementation.getJavalinMetaData() + .withQueryWithoutLimitAllowed(false) + .withQueryWithoutLimitDefault(1000) + .withQueryWithoutLimitLogLevel(Level.INFO); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -1029,7 +1127,7 @@ class QJavalinImplementationTest extends QJavalinTestBase // filter use-case, with no values, should return options. // ///////////////////////////////////////////////////////////// HttpResponse response = Unirest.post(BASE_URL + "/data/pet/possibleValues/ownerPersonId?searchTerm=&useCase=filter").asString(); - JSONArray options = assertPossibleValueSuccessfulResponseAndGetOptionsArray(response); + JSONArray options = assertPossibleValueSuccessfulResponseAndGetOptionsArray(response); assertNotNull(options); assertThat(options.length()).isGreaterThanOrEqualTo(5); diff --git a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinTestBase.java b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinTestBase.java index f8ee594f..9ca159cd 100644 --- a/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinTestBase.java +++ b/qqq-middleware-javalin/src/test/java/com/kingsrook/qqq/backend/javalin/QJavalinTestBase.java @@ -102,7 +102,7 @@ public class QJavalinTestBase { qJavalinImplementation.stopJavalinServer(); } - qJavalinImplementation = new QJavalinImplementation(qInstance); + qJavalinImplementation = new QJavalinImplementation(qInstance, new QJavalinMetaData()); QJavalinProcessHandler.setAsyncStepTimeoutMillis(250); qJavalinImplementation.startJavalinServer(PORT); }