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,
 | 
			
		||||
        ENDS_WITH,
 | 
			
		||||
        CONTAINS,
 | 
			
		||||
        NOT_CONTAINS
 | 
			
		||||
        NOT_CONTAINS,
 | 
			
		||||
        IN,
 | 
			
		||||
        NOT_IN
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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());
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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',
 | 
			
		||||
  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']
 | 
			
		||||
  ]
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user