diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java index fcfd2fa1..7816dba4 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceAction.java @@ -23,6 +23,8 @@ package com.kingsrook.qqq.backend.core.actions.values; import java.io.Serializable; +import java.time.Instant; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -208,37 +210,50 @@ public class SearchPossibleValueSourceAction } else { - if(StringUtils.hasContent(input.getSearchTerm())) + String searchTerm = input.getSearchTerm(); + if(StringUtils.hasContent(searchTerm)) { for(String valueField : possibleValueSource.getSearchFields()) { - QFieldMetaData field = table.getField(valueField); - if(field.getType().equals(QFieldType.STRING)) + try { - queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.STARTS_WITH, List.of(input.getSearchTerm()))); - } - else if(field.getType().equals(QFieldType.DATE) || field.getType().equals(QFieldType.DATE_TIME)) - { - LOG.debug("Not querying PVS [" + possibleValueSource.getName() + "] on date field [" + field.getName() + "]"); - // todo - what? queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.STARTS_WITH, List.of(input.getSearchTerm()))); - } - else - { - try + QFieldMetaData field = table.getField(valueField); + if(field.getType().equals(QFieldType.STRING)) { - Integer valueAsInteger = ValueUtils.getValueAsInteger(input.getSearchTerm()); + queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.STARTS_WITH, List.of(searchTerm))); + } + else if(field.getType().equals(QFieldType.DATE)) + { + LocalDate searchDate = ValueUtils.getValueAsLocalDate(searchTerm); + if(searchDate != null) + { + queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.EQUALS, searchDate)); + } + } + else if(field.getType().equals(QFieldType.DATE_TIME)) + { + Instant searchDate = ValueUtils.getValueAsInstant(searchTerm); + if(searchDate != null) + { + queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.EQUALS, searchDate)); + } + } + else + { + Integer valueAsInteger = ValueUtils.getValueAsInteger(searchTerm); if(valueAsInteger != null) { queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.EQUALS, List.of(valueAsInteger))); } } - catch(Exception e) - { - //////////////////////////////////////////////////////// - // write a FALSE criteria if the value isn't a number // - //////////////////////////////////////////////////////// - queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.IN, List.of())); - } + } + catch(Exception e) + { + ////////////////////////////////////////////////////////////////////////////////////////// + // write a FALSE criteria upon exceptions (e.g., type conversion fails) // + // Why are we doing this? so a single-field query finds nothing instead of everything. // + ////////////////////////////////////////////////////////////////////////////////////////// + queryFilter.addCriteria(new QFilterCriteria(valueField, QCriteriaOperator.IN, List.of())); } } } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceActionTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceActionTest.java index 8a15a6d8..ee2bb104 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceActionTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/values/SearchPossibleValueSourceActionTest.java @@ -23,12 +23,18 @@ package com.kingsrook.qqq.backend.core.actions.values; import java.io.Serializable; +import java.time.LocalDate; +import java.time.Month; import java.util.List; 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.model.actions.tables.insert.InsertInput; 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.metadata.possiblevalues.QPossibleValueSource; 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; @@ -224,6 +230,74 @@ class SearchPossibleValueSourceActionTest extends BaseTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testSearchPvsAction_tableByIdOnlyNonNumeric() throws QException + { + QContext.getQInstance().getPossibleValueSource(TestUtils.TABLE_NAME_SHAPE) + .withSearchFields(List.of("id")); + + ///////////////////////////////////////////////////////////////////////////////////////////// + // a non-integer input should find nothing // + // the catch { (IN, empty) } code makes this happen - without that, all records are found. // + // (furthermore, i think that's only exposed if there's only 1 search field, maybe) // + ///////////////////////////////////////////////////////////////////////////////////////////// + SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput("A", TestUtils.TABLE_NAME_SHAPE); + assertEquals(0, output.getResults().size()); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testSearchPvsAction_tableByLocalDate() throws QException + { + MemoryRecordStore.getInstance().reset(); + + //////////////////////////////////////////// + // make a PVS for the person-memory table // + //////////////////////////////////////////// + QContext.getQInstance().addPossibleValueSource(QPossibleValueSource.newForTable(TestUtils.TABLE_NAME_PERSON_MEMORY) + .withSearchFields(List.of("id", "firstName", "birthDate")) + ); + + List shapeRecords = List.of( + new QRecord().withValue("id", 1).withValue("firstName", "Homer").withValue("birthDate", LocalDate.of(1960, Month.JANUARY, 1)), + new QRecord().withValue("id", 2).withValue("firstName", "Marge").withValue("birthDate", LocalDate.of(1961, Month.FEBRUARY, 2)), + new QRecord().withValue("id", 3).withValue("firstName", "Bart").withValue("birthDate", LocalDate.of(1980, Month.MARCH, 3))); + + InsertInput insertInput = new InsertInput(); + insertInput.setTableName(TestUtils.TABLE_NAME_PERSON_MEMORY); + insertInput.setRecords(shapeRecords); + new InsertAction().execute(insertInput); + + ///////////////////////////////////// + // a parseable date yields a match // + ///////////////////////////////////// + SearchPossibleValueSourceOutput output = getSearchPossibleValueSourceOutput("1960-01-01", TestUtils.TABLE_NAME_PERSON_MEMORY); + assertEquals(1, output.getResults().size()); + assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1)); + + /////////////////////////////////////////////////////////////////////// + // alternative date format also works (thanks to ValueUtils parsing) // + /////////////////////////////////////////////////////////////////////// + output = getSearchPossibleValueSourceOutput("1/1/1960", TestUtils.TABLE_NAME_PERSON_MEMORY); + assertEquals(1, output.getResults().size()); + assertThat(output.getResults()).anyMatch(pv -> pv.getId().equals(1)); + + /////////////////////////////////// + // incomplete date finds nothing // + /////////////////////////////////// + output = getSearchPossibleValueSourceOutput("1960-01", TestUtils.TABLE_NAME_PERSON_MEMORY); + assertEquals(0, output.getResults().size()); + } + + + /******************************************************************************* ** *******************************************************************************/