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:
commit
c875e36dc0
@ -38,6 +38,8 @@ public class StringFilterPredicate implements SimpleKeyFilterPredicate<String> {
|
|||||||
STARTS_WITH,
|
STARTS_WITH,
|
||||||
ENDS_WITH,
|
ENDS_WITH,
|
||||||
CONTAINS,
|
CONTAINS,
|
||||||
NOT_CONTAINS
|
NOT_CONTAINS,
|
||||||
|
IN,
|
||||||
|
NOT_IN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -560,11 +560,47 @@ public class EntityKeyMapping {
|
|||||||
value = "%" + value + "%";
|
value = "%" + value + "%";
|
||||||
stringOperationQuery = String.format("%s not like :%s or %s is null)", operationField, paramName, operationField);
|
stringOperationQuery = String.format("%s not like :%s or %s is null)", operationField, paramName, operationField);
|
||||||
break;
|
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);
|
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) {
|
private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) {
|
||||||
String paramName = getNextParameterName(field);
|
String paramName = getNextParameterName(field);
|
||||||
ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue().getValue());
|
ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue().getValue());
|
||||||
|
|||||||
@ -1307,6 +1307,14 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
|
|||||||
notEqualStrings.add(operationName);
|
notEqualStrings.add(operationName);
|
||||||
containsStrings.add(operationName);
|
containsStrings.add(operationName);
|
||||||
break;
|
break;
|
||||||
|
case IN:
|
||||||
|
notEqualStrings.add(operationName);
|
||||||
|
notContainsStrings.add(operationName);
|
||||||
|
break;
|
||||||
|
case NOT_IN:
|
||||||
|
notEqualStrings.add(operationName);
|
||||||
|
notContainsStrings.add(operationName);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -226,7 +226,9 @@ export enum StringOperation {
|
|||||||
STARTS_WITH = 'STARTS_WITH',
|
STARTS_WITH = 'STARTS_WITH',
|
||||||
ENDS_WITH = 'ENDS_WITH',
|
ENDS_WITH = 'ENDS_WITH',
|
||||||
CONTAINS = 'CONTAINS',
|
CONTAINS = 'CONTAINS',
|
||||||
NOT_CONTAINS = 'NOT_CONTAINS'
|
NOT_CONTAINS = 'NOT_CONTAINS',
|
||||||
|
IN = 'IN',
|
||||||
|
NOT_IN = 'NOT_IN'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const stringOperationTranslationMap = new Map<StringOperation, string>(
|
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.STARTS_WITH, 'filter.operation.starts-with'],
|
||||||
[StringOperation.ENDS_WITH, 'filter.operation.ends-with'],
|
[StringOperation.ENDS_WITH, 'filter.operation.ends-with'],
|
||||||
[StringOperation.CONTAINS, 'filter.operation.contains'],
|
[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']
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -2076,7 +2076,9 @@
|
|||||||
"greater-or-equal": "greater or equal",
|
"greater-or-equal": "greater or equal",
|
||||||
"less-or-equal": "less or equal",
|
"less-or-equal": "less or equal",
|
||||||
"and": "and",
|
"and": "and",
|
||||||
"or": "or"
|
"or": "or",
|
||||||
|
"in": "in",
|
||||||
|
"not-in": "not in"
|
||||||
},
|
},
|
||||||
"ignore-case": "ignore case",
|
"ignore-case": "ignore case",
|
||||||
"value": "Value",
|
"value": "Value",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user