QQQ-40 getting closer to production-ready on automations

This commit is contained in:
2022-09-01 15:50:33 -05:00
parent e157809b35
commit 64e801747f
16 changed files with 933 additions and 176 deletions

View File

@ -11,12 +11,10 @@ import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationHandler;
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.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
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.automation.RecordAutomationInput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
@ -99,56 +97,6 @@ class PollingAutomationExecutorTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testUpdate() throws QException
{
QInstance qInstance = TestUtils.defineInstance();
///////////////////////////////////////////////////////////////////////////////
// insert 2 people - one who should be logged by logger-on-update automation //
///////////////////////////////////////////////////////////////////////////////
InsertInput insertInput = new InsertInput(qInstance);
insertInput.setSession(new QSession());
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("firstName", "Tim"),
new QRecord().withValue("id", 2).withValue("firstName", "Darin")
));
new InsertAction().execute(insertInput);
////////////////////////////////////////////////
// have the polling executor run "for awhile" //
////////////////////////////////////////////////
runPollingAutomationExecutorForAwhile(qInstance);
//////////////////////////////////////////////////
// assert that the update-automation didn't run //
//////////////////////////////////////////////////
assertThat(TestUtils.LogPersonUpdate.updatedIds).isNullOrEmpty();
UpdateInput updateInput = new UpdateInput(qInstance);
updateInput.setSession(new QSession());
updateInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
updateInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("lastName", "now with a LastName"),
new QRecord().withValue("id", 2).withValue("lastName", "now with a LastName")
));
new UpdateAction().execute(updateInput);
////////////////////////////////////////////////
// have the polling executor run "for awhile" //
////////////////////////////////////////////////
runPollingAutomationExecutorForAwhile(qInstance);
///////////////////////////////////////////////////
// assert that the update-automation DID run now //
///////////////////////////////////////////////////
assertThat(TestUtils.LogPersonUpdate.updatedIds).contains(2);
}
/*******************************************************************************
@ -166,14 +114,14 @@ class PollingAutomationExecutorTest
.getAutomationDetails().getActions().get(0)
.setCodeReference(new QCodeReference(CaptureSessionIdAutomationHandler.class));
/////////////////////
// insert a person //
/////////////////////
////////////////////////////////////////////////////////////
// insert a person that will trigger the on-insert action //
////////////////////////////////////////////////////////////
InsertInput insertInput = new InsertInput(qInstance);
insertInput.setSession(new QSession());
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("firstName", "Tim")
new QRecord().withValue("id", 1).withValue("firstName", "Tim").withValue("birthDate", LocalDate.now())
));
new InsertAction().execute(insertInput);

View File

@ -0,0 +1,226 @@
package com.kingsrook.qqq.backend.core.actions.automation.polling;
import java.time.LocalDate;
import java.time.Month;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
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.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.session.QSession;
import com.kingsrook.qqq.backend.core.modules.backend.implementations.memory.MemoryRecordStore;
import com.kingsrook.qqq.backend.core.utils.TestUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
** Unit test for PollingAutomationRunner
*******************************************************************************/
class PollingAutomationRunnerTest
{
/*******************************************************************************
**
*******************************************************************************/
@BeforeEach
@AfterEach
void beforeAndAfterEach()
{
MemoryRecordStore.getInstance().reset();
}
/*******************************************************************************
** Test a cycle that does an insert, some automations, then and an update, and more automations.
*******************************************************************************/
@Test
void testInsertAndUpdate() throws QException
{
QInstance qInstance = TestUtils.defineInstance();
PollingAutomationRunner pollingAutomationRunner = new PollingAutomationRunner(qInstance, TestUtils.POLLING_AUTOMATION, null);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// insert 2 person records, one who should be both updated by the insert action, and should be logged by logger-on-update automation //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
InsertInput insertInput = new InsertInput(qInstance);
insertInput.setSession(new QSession());
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")
));
new InsertAction().execute(insertInput);
assertAllRecordsAutomationStatus(AutomationStatus.PENDING_INSERT_AUTOMATIONS);
//////////////////////////////////////////////////////////////////////////////////////////
// assert that the update-automation won't run - as no UPDATE has happened on the table //
// even though the insert action does update the records!! //
//////////////////////////////////////////////////////////////////////////////////////////
pollingAutomationRunner.run();
assertThat(TestUtils.LogPersonUpdate.updatedIds).isNullOrEmpty();
assertAllRecordsAutomationStatus(AutomationStatus.OK);
////////////////////////////////////////////
// make sure the minor person was updated //
////////////////////////////////////////////
Optional<QRecord> updatedMinorRecord = TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY).stream().filter(r -> r.getValueInteger("id").equals(1)).findFirst();
assertThat(updatedMinorRecord)
.isPresent()
.get()
.extracting(r -> r.getValueString("firstName"))
.isEqualTo("Tim" + TestUtils.CheckAge.SUFFIX_FOR_MINORS);
/////////////////////////////////////////////////////////////////////////////////////////
// run automations again - make sure that there haven't been any updates triggered yet //
/////////////////////////////////////////////////////////////////////////////////////////
pollingAutomationRunner.run();
assertThat(TestUtils.LogPersonUpdate.updatedIds).isNullOrEmpty();
assertAllRecordsAutomationStatus(AutomationStatus.OK);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// now do an user-driven update - this SHOULD trigger the update automation next time we run automations. //
////////////////////////////////////////////////////////////////////////////////////////////////////////////
UpdateInput updateInput = new UpdateInput(qInstance);
updateInput.setSession(new QSession());
updateInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
updateInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("lastName", "now with a LastName"),
new QRecord().withValue("id", 2).withValue("lastName", "now with a LastName")
));
new UpdateAction().execute(updateInput);
assertAllRecordsAutomationStatus(AutomationStatus.PENDING_UPDATE_AUTOMATIONS);
/////////////////////////////////////////////////////////////////////////////////
// assert that the update-automation DOES run now - and that it only runs once //
// note that it will only run on a sub-set of the records //
/////////////////////////////////////////////////////////////////////////////////
pollingAutomationRunner.run();
assertThat(TestUtils.LogPersonUpdate.updatedIds)
.contains(2)
.hasSize(1);
assertAllRecordsAutomationStatus(AutomationStatus.OK);
/////////////////////////////////////////////////////
// re-run and assert no further automations happen //
/////////////////////////////////////////////////////
TestUtils.LogPersonUpdate.updatedIds.clear();
pollingAutomationRunner.run();
assertThat(TestUtils.LogPersonUpdate.updatedIds).isNullOrEmpty();
assertAllRecordsAutomationStatus(AutomationStatus.OK);
}
/*******************************************************************************
** Test a large-ish number - to demonstrate paging working.
**
** Note - this caught an issue during original development, where the QueryFilter
** attached to the Action was being re-used, w/ new "id IN *" criteria being re-added
** to it - so, good test.
*******************************************************************************/
@Test
void testMultiPages() throws QException
{
QInstance qInstance = TestUtils.defineInstance();
PollingAutomationRunner pollingAutomationRunner = new PollingAutomationRunner(qInstance, TestUtils.POLLING_AUTOMATION, null);
//////////////////////////////////////////////////////////////////////////////////
// insert many people - half who should be updated by the AgeChecker automation //
//////////////////////////////////////////////////////////////////////////////////
InsertInput insertInput = new InsertInput(qInstance);
insertInput.setSession(new QSession());
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
insertInput.setRecords(new ArrayList<>());
int SIZE = 2_500;
for(int i = 0; i < SIZE; i++)
{
insertInput.getRecords().add(new QRecord().withValue("firstName", "Tim").withValue("lastName", "Number " + i).withValue("birthDate", LocalDate.now()));
insertInput.getRecords().add(new QRecord().withValue("firstName", "Darin").withValue("lastName", "Number " + i));
}
new InsertAction().execute(insertInput);
assertAllRecordsAutomationStatus(AutomationStatus.PENDING_INSERT_AUTOMATIONS);
/////////////////////////
// run the automations //
/////////////////////////
pollingAutomationRunner.run();
assertAllRecordsAutomationStatus(AutomationStatus.OK);
///////////////////////////////////////////////////////////////////////////
// make sure that all 'minor' persons were updated (e.g., all the Tim's) //
///////////////////////////////////////////////////////////////////////////
int updatedMinorsCount = 0;
for(QRecord qRecord : TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY))
{
if(qRecord.getValueString("firstName").startsWith("Tim"))
{
assertEquals("Tim" + TestUtils.CheckAge.SUFFIX_FOR_MINORS, qRecord.getValueString("firstName"));
updatedMinorsCount++;
}
}
assertEquals(SIZE, updatedMinorsCount, "Expected number of updated records");
}
/*******************************************************************************
** Test a cycle that does an insert, some automations, then and an update, and more automations.
*******************************************************************************/
@Test
void testRunningProcess() throws QException
{
QInstance qInstance = TestUtils.defineInstance();
PollingAutomationRunner pollingAutomationRunner = new PollingAutomationRunner(qInstance, TestUtils.POLLING_AUTOMATION, null);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// insert 2 person records, one who should be both updated by the insert action, and should be logged by logger-on-update automation //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
InsertInput insertInput = new InsertInput(qInstance);
insertInput.setSession(new QSession());
insertInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY);
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("firstName", "Tim").withValue("birthDate", LocalDate.of(1886, Month.JUNE, 6)),
new QRecord().withValue("id", 2).withValue("firstName", "Darin").withValue("birthDate", LocalDate.of(1904, Month.APRIL, 4))
));
new InsertAction().execute(insertInput);
pollingAutomationRunner.run();
/////////////////////////////////////////////////////////////////////////////////////////////
// make sure the process ran - which means, it would have updated Tim's birth year to 1900 //
/////////////////////////////////////////////////////////////////////////////////////////////
Optional<QRecord> updatedMinorRecord = TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY).stream().filter(r -> r.getValueInteger("id").equals(1)).findFirst();
assertThat(updatedMinorRecord)
.isPresent()
.get()
.extracting(r -> r.getValueLocalDate("birthDate").getYear())
.isEqualTo(1900);
}
/*******************************************************************************
**
*******************************************************************************/
private void assertAllRecordsAutomationStatus(AutomationStatus pendingInsertAutomations) throws QException
{
assertThat(TestUtils.queryTable(TestUtils.TABLE_NAME_PERSON_MEMORY))
.isNotEmpty()
.allMatch(r -> pendingInsertAutomations.getId().equals(r.getValue(TestUtils.standardQqqAutomationStatusField().getName())));
}
}

