Fix usage of subfilters in automation actions

This commit is contained in:
2023-06-06 13:31:25 -05:00
parent 12dd3617e5
commit e97ca5b5c5
2 changed files with 67 additions and 10 deletions

View File

@ -365,26 +365,29 @@ public class PollingAutomationPerTableRunner implements Runnable
QueryInput queryInput = new QueryInput();
queryInput.setTableName(table.getName());
///////////////////////////////////////////////////////////////////////////////////////
// set up a filter that is for the primary keys IN the list that we identified above //
///////////////////////////////////////////////////////////////////////////////////////
QQueryFilter filter = new QQueryFilter();
filter.addCriteria(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, records.stream().map(r -> r.getValue(table.getPrimaryKeyField())).toList()));
/////////////////////////////////////////////////////////////////////////////////////////////////////
// copy filter criteria from the action's filter to a new filter that we'll run here. //
// Critically - don't modify the filter object on the action! as that object has a long lifespan. //
/////////////////////////////////////////////////////////////////////////////////////////////////////
if(action.getFilter() != null)
{
if(action.getFilter().getCriteria() != null)
{
action.getFilter().getCriteria().forEach(filter::addCriteria);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// if the action defines a filter of its own, add that to the filter we'll run now as a sub-filter //
// not entirely clear if this needs to be a clone, but, it feels safe and cheap enough //
/////////////////////////////////////////////////////////////////////////////////////////////////////
filter.addSubFilter(action.getFilter().clone());
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// we also want to set order-bys from the action into our filter (since they only apply at the top-level) //
////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(action.getFilter().getOrderBys() != null)
{
action.getFilter().getOrderBys().forEach(filter::addOrderBy);
}
}
filter.addCriteria(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, records.stream().map(r -> r.getValue(table.getPrimaryKeyField())).toList()));
/////////////////////////////////////////////////////////////////////////////////////////////
// always add order-by the primary key, to give more predictable/consistent results //
// todo - in future - if this becomes a source of slowness, make this a config to opt-out? //

View File

@ -34,12 +34,16 @@ 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.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.update.UpdateInput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.AutomationStatusTracking;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.AutomationStatusTrackingType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.QTableAutomationDetails;
@ -313,6 +317,56 @@ class PollingAutomationPerTableRunnerTest extends BaseTest
/*******************************************************************************
** Test that sub-filters in filters work correctly to limit the records that get
** applied (as at one point in time, they didn't!!
*******************************************************************************/
@Test
void testFilterWithSubFilter() throws QException
{
QInstance qInstance = QContext.getQInstance();
///////////////////////////////////////////////////////////////////////////////////////////
// update the CheckAge automation to have a sub-filter that should make Tim not be found //
///////////////////////////////////////////////////////////////////////////////////////////
QTableMetaData table = qInstance.getTable(TestUtils.TABLE_NAME_PERSON_MEMORY);
TableAutomationAction checkAgeOnInsert = table.getAutomationDetails().getActions().stream()
.filter(a -> a.getName().equals("checkAgeOnInsert"))
.findFirst()
.orElseThrow();
QQueryFilter filter = checkAgeOnInsert.getFilter();
filter.addSubFilter(new QQueryFilter(new QFilterCriteria("firstName", QCriteriaOperator.NOT_EQUALS, "Tim")));
////////////////////////////////////////////////////////////////////////
// insert 2 person records - but only Darin should get the automation //
////////////////////////////////////////////////////////////////////////
InsertInput insertInput = new InsertInput();
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("firstName", "Tim").withValue("birthDate", LocalDate.now()),
new QRecord().withValue("id", 2).withValue("firstName", "Darin").withValue("birthDate", LocalDate.now())));
new InsertAction().execute(insertInput);
runAllTableActions(qInstance);
/////////////////////////////////
// make sure Darin was updated //
/////////////////////////////////
assertThat(TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
.stream().filter(r -> r.getValueString("firstName").startsWith("Darin"))).first()
.matches(r -> r.getValueString("firstName").endsWith(TestUtils.CheckAge.SUFFIX_FOR_MINORS));
////////////////////////////////////
// make sure Tim was not updated. //
////////////////////////////////////
assertThat(TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY)
.stream().filter(r -> r.getValueString("firstName").startsWith("Tim"))).first()
.matches(r -> !r.getValueString("firstName").endsWith(TestUtils.CheckAge.SUFFIX_FOR_MINORS));
}
/*******************************************************************************
**
*******************************************************************************/