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 e4b14053..7bf01589 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 @@ -196,14 +196,7 @@ public class GetAction } queryInput.setFilter(filter); - queryInput.setTransaction(getInput.getTransaction()); - queryInput.setIncludeAssociations(getInput.getIncludeAssociations()); - queryInput.setAssociationNamesToInclude(getInput.getAssociationNamesToInclude()); - queryInput.setShouldTranslatePossibleValues(getInput.getShouldTranslatePossibleValues()); - queryInput.setShouldGenerateDisplayValues(getInput.getShouldGenerateDisplayValues()); - queryInput.setShouldFetchHeavyFields(getInput.getShouldFetchHeavyFields()); - queryInput.setShouldMaskPasswords(getInput.getShouldMaskPasswords()); - queryInput.setShouldOmitHiddenFields(getInput.getShouldOmitHiddenFields()); + queryInput.setCommonParamsFrom(getInput); return queryInput; } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryActionCacheHelper.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryActionCacheHelper.java index 188eae69..e8b79d6f 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryActionCacheHelper.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/tables/helpers/QueryActionCacheHelper.java @@ -34,12 +34,16 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import com.kingsrook.qqq.backend.core.actions.tables.DeleteAction; +import com.kingsrook.qqq.backend.core.actions.tables.GetAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.QueryAction; import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction; +import com.kingsrook.qqq.backend.core.context.QContext; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.logging.QLogger; import com.kingsrook.qqq.backend.core.model.actions.tables.delete.DeleteInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput; import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator; @@ -50,6 +54,8 @@ import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput; import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; +import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.tables.Capability; import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData; import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheUseCase; @@ -532,7 +538,7 @@ public class QueryActionCacheHelper if(CacheUseCase.Type.UNIQUE_KEY_TO_UNIQUE_KEY.equals(activeCacheUseCase)) { - recordsFromSource = getFromCachedSourceForUniqueKeyToUniqueKey(uniqueKeyValues, table.getCacheOf().getSourceTable()); + recordsFromSource = getFromCachedSourceForUniqueKeyToUniqueKey(queryInput, uniqueKeyValues, table.getCacheOf().getSourceTable()); } else { @@ -548,30 +554,69 @@ public class QueryActionCacheHelper /******************************************************************************* ** *******************************************************************************/ - private List getFromCachedSourceForUniqueKeyToUniqueKey(Set> uniqueKeyValues, String sourceTableName) throws QException + private List getFromCachedSourceForUniqueKeyToUniqueKey(QueryInput cacheQueryInput, Set> uniqueKeyValues, String sourceTableName) throws QException { - /////////////////////////////////////////////////////// - // do a Query on the source table, by the unique key // - /////////////////////////////////////////////////////// - QueryInput sourceQueryInput = new QueryInput(); - sourceQueryInput.setTableName(sourceTableName); + QTableMetaData sourceTable = QContext.getQInstance().getTable(sourceTableName); + QBackendMetaData sourceBackend = QContext.getQInstance().getBackendForTable(sourceTableName); - QQueryFilter filter = new QQueryFilter().withBooleanOperator(QQueryFilter.BooleanOperator.OR); - sourceQueryInput.setFilter(filter); - - for(List uniqueKeyValue : uniqueKeyValues) + if(sourceTable.isCapabilityEnabled(sourceBackend, Capability.TABLE_QUERY)) { - QQueryFilter subFilter = new QQueryFilter(); - filter.addSubFilter(subFilter); + /////////////////////////////////////////////////////// + // do a Query on the source table, by the unique key // + /////////////////////////////////////////////////////// + QueryInput sourceQueryInput = new QueryInput(); + sourceQueryInput.setTableName(sourceTableName); - for(int i = 0; i < cacheUniqueKey.getFieldNames().size(); i++) + QQueryFilter filter = new QQueryFilter().withBooleanOperator(QQueryFilter.BooleanOperator.OR); + sourceQueryInput.setFilter(filter); + sourceQueryInput.setCommonParamsFrom(cacheQueryInput); + + for(List uniqueKeyValue : uniqueKeyValues) { - subFilter.addCriteria(new QFilterCriteria(cacheUniqueKey.getFieldNames().get(i), QCriteriaOperator.EQUALS, uniqueKeyValue.get(i))); - } - } + QQueryFilter subFilter = new QQueryFilter(); + filter.addSubFilter(subFilter); - QueryOutput sourceQueryOutput = new QueryAction().execute(sourceQueryInput); - return (sourceQueryOutput.getRecords()); + for(int i = 0; i < cacheUniqueKey.getFieldNames().size(); i++) + { + subFilter.addCriteria(new QFilterCriteria(cacheUniqueKey.getFieldNames().get(i), QCriteriaOperator.EQUALS, uniqueKeyValue.get(i))); + } + } + + QueryOutput sourceQueryOutput = new QueryAction().execute(sourceQueryInput); + return (sourceQueryOutput.getRecords()); + } + else if(sourceTable.isCapabilityEnabled(sourceBackend, Capability.TABLE_GET)) + { + /////////////////////////////////////////////////////////////////////// + // if the table only supports GET, then do a GET for each unique key // + /////////////////////////////////////////////////////////////////////// + List outputRecords = new ArrayList<>(); + for(List uniqueKeyValue : uniqueKeyValues) + { + Map uniqueKey = new HashMap<>(); + for(int i = 0; i < cacheUniqueKey.getFieldNames().size(); i++) + { + uniqueKey.put(cacheUniqueKey.getFieldNames().get(i), uniqueKeyValue.get(i)); + } + + GetInput getInput = new GetInput(); + getInput.setTableName(sourceTableName); + getInput.setUniqueKey(uniqueKey); + getInput.setCommonParamsFrom(cacheQueryInput); + GetOutput getOutput = new GetAction().execute(getInput); + + if(getOutput.getRecord() != null) + { + outputRecords.add(getOutput.getRecord()); + } + } + + return (outputRecords); + } + else + { + throw (new QException("Cache source table " + sourceTableName + " does not support Query or Get capability.")); + } } } diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/QueryOrGetInputInterface.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/QueryOrGetInputInterface.java new file mode 100644 index 00000000..63f175e9 --- /dev/null +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/QueryOrGetInputInterface.java @@ -0,0 +1,149 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2023. 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.actions.tables; + + +import java.util.Collection; +import com.kingsrook.qqq.backend.core.actions.QBackendTransaction; + + +/******************************************************************************* + ** Common getters & setters, shared by both QueryInput and GetInput. + ** + ** Original impetus for this class is the setCommonParamsFrom() method - for cases + ** where we need to change a Query to a Get, or vice-versa, and we want to copy over + ** all of those input params. + *******************************************************************************/ +public interface QueryOrGetInputInterface +{ + /******************************************************************************* + ** Set in THIS, the "common params" (e.g., common to both Query & Get inputs) + ** from the parameter SOURCE object. + *******************************************************************************/ + default void setCommonParamsFrom(QueryOrGetInputInterface source) + { + this.setTransaction(source.getTransaction()); + this.setShouldTranslatePossibleValues(source.getShouldTranslatePossibleValues()); + this.setShouldGenerateDisplayValues(source.getShouldGenerateDisplayValues()); + this.setShouldFetchHeavyFields(source.getShouldFetchHeavyFields()); + this.setShouldOmitHiddenFields(source.getShouldOmitHiddenFields()); + this.setShouldMaskPasswords(source.getShouldMaskPasswords()); + this.setIncludeAssociations(source.getIncludeAssociations()); + this.setAssociationNamesToInclude(source.getAssociationNamesToInclude()); + } + + /******************************************************************************* + ** Getter for transaction + *******************************************************************************/ + QBackendTransaction getTransaction(); + + + /******************************************************************************* + ** Setter for transaction + *******************************************************************************/ + void setTransaction(QBackendTransaction transaction); + + + /******************************************************************************* + ** Getter for shouldTranslatePossibleValues + *******************************************************************************/ + boolean getShouldTranslatePossibleValues(); + + + /******************************************************************************* + ** Setter for shouldTranslatePossibleValues + *******************************************************************************/ + void setShouldTranslatePossibleValues(boolean shouldTranslatePossibleValues); + + + /******************************************************************************* + ** Getter for shouldGenerateDisplayValues + *******************************************************************************/ + boolean getShouldGenerateDisplayValues(); + + + /******************************************************************************* + ** Setter for shouldGenerateDisplayValues + *******************************************************************************/ + void setShouldGenerateDisplayValues(boolean shouldGenerateDisplayValues); + + + /******************************************************************************* + ** Getter for shouldFetchHeavyFields + *******************************************************************************/ + boolean getShouldFetchHeavyFields(); + + + /******************************************************************************* + ** Setter for shouldFetchHeavyFields + *******************************************************************************/ + void setShouldFetchHeavyFields(boolean shouldFetchHeavyFields); + + + /******************************************************************************* + ** Getter for shouldOmitHiddenFields + *******************************************************************************/ + boolean getShouldOmitHiddenFields(); + + + /******************************************************************************* + ** Setter for shouldOmitHiddenFields + *******************************************************************************/ + void setShouldOmitHiddenFields(boolean shouldOmitHiddenFields); + + + /******************************************************************************* + ** Getter for shouldMaskPasswords + *******************************************************************************/ + boolean getShouldMaskPasswords(); + + + /******************************************************************************* + ** Setter for shouldMaskPasswords + *******************************************************************************/ + void setShouldMaskPasswords(boolean shouldMaskPasswords); + + + /******************************************************************************* + ** Getter for includeAssociations + *******************************************************************************/ + boolean getIncludeAssociations(); + + + /******************************************************************************* + ** Setter for includeAssociations + *******************************************************************************/ + void setIncludeAssociations(boolean includeAssociations); + + + /******************************************************************************* + ** Getter for associationNamesToInclude + *******************************************************************************/ + Collection getAssociationNamesToInclude(); + + + /******************************************************************************* + ** Setter for associationNamesToInclude + *******************************************************************************/ + void setAssociationNamesToInclude(Collection associationNamesToInclude); + +} 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 0e3f8e59..4de83c89 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 @@ -27,13 +27,14 @@ import java.util.Collection; 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.QueryOrGetInputInterface; /******************************************************************************* ** Input data for the Get action ** *******************************************************************************/ -public class GetInput extends AbstractTableActionInput +public class GetInput extends AbstractTableActionInput implements QueryOrGetInputInterface { private QBackendTransaction transaction; diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java index 6cb2c556..1c63691f 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java @@ -29,13 +29,14 @@ import java.util.Set; import com.kingsrook.qqq.backend.core.actions.QBackendTransaction; import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe; import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput; +import com.kingsrook.qqq.backend.core.model.actions.tables.QueryOrGetInputInterface; /******************************************************************************* ** Input data for the Query action ** *******************************************************************************/ -public class QueryInput extends AbstractTableActionInput +public class QueryInput extends AbstractTableActionInput implements QueryOrGetInputInterface { private QBackendTransaction transaction; private QQueryFilter filter;