added ability to use filters to stop certain records from being cached, fixed insert bug due to binding instants to its default timestamp

This commit is contained in:
Tim Chamberlain
2023-03-13 20:02:37 -05:00
parent ec05f7ab7e
commit e0f5c3ff49
5 changed files with 96 additions and 9 deletions

View File

@ -36,6 +36,8 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.GetInterface;
import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator; import com.kingsrook.qqq.backend.core.actions.values.QPossibleValueTranslator;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.logging.LogPair;
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.delete.DeleteInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput; 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.get.GetOutput;
@ -53,6 +55,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheUseCase; import com.kingsrook.qqq.backend.core.model.metadata.tables.cache.CacheUseCase;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleDispatcher;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface; import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.utils.BackendQueryFilterUtils;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils; import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils; import com.kingsrook.qqq.backend.core.utils.StringUtils;
import org.apache.commons.lang.NotImplementedException; import org.apache.commons.lang.NotImplementedException;
@ -64,6 +67,8 @@ import org.apache.commons.lang.NotImplementedException;
*******************************************************************************/ *******************************************************************************/
public class GetAction public class GetAction
{ {
private static final QLogger LOG = QLogger.getLogger(InsertAction.class);
private Optional<AbstractPostQueryCustomizer> postGetRecordCustomizer; private Optional<AbstractPostQueryCustomizer> postGetRecordCustomizer;
private GetInput getInput; private GetInput getInput;
@ -125,13 +130,34 @@ public class GetAction
QRecord recordFromSource = tryToGetFromCacheSource(getInput, getOutput); QRecord recordFromSource = tryToGetFromCacheSource(getInput, getOutput);
if(recordFromSource != null) if(recordFromSource != null)
{ {
QRecord recordToCache = mapSourceRecordToCacheRecord(table, recordFromSource); QRecord recordToCache = mapSourceRecordToCacheRecord(table, recordFromSource);
boolean shouldCacheRecord = true;
InsertInput insertInput = new InsertInput(); ////////////////////////////////////////////////////////////////////////////////
insertInput.setTableName(getInput.getTableName()); // see if there are any exclustions that need to be considered for this table //
insertInput.setRecords(List.of(recordToCache)); ////////////////////////////////////////////////////////////////////////////////
InsertOutput insertOutput = new InsertAction().execute(insertInput); recordMatchExclusionLoop:
getOutput.setRecord(insertOutput.getRecords().get(0)); for(CacheUseCase useCase : CollectionUtils.nonNullList(table.getCacheOf().getUseCases()))
{
for(QQueryFilter filter : CollectionUtils.nonNullList(useCase.getExcludeRecordsMatching()))
{
if(BackendQueryFilterUtils.doesRecordMatch(filter, recordToCache))
{
LOG.info("Not catching record because it matches a use case's filter exclusion", new LogPair("record", recordToCache), new LogPair("filter", filter));
shouldCacheRecord = false;
break recordMatchExclusionLoop;
}
}
}
if(shouldCacheRecord)
{
InsertInput insertInput = new InsertInput();
insertInput.setTableName(getInput.getTableName());
insertInput.setRecords(List.of(recordToCache));
InsertOutput insertOutput = new InsertAction().execute(insertInput);
getOutput.setRecord(insertOutput.getRecords().get(0));
}
} }
} }
else else
@ -257,7 +283,9 @@ public class GetAction
sourceGetInput.setTableName(sourceTableName); sourceGetInput.setTableName(sourceTableName);
sourceGetInput.setUniqueKey(getInput.getUniqueKey()); sourceGetInput.setUniqueKey(getInput.getUniqueKey());
GetOutput sourceGetOutput = new GetAction().execute(sourceGetInput); GetOutput sourceGetOutput = new GetAction().execute(sourceGetInput);
return (sourceGetOutput.getRecord()); QRecord outputRecord = sourceGetOutput.getRecord();
return (outputRecord);
} }

View File

