Skip to content

Commit

Permalink
#2192 Adjusted unit tests for dynamic query builder and adjusted prep…
Browse files Browse the repository at this point in the history
…are utility method to control triming of input string.
  • Loading branch information
oleh-maikovych committed Feb 27, 2024
1 parent 2f68814 commit f1fca8d
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ua.com.fielden.platform.dao.dynamic;

import static java.util.Arrays.stream;
import static org.junit.Assert.assertEquals;
import static ua.com.fielden.platform.entity.query.fluent.EntityQueryUtils.cond;
import static ua.com.fielden.platform.entity.query.fluent.EntityQueryUtils.select;
Expand Down Expand Up @@ -54,6 +55,7 @@
import ua.com.fielden.platform.test.CommonTestEntityModuleWithPropertyFactory;
import ua.com.fielden.platform.test.EntityModuleWithPropertyFactory;
import ua.com.fielden.platform.types.Money;
import ua.com.fielden.platform.utils.CollectionUtil;
import ua.com.fielden.platform.utils.IDates;

/**
Expand Down Expand Up @@ -557,7 +559,27 @@ public void query_composition_for_property_of_type_string_without_wildchards_in_
}

@Test
public void query_composition_for_property_of_type_string_with_wildchards_in_crit_value_preserves_the_original_placement_of_wildcards_and_does_not_inject_them_at_the_beginning_and_end() {
public void query_composition_for_property_of_type_string_without_wildcards_and_with_whitespaces_in_crit_value_should_not_trim_whitespaces_and_should_automatically_injects_wildcards_at_the_beginning_and_end() {
//"entityProp.stringProp"
set_up();
final QueryProperty property = queryProperties.get("stringProp");
property.setValue(" Some string value ");

final String cbn = property.getConditionBuildingName();

final ICompleted<? extends AbstractEntity<?>> expected = //
/**/iJoin.where().condition(cond() //
/* */.condition(cond().prop(cbn).isNotNull().and() //
/* */.condition(cond().prop(cbn).iLike().anyOfValues(new Object[] { "% Some string value %" }).model()) //
/* */.model()) //
/**/.model()); //
final ICompleted<? extends AbstractEntity<?>> actual = createQuery(masterKlass, new ArrayList<>(queryProperties.values()), dates);

assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_property_of_type_string_with_wildcards_in_crit_value_preserves_the_original_placement_of_wildcards_and_does_not_inject_them_at_the_beginning_and_end() {
//"entityProp.stringProp"
set_up();
final QueryProperty property = queryProperties.get("stringProp");
Expand All @@ -578,7 +600,28 @@ public void query_composition_for_property_of_type_string_with_wildchards_in_cri
}

