Missed things re: custom pvs

This commit is contained in:
2023-02-23 13:19:13 -06:00
parent 8440536d35
commit ea795ed701
6 changed files with 166 additions and 12 deletions

View File

@ -22,6 +22,7 @@
package com.kingsrook.qqq.backend.core.actions.dashboard.widgets; package com.kingsrook.qqq.backend.core.actions.dashboard.widgets;
import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.Instant; import java.time.Instant;
@ -270,6 +271,16 @@ public class NoCodeWidgetVelocityUtils
/*******************************************************************************
**
*******************************************************************************/
public String format(String displayFormat, Serializable value)
{
return (QValueFormatter.formatValue(displayFormat, value));
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -36,18 +36,20 @@ import com.kingsrook.qqq.backend.core.utils.ValueUtils;
/******************************************************************************* /*******************************************************************************
** Interface to be implemented by user-defined code that serves as the backing ** Interface to be implemented by user-defined code that serves as the backing
** for a CUSTOM type possibleValueSource ** for a CUSTOM type possibleValueSource
**
** Type parameter `T` is the id-type of the possible value.
*******************************************************************************/ *******************************************************************************/
public interface QCustomPossibleValueProvider public interface QCustomPossibleValueProvider<T extends Serializable>
{ {
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
QPossibleValue<?> getPossibleValue(Serializable idValue); QPossibleValue<T> getPossibleValue(Serializable idValue);
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
List<QPossibleValue<?>> search(SearchPossibleValueSourceInput input) throws QException; List<QPossibleValue<T>> search(SearchPossibleValueSourceInput input) throws QException;
/******************************************************************************* /*******************************************************************************
@ -55,7 +57,7 @@ public interface QCustomPossibleValueProvider
** the type of the ids in the enum (e.g., strings from a frontend, integers ** the type of the ids in the enum (e.g., strings from a frontend, integers
** in an enum). So, this method looks maps a list of input ids to the requested type. ** in an enum). So, this method looks maps a list of input ids to the requested type.
*******************************************************************************/ *******************************************************************************/
default <T extends Serializable> List<T> convertInputIdsToIdType(Class<T> type, List<Serializable> inputIdList) default List<T> convertInputIdsToIdType(Class<T> type, List<Serializable> inputIdList)
{ {
List<T> rs = new ArrayList<>(); List<T> rs = new ArrayList<>();
if(CollectionUtils.nullSafeIsEmpty(inputIdList)) if(CollectionUtils.nullSafeIsEmpty(inputIdList))
@ -75,10 +77,8 @@ public interface QCustomPossibleValueProvider
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
default <T extends Serializable> boolean doesPossibleValueMatchSearchInput(Class<T> idType, QPossibleValue<T> possibleValue, SearchPossibleValueSourceInput input) default boolean doesPossibleValueMatchSearchInput(List<T> idsInType, QPossibleValue<T> possibleValue, SearchPossibleValueSourceInput input)
{ {
List<T> idsInType = convertInputIdsToIdType(idType, input.getIdList());
boolean match = false; boolean match = false;
if(input.getIdList() != null) if(input.getIdList() != null)
{ {

View File

@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.model.metadata.possiblevalues;
/******************************************************************************* /*******************************************************************************
** An actual possible value - an id and label. ** An actual possible value - an id and label.
** **
** Type parameter `T` is the type of the id (often Integer, maybe String)
*******************************************************************************/ *******************************************************************************/
public class QPossibleValue<T> public class QPossibleValue<T>
{ {

View File

@ -224,6 +224,82 @@ class SearchPossibleValueSourceActionTest extends BaseTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSearchPvsAction_customSearchTermFound() throws QException
{
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput("Custom[3]", TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
assertEquals(1, output.getResults().size());
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals("3") && pv.getLabel().equals("Custom[3]"));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSearchPvsAction_customSearchTermNotFound() throws QException
{
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput("Foo", TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
assertEquals(0, output.getResults().size());
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSearchPvsAction_customSearchTermManyFound() throws QException
{
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput("Custom", TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
assertEquals(10, output.getResults().size());
assertThat(output.getResults()).allMatch(pv -> pv.getLabel().startsWith("Custom["));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSearchPvsAction_customIdFound() throws QException
{
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputById("4", TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
assertEquals(1, output.getResults().size());
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals("4") && pv.getLabel().equals("Custom[4]"));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSearchPvsAction_customIdFoundDifferentType() throws QException
{
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputById(5, TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
assertEquals(1, output.getResults().size());
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals("5") && pv.getLabel().equals("Custom[5]"));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testSearchPvsAction_customIdNotFound() throws QException
{
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputById(-1, TestUtils.POSSIBLE_VALUE_SOURCE_CUSTOM);
assertEquals(0, output.getResults().size());
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/

View File

@ -1083,16 +1083,16 @@ public class TestUtils
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
public static class CustomPossibleValueSource implements QCustomPossibleValueProvider public static class CustomPossibleValueSource implements QCustomPossibleValueProvider<String>
{ {
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@Override @Override
public QPossibleValue<?> getPossibleValue(Serializable idValue) public QPossibleValue<String> getPossibleValue(Serializable idValue)
{ {
return (new QPossibleValue<>(idValue, "Custom[" + idValue + "]")); return (new QPossibleValue<>(ValueUtils.getValueAsString(idValue), "Custom[" + idValue + "]"));
} }
@ -1101,9 +1101,19 @@ public class TestUtils
** **
*******************************************************************************/ *******************************************************************************/
@Override @Override
public List<QPossibleValue<?>> search(SearchPossibleValueSourceInput input) public List<QPossibleValue<String>> search(SearchPossibleValueSourceInput input)
{ {
return (new ArrayList<>()); List<QPossibleValue<String>> rs = new ArrayList<>();
for(int i = 0; i < 10; i++)
{
QPossibleValue<String> possibleValue = getPossibleValue(i);
List<String> idsInType = convertInputIdsToIdType(String.class, input.getIdList());
if(doesPossibleValueMatchSearchInput(idsInType, possibleValue, input))
{
rs.add(possibleValue);
}
}
return (rs);
} }
} }

View File

@ -50,6 +50,7 @@ import com.kingsrook.qqq.backend.core.actions.processes.RunProcessAction;
import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction; import com.kingsrook.qqq.backend.core.actions.reporting.GenerateReportAction;
import com.kingsrook.qqq.backend.core.actions.tables.InsertAction; import com.kingsrook.qqq.backend.core.actions.tables.InsertAction;
import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter; import com.kingsrook.qqq.backend.core.actions.values.QValueFormatter;
import com.kingsrook.qqq.backend.core.actions.values.SearchPossibleValueSourceAction;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException; import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException; import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException; import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
@ -65,6 +66,8 @@ 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.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria; 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.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceInput;
import com.kingsrook.qqq.backend.core.model.actions.values.SearchPossibleValueSourceOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord; 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.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
@ -126,6 +129,8 @@ public class QJavalinProcessHandler
get("/status/{jobUUID}", QJavalinProcessHandler::processStatus); get("/status/{jobUUID}", QJavalinProcessHandler::processStatus);
get("/records", QJavalinProcessHandler::processRecords); get("/records", QJavalinProcessHandler::processRecords);
}); });
get("/possibleValues/{fieldName}", QJavalinProcessHandler::possibleValues);
}); });
}); });
get("/download/{file}", QJavalinProcessHandler::downloadFile); get("/download/{file}", QJavalinProcessHandler::downloadFile);
@ -734,6 +739,57 @@ public class QJavalinProcessHandler
/*******************************************************************************
**
*******************************************************************************/
private static void possibleValues(Context context)
{
try
{
String processName = context.pathParam("processName");
String fieldName = context.pathParam("fieldName");
String searchTerm = context.queryParam("searchTerm");
String ids = context.queryParam("ids");
QProcessMetaData process = QJavalinImplementation.qInstance.getProcess(processName);
if(process == null)
{
throw (new QNotFoundException("Could not find process named " + processName + " in this instance."));
}
Optional<QFieldMetaData> optField = process.getInputFields().stream().filter(f -> f.getName().equals(fieldName)).findFirst();
QFieldMetaData field = optField.orElseThrow(() -> new QNotFoundException("Could not find field named " + fieldName + " in process " + processName + "."));
if(!StringUtils.hasContent(field.getPossibleValueSourceName()))
{
throw (new QNotFoundException("Field " + fieldName + " in process " + processName + " is not associated with a possible value source."));
}
SearchPossibleValueSourceInput input = new SearchPossibleValueSourceInput();
QJavalinImplementation.setupSession(context, input);
input.setPossibleValueSourceName(field.getPossibleValueSourceName());
input.setSearchTerm(searchTerm);
if(StringUtils.hasContent(ids))
{
List<Serializable> idList = new ArrayList<>(Arrays.asList(ids.split(",")));
input.setIdList(idList);
}
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(input);
Map<String, Object> result = new HashMap<>();
result.put("options", output.getResults());
context.result(JsonUtils.toJson(result));
}
catch(Exception e)
{
QJavalinImplementation.handleException(context, e);
}
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/