Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #2192 - Entity centres and masters: remove trailing and leading whitespace from search values in autocompleters #2200

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -27,6 +27,7 @@
import static ua.com.fielden.platform.utils.EntityUtils.isString;
import static ua.com.fielden.platform.utils.EntityUtils.isUnionEntityType;
import static ua.com.fielden.platform.utils.MiscUtilities.prepare;
import static ua.com.fielden.platform.utils.MiscUtilities.prepareStringExpression;
import static ua.com.fielden.platform.utils.Pair.pair;

import java.lang.reflect.Field;
Expand All @@ -40,6 +41,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -849,7 +851,7 @@ public static String[] prepCritValuesForStringTypedProp(final String criteria) {
if (!crits[index].contains("*")) {
crits[index] = "*" + crits[index] + "*";
}
crits[index] = prepare(crits[index]);
crits[index] = prepareStringExpression(crits[index]);
}
return crits;
}
Expand All @@ -863,9 +865,9 @@ public static String[] prepCritValuesForStringTypedProp(final String criteria) {
*/
private static String prepCritValuesForSingleStringTypedProp(final String criteria) {
if (!criteria.contains("*")) {
return prepare("*" + criteria + "*");
return prepareStringExpression("*" + criteria + "*");
}
return prepare(criteria);
return prepareStringExpression(criteria);
}

/**
Expand All @@ -878,6 +880,16 @@ public static String[] prepCritValuesForEntityTypedProp(final List<String> crite
return prepare(criteria);
}

/**
* Creates new array based on the passed list of string. This method also trims every element of the passed list.
*
* @param criteria
* @return
*/
public static String[] prepExectCritValuesForEntityTypedProp(final List<String> criteria) {
return criteria.stream().map(crit -> crit.trim()).toArray(String[]::new);
}

/**
* Returns <code>true</code> if the <code>type</code> is supported in dynamic criteria, <code>false</code> otherwise.
*
Expand Down Expand Up @@ -1115,7 +1127,7 @@ private static ConditionModel propertyDescriptorLike(final String propertyNameWi
final Map<Boolean, List<String>> searchVals = searchValues.stream().collect(groupingBy(str -> str.contains("*")));
final Set<PropertyDescriptor<AbstractEntity<?>>> matchedPropDescriptors = new LinkedHashSet<>();
concat(
searchVals.getOrDefault(false, emptyList()).stream(),
stream(prepExectCritValuesForEntityTypedProp(searchVals.getOrDefault(false, emptyList()))),
stream(prepCritValuesForEntityTypedProp(searchVals.getOrDefault(true, emptyList())))
).forEach(val -> matchedPropDescriptors.addAll(new PojoValueMatcher<>(allPropertyDescriptors, KEY, allPropertyDescriptors.size()).findMatches(val)));
return matchedPropDescriptors.isEmpty()
Expand All @@ -1138,13 +1150,13 @@ 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
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()).model();
.prop(propertyNameWithoutKey + (isUnionEntityType(propType) ? ".id" : "")).in().model(select(propType).where().prop(KEY).in().values(prepExectCritValuesForEntityTypedProp(exactAndWildcardSearchVals.get(false))).model()).model();
} else { // only whildcard search values are present
return cond()
// Condition for wildcard search values.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,19 @@ public static String prepare(final String autocompleterExp) {
return autocompleterExp.replace("*", "%").trim();
}

/**
* Converts auto-completer-like regular expression for string typed property into normal regular expression (simply replaces all '*' with '%' characters) without trimming it
*
* @param stringExpr - The expression for string property
* @return converted into SQL like regular expression without trimming stringExpr
*/
public static String prepareStringExpression(final String stringExpr) {
if ("*".equals(stringExpr)) {
return null;
}
return stringExpr.replace("*", "%");
}

/**
* Converts the content of the input stream into a string.
*
Expand Down