handle empty values for QueryParameterUtils.toEqualToOrInPredicate and QueryParameterUtils.toNotEqualToOrInPredicate

This commit is contained in:
nathaniel.doef 2023-03-22 19:50:00 -04:00
parent 5f2c88d9d9
commit 4382cd3139
3 changed files with 100 additions and 0 deletions

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 4675
title: "Previously, when Postgres was configured and a `_has` query was performed with a non-existent `SearchParameter`,
a 500 Server Error was received. This has been corrected."

View File

@ -37,6 +37,7 @@ import com.healthmarketscience.sqlbuilder.BinaryCondition;
import com.healthmarketscience.sqlbuilder.ComboCondition; import com.healthmarketscience.sqlbuilder.ComboCondition;
import com.healthmarketscience.sqlbuilder.Condition; import com.healthmarketscience.sqlbuilder.Condition;
import com.healthmarketscience.sqlbuilder.InCondition; import com.healthmarketscience.sqlbuilder.InCondition;
import com.healthmarketscience.sqlbuilder.CustomCondition;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn; import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
import org.apache.commons.collections4.BidiMap; import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.bidimap.DualHashBidiMap; import org.apache.commons.collections4.bidimap.DualHashBidiMap;
@ -45,6 +46,7 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -72,6 +74,8 @@ public class QueryParameterUtils {
private static final BidiMap<SearchFilterParser.CompareOperation, ParamPrefixEnum> ourCompareOperationToParamPrefix; private static final BidiMap<SearchFilterParser.CompareOperation, ParamPrefixEnum> ourCompareOperationToParamPrefix;
public static final Condition[] EMPTY_CONDITION_ARRAY = new Condition[0]; public static final Condition[] EMPTY_CONDITION_ARRAY = new Condition[0];
public static final String FALSE_CONDITION = "1 = 2";
public static final String TRUE_CONDITION = "1 = 1";
static { static {
DualHashBidiMap<SearchFilterParser.CompareOperation, ParamPrefixEnum> compareOperationToParamPrefix = new DualHashBidiMap<>(); DualHashBidiMap<SearchFilterParser.CompareOperation, ParamPrefixEnum> compareOperationToParamPrefix = new DualHashBidiMap<>();
@ -136,6 +140,10 @@ public class QueryParameterUtils {
@Nonnull @Nonnull
public static Condition toEqualToOrInPredicate(DbColumn theColumn, List<String> theValuePlaceholders) { public static Condition toEqualToOrInPredicate(DbColumn theColumn, List<String> theValuePlaceholders) {
if (CollectionUtils.isEmpty(theValuePlaceholders)){
ourLog.debug("No parameters provided for IN() on column: {}", theColumn);
return new CustomCondition(FALSE_CONDITION);
}
if (theValuePlaceholders.size() == 1) { if (theValuePlaceholders.size() == 1) {
return BinaryCondition.equalTo(theColumn, theValuePlaceholders.get(0)); return BinaryCondition.equalTo(theColumn, theValuePlaceholders.get(0));
} }
@ -144,6 +152,10 @@ public class QueryParameterUtils {
@Nonnull @Nonnull
public static Condition toNotEqualToOrNotInPredicate(DbColumn theColumn, List<String> theValuePlaceholders) { public static Condition toNotEqualToOrNotInPredicate(DbColumn theColumn, List<String> theValuePlaceholders) {
if (CollectionUtils.isEmpty(theValuePlaceholders)){
ourLog.debug("No parameters provided for NOT IN() on column: {}", theColumn);
return new CustomCondition(TRUE_CONDITION);
}
if (theValuePlaceholders.size() == 1) { if (theValuePlaceholders.size() == 1) {
return BinaryCondition.notEqualTo(theColumn, theValuePlaceholders.get(0)); return BinaryCondition.notEqualTo(theColumn, theValuePlaceholders.get(0));
} }

View File

@ -0,0 +1,83 @@
package ca.uhn.fhir.jpa.util;
import com.healthmarketscience.sqlbuilder.Condition;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSchema;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSpec;
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ExtendWith(MockitoExtension.class)
public class QueryParameterUtilsTest {
private static final String VALUE_1 = "value1";
private static final String VALUE_2 = "value2";
public static final String SPEC_NAME = "some_spec";
public static final String SCHEMA_NAME = "some_schema";
public static final String TABLE_NAME = "some_table";
public static final String COLUMN_NAME = "some_column";
private DbSpec myDbSpec;
private DbSchema myDbSchema;
private DbTable myDbTable;
private DbColumn myColumn;
@BeforeEach
public void setup(){
myDbSpec = new DbSpec(SPEC_NAME);
myDbSchema = new DbSchema(myDbSpec, SCHEMA_NAME);
myDbTable = new DbTable(myDbSchema, TABLE_NAME);
myColumn = new DbColumn(myDbTable, COLUMN_NAME, "VARCHAR", 10);
}
@Test
public void toEqualToOrInPredicate_withNoValueParameters_returnsFalseCondition(){
Condition result = QueryParameterUtils.toEqualToOrInPredicate(myColumn, Collections.EMPTY_LIST);
String expected = String.format("(%s)", QueryParameterUtils.FALSE_CONDITION);
assertEquals(expected, result.toString());
}
@Test
public void toEqualToOrInPredicate_withSingleParameter_returnBinaryEqualsCondition(){
Condition result = QueryParameterUtils.toEqualToOrInPredicate(myColumn, List.of(VALUE_1));
String expected = String.format("(%s0.%s = '%s')", SPEC_NAME, COLUMN_NAME, VALUE_1);
assertEquals(expected, result.toString());
}
@Test
public void toEqualToOrInPredicate_withMultipleParameters_returnsInCondition(){
Condition result = QueryParameterUtils.toEqualToOrInPredicate(myColumn, List.of(VALUE_1, VALUE_2));
String expected = String.format("(%s0.%s IN ('%s','%s') )", SPEC_NAME, COLUMN_NAME, VALUE_1, VALUE_2);
assertEquals(expected, result.toString());
}
@Test
public void toNotEqualToOrNotInPredicate_withNoValueParameters_returnsTrueCondition(){
Condition result = QueryParameterUtils.toNotEqualToOrNotInPredicate(myColumn, Collections.EMPTY_LIST);
String expected = String.format("(%s)", QueryParameterUtils.TRUE_CONDITION);
assertEquals(expected, result.toString());
}
@Test
public void toNotEqualToOrNotInPredicate_withSingleParameter_returnBinaryNotEqualsCondition(){
Condition result = QueryParameterUtils.toNotEqualToOrNotInPredicate(myColumn, List.of(VALUE_1));
String expected = String.format("(%s0.%s <> '%s')", SPEC_NAME, COLUMN_NAME, VALUE_1);
assertEquals(expected, result.toString());
}
@Test
public void toNotEqualToOrNotInPredicate_withMultipleParameters_returnsNotInCondition(){
Condition result = QueryParameterUtils.toNotEqualToOrNotInPredicate(myColumn, List.of(VALUE_1, VALUE_2));
String expected = String.format("(%s0.%s NOT IN ('%s','%s') )", SPEC_NAME, COLUMN_NAME, VALUE_1, VALUE_2);
assertEquals(expected, result.toString());
}
}