Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/smart-correlation-protot…
Browse files Browse the repository at this point in the history
…ype' into feature/smart-correlation-prototype
  • Loading branch information
mederly committed Jul 27, 2022
2 parents 7ec548c + 16edb94 commit 1a4009f
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.query.FuzzyStringMatchFilter;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.query.PropertyValueFilter;
import com.evolveum.midpoint.prism.query.RefFilter;
Expand Down Expand Up @@ -107,6 +108,13 @@ public Predicate process(ValueFilter<?, ?> filter) throws RepositoryException {

PropertyValueFilter<?> propertyValueFilter = (PropertyValueFilter<?>) filter;
ValueFilterValues<?, ?> values = ValueFilterValues.from(propertyValueFilter);

if (filter instanceof FuzzyStringMatchFilter<?>) {
return fuzzyStringPredicate((FuzzyStringMatchFilter<?>) filter,
stringTemplate("{0}->>'{1s}'", path, extItem.id), // Resolve nested value
values);
}

FilterOperation operation = operation(filter);

if (values.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,12 +565,15 @@ protected void displayQuery(@Nullable ObjectQuery query) throws SchemaException
if (query == null) {
return;
}

String serializedQuery = null;
try {
QueryType queryType = prismContext.getQueryConverter().createQueryType(query);
String serializedQuery = prismContext.xmlSerializer().serializeAnyData(
serializedQuery = prismContext.xmlSerializer().serializeAnyData(
queryType, SchemaConstants.MODEL_EXTENSION_OBJECT_QUERY);
display("Serialized QUERY: " + serializedQuery);

} catch (Exception e) {
display("Can not serialize query");
}
if (query.getFilter() != null) {
try {
PrismQuerySerialization serialization = prismContext.querySerializer().serialize(query.getFilter());
Expand All @@ -581,8 +584,10 @@ protected void displayQuery(@Nullable ObjectQuery query) throws SchemaException
}

// sanity check if it's re-parsable
assertThat(prismContext.parserFor(serializedQuery).parseRealValue(QueryType.class))
if (serializedQuery != null) {
assertThat(prismContext.parserFor(serializedQuery).parseRealValue(QueryType.class))
.isNotNull();
}
}

/** Parses object from byte array form and returns its real value (not Prism structure). */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@
import java.util.Collection;
import java.util.List;

import javax.xml.namespace.QName;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.evolveum.midpoint.prism.Containerable;
import com.evolveum.midpoint.prism.PrismConstants;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.path.ItemName;
import com.evolveum.midpoint.prism.query.ObjectQuery;
import com.evolveum.midpoint.repo.sqale.SqaleRepoBaseTest;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SchemaService;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

Expand Down Expand Up @@ -104,5 +111,25 @@ public void test115GetUserWithRetrieveOptions() throws CommonException {
.containsExactlyInAnyOrder("givenName", "familyName", "familyName.3", "dateOfBirth", "nationalId");
}


@Test
public void testSeachUsingFuzzyMatching() throws CommonException {
when("user is obtained with retrieve options for identities");
Collection<SelectorOptions<GetOperationOptions>> getOptions = SchemaService.get()
.getOperationOptionsBuilder().item(FocusType.F_IDENTITIES).retrieve().build();
OperationResult result = createOperationResult();
ItemName familyNameQName = new ItemName(SchemaConstants.NS_MIDPOINT_PUBLIC_COMMON, "familyName");
var def = PrismContext.get().definitionFactory().createPropertyDefinition(familyNameQName, DOMUtil.XSD_STRING, null, null);
def.toMutable().setRuntimeSchema(true);

ObjectQuery query = PrismContext.get().queryFor(UserType.class).itemWithDef(def, UserType.F_IDENTITIES,
FocusIdentitiesType.F_IDENTITY,
FocusIdentityType.F_ITEMS,
FocusIdentityItemsType.F_NORMALIZED,
new ItemName(SchemaConstants.NS_MIDPOINT_PUBLIC_COMMON, "familyName")
).eq("alice").build();
var ret = repositoryService.searchObjects(UserType.class, query, null, result);
assertThat(ret.size()).isEqualTo(1);
}
// TODO modification test + hopefully updateGetOptions in QFocusMapping does the trick
}
Original file line number Diff line number Diff line change
Expand Up @@ -2762,5 +2762,17 @@ public void test991SearchObjectWithStringIgnoreCaseWithoutNamespace()
.matching(new QName(STRING_IGNORE_CASE_MATCHING_RULE_NAME.getLocalPart())),
user1Oid);
}

@Test
public void fuzzyStringSearchTest() throws SchemaException {
searchUsersTest("With levelstein",
f -> f.item(UserType.F_EMPLOYEE_NUMBER).fuzzyString("User1").levenshtein(2, true),
user1Oid);

searchUsersTest("With levelstein in extension",
f -> f.item(UserType.F_EXTENSION, new ItemName("string")).fuzzyString("string_value").levenshtein(2, true),
user1Oid);

}
// endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
import static com.evolveum.midpoint.prism.PrismConstants.STRING_IGNORE_CASE_MATCHING_RULE_NAME;

import com.querydsl.core.types.*;
import com.querydsl.core.types.dsl.Expressions;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.query.*;
import com.evolveum.midpoint.prism.query.FuzzyStringMatchFilter.FuzzyMatchingMethod;
import com.evolveum.midpoint.prism.query.FuzzyStringMatchFilter.Levenshtein;
import com.evolveum.midpoint.repo.sqlbase.QueryException;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
Expand Down Expand Up @@ -87,6 +91,10 @@ protected boolean isIgnoreCaseFilter(ValueFilter<?, ?> filter) {
protected <T> Predicate createBinaryCondition(
ValueFilter<?, ?> filter, Path<T> path, ValueFilterValues<?, T> values)
throws QueryException {
if (filter instanceof FuzzyStringMatchFilter<?>) {
return fuzzyStringPredicate((FuzzyStringMatchFilter<?>) filter, path, values);
}

FilterOperation operation = operation(filter);
if (values.isEmpty()) {
if (operation.isAnyEqualOperation()) {
Expand All @@ -108,6 +116,16 @@ protected <T> Predicate createBinaryCondition(
return singleValuePredicateWithNotTreated(path, operation, values.singleValue());
}

protected Predicate fuzzyStringPredicate(FuzzyStringMatchFilter<?> filter, Expression<?> path,
ValueFilterValues<?, ?> values) throws QueryException {
FuzzyMatchingMethod method = filter.getMatchingMethod();
if (method instanceof Levenshtein) {
var levenstein = (Levenshtein) method;
return Expressions.booleanTemplate("levenshtein_less_equal({0}, '{1s}', {2} ) <= {2}", path, values.singleValue().toString(), levenstein.getThreshold());
}
throw new QueryException("Unsupported filter " + filter.toString());
}

/**
* Creates predicate for specified path and value using the provided operator.
* If the value is not Querydsl {@link Expression} it is changed to constant expression,
Expand Down

0 comments on commit 1a4009f

Please sign in to comment.