mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
CE-1955 Add search-by labels - e.g., exact-matches on a single-field used as the PVS's label... definitely not perfect, but a passable first-version for bulk-load to do PVS mapping
This commit is contained in:
@ -26,8 +26,12 @@ import java.io.Serializable;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||||
@ -50,7 +54,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
|
|||||||
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
import com.kingsrook.qqq.backend.core.utils.StringUtils;
|
||||||
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
|
||||||
import org.apache.commons.lang.NotImplementedException;
|
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -61,6 +65,9 @@ public class SearchPossibleValueSourceAction
|
|||||||
{
|
{
|
||||||
private static final QLogger LOG = QLogger.getLogger(SearchPossibleValueSourceAction.class);
|
private static final QLogger LOG = QLogger.getLogger(SearchPossibleValueSourceAction.class);
|
||||||
|
|
||||||
|
private static final Set<String> warnedAboutUnexpectedValueField = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
private static final Set<String> warnedAboutUnexpectedNoOfFieldsToSearchByLabel = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
private QPossibleValueTranslator possibleValueTranslator;
|
private QPossibleValueTranslator possibleValueTranslator;
|
||||||
|
|
||||||
|
|
||||||
@ -110,6 +117,7 @@ public class SearchPossibleValueSourceAction
|
|||||||
List<Serializable> matchingIds = new ArrayList<>();
|
List<Serializable> matchingIds = new ArrayList<>();
|
||||||
|
|
||||||
List<?> inputIdsAsCorrectType = convertInputIdsToEnumIdType(possibleValueSource, input.getIdList());
|
List<?> inputIdsAsCorrectType = convertInputIdsToEnumIdType(possibleValueSource, input.getIdList());
|
||||||
|
Set<String> labels = null;
|
||||||
|
|
||||||
for(QPossibleValue<?> possibleValue : possibleValueSource.getEnumValues())
|
for(QPossibleValue<?> possibleValue : possibleValueSource.getEnumValues())
|
||||||
{
|
{
|
||||||
@ -122,6 +130,18 @@ public class SearchPossibleValueSourceAction
|
|||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(input.getLabelList() != null)
|
||||||
|
{
|
||||||
|
if(labels == null)
|
||||||
|
{
|
||||||
|
labels = input.getLabelList().stream().filter(Objects::nonNull).map(l -> l.toLowerCase()).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(labels.contains(possibleValue.getLabel().toLowerCase()))
|
||||||
|
{
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(StringUtils.hasContent(input.getSearchTerm()))
|
if(StringUtils.hasContent(input.getSearchTerm()))
|
||||||
@ -168,22 +188,38 @@ public class SearchPossibleValueSourceAction
|
|||||||
|
|
||||||
Object anIdFromTheEnum = possibleValueSource.getEnumValues().get(0).getId();
|
Object anIdFromTheEnum = possibleValueSource.getEnumValues().get(0).getId();
|
||||||
|
|
||||||
|
for(Serializable inputId : inputIdList)
|
||||||
|
{
|
||||||
|
Object properlyTypedId = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
if(anIdFromTheEnum instanceof Integer)
|
if(anIdFromTheEnum instanceof Integer)
|
||||||
{
|
{
|
||||||
inputIdList.forEach(id -> rs.add(ValueUtils.getValueAsInteger(id)));
|
properlyTypedId = ValueUtils.getValueAsInteger(inputId);
|
||||||
}
|
}
|
||||||
else if(anIdFromTheEnum instanceof String)
|
else if(anIdFromTheEnum instanceof String)
|
||||||
{
|
{
|
||||||
inputIdList.forEach(id -> rs.add(ValueUtils.getValueAsString(id)));
|
properlyTypedId = ValueUtils.getValueAsString(inputId);
|
||||||
}
|
}
|
||||||
else if(anIdFromTheEnum instanceof Boolean)
|
else if(anIdFromTheEnum instanceof Boolean)
|
||||||
{
|
{
|
||||||
inputIdList.forEach(id -> rs.add(ValueUtils.getValueAsBoolean(id)));
|
properlyTypedId = ValueUtils.getValueAsBoolean(inputId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG.warn("Unexpected type [" + anIdFromTheEnum.getClass().getSimpleName() + "] for ids in enum: " + possibleValueSource.getName());
|
LOG.warn("Unexpected type [" + anIdFromTheEnum.getClass().getSimpleName() + "] for ids in enum: " + possibleValueSource.getName());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.debug("Error converting possible value id to expected id type", e, logPair("value", inputId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properlyTypedId != null)
|
||||||
|
{
|
||||||
|
rs.add(properlyTypedId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (rs);
|
return (rs);
|
||||||
}
|
}
|
||||||
@ -209,6 +245,53 @@ public class SearchPossibleValueSourceAction
|
|||||||
{
|
{
|
||||||
queryFilter.addCriteria(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, input.getIdList()));
|
queryFilter.addCriteria(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.IN, input.getIdList()));
|
||||||
}
|
}
|
||||||
|
else if(input.getLabelList() != null)
|
||||||
|
{
|
||||||
|
List<String> fieldNames = new ArrayList<>();
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// the 'value fields' will either be 'id' or 'label' (which means, use the fields from the tableMetaData's label fields) //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
for(String valueField : possibleValueSource.getValueFields())
|
||||||
|
{
|
||||||
|
if("id".equals(valueField))
|
||||||
|
{
|
||||||
|
fieldNames.add(table.getPrimaryKeyField());
|
||||||
|
}
|
||||||
|
else if("label".equals(valueField))
|
||||||
|
{
|
||||||
|
if(table.getRecordLabelFields() != null)
|
||||||
|
{
|
||||||
|
fieldNames.addAll(table.getRecordLabelFields());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String message = "Unexpected valueField defined in possibleValueSource when searching possibleValueSource by label (required: 'id' or 'label')";
|
||||||
|
if(!warnedAboutUnexpectedValueField.contains(possibleValueSource.getName()))
|
||||||
|
{
|
||||||
|
LOG.warn(message, logPair("valueField", valueField), logPair("possibleValueSource", possibleValueSource.getName()));
|
||||||
|
warnedAboutUnexpectedValueField.add(possibleValueSource.getName());
|
||||||
|
}
|
||||||
|
output.setWarning(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fieldNames.size() == 1)
|
||||||
|
{
|
||||||
|
queryFilter.addCriteria(new QFilterCriteria(fieldNames.get(0), QCriteriaOperator.IN, input.getLabelList()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String message = "Unexpected number of fields found for searching possibleValueSource by label (required: 1, found: " + fieldNames.size() + ")";
|
||||||
|
if(!warnedAboutUnexpectedNoOfFieldsToSearchByLabel.contains(possibleValueSource.getName()))
|
||||||
|
{
|
||||||
|
LOG.warn(message);
|
||||||
|
warnedAboutUnexpectedNoOfFieldsToSearchByLabel.add(possibleValueSource.getName());
|
||||||
|
}
|
||||||
|
output.setWarning(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
String searchTerm = input.getSearchTerm();
|
String searchTerm = input.getSearchTerm();
|
||||||
@ -269,8 +352,8 @@ public class SearchPossibleValueSourceAction
|
|||||||
queryFilter = input.getDefaultQueryFilter();
|
queryFilter = input.getDefaultQueryFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo - skip & limit as params
|
queryFilter.setLimit(input.getLimit());
|
||||||
queryFilter.setLimit(250);
|
queryFilter.setSkip(input.getSkip());
|
||||||
|
|
||||||
queryFilter.setOrderBys(possibleValueSource.getOrderByFields());
|
queryFilter.setOrderBys(possibleValueSource.getOrderByFields());
|
||||||
|
|
||||||
@ -301,7 +384,7 @@ public class SearchPossibleValueSourceAction
|
|||||||
**
|
**
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private SearchPossibleValueSourceOutput searchPossibleValueCustom(SearchPossibleValueSourceInput input, QPossibleValueSource possibleValueSource)
|
private SearchPossibleValueSourceOutput searchPossibleValueCustom(SearchPossibleValueSourceInput input, QPossibleValueSource possibleValueSource) throws QException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -314,11 +397,10 @@ public class SearchPossibleValueSourceAction
|
|||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
// LOG.warn("Error sending [" + value + "] for field [" + field + "] through custom code for PVS [" + field.getPossibleValueSourceName() + "]", e);
|
String message = "Error sending searching custom possible value source [" + input.getPossibleValueSourceName() + "]";
|
||||||
|
LOG.warn(message, e);
|
||||||
|
throw (new QException(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException("Not impleemnted");
|
|
||||||
// return (null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,10 @@ public class SearchPossibleValueSourceInput extends AbstractActionInput implemen
|
|||||||
private QQueryFilter defaultQueryFilter;
|
private QQueryFilter defaultQueryFilter;
|
||||||
private String searchTerm;
|
private String searchTerm;
|
||||||
private List<Serializable> idList;
|
private List<Serializable> idList;
|
||||||
|
private List<String> labelList;
|
||||||
|
|
||||||
private Integer skip = 0;
|
private Integer skip = 0;
|
||||||
private Integer limit = 100;
|
private Integer limit = 250;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -281,4 +282,35 @@ public class SearchPossibleValueSourceInput extends AbstractActionInput implemen
|
|||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for labelList
|
||||||
|
*******************************************************************************/
|
||||||
|
public List<String> getLabelList()
|
||||||
|
{
|
||||||
|
return (this.labelList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for labelList
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setLabelList(List<String> labelList)
|
||||||
|
{
|
||||||
|
this.labelList = labelList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for labelList
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceInput withLabelList(List<String> labelList)
|
||||||
|
{
|
||||||
|
this.labelList = labelList;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ public class SearchPossibleValueSourceOutput extends AbstractActionOutput
|
|||||||
{
|
{
|
||||||
private List<QPossibleValue<?>> results = new ArrayList<>();
|
private List<QPossibleValue<?>> results = new ArrayList<>();
|
||||||
|
|
||||||
|
private String warning;
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -88,4 +89,35 @@ public class SearchPossibleValueSourceOutput extends AbstractActionOutput
|
|||||||
return (this);
|
return (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Getter for warning
|
||||||
|
*******************************************************************************/
|
||||||
|
public String getWarning()
|
||||||
|
{
|
||||||
|
return (this.warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Setter for warning
|
||||||
|
*******************************************************************************/
|
||||||
|
public void setWarning(String warning)
|
||||||
|
{
|
||||||
|
this.warning = warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Fluent setter for warning
|
||||||
|
*******************************************************************************/
|
||||||
|
public SearchPossibleValueSourceOutput withWarning(String warning)
|
||||||
|
{
|
||||||
|
this.warning = warning;
|
||||||
|
return (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,63 @@ class SearchPossibleValueSourceActionTest extends BaseTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSearchPvsAction_tableByLabels() throws QException
|
||||||
|
{
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByLabels(List.of("Square", "Circle"), TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(2, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("Square"));
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(3) && pv.getLabel().equals("Circle"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByLabels(List.of(), TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(0, output.getResults().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByLabels(List.of("notFound"), TestUtils.POSSIBLE_VALUE_SOURCE_SHAPE);
|
||||||
|
assertEquals(0, output.getResults().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
@Test
|
||||||
|
void testSearchPvsAction_enumByLabel() throws QException
|
||||||
|
{
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByLabels(List.of("IL", "MO", "XX"), TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(2, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1) && pv.getLabel().equals("IL"));
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("MO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByLabels(List.of("Il", "mo", "XX"), TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(2, output.getResults().size());
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1) && pv.getLabel().equals("IL"));
|
||||||
|
assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(2) && pv.getLabel().equals("MO"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByLabels(List.of(), TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(0, output.getResults().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutputByLabels(List.of("not-found"), TestUtils.POSSIBLE_VALUE_SOURCE_STATE);
|
||||||
|
assertEquals(0, output.getResults().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
**
|
**
|
||||||
@ -414,4 +471,18 @@ class SearchPossibleValueSourceActionTest extends BaseTest
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
private SearchPossibleValueSourceOutput getSearchPossibleValueSourceOutputByLabels(List<String> labels, String possibleValueSourceName) throws QException
|
||||||
|
{
|
||||||
|
SearchPossibleValueSourceInput input = new SearchPossibleValueSourceInput();
|
||||||
|
input.setLabelList(labels);
|
||||||
|
input.setPossibleValueSourceName(possibleValueSourceName);
|
||||||
|
SearchPossibleValueSourceOutput output = new SearchPossibleValueSourceAction().execute(input);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Reference in New Issue
Block a user