mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
Fix usage of subfilters in automation actions
This commit is contained in:
@ -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? //
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
Reference in New Issue
Block a user