From dcb8fdd053e7d0d02710d7427819118df85d116e Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 10 Jun 2025 19:19:38 +0300 Subject: [PATCH 1/7] EdgeGrpcService - destroy if previous session exists --- .../server/service/edge/rpc/EdgeGrpcService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java index 73da3694f9..d1448d2345 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java @@ -328,6 +328,9 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i Edge edge = edgeGrpcSession.getEdge(); TenantId tenantId = edge.getTenantId(); log.info("[{}][{}] edge [{}] connected successfully.", tenantId, edgeGrpcSession.getSessionId(), edgeId); + if (sessions.containsKey(edgeId)) { + destroySession(sessions.get(edgeId)); + } sessions.put(edgeId, edgeGrpcSession); final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); newEventLock.lock(); @@ -493,7 +496,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i } finally { newEventLock.unlock(); } - toRemove.destroy(); + destroySession(toRemove); TenantId tenantId = toRemove.getEdge().getTenantId(); save(tenantId, edgeId, ACTIVITY_STATE, false); long lastDisconnectTs = System.currentTimeMillis(); @@ -506,6 +509,12 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i edgeIdServiceIdCache.evict(edgeId); } + private void destroySession(EdgeGrpcSession session) { + try (session) { + session.destroy(); + } + } + private void save(TenantId tenantId, EdgeId edgeId, String key, long value) { log.debug("[{}][{}] Updating long edge telemetry [{}] [{}]", tenantId, edgeId, key, value); if (persistToTelemetry) { From 2bd7b4d01d51930009633d957de5ce919800d2ad Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 10 Jun 2025 19:22:00 +0300 Subject: [PATCH 2/7] EDQS - fixed relations query in case multiple previous path are present --- .../query/processor/AbstractRelationQueryProcessor.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractRelationQueryProcessor.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractRelationQueryProcessor.java index 2842d57ff0..193f3bb22e 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractRelationQueryProcessor.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractRelationQueryProcessor.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.edqs.query.processor; +import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import org.thingsboard.server.common.data.permission.QueryContext; import org.thingsboard.server.common.data.query.EntityFilter; @@ -106,7 +107,7 @@ public abstract class AbstractRelationQueryProcessor ext private Set> getEntitiesSet(RelationsRepo relations) { Set> result = new HashSet<>(); - Set processed = new HashSet<>(); + Set processed = new HashSet<>(); Queue tasks = new LinkedList<>(); int maxLvl = getMaxLevel() == 0 ? MAXIMUM_QUERY_LEVEL : Math.max(1, getMaxLevel()); for (UUID uuid : getRootEntities()) { @@ -114,7 +115,7 @@ public abstract class AbstractRelationQueryProcessor ext } while (!tasks.isEmpty()) { RelationSearchTask task = tasks.poll(); - if (processed.add(task.entityId)) { + if (processed.add(task)) { var entityLvl = task.lvl + 1; Set entities = EntitySearchDirection.FROM.equals(getDirection()) ? relations.getFrom(task.entityId) : relations.getTo(task.entityId); if (isFetchLastLevelOnly() && entities.isEmpty() && task.previous != null && check(task.previous)) { @@ -157,6 +158,7 @@ public abstract class AbstractRelationQueryProcessor ext protected abstract boolean check(RelationInfo relationInfo); @RequiredArgsConstructor + @EqualsAndHashCode private static class RelationSearchTask { private final UUID entityId; private final int lvl; From dd9d954c2f232b79cd28d268e141ebab9b71881a Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 10 Jun 2025 19:29:16 +0300 Subject: [PATCH 3/7] EDQS - added SQL like style for filter contains/starts with/ends with --- ...stractEntityProfileNameQueryProcessor.java | 2 +- .../AbstractEntityProfileQueryProcessor.java | 2 +- .../processor/EntityNameQueryProcessor.java | 2 +- .../server/edqs/util/RepositoryUtils.java | 62 +++++++++++++------ .../server/edqs/repo/RepositoryUtilsTest.java | 40 +++++++++++- 5 files changed, 85 insertions(+), 23 deletions(-) diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java index b78e49879e..f881d616ef 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java @@ -36,7 +36,7 @@ public abstract class AbstractEntityProfileNameQueryProcessor(getProfileNames(this.filter)); - pattern = RepositoryUtils.toSqlLikePattern(getEntityNameFilter(filter)); + pattern = RepositoryUtils.toContainsSqlLikePattern(getEntityNameFilter(filter)); } protected abstract String getEntityNameFilter(T filter); diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java index 301ead7c63..9d043ff6fc 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java @@ -43,7 +43,7 @@ public abstract class AbstractEntityProfileQueryProcessor value.equals(predicateValue); - case STARTS_WITH -> value.startsWith(predicateValue); - case ENDS_WITH -> value.endsWith(predicateValue); + case STARTS_WITH -> toStartsWithSqlLikePattern(predicateValue).matcher(value).matches(); + case ENDS_WITH -> toEndsWithSqlLikePattern(predicateValue).matcher(value).matches(); case NOT_EQUAL -> !value.equals(predicateValue); - case CONTAINS -> value.contains(predicateValue); - case NOT_CONTAINS -> !value.contains(predicateValue); + case CONTAINS -> toContainsSqlLikePattern(predicateValue).matcher(value).matches(); + case NOT_CONTAINS -> !toContainsSqlLikePattern(predicateValue).matcher(value).matches(); case IN -> equalsAny(value, splitByCommaWithoutQuotes(predicateValue)); case NOT_IN -> !equalsAny(value, splitByCommaWithoutQuotes(predicateValue)); }; @@ -304,6 +304,15 @@ public class RepositoryUtils { return true; } else if (filterPredicates.getOperation() == OR) { for (KeyFilterPredicate filterPredicate : filterPredicates.getPredicates()) { + + // Emulate the SQL-like behavior of ThingsBoard's Entity Data Query service: + // for COMPLEX filters, return no results if filter value is empty + if (filterPredicate instanceof StringFilterPredicate stringFilterPredicate) { + if (StringUtils.isEmpty(stringFilterPredicate.getValue().getValue())) { + continue; + } + } + if (simpleKeyFilter.check(value, filterPredicate)) { return true; } @@ -314,25 +323,40 @@ public class RepositoryUtils { } } - public static Pattern toSqlLikePattern(String nameFilter) { - if (StringUtils.isNotBlank(nameFilter)) { - boolean percentSymbolOnStart = nameFilter.startsWith("%"); - boolean percentSymbolOnEnd = nameFilter.endsWith("%"); - if (percentSymbolOnStart) { - nameFilter = nameFilter.substring(1); - } - if (percentSymbolOnEnd) { - nameFilter = nameFilter.substring(0, nameFilter.length() - 1); - } - if (percentSymbolOnStart || percentSymbolOnEnd) { - return Pattern.compile((percentSymbolOnStart ? ".*" : "") + Pattern.quote(nameFilter) + (percentSymbolOnEnd ? ".*" : ""), Pattern.CASE_INSENSITIVE); - } else { - return Pattern.compile(Pattern.quote(nameFilter) + ".*", Pattern.CASE_INSENSITIVE); - } + public static Pattern toContainsSqlLikePattern(String filter) { + if (StringUtils.isNotBlank(filter)) { + return toSqlLikePattern(filter, ".*", ".*"); } return null; } + private static Pattern toStartsWithSqlLikePattern(String filter) { + return toSqlLikePattern(filter, "^", ".*"); + } + + private static Pattern toEndsWithSqlLikePattern(String filter) { + return toSqlLikePattern(filter, ".*", "$"); + } + + private static Pattern toSqlLikePattern(String value, String prefix, String suffix ) { + if (value.contains("%") || value.contains("_")) { + String regexValue = value + .replace("_", ".") + .replace("%", ".*"); + String regex; + if ("^".equals(prefix)) { + regex = "^" + regexValue + (regexValue.endsWith(".*") ? "" : ".*"); + } else if ("$".equals(suffix)) { + regex = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + "$"; + } else { + regex = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + (regexValue.endsWith(".*") ? "" : ".*"); + } + return Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + } else { + return Pattern.compile(prefix + Pattern.quote(value) + suffix, Pattern.CASE_INSENSITIVE); + } + } + @FunctionalInterface public interface SimpleKeyFilter { diff --git a/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java b/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java index 6c7444c92a..fa3784ca19 100644 --- a/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java +++ b/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java @@ -70,7 +70,45 @@ public class RepositoryUtilsTest { Arguments.of("loranet 123", getNameFilter(StringOperation.IN, "loranet 123, loranet 124"), true), Arguments.of("loranet 123", getNameFilter(StringOperation.IN, "loranet 125, loranet 126"), false), Arguments.of("loranet 123", getNameFilter(StringOperation.NOT_IN, "loranet 125, loranet 126"), true), - Arguments.of("loranet 123", getNameFilter(StringOperation.NOT_IN, "loranet 123, loranet 126"), false) + Arguments.of("loranet 123", getNameFilter(StringOperation.NOT_IN, "loranet 123, loranet 126"), false), + + // Basic CONTAINS + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%loranet"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "loranet%"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%ranet%"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%123"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%loranx%"), false), + + // Basic STARTS_WITH + Arguments.of("loranet 123", getNameFilter(StringOperation.STARTS_WITH, "loranet%"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.STARTS_WITH, "lora%"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.STARTS_WITH, "lorax%"), false), + + // Basic ENDS_WITH + Arguments.of("loranet 123", getNameFilter(StringOperation.ENDS_WITH, "%123"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.ENDS_WITH, "%23"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.ENDS_WITH, "%124"), false), + + // CONTAINS with _ + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "loranet_123"), true), // '_' = ' ' + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "loranet_12_"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "loran_t%"), true), + + // STARTS_WITH with _ + Arguments.of("loranet 123", getNameFilter(StringOperation.STARTS_WITH, "loranet_"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.STARTS_WITH, "lora__t%"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.STARTS_WITH, "lor_net%"), true), + + // ENDS_WITH with _ + Arguments.of("loranet 123", getNameFilter(StringOperation.ENDS_WITH, "_23"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.ENDS_WITH, "_2_"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.ENDS_WITH, "_3"), true), + + // Mixed patterns + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "lora__t 1%"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "lora%net%3"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%o_anet%2_3"), false), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "lora___ ___"), true) ); } From e752902cfc2d8baae5ada011042ab91c6f8e08ae Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 11 Jun 2025 12:16:56 +0300 Subject: [PATCH 4/7] Fixed case sensitive matcher --- .../org/thingsboard/server/edqs/util/RepositoryUtils.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java index 1a47c4814f..1550c1df30 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java @@ -54,7 +54,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Stream; @@ -338,7 +337,7 @@ public class RepositoryUtils { return toSqlLikePattern(filter, ".*", "$"); } - private static Pattern toSqlLikePattern(String value, String prefix, String suffix ) { + private static Pattern toSqlLikePattern(String value, String prefix, String suffix) { if (value.contains("%") || value.contains("_")) { String regexValue = value .replace("_", ".") @@ -351,9 +350,9 @@ public class RepositoryUtils { } else { regex = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + (regexValue.endsWith(".*") ? "" : ".*"); } - return Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + return Pattern.compile(regex); } else { - return Pattern.compile(prefix + Pattern.quote(value) + suffix, Pattern.CASE_INSENSITIVE); + return Pattern.compile(prefix + Pattern.quote(value) + suffix); } } From 3288ec257f8e898a7c2de2ba25fb03991b964386 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 17 Jun 2025 12:37:24 +0300 Subject: [PATCH 5/7] EDQS SQL like query updates to be in sync with legacy --- ...stractEntityProfileNameQueryProcessor.java | 2 +- .../AbstractEntityProfileQueryProcessor.java | 2 +- .../processor/EntityNameQueryProcessor.java | 2 +- .../server/edqs/util/RepositoryUtils.java | 29 ++++++------------- .../server/edqs/repo/RepositoryUtilsTest.java | 2 +- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java index f881d616ef..95a1a79392 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileNameQueryProcessor.java @@ -36,7 +36,7 @@ public abstract class AbstractEntityProfileNameQueryProcessor(getProfileNames(this.filter)); - pattern = RepositoryUtils.toContainsSqlLikePattern(getEntityNameFilter(filter)); + pattern = RepositoryUtils.toEntityNameSqlLikePattern(getEntityNameFilter(filter)); } protected abstract String getEntityNameFilter(T filter); diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java index 9d043ff6fc..94a7a95404 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/query/processor/AbstractEntityProfileQueryProcessor.java @@ -43,7 +43,7 @@ public abstract class AbstractEntityProfileQueryProcessor value.equals(predicateValue); - case STARTS_WITH -> toStartsWithSqlLikePattern(predicateValue).matcher(value).matches(); - case ENDS_WITH -> toEndsWithSqlLikePattern(predicateValue).matcher(value).matches(); + case STARTS_WITH -> toSqlLikePattern(predicateValue, "^", ".*").matcher(value).matches(); + case ENDS_WITH -> toSqlLikePattern(predicateValue, ".*", "$").matcher(value).matches(); case NOT_EQUAL -> !value.equals(predicateValue); - case CONTAINS -> toContainsSqlLikePattern(predicateValue).matcher(value).matches(); - case NOT_CONTAINS -> !toContainsSqlLikePattern(predicateValue).matcher(value).matches(); + case CONTAINS -> toSqlLikePattern(predicateValue, ".*", ".*").matcher(value).matches(); + case NOT_CONTAINS -> !toSqlLikePattern(predicateValue, ".*", ".*").matcher(value).matches(); case IN -> equalsAny(value, splitByCommaWithoutQuotes(predicateValue)); case NOT_IN -> !equalsAny(value, splitByCommaWithoutQuotes(predicateValue)); }; @@ -322,35 +322,24 @@ public class RepositoryUtils { } } - public static Pattern toContainsSqlLikePattern(String filter) { + public static Pattern toEntityNameSqlLikePattern(String filter) { if (StringUtils.isNotBlank(filter)) { - return toSqlLikePattern(filter, ".*", ".*"); + return toSqlLikePattern(filter, "", ".*"); } return null; } - private static Pattern toStartsWithSqlLikePattern(String filter) { - return toSqlLikePattern(filter, "^", ".*"); - } - - private static Pattern toEndsWithSqlLikePattern(String filter) { - return toSqlLikePattern(filter, ".*", "$"); - } - private static Pattern toSqlLikePattern(String value, String prefix, String suffix) { if (value.contains("%") || value.contains("_")) { String regexValue = value .replace("_", ".") .replace("%", ".*"); - String regex; if ("^".equals(prefix)) { - regex = "^" + regexValue + (regexValue.endsWith(".*") ? "" : ".*"); + regexValue = "^" + regexValue + (regexValue.endsWith(".*") ? "" : ".*"); } else if ("$".equals(suffix)) { - regex = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + "$"; - } else { - regex = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + (regexValue.endsWith(".*") ? "" : ".*"); + regexValue = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + "$"; } - return Pattern.compile(regex); + return Pattern.compile(regexValue); } else { return Pattern.compile(prefix + Pattern.quote(value) + suffix); } diff --git a/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java b/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java index fa3784ca19..f4c256a8cf 100644 --- a/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java +++ b/edqs/src/test/java/org/thingsboard/server/edqs/repo/RepositoryUtilsTest.java @@ -73,7 +73,7 @@ public class RepositoryUtilsTest { Arguments.of("loranet 123", getNameFilter(StringOperation.NOT_IN, "loranet 123, loranet 126"), false), // Basic CONTAINS - Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%loranet"), true), + Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%loranet"), false), Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "loranet%"), true), Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%ranet%"), true), Arguments.of("loranet 123", getNameFilter(StringOperation.CONTAINS, "%123"), true), From 969b0fec00cbce93f59ac5ccd6786ffebbc3bc9e Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 17 Jun 2025 15:49:01 +0300 Subject: [PATCH 6/7] Edqs - sql like queries case insensitive --- .../org/thingsboard/server/edqs/util/RepositoryUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java index 3ecbe0d5fa..6a3fb0fe40 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java @@ -339,9 +339,9 @@ public class RepositoryUtils { } else if ("$".equals(suffix)) { regexValue = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + "$"; } - return Pattern.compile(regexValue); + return Pattern.compile(regexValue, Pattern.CASE_INSENSITIVE); } else { - return Pattern.compile(prefix + Pattern.quote(value) + suffix); + return Pattern.compile(prefix + Pattern.quote(value) + suffix, Pattern.CASE_INSENSITIVE); } } From b0a8b9fc25b8a1045f0968a0dac6a5edf6f098c1 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 17 Jun 2025 17:32:04 +0300 Subject: [PATCH 7/7] EDQS - ignore case for name and not ignore for filters --- .../server/edqs/util/RepositoryUtils.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java index 6a3fb0fe40..fab98027ed 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/util/RepositoryUtils.java @@ -324,14 +324,19 @@ public class RepositoryUtils { public static Pattern toEntityNameSqlLikePattern(String filter) { if (StringUtils.isNotBlank(filter)) { - return toSqlLikePattern(filter, "", ".*"); + return toSqlLikePattern(filter, "", ".*", true); } return null; } private static Pattern toSqlLikePattern(String value, String prefix, String suffix) { + return toSqlLikePattern(value, prefix, suffix, false); + } + + private static Pattern toSqlLikePattern(String value, String prefix, String suffix, boolean ignoreCase) { + String regexValue; if (value.contains("%") || value.contains("_")) { - String regexValue = value + regexValue = value .replace("_", ".") .replace("%", ".*"); if ("^".equals(prefix)) { @@ -339,10 +344,10 @@ public class RepositoryUtils { } else if ("$".equals(suffix)) { regexValue = (regexValue.startsWith(".*") ? "" : ".*") + regexValue + "$"; } - return Pattern.compile(regexValue, Pattern.CASE_INSENSITIVE); } else { - return Pattern.compile(prefix + Pattern.quote(value) + suffix, Pattern.CASE_INSENSITIVE); + regexValue = prefix + Pattern.quote(value) + suffix; } + return ignoreCase ? Pattern.compile(regexValue, Pattern.CASE_INSENSITIVE) : Pattern.compile(regexValue); } @FunctionalInterface