From 27682870a15a2047df6d6393d5381a097ea78d4d Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 7 Jun 2024 16:22:56 -0500 Subject: [PATCH] Update API query & get with MAY_USE_READ_ONLY query hint (adding that option to Get's) --- .../model/actions/tables/get/GetInput.java | 79 +++++++++++++++++++ .../rdbms/actions/AbstractRDBMSAction.java | 5 ++ .../qqq/api/actions/ApiImplementation.java | 8 +- 3 files changed, 90 insertions(+), 2 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java index 2cf7872f..711c3280 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java @@ -25,10 +25,12 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.get; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; +import java.util.EnumSet; import java.util.List; import java.util.Map; import com.kingsrook.qqq.backend.core.actions.QBackendTransaction; import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint; import com.kingsrook.qqq.backend.core.model.actions.tables.QueryOrGetInputInterface; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin; @@ -60,6 +62,8 @@ public class GetInput extends AbstractTableActionInput implements QueryOrGetInpu private boolean includeAssociations = false; private Collection associationNamesToInclude = null; + private EnumSet queryHints = EnumSet.noneOf(QueryHint.class); + /******************************************************************************* @@ -462,4 +466,79 @@ public class GetInput extends AbstractTableActionInput implements QueryOrGetInpu return (this); } + + + /******************************************************************************* + ** Getter for queryHints + *******************************************************************************/ + public EnumSet getQueryHints() + { + return (this.queryHints); + } + + + + /******************************************************************************* + ** Setter for queryHints + *******************************************************************************/ + public void setQueryHints(EnumSet queryHints) + { + this.queryHints = queryHints; + } + + + + /******************************************************************************* + ** Fluent setter for queryHints + *******************************************************************************/ + public GetInput withQueryHints(EnumSet queryHints) + { + this.queryHints = queryHints; + return (this); + } + + + + /******************************************************************************* + ** Fluent setter for queryHints + *******************************************************************************/ + public GetInput withQueryHint(QueryHint queryHint) + { + if(this.queryHints == null) + { + this.queryHints = EnumSet.noneOf(QueryHint.class); + } + this.queryHints.add(queryHint); + return (this); + } + + + + /******************************************************************************* + ** Fluent setter for queryHints + *******************************************************************************/ + public GetInput withoutQueryHint(QueryHint queryHint) + { + if(this.queryHints != null) + { + this.queryHints.remove(queryHint); + } + return (this); + } + + + + /******************************************************************************* + ** null-safely check if query hints map contains the specified hint + *******************************************************************************/ + public boolean hasQueryHint(QueryHint queryHint) + { + if(this.queryHints == null) + { + return (false); + } + + return (queryHints.contains(queryHint)); + } + } diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java index 3940f31b..082759bc 100644 --- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java +++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java @@ -54,6 +54,7 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.GroupBy; import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.QFilterOrderByAggregate; import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.QFilterOrderByGroupBy; import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.JoinsContext; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy; @@ -156,6 +157,10 @@ public abstract class AbstractRDBMSAction { useReadOnly = countInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND); } + else if(tableActionInput instanceof GetInput getInput) + { + useReadOnly = getInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND); + } else if(tableActionInput instanceof AggregateInput aggregateInput) { useReadOnly = aggregateInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND); diff --git a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java index 84137b7d..b56c7542 100644 --- a/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java +++ b/qqq-middleware-api/src/main/java/com/kingsrook/qqq/api/actions/ApiImplementation.java @@ -76,6 +76,7 @@ import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessState; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessInput; import com.kingsrook.qqq.backend.core.model.actions.processes.RunProcessOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.QInputSource; +import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint; import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput; import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; @@ -160,6 +161,7 @@ public class ApiImplementation queryInput.setTableName(tableName); queryInput.setIncludeAssociations(true); queryInput.setShouldFetchHeavyFields(true); + queryInput.withQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND); PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ); @@ -394,6 +396,7 @@ public class ApiImplementation CountInput countInput = new CountInput(); countInput.setTableName(tableName); countInput.setFilter(filter); + countInput.withQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND); CountOutput countOutput = new CountAction().execute(countInput); output.put("count", countOutput.getCount()); } @@ -595,6 +598,7 @@ public class ApiImplementation GetInput getInput = new GetInput(); getInput.setTableName(tableName); + getInput.withQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND); PermissionsHelper.checkTablePermissionThrowing(getInput, TablePermissionSubType.READ); @@ -1144,8 +1148,8 @@ public class ApiImplementation ApiProcessOutputInterface output = apiProcessMetaData.getOutput(); if(output != null) { - Serializable outputForProcess = output.getOutputForProcess(runProcessInput, runProcessOutput); - HttpApiResponse httpApiResponse = new HttpApiResponse(output.getSuccessStatusCode(runProcessInput, runProcessOutput), outputForProcess); + Serializable outputForProcess = output.getOutputForProcess(runProcessInput, runProcessOutput); + HttpApiResponse httpApiResponse = new HttpApiResponse(output.getSuccessStatusCode(runProcessInput, runProcessOutput), outputForProcess); output.customizeHttpApiResponse(httpApiResponse, runProcessInput, runProcessOutput); return httpApiResponse; }