mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
Implement min/max records enforcement
This commit is contained in:
@ -34,6 +34,7 @@ import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
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.query.QQueryFilter;
|
||||
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.metadata.code.QCodeReference;
|
||||
@ -82,7 +83,7 @@ public class RunBackendStepAction
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// ensure input data is set as needed - use callback object to get anything missing //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
ensureRecordsAreInRequest(runBackendStepInput, backendStepMetaData);
|
||||
ensureRecordsAreInRequest(runBackendStepInput, backendStepMetaData, process);
|
||||
ensureInputFieldsAreInRequest(runBackendStepInput, backendStepMetaData);
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -167,7 +168,7 @@ public class RunBackendStepAction
|
||||
** check if this step uses a record list - and if so, if we need to get one
|
||||
** via the callback
|
||||
*******************************************************************************/
|
||||
private void ensureRecordsAreInRequest(RunBackendStepInput runBackendStepInput, QBackendStepMetaData step) throws QException
|
||||
private void ensureRecordsAreInRequest(RunBackendStepInput runBackendStepInput, QBackendStepMetaData step, QProcessMetaData process) throws QException
|
||||
{
|
||||
QFunctionInputMetaData inputMetaData = step.getInputMetaData();
|
||||
if(inputMetaData != null && inputMetaData.getRecordListMetaData() != null)
|
||||
@ -190,9 +191,44 @@ public class RunBackendStepAction
|
||||
|
||||
queryInput.setFilter(callback.getQueryFilter());
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if process has a max-no of records, set a limit on the process of that number plus 1 //
|
||||
// (the plus 1 being so we can see "oh, you selected more than that many; error!" //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
if(process.getMaxInputRecords() != null)
|
||||
{
|
||||
if(callback.getQueryFilter() == null)
|
||||
{
|
||||
queryInput.setFilter(new QQueryFilter());
|
||||
}
|
||||
|
||||
queryInput.getFilter().setLimit(process.getMaxInputRecords() + 1);
|
||||
}
|
||||
|
||||
QueryOutput queryOutput = new QueryAction().execute(queryInput);
|
||||
runBackendStepInput.setRecords(queryOutput.getRecords());
|
||||
// todo - handle 0 results found?
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// if process defines a max, and more than the max were found, throw an error //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
if(process.getMaxInputRecords() != null)
|
||||
{
|
||||
if(queryOutput.getRecords().size() > process.getMaxInputRecords())
|
||||
{
|
||||
throw (new QUserFacingException("Too many records were selected for this process. At most, only " + process.getMaxInputRecords() + " can be selected."));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// if process defines a min, and fewer than the min were found, throw an error //
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
if(process.getMinInputRecords() != null)
|
||||
{
|
||||
if(queryOutput.getRecords().size() < process.getMinInputRecords())
|
||||
{
|
||||
throw (new QUserFacingException("Too few records were selected for this process. At least " + process.getMinInputRecords() + " must be selected."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,13 +27,21 @@ import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
|
||||
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.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.data.QRecord;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
|
||||
import com.kingsrook.qqq.backend.core.utils.TestUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@ -53,7 +61,7 @@ public class RunBackendStepActionTest extends BaseTest
|
||||
{
|
||||
TestCallback callback = new TestCallback();
|
||||
RunBackendStepInput request = new RunBackendStepInput();
|
||||
request.setProcessName("greet");
|
||||
request.setProcessName(TestUtils.PROCESS_NAME_GREET_PEOPLE);
|
||||
request.setStepName("prepare");
|
||||
request.setCallback(callback);
|
||||
RunBackendStepOutput result = new RunBackendStepAction().execute(request);
|
||||
@ -67,6 +75,60 @@ public class RunBackendStepActionTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testMinMaxInputRecords() throws QException
|
||||
{
|
||||
////////////////////////////////////////////
|
||||
// put a min-input-records on the process //
|
||||
////////////////////////////////////////////
|
||||
QContext.getQInstance().getProcess(TestUtils.PROCESS_NAME_GREET_PEOPLE).withMinInputRecords(5);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// insert fewer than that min - then run w/ non-filtered filter, and assert we fail //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_PERSON_MEMORY).withRecord(new QRecord().withValue("firstName", String.valueOf(i))));
|
||||
}
|
||||
|
||||
Supplier<RunBackendStepInput> inputSupplier = () ->
|
||||
{
|
||||
RunBackendStepInput input = new RunBackendStepInput();
|
||||
input.setProcessName(TestUtils.PROCESS_NAME_GREET_PEOPLE);
|
||||
input.setStepName("prepare");
|
||||
input.setCallback(QProcessCallbackFactory.forFilter(new QQueryFilter()));
|
||||
return (input);
|
||||
};
|
||||
|
||||
assertThatThrownBy(() -> new RunBackendStepAction().execute(inputSupplier.get()))
|
||||
.isInstanceOf(QUserFacingException.class)
|
||||
.hasMessageContaining("Too few records");
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// insert a few more - and then it should succeed //
|
||||
////////////////////////////////////////////////////
|
||||
for(int i = 3; i < 10; i++)
|
||||
{
|
||||
new InsertAction().execute(new InsertInput(TestUtils.TABLE_NAME_PERSON_MEMORY).withRecord(new QRecord().withValue("firstName", String.valueOf(i))));
|
||||
}
|
||||
|
||||
new RunBackendStepAction().execute(inputSupplier.get());
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// now put a max on the process, and it should fail again //
|
||||
////////////////////////////////////////////////////////////
|
||||
QContext.getQInstance().getProcess(TestUtils.PROCESS_NAME_GREET_PEOPLE).withMaxInputRecords(8);
|
||||
|
||||
assertThatThrownBy(() -> new RunBackendStepAction().execute(inputSupplier.get()))
|
||||
.isInstanceOf(QUserFacingException.class)
|
||||
.hasMessageContaining("Too many records");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -100,20 +162,20 @@ public class RunBackendStepActionTest extends BaseTest
|
||||
for(QFieldMetaData field : fields)
|
||||
{
|
||||
rs.put(field.getName(), switch(field.getType())
|
||||
{
|
||||
case STRING -> "ABC";
|
||||
case INTEGER -> 42;
|
||||
case LONG -> 42L;
|
||||
case DECIMAL -> new BigDecimal("47");
|
||||
case BOOLEAN -> true;
|
||||
case DATE, TIME, DATE_TIME -> null;
|
||||
case TEXT -> """
|
||||
ABC
|
||||
XYZ""";
|
||||
case HTML -> "<b>Oh my</b>";
|
||||
case PASSWORD -> "myPa**word";
|
||||
case BLOB -> new byte[] { 1, 2, 3, 4 };
|
||||
});
|
||||
{
|
||||
case STRING -> "ABC";
|
||||
case INTEGER -> 42;
|
||||
case LONG -> 42L;
|
||||
case DECIMAL -> new BigDecimal("47");
|
||||
case BOOLEAN -> true;
|
||||
case DATE, TIME, DATE_TIME -> null;
|
||||
case TEXT -> """
|
||||
ABC
|
||||
XYZ""";
|
||||
case HTML -> "<b>Oh my</b>";
|
||||
case PASSWORD -> "myPa**word";
|
||||
case BLOB -> new byte[] { 1, 2, 3, 4 };
|
||||
});
|
||||
}
|
||||
return (rs);
|
||||
}
|
||||
|
Reference in New Issue
Block a user