View File

@ -81,7 +81,7 @@ class ReportActionTest
public void testBigger() throws Exception
{
// int recordCount = 2_000_000; // to really stress locally, use this.
int recordCount = 50_000;
int recordCount = 10_000;
String filename = "/tmp/ReportActionTest.csv";
runReport(recordCount, filename, ReportFormat.CSV, false);

View File

@ -22,6 +22,8 @@
package com.kingsrook.qqq.backend.core.modules.backend.implementations.memory;
import java.time.LocalDate;
import java.time.Month;
import java.util.List;
import java.util.function.Function;
import com.kingsrook.qqq.backend.core.actions.customizers.TableCustomizers;
@ -54,6 +56,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -193,6 +196,101 @@ class MemoryBackendModuleTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testQueryOperators() throws QException
{
QInstance qInstance = TestUtils.defineInstance();
QTableMetaData table = qInstance.getTable(TestUtils.TABLE_NAME_SHAPE);
QSession session = new QSession();
InsertInput insertInput = new InsertInput(qInstance);
insertInput.setSession(session);
insertInput.setTableName(table.getName());
insertInput.setRecords(List.of(
new QRecord().withValue("id", 1).withValue("name", "Square").withValue("date", LocalDate.of(1980, Month.MAY, 31)),
new QRecord().withValue("id", 2).withValue("name", "Triangle").withValue("date", LocalDate.of(1999, Month.DECEMBER, 31))
));
new InsertAction().execute(insertInput);
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.IN, List.of(1, 2))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.IN, List.of(2, 3))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.NOT_IN, List.of(3, 4))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.NOT_IN, List.of(2, 3))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.EQUALS, List.of("Square"))).size());
assertEquals("Square", queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.EQUALS, List.of("Square"))).get(0).getValue("name"));
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("notAFieldSoNull", QCriteriaOperator.EQUALS, List.of("Square"))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.NOT_EQUALS, List.of("notFound"))).size());
assertEquals("Square", queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.NOT_EQUALS, List.of("Triangle"))).get(0).getValue("name"));
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.CONTAINS, List.of("ria"))).size());
assertEquals("Triangle", queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.CONTAINS, List.of("ria"))).get(0).getValue("name"));
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.NOT_CONTAINS, List.of("notFound"))).size());
assertEquals("Square", queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.NOT_CONTAINS, List.of("ria"))).get(0).getValue("name"));
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.CONTAINS, List.of("ria"))));
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.CONTAINS, List.of(1))));
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.CONTAINS, List.of())));
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.GREATER_THAN, List.of(LocalDate.of(2022, Month.SEPTEMBER, 1)))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.GREATER_THAN, List.of(LocalDate.of(1990, Month.JANUARY, 1)))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.GREATER_THAN, List.of(LocalDate.of(1970, Month.JANUARY, 1)))).size());
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN, List.of(2))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN, List.of(1))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN, List.of(0))).size());
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(LocalDate.of(2022, Month.SEPTEMBER, 1)))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(LocalDate.of(1990, Month.JANUARY, 1)))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(LocalDate.of(1970, Month.JANUARY, 1)))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(LocalDate.of(1980, Month.MAY, 31)))).size());
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(3))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(2))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(1))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of(0))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.LESS_THAN, List.of(LocalDate.of(2022, Month.SEPTEMBER, 1)))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.LESS_THAN, List.of(LocalDate.of(1990, Month.JANUARY, 1)))).size());
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.LESS_THAN, List.of(LocalDate.of(1970, Month.JANUARY, 1)))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, List.of(3))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, List.of(2))).size());
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, List.of(1))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(LocalDate.of(2022, Month.SEPTEMBER, 1)))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(LocalDate.of(1990, Month.JANUARY, 1)))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(LocalDate.of(1980, Month.MAY, 31)))).size());
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("date", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(LocalDate.of(1970, Month.JANUARY, 1)))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(3))).size());
assertEquals(2, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(2))).size());
assertEquals(1, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(1))).size());
assertEquals(0, queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of(0))).size());
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN, List.of())));
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.GREATER_THAN_OR_EQUALS, List.of())));
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN, List.of())));
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("id", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of())));
assertThrows(QException.class, () -> queryShapes(qInstance, table, session, new QFilterCriteria("name", QCriteriaOperator.LESS_THAN_OR_EQUALS, List.of("Bob"))));
}
private List<QRecord> queryShapes(QInstance qInstance, QTableMetaData table, QSession session, QFilterCriteria criteria) throws QException
{
QueryInput queryInput = new QueryInput(qInstance);
queryInput.setSession(session);
queryInput.setTableName(table.getName());
queryInput.setFilter(new QQueryFilter().withCriteria(criteria));
QueryOutput queryOutput = new QueryAction().execute(queryInput);
return queryOutput.getRecords();
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -24,10 +24,12 @@ package com.kingsrook.qqq.backend.core.utils;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.Month;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.actions.automation.AutomationStatus;
import com.kingsrook.qqq.backend.core.actions.automation.RecordAutomationHandler;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.AddAge;
import com.kingsrook.qqq.backend.core.actions.processes.person.addtopeoplesage.GetAgeStatistics;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
@ -35,6 +37,8 @@ import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.actions.tables.UpdateAction;
import com.kingsrook.qqq.backend.core.actions.values.QCustomPossibleValueProvider;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
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;
@ -65,10 +69,10 @@ import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMet
import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionOutputMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.processes.QRecordListMetaData;
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;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.TableAutomationAction;
import com.kingsrook.qqq.backend.core.model.metadata.tables.automation.TriggerEvent;
import com.kingsrook.qqq.backend.core.model.session.QSession;
@ -103,6 +107,7 @@ public class TestUtils
public static final String PROCESS_NAME_GREET_PEOPLE = "greet";
public static final String PROCESS_NAME_GREET_PEOPLE_INTERACTIVE = "greetInteractive";
public static final String PROCESS_NAME_INCREASE_BIRTHDATE = "increaseBirthdate";
public static final String PROCESS_NAME_ADD_TO_PEOPLES_AGE = "addToPeoplesAge";
public static final String TABLE_NAME_PERSON_FILE = "personFile";
public static final String TABLE_NAME_PERSON_MEMORY = "personMemory";
@ -144,6 +149,7 @@ public class TestUtils
qInstance.addProcess(defineProcessAddToPeoplesAge());
qInstance.addProcess(new BasicETLProcess().defineProcessMetaData());
qInstance.addProcess(new StreamedETLProcess().defineProcessMetaData());
qInstance.addProcess(defineProcessIncreasePersonBirthdate());
qInstance.addAutomationProvider(definePollingAutomationProvider());
@ -154,6 +160,72 @@ public class TestUtils
/*******************************************************************************
**
*******************************************************************************/
private static QProcessMetaData defineProcessIncreasePersonBirthdate()
{
return new QProcessMetaData()
.withName(PROCESS_NAME_INCREASE_BIRTHDATE)
.withTableName(TABLE_NAME_PERSON_MEMORY)
.addStep(new QFrontendStepMetaData()
.withName("preview")
)
.addStep(new QBackendStepMetaData()
.withName("doWork")
.withCode(new QCodeReference(IncreaseBirthdateStep.class))
.withInputData(new QFunctionInputMetaData()
.withRecordListMetaData(new QRecordListMetaData().withTableName(TABLE_NAME_PERSON_MEMORY)))
.withOutputMetaData(new QFunctionOutputMetaData()
.withFieldList(List.of(new QFieldMetaData("outputMessage", QFieldType.STRING).withDefaultValue("Success!"))))
)
.addStep(new QFrontendStepMetaData()
.withName("results")
.withFormField(new QFieldMetaData("outputMessage", QFieldType.STRING))
);
}
/*******************************************************************************
**
*******************************************************************************/
public static class IncreaseBirthdateStep implements BackendStep
{
/*******************************************************************************
** Execute the backend step - using the request as input, and the result as output.
**
*******************************************************************************/
@Override
public void run(RunBackendStepInput runBackendStepInput, RunBackendStepOutput runBackendStepOutput) throws QException
{
List<QRecord> recordsToUpdate = new ArrayList<>();
for(QRecord record : runBackendStepInput.getRecords())
{
LocalDate birthDate = record.getValueLocalDate("birthDate");
if(birthDate != null && birthDate.getYear() < 1900)
{
recordsToUpdate.add(new QRecord()
.withValue("id", record.getValue("id"))
.withValue("birthDate", birthDate.withYear(1900))
);
}
}
UpdateInput updateInput = new UpdateInput(runBackendStepInput.getInstance());
updateInput.setSession(runBackendStepInput.getSession());
updateInput.setTableName(TABLE_NAME_PERSON_MEMORY);
updateInput.setRecords(recordsToUpdate);
new UpdateAction().execute(updateInput);
}
}
/*******************************************************************************
**
*******************************************************************************/
@ -375,6 +447,16 @@ public class TestUtils
*******************************************************************************/
public static QTableMetaData definePersonMemoryTable()
{
/////////////////////////////////////////////////////////////////////////////
// the checkAge automation will only run on persons younger than this date //
/////////////////////////////////////////////////////////////////////////////
LocalDate youngPersonLimitDate = LocalDate.now().minusYears(18);
/////////////////////////////////////////////////////////////////////////////////////
// the increaseBirthdate automation will only run on persons born before this date //
/////////////////////////////////////////////////////////////////////////////////////
LocalDate increaseBirthdateLimitDate = LocalDate.of(1900, Month.JANUARY, 1);
return (new QTableMetaData()
.withName(TABLE_NAME_PERSON_MEMORY)
.withBackendName(MEMORY_BACKEND_NAME)
@ -386,12 +468,19 @@ public class TestUtils
.withAction(new TableAutomationAction()
.withName("checkAgeOnInsert")
.withTriggerEvent(TriggerEvent.POST_INSERT)
.withFilter(new QQueryFilter().withCriteria(new QFilterCriteria("birthDate", QCriteriaOperator.GREATER_THAN, List.of(youngPersonLimitDate))))
.withCodeReference(new QCodeReference(CheckAge.class))
)
.withAction(new TableAutomationAction()
.withName("increaseBirthdate")
.withTriggerEvent(TriggerEvent.POST_INSERT)
.withFilter(new QQueryFilter().withCriteria(new QFilterCriteria("birthDate", QCriteriaOperator.LESS_THAN, List.of(increaseBirthdateLimitDate))))
.withProcessName(PROCESS_NAME_INCREASE_BIRTHDATE)
)
.withAction(new TableAutomationAction()
.withName("logOnUpdatePerFilter")
.withTriggerEvent(TriggerEvent.POST_UPDATE)
.withFilter(new QQueryFilter().withCriteria(new QFilterCriteria("firstName", QCriteriaOperator.EQUALS, List.of("Darin"))))
.withFilter(new QQueryFilter().withCriteria(new QFilterCriteria("firstName", QCriteriaOperator.CONTAINS, List.of("Darin"))))
.withCodeReference(new QCodeReference(LogPersonUpdate.class))
)
);
@ -420,7 +509,6 @@ public class TestUtils
LocalDate birthDate = record.getValueLocalDate("birthDate");
if(birthDate != null && birthDate.isAfter(limitDate))
{
LOG.info("Person [" + record.getValueInteger("id") + "] is a minor - updating their firstName to state such.");
recordsToUpdate.add(new QRecord()
.withValue("id", record.getValue("id"))
.withValue("firstName", record.getValueString("firstName") + SUFFIX_FOR_MINORS)