From 030304a94cf5aabe14420f965a170deadec791e1 Mon Sep 17 00:00:00 2001 From: Mark Czotter Date: Mon, 13 May 2024 15:09:16 +0200 Subject: [PATCH] fix(ecl): use wildcard care instead of handcrafted regex query... ...for wild lexical search type --- .../request/ecl/EclEvaluationRequest.java | 9 ++++--- ...clEvaluationRequestPropertyFilterTest.java | 25 +++++++++++++++++++ .../core/ecl/SnomedEclEvaluationRequest.java | 9 +++++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/request/ecl/EclEvaluationRequest.java b/core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/request/ecl/EclEvaluationRequest.java index 5df61128b5..8dfd45a96a 100644 --- a/core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/request/ecl/EclEvaluationRequest.java +++ b/core/com.b2international.snowowl.core/src/com/b2international/snowowl/core/request/ecl/EclEvaluationRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2022-2023 B2i Healthcare, https://b2ihealthcare.com + * Copyright 2022-2024 B2i Healthcare, https://b2ihealthcare.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -512,8 +512,7 @@ protected Expression toExpression(final TypedSearchTermClause clause) { if (WILD_ANY.matcher(term).matches()) { return Expressions.matchAll(); } else { - final String regex = term.replace("*", ".*"); - return termRegexExpression(regex, true); + return termWildExpression(term, true); } case REGEX: if (REGEX_ANY.matcher(term).matches()) { @@ -556,6 +555,10 @@ protected Expression termCaseInsensitiveExpression(String term) { return throwUnsupported("Unable to provide case insensitive term expression for term filter: " + term); } + protected Expression termWildExpression(String wild, boolean caseInsensitive) { + return throwUnsupported("Unable to provide wild term expression for term filter: " + wild); + } + protected Expression termRegexExpression(String regex, boolean caseInsensitive) { return throwUnsupported("Unable to provide regex term expression for term filter: " + regex); } diff --git a/snomed/com.b2international.snowowl.snomed.datastore.tests/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequestPropertyFilterTest.java b/snomed/com.b2international.snowowl.snomed.datastore.tests/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequestPropertyFilterTest.java index 2d6b1f4782..69eb1982bf 100644 --- a/snomed/com.b2international.snowowl.snomed.datastore.tests/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequestPropertyFilterTest.java +++ b/snomed/com.b2international.snowowl.snomed.datastore.tests/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequestPropertyFilterTest.java @@ -291,6 +291,31 @@ public void termRegexAnyCharacterShouldNotCreateQueryClause() throws Exception { assertEquals(expected, actualThree); } + @Test + public void termWildEscapedAnyCharacterShouldNotGenerateInvalidRegexQuery() throws Exception { + indexRevision(MAIN, SnomedDescriptionIndexEntry.builder() + .id(generateDescriptionId()) + .active(true) + .moduleId(Concepts.MODULE_SCT_CORE) + .term("Clinical finding with * character") + .conceptId(Concepts.ALL_SNOMEDCT_CONTENT) + .typeId(Concepts.TEXT_DEFINITION) + .build()); + + indexRevision(MAIN, SnomedDescriptionIndexEntry.builder() + .id(generateDescriptionId()) + .active(true) + .moduleId(Concepts.MODULE_SCT_CORE) + .term("Clinical finding without the any character") + .conceptId(Concepts.ALL_PRECOORDINATED_CONTENT) + .typeId(Concepts.TEXT_DEFINITION) + .build()); + + final Expression actual = eval("* {{ term = wild:'*\\\\**\' }}"); + Expression expected = SnomedDocument.Expressions.ids(Set.of(Concepts.ALL_SNOMEDCT_CONTENT)); + assertEquals(expected, actual); + } + @Test public void disjunctionActiveAndModuleId() throws Exception { final Expression actual = eval("* {{ c active = true OR moduleId = " + Concepts.MODULE_SCT_CORE + " }}"); diff --git a/snomed/com.b2international.snowowl.snomed.datastore/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequest.java b/snomed/com.b2international.snowowl.snomed.datastore/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequest.java index 523b5bb100..cc6c6a890d 100644 --- a/snomed/com.b2international.snowowl.snomed.datastore/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequest.java +++ b/snomed/com.b2international.snowowl.snomed.datastore/src/com/b2international/snowowl/snomed/core/ecl/SnomedEclEvaluationRequest.java @@ -23,8 +23,6 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import jakarta.validation.constraints.NotNull; - import org.eclipse.emf.ecore.EObject; import com.b2international.commons.collections.Collections3; @@ -63,6 +61,8 @@ import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimap; +import jakarta.validation.constraints.NotNull; + /** * Evaluates the given ECL expression {@link String} or parsed {@link ExpressionConstraint} to an executable {@link Expression query expression}. *

@@ -632,6 +632,11 @@ protected Expression termRegexExpression(String regex, boolean caseInsensitive) return Expressions.regexp(SnomedDescriptionIndexEntry.Fields.TERM, regex, caseInsensitive); } + @Override + protected Expression termWildExpression(String wild, boolean caseInsensitive) { + return Expressions.wildcard(SnomedDescriptionIndexEntry.Fields.TERM, wild, caseInsensitive); + } + @Override protected Expression termCaseInsensitiveExpression(String term) { return com.b2international.snowowl.core.request.search.TermFilter.exact().term(term).caseSensitive(false).build().toExpression(SnomedDescriptionIndexEntry.Fields.TERM);