@ -22,6 +22,8 @@
package com.kingsrook.qqq.backend.core.model.metadata.tables.cache; package com.kingsrook.qqq.backend.core.model.metadata.tables.cache;
import java.util.List;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey; import com.kingsrook.qqq.backend.core.model.metadata.tables.UniqueKey;
@ -48,6 +50,8 @@ public class CacheUseCase
private UniqueKey cacheUniqueKey; private UniqueKey cacheUniqueKey;
private UniqueKey sourceUniqueKey; private UniqueKey sourceUniqueKey;
private List<QQueryFilter> excludeRecordsMatching;
/******************************************************************************* /*******************************************************************************
@ -184,4 +188,38 @@ public class CacheUseCase
return (this); return (this);
} }
/*******************************************************************************
** Getter for excludeRecordsMatching
**
*******************************************************************************/
public List<QQueryFilter> getExcludeRecordsMatching()
{
return excludeRecordsMatching;
}
/*******************************************************************************
** Setter for excludeRecordsMatching
**
*******************************************************************************/
public void setExcludeRecordsMatching(List<QQueryFilter> excludeRecordsMatching)
{
this.excludeRecordsMatching = excludeRecordsMatching;
}
/*******************************************************************************
** Fluent setter for excludeRecordsMatching
**
*******************************************************************************/
public CacheUseCase withExcludeRecordsMatching(List<QQueryFilter> excludeRecordsMatching)
{
this.excludeRecordsMatching = excludeRecordsMatching;
return (this);
}
} }

View File

@ -101,7 +101,8 @@ class GetActionTest extends BaseTest
TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of( TestUtils.insertRecords(qInstance, qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY), List.of(
new QRecord().withValue("id", 1).withValue("firstName", "George").withValue("lastName", "Washington").withValue("noOfShoes", 5), new QRecord().withValue("id", 1).withValue("firstName", "George").withValue("lastName", "Washington").withValue("noOfShoes", 5),
new QRecord().withValue("id", 2).withValue("firstName", "John").withValue("lastName", "Adams"), new QRecord().withValue("id", 2).withValue("firstName", "John").withValue("lastName", "Adams"),
new QRecord().withValue("id", 3).withValue("firstName", "Thomas").withValue("lastName", "Jefferson") new QRecord().withValue("id", 3).withValue("firstName", "Thomas").withValue("lastName", "Jefferson"),
new QRecord().withValue("id", 3).withValue("firstName", "Thomas 503").withValue("lastName", "Jefferson")
)); ));
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -117,6 +118,17 @@ class GetActionTest extends BaseTest
assertEquals(5, getOutput.getRecord().getValue("noOfShoes")); assertEquals(5, getOutput.getRecord().getValue("noOfShoes"));
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// try to get from the table which caches it - but should not find because use case should filter out because of matching 503 //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{
GetInput getInput = new GetInput();
getInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY_CACHE);
getInput.setUniqueKey(Map.of("firstName", "Thomas 503", "lastName", "Jefferson"));
GetOutput getOutput = new GetAction().execute(getInput);
assertNull(getOutput.getRecord());
}
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// request a row that doesn't exist in cache or source, should miss both // // request a row that doesn't exist in cache or source, should miss both //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////

View File

@ -739,6 +739,15 @@ public class TestUtils
.withSourceUniqueKey(uniqueKey) .withSourceUniqueKey(uniqueKey)
.withCacheUniqueKey(uniqueKey) .withCacheUniqueKey(uniqueKey)
.withCacheSourceMisses(false) .withCacheSourceMisses(false)
.withExcludeRecordsMatching(List.of(
new QQueryFilter(
new QFilterCriteria(
"firstName",
QCriteriaOperator.CONTAINS,
List.of("503")
)
)
))
)); ));
} }

View File

@ -739,7 +739,7 @@ public class QueryManager
} }
else if(value instanceof Instant i) else if(value instanceof Instant i)
{ {
statement.setString(index, i.toString()); statement.setString(index, i.toString().replaceAll("T", " ").replaceAll("Z", ""));
return (1); return (1);
} }
else if(value instanceof LocalDate ld) else if(value instanceof LocalDate ld)