Merge pull request #5200 from van-vanich/command_in

[3.3.3] Add operation IN and NOT_IN for String value type to key filter
This commit is contained in:
Andrew Shvayka 2021-12-30 13:05:39 +02:00 committed by GitHub
commit c875e36dc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 160 additions and 5 deletions

View File

@ -38,6 +38,8 @@ public class StringFilterPredicate implements SimpleKeyFilterPredicate<String> {
STARTS_WITH,
ENDS_WITH,
CONTAINS,
NOT_CONTAINS
NOT_CONTAINS,
IN,
NOT_IN
}
}

View File

@ -560,11 +560,47 @@ public class EntityKeyMapping {
value = "%" + value + "%";
stringOperationQuery = String.format("%s not like :%s or %s is null)", operationField, paramName, operationField);
break;
case IN:
stringOperationQuery = String.format("%s in (:%s))", operationField, paramName);
break;
case NOT_IN:
stringOperationQuery = String.format("%s not in (:%s))", operationField, paramName);
break;
}
switch (stringFilterPredicate.getOperation()) {
case IN:
case NOT_IN:
ctx.addStringListParameter(paramName, getListValuesWithoutQuote(value));
break;
default:
ctx.addStringParameter(paramName, value);
}
ctx.addStringParameter(paramName, value);
return String.format("((%s is not null and %s)", field, stringOperationQuery);
}
protected List<String> getListValuesWithoutQuote(String value) {
List<String> splitValues = List.of(value.trim().split("\\s*,\\s*"));
List<String> result = new ArrayList<>();
char lastWayInputValue = '#';
for (String str : splitValues) {
char startWith = str.charAt(0);
char endWith = str.charAt(str.length() - 1);
// if first value is not quote, so we return values after split
if (startWith != '\'' && startWith != '"') return splitValues;
// if value is not in quote, so we return values after split
if (startWith != endWith) return splitValues;
// if different way values, so don't replace quote and return values after split
if (lastWayInputValue != '#' && startWith != lastWayInputValue) return splitValues;
result.add(str.substring(1, str.length() - 1));
lastWayInputValue = startWith;
}
return result;
}
private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) {
String paramName = getNextParameterName(field);
ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue().getValue());

View File

@ -1307,6 +1307,14 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
notEqualStrings.add(operationName);
containsStrings.add(operationName);
break;
case IN:
notEqualStrings.add(operationName);
notContainsStrings.add(operationName);
break;
case NOT_IN:
notEqualStrings.add(operationName);
notContainsStrings.add(operationName);
break;
}
}

View File

@ -0,0 +1,103 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.sql.query;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class )
@SpringBootTest(classes = EntityKeyMapping.class)
public class EntityKeyMappingTest {
@Autowired
private EntityKeyMapping entityKeyMapping;
private static final List<String> result = List.of("device1", "device2", "device3");
@Test
public void testSplitToList() {
String value = "device1, device2, device3";
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
}
@Test
public void testReplaceSingleQuote() {
String value = "'device1', 'device2', 'device3'";
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
}
@Test
public void testReplaceDoubleQuote() {
String value = "\"device1\", \"device2\", \"device3\"";
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
}
@Test
public void testSplitWithoutSpace() {
String value = "\"device1\" , \"device2\" , \"device3\"";
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
}
@Test
public void testSaveSpacesBetweenString() {
String value = "device 1 , device 2 , device 3";
List<String> result = List.of("device 1", "device 2", "device 3");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
}
@Test
public void testSaveQuoteInString() {
String value = "device ''1 , device \"\"2 , device \"'3";
List<String> result = List.of("device ''1", "device \"\"2", "device \"'3");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
}
@Test
public void testNotDeleteQuoteWhenDifferentStyle() {
String value = "\"device1\", 'device2', \"device3\"";
List<String> result = List.of("\"device1\"", "'device2'", "\"device3\"");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
value = "'device1', \"device2\", \"device3\"";
result = List.of("'device1'", "\"device2\"", "\"device3\"");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
value = "device1, 'device2', \"device3\"";
result = List.of("device1", "'device2'", "\"device3\"");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
value = "'device1', device2, \"device3\"";
result = List.of("'device1'", "device2", "\"device3\"");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
value = "device1, \"device2\", \"device3\"";
result = List.of("device1", "\"device2\"", "\"device3\"");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
value = "\"device1\", device2, \"device3\"";
result = List.of("\"device1\"", "device2", "\"device3\"");
Assert.assertEquals(entityKeyMapping.getListValuesWithoutQuote(value), result);
}
}

View File

@ -226,7 +226,9 @@ export enum StringOperation {
STARTS_WITH = 'STARTS_WITH',
ENDS_WITH = 'ENDS_WITH',
CONTAINS = 'CONTAINS',
NOT_CONTAINS = 'NOT_CONTAINS'
NOT_CONTAINS = 'NOT_CONTAINS',
IN = 'IN',
NOT_IN = 'NOT_IN'
}
export const stringOperationTranslationMap = new Map<StringOperation, string>(
@ -236,7 +238,9 @@ export const stringOperationTranslationMap = new Map<StringOperation, string>(
[StringOperation.STARTS_WITH, 'filter.operation.starts-with'],
[StringOperation.ENDS_WITH, 'filter.operation.ends-with'],
[StringOperation.CONTAINS, 'filter.operation.contains'],
[StringOperation.NOT_CONTAINS, 'filter.operation.not-contains']
[StringOperation.NOT_CONTAINS, 'filter.operation.not-contains'],
[StringOperation.IN, 'filter.operation.in'],
[StringOperation.NOT_IN, 'filter.operation.not-in']
]
);

View File

@ -2076,7 +2076,9 @@
"greater-or-equal": "greater or equal",
"less-or-equal": "less or equal",
"and": "and",
"or": "or"
"or": "or",
"in": "in",
"not-in": "not in"
},
"ignore-case": "ignore case",
"value": "Value",