@Test
public void query_composition_for_property_of_type_string_with_and_without_wildchards_in_crit_values_retain_original_whildcards_and_autoinject_wildcards_at_the_beginning_and_end_for_values_with_no_wildcards() {
public void query_composition_for_property_of_type_string_with_wildcards_and_whitespaces_in_crit_value_should_not_trim_whitespaces_and_should_preserves_the_original_placement_of_wildcards_and_does_not_inject_them_at_the_beginning_and_end() {
//"entityProp.stringProp"
set_up();
final QueryProperty property = queryProperties.get("stringProp");
final String critValue = " Some string value* , *Some string value , Some string *values, *Some string value* ";
property.setValue(critValue);

final String cbn = property.getConditionBuildingName();

final ICompleted<? extends AbstractEntity<?>> expected = //
/**/iJoin.where().condition(cond() //
/* */.condition(cond().prop(cbn).isNotNull().and() //
/* */.condition(cond().prop(cbn).iLike().anyOfValues(critValue.replace("*", "%").split(",")).model()) //
/* */.model()) //
/**/.model()); //
final ICompleted<? extends AbstractEntity<?>> actual = createQuery(masterKlass, new ArrayList<>(queryProperties.values()), dates);

assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_property_of_type_string_with_and_without_wildcards_in_crit_values_retain_original_whildcards_and_autoinject_wildcards_at_the_beginning_and_end_for_values_with_no_wildcards() {
//"entityProp.stringProp"
set_up();
final QueryProperty property = queryProperties.get("stringProp");
Expand All @@ -597,6 +640,25 @@ public void query_composition_for_property_of_type_string_with_and_without_wildc
assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_property_of_type_string_with_and_without_wildhards_and_with_whitespaces_in_crit_values_should_not_trim_whitespaces_and_should_retain_original_whildcards_and_autoinject_wildcards_at_the_beginning_and_end_for_values_with_no_wildcards() {
//"entityProp.stringProp"
set_up();
final QueryProperty property = queryProperties.get("stringProp");
property.setValue(" Some string value,*Some string value , Some string *value , *Some string* value");

final String cbn = property.getConditionBuildingName();

final ICompleted<? extends AbstractEntity<?>> expected = //
/**/iJoin.where().condition(cond() //
/* */.condition(cond().prop(cbn).isNotNull().and() //
/* */.condition(cond().prop(cbn).iLike().anyOfValues(new String[] {"% Some string value%", "%Some string value ", " Some string %value ", " %Some string% value"}).model()) //
/* */.model()) //
/**/.model()); //
final ICompleted<? extends AbstractEntity<?>> actual = createQuery(masterKlass, new ArrayList<>(queryProperties.values()), dates);

assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_properties_of_entity_type_with_wildcard_selection_crit_value_uses_iLike_operator() {
Expand All @@ -619,6 +681,28 @@ public void query_composition_for_properties_of_entity_type_with_wildcard_select
assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_selection_crit_of_entity_value_with_wildcards_and_whitespaces_should_trim_whitespaces() {
final String propertyName = "entityProp";

set_up();
final QueryProperty property = queryProperties.get(propertyName);
property.setValue(Arrays.asList(" some val 1* ", " some val 2* "));

final String cbn = property.getConditionBuildingName();
final List<String> critValuesWithWildcard = CollectionUtil.listOf("some val 1*", "some val 2*");

final ICompleted<? extends AbstractEntity<?>> expected = //
/**/iJoin.where().condition(cond() //
/* */.condition(cond().prop(getPropertyNameWithoutKeyPart(cbn)).isNotNull().and() //
/* */.condition(cond().prop(cbn).iLike().anyOfValues(DynamicQueryBuilder.prepCritValuesForEntityTypedProp(critValuesWithWildcard)).model()) //
/* */.model()) //
/**/.model()); //
final ICompleted<? extends AbstractEntity<?>> actual = createQuery(masterKlass, new ArrayList<>(queryProperties.values()), dates);

assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_properties_of_entity_type_without_wildcard_selection_crit_value_uses_in_operator_with_subselect() {
final String propertyName = "entityProp";
Expand All @@ -643,6 +727,30 @@ public void query_composition_for_properties_of_entity_type_without_wildcard_sel
assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_selection_crit_of_entity_value_with_whitespaces_should_trim_whitespaces() {
final String propertyName = "entityProp";

set_up();
final QueryProperty property = queryProperties.get(propertyName);
final String[] critValues = new String[] {" some val 1 ", " some val 2 "};
property.setValue(Arrays.asList(critValues));


final String cbn = property.getConditionBuildingName();
final String cbnNoKey = cbn.substring(0, cbn.length() - 4); // cut off ".key" from the name

final ICompleted<? extends AbstractEntity<?>> expected = //
/**/iJoin.where().condition(cond() //
/* */.condition(cond().prop(getPropertyNameWithoutKeyPart(cbn)).isNotNull().and() //
/* */.condition(cond().prop(cbnNoKey).in().model(select(SlaveEntity.class).where().prop("key").in().values("some val 1", "some val 2").model()).model()) //
/* */.model()) //
/**/.model()); //
final ICompleted<? extends AbstractEntity<?>> actual = createQuery(masterKlass, new ArrayList<>(queryProperties.values()), dates);

assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_properties_of_entity_type_with_and_without_wildcard_selection_crit_value_uses_combination_of_in_operator_with_subselect_and_iLike_operator() {
final String propertyName = "entityProp";
Expand Down Expand Up @@ -678,6 +786,41 @@ public void query_composition_for_properties_of_entity_type_with_and_without_wil
assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}

@Test
public void query_composition_for_selection_crit_of_entity_typed_values_with_some_wildcard_and_whitespaces_also_trims_whitespaces() {
final String propertyName = "entityProp";

set_up();
final QueryProperty property = queryProperties.get(propertyName);
final String[] critValues = new String[] {"some val 1 ", " some val 2* ", " some val 3*", " some val 4",};
property.setValue(Arrays.asList(critValues));

final String[] critValuesWithWildcard = new String[] {"some val 2*", "some val 3*"};

final String cbn = property.getConditionBuildingName();
final String cbnNoKey = cbn.substring(0, cbn.length() - 4); // cut off ".key" from the name


final EntityResultQueryModel<SlaveEntity> subSelect = select(SlaveEntity.class).where().prop("key").in().values("some val 1", "some val 4").model();
final ConditionModel whereCondition = cond()
.condition(
cond().prop(getPropertyNameWithoutKeyPart(cbn)).isNotNull()
.and()
.condition(
cond().prop(cbnNoKey).in().model(subSelect)
.or().prop(cbn).iLike().anyOfValues(prepCritValuesForEntityTypedProp(Arrays.asList(critValuesWithWildcard)))
.model())
.model())
.model();

final ICompleted<? extends AbstractEntity<?>> expected = //
/**/iJoin.where().condition(whereCondition);

final ICompleted<? extends AbstractEntity<?>> actual = createQuery(masterKlass, new ArrayList<>(queryProperties.values()), dates);

assertEquals("Incorrect query model has been built.", expected.model(), actual.model());
}


////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// 2. Property level (Negation / Null) /////////////////////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -848,9 +848,9 @@ public static String[] prepCritValuesForStringTypedProp(final String criteria) {
final String[] crits = criteria.split(",");
for (int index = 0; index < crits.length; index++) {
if (!crits[index].contains("*")) {
crits[index] = "*" + crits[index].trim() + "*";
crits[index] = "*" + crits[index] + "*";
}
crits[index] = prepare(crits[index]);
crits[index] = prepare(crits[index], false);
}
return crits;
}
Expand All @@ -864,9 +864,9 @@ public static String[] prepCritValuesForStringTypedProp(final String criteria) {
*/
private static String prepCritValuesForSingleStringTypedProp(final String criteria) {
if (!criteria.contains("*")) {
return prepare("*" + criteria.trim() + "*");
return prepare("*" + criteria + "*", false);
}
return prepare(criteria);
return prepare(criteria, false);
}

/**
Expand All @@ -876,7 +876,7 @@ private static String prepCritValuesForSingleStringTypedProp(final String criter
* @return
*/
public static String[] prepCritValuesForEntityTypedProp(final List<String> criteria) {
return prepare(criteria);
return prepare(criteria, true);
}

/**
Expand Down Expand Up @@ -1149,7 +1149,7 @@ private static ConditionModel propertyLike(final String propertyNameWithKey, fin
if (exactAndWildcardSearchVals.containsKey(false) && exactAndWildcardSearchVals.containsKey(true)) { // both exact and whildcard search values are present
return cond()
// Condition for exact search values; union entities need ".id" to help EQL.
.prop(propertyNameWithoutKey + (isUnionEntityType(propType) ? ".id" : "")).in().model(select(propType).where().prop(KEY).in().values(exactAndWildcardSearchVals.get(false).toArray()).model())
.prop(propertyNameWithoutKey + (isUnionEntityType(propType) ? ".id" : "")).in().model(select(propType).where().prop(KEY).in().values(prepExectCritValuesForEntityTypedProp(exactAndWildcardSearchVals.get(false))).model())
// Condition for wildcard search values.
.or().prop(propertyNameWithKey).iLike().anyOfValues(prepCritValuesForEntityTypedProp(exactAndWildcardSearchVals.get(true))).model();
} else if (exactAndWildcardSearchVals.containsKey(false) && !exactAndWildcardSearchVals.containsKey(true)) { // only exact search values are present
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ public String getDescription() {
* Creates a new array of values based on the passed list by changing * to %.
*
* @param criteria
* @param trim - indicates whether elements of criteria list parameter should be trimmed or not.
* @return
*/
public static String[] prepare(final List<String> criteria) {
public static String[] prepare(final List<String> criteria, final boolean trim) {
final List<String> result = new ArrayList<>();
if (criteria != null) {
for (final String crit : criteria) {
result.add(prepare(crit));
result.add(prepare(crit, trim));
}
}
// eliminate empty or null values
Expand Down Expand Up @@ -96,13 +97,15 @@ public static boolean valueMatchesPattern(final String value, final String value
* Converts auto-completer-like regular expression to normal regular expression (simply replaces all '*' with '%' characters)
*
* @param autocompleterExp
* @param trim - indicates whether autocompleterExp parameter should be trimmed or not.
* @return
*/
public static String prepare(final String autocompleterExp) {
if ("*".equals(autocompleterExp.trim())) {
public static String prepare(final String autocompleterExp, final boolean trim) {
if ("*".equals(trim ? autocompleterExp.trim(): autocompleterExp)) {
return null;
}
return autocompleterExp.replace("*", "%").trim();
final String processedExpr = autocompleterExp.replace("*", "%");
return trim ? processedExpr.trim(): processedExpr;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ private static <M extends AbstractEntity<?>> Object convert(final Class<M> type,
public static AbstractEntity<?> findAndFetchBy(final String searchString, final Class<AbstractEntity<?>> entityType, final Optional<String> optActiveProp, final fetch<AbstractEntity<?>> fetch, final IEntityDao<AbstractEntity<?>> companion) {
if (isCompositeEntity(entityType)) {
//logger.debug(format("KEY-based restoration of value: type [%s] property [%s] propertyType [%s] id [%s] reflectedValue [%s].", type.getSimpleName(), propertyName, entityPropertyType.getSimpleName(), reflectedValueId, reflectedValue));
final String compositeKeyAsString = MiscUtilities.prepare(prepSearchStringForCompositeKey(entityType, searchString));
final String compositeKeyAsString = MiscUtilities.prepare(prepSearchStringForCompositeKey(entityType, searchString), true);
final EntityResultQueryModel<AbstractEntity<?>> model = select(entityType).where().prop(KEY).iLike().val(compositeKeyAsString).model().setFilterable(true);
final QueryExecutionModel<AbstractEntity<?>, EntityResultQueryModel<AbstractEntity<?>>> qem = from(model).with(fetch).model();
try {
Expand Down Expand Up @@ -798,7 +798,7 @@ public static AbstractEntity<?> findAndFetchBy(final String searchString, final
}
} else {
//logger.debug(format("KEY-based restoration of value: type [%s] property [%s] propertyType [%s] id [%s] reflectedValue [%s].", type.getSimpleName(), propertyName, entityPropertyType.getSimpleName(), reflectedValueId, reflectedValue));
final String[] keys = MiscUtilities.prepare(Arrays.asList(searchString));
final String[] keys = MiscUtilities.prepare(Arrays.asList(searchString), true);
final String key;
if (keys.length > 1) {
throw new IllegalArgumentException(format("Value [%s] does not represent a single key value, which is required for coversion to an instance of type [%s].", searchString, entityType.getName()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public Representation post(final Representation envelope) {
*/
public static T2<String, Integer> prepSearchString(final CentreContextHolder centreContextHolder, final boolean shouldUpperCase) {
final String searchStringVal = (String) centreContextHolder.getCustomObject().get("@@searchString"); // custom property inside paramsHolder
final Optional<String> maybeSearchString = ofNullable(prepare(searchStringVal.contains("*") || searchStringVal.contains("%") ? searchStringVal : "*" + searchStringVal + "*"));
final Optional<String> maybeSearchString = ofNullable(prepare(searchStringVal.contains("*") || searchStringVal.contains("%") ? searchStringVal : "*" + searchStringVal + "*", true));
final String searchString = maybeSearchString.map(str -> shouldUpperCase ? str.toUpperCase() : str).orElse("%");
final Optional<Integer> maybeDataPage = ofNullable((Integer) centreContextHolder.getCustomObject().get("@@dataPage"));
final int dataPageNo = maybeDataPage.orElse(1);
Expand Down

0 comments on commit f1fca8d

Please sign in to comment.