BJ-197: Add collection support in filter (#51)

* BJ-197: Add collection support

* BJ-197: Review performance fix

* BJ-197: Bump version to 0.5.0-SNAPSHOT

* BJ-197: Rewrite split function

* BJ-197: Rewrite test expected values
This commit is contained in:
Pavel Popov 2017-07-06 16:59:24 +03:00 committed by GitHub
parent ab86104b0a
commit db78998480
9 changed files with 136 additions and 59 deletions

View File

@ -1,6 +1,7 @@
package com.rbkmoney.geck.common.util;
import java.nio.charset.Charset;
import java.util.StringTokenizer;
/**
* Created by vpankrashkin on 03.02.17.
@ -85,6 +86,18 @@ public final class StringUtil {
return true;
}
public static String[] split(String value, String delimiter) {
StringTokenizer tokenizer = new StringTokenizer(value, delimiter);
String[] items = new String[tokenizer.countTokens()];
int itemId = 0;
while (tokenizer.hasMoreTokens()) {
items[itemId++] = tokenizer.nextToken();
}
return items;
}
public static String intToString(int number, int groupSize, int maxBits) {
StringBuilder result = new StringBuilder();

View File

@ -9,6 +9,8 @@ public interface Parser {
String getItemPath(int item);
Parser getSubParser(int from);
int size();
}

View File

@ -5,6 +5,9 @@ import com.rbkmoney.geck.common.util.TypeUtil;
import com.rbkmoney.geck.filter.rule.PathConditionRule;
import org.apache.thrift.TBase;
import org.apache.thrift.TFieldIdEnum;
import org.apache.thrift.TUnion;
import java.util.Collection;
/**
* Created by tolkonepiu on 17/03/2017.
@ -17,35 +20,45 @@ public class PathConditionFilter implements Filter<TBase> {
this.rules = rules;
}
@Override
public boolean match(TBase object) {
public boolean match(TBase value) {
for (PathConditionRule rule : rules) {
Object value = object;
Parser parser = rule.getParser();
for (int item = 0; item < parser.size(); item++) {
if (value == null || !(value instanceof TBase)) {
return false;
}
value = getFieldValue(parser.getItem(item), TypeUtil.convertType(TBase.class, value));
}
for (Condition condition : rule.getConditions()) {
if(!condition.accept(value)) {
return false;
}
if (!match(value, parser, rule.getConditions())) {
return false;
}
}
return true;
}
private Object getFieldValue(String path, TBase tBase) {
TFieldIdEnum tFieldIdEnum = TBaseUtil.getField(path, tBase);
if (tFieldIdEnum != null && tBase.isSet(tFieldIdEnum)) {
return tBase.getFieldValue(tFieldIdEnum);
public boolean match(Object value, Parser parser, Condition... conditions) {
for (int item = 0; item < parser.size(); item++) {
if (value instanceof TBase) {
TBase tBase = TypeUtil.convertType(TBase.class, value);
TFieldIdEnum tFieldIdEnum = TBaseUtil.getField(parser.getItem(item), tBase);
if (tFieldIdEnum == null
|| ((tBase instanceof TUnion) && !tBase.isSet(tFieldIdEnum))) {
return false;
}
value = tBase.getFieldValue(tFieldIdEnum);
} else if (value instanceof Collection) {
Collection collection = TypeUtil.convertType(Collection.class, value);
for (Object collectionItem : collection) {
if (match(collectionItem, parser.getSubParser(item), conditions)) {
return true;
}
}
return false;
}
}
return null;
for (Condition condition : conditions) {
if (!condition.accept(value)) {
return false;
}
}
return true;
}
}

View File

@ -1,62 +1,51 @@
package com.rbkmoney.geck.filter.parser;
import com.rbkmoney.geck.common.util.StringUtil;
import com.rbkmoney.geck.filter.Parser;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
/**
* Created by tolkonepiu on 16/03/2017.
*/
public class PathParser implements Parser {
private String fieldPath;
private List<String> items;
private List<String> forNameItems;
private final String[] items;
private final String delimiter;
public static final String DEFAULT_DELIMITER = ".";
private String delimiter;
public PathParser(String fieldPath) {
this(fieldPath, DEFAULT_DELIMITER);
}
public PathParser(String fieldPath, String delimiter) {
this.fieldPath = fieldPath;
this.delimiter = delimiter;
init();
this(StringUtil.split(fieldPath, delimiter), delimiter);
}
private void init() {
List<String> items = new ArrayList<>();
List<String> forNameItems = new ArrayList<>();
int last = 0;
int next;
while ((next = fieldPath.indexOf(delimiter, last)) != -1) {
items.add(fieldPath.substring(last, next));
forNameItems.add(fieldPath.substring(0, next));
last = next + delimiter.length();
}
forNameItems.add(fieldPath.substring(0, fieldPath.length()));
items.add(fieldPath.substring(last, fieldPath.length()));
public PathParser(String[] items, String delimiter) {
this.items = items;
this.forNameItems = forNameItems;
this.delimiter = delimiter;
}
@Override
public String getItem(int item) {
return items.get(item);
return items[item];
}
@Override
public String getItemPath(int item) {
return forNameItems.get(item);
return String.join(delimiter, Arrays.copyOfRange(items, 0, item + 1));
}
@Override
public Parser getSubParser(int from) {
return new PathParser(Arrays.copyOfRange(items, from, items.length), delimiter);
}
@Override
public int size() {
return items.size();
return items.length;
}
}

View File

@ -5,8 +5,6 @@ import com.rbkmoney.geck.filter.Parser;
import com.rbkmoney.geck.filter.Rule;
import com.rbkmoney.geck.filter.parser.PathParser;
import java.util.Objects;
/**
* Created by tolkonepiu on 16/03/2017.
*/

View File

@ -12,6 +12,7 @@ import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Created by tolkonepiu on 17/03/2017.
@ -35,6 +36,40 @@ public class PathConditionFilterTest {
testObject.setStatus(Status.ok_status(new Ok()));
testObject.setType(Type.BLACK);
testObject.setNumbers(Arrays.asList(new Long[]{23L, 31L, 41L}));
List<Ids> listIds = new ArrayList<>();
listIds.add(ids);
ids = new Ids();
ids.setMicroId((byte) 32);
ids.setMiniId((short) 33);
ids.setId(34);
listIds.add(ids);
testObject.setListIds(listIds);
List<Status> statuses1 = new ArrayList<>();
statuses1.add(Status.ok_status(new Ok()));
Unknown unknownField = new Unknown();
List<Type> resultTypes = new ArrayList<>();
resultTypes.add(Type.BLACK);
resultTypes.add(Type.GREEN);
unknownField.setUnknown(UnknownType.resultTypes(resultTypes));
statuses1.add(Status.unknown_status(unknownField));
List<List<Status>> kebabStatus = new ArrayList<>();
kebabStatus.add(statuses1);
Unknown unknownField2 = new Unknown();
List<Type> resultTypes2 = new ArrayList<>();
resultTypes2.add(Type.BLACK);
resultTypes2.add(Type.GREEN);
unknownField2.setUnknown(UnknownType.resultTypes(resultTypes));
statuses1.add(Status.unknown_status(unknownField));
List<Status> statuses2 = new ArrayList<>();
statuses1.add(Status.ok_status(new Ok()));
kebabStatus.add(statuses2);
testObject.setStatuses(kebabStatus);
testObjectList.add(testObject);
testObject = new TestObject();
@ -111,4 +146,20 @@ public class PathConditionFilterTest {
assertEquals(filter.match(testObjectList.get(0)), false);
}
@Test
public void filterInCollectionTest() {
PathConditionRule rule = new PathConditionRule("list_ids.micro_id", new EqualsCondition((byte) 32));
Filter filter = new PathConditionFilter(rule);
assertTrue(filter.match(testObjectList.get(0)));
List<Type> resultTypes = new ArrayList<>();
resultTypes.add(Type.BLACK);
resultTypes.add(Type.GREEN);
rule = new PathConditionRule("statuses.unknown_status.unknown.resultTypes", new EqualsCondition(resultTypes));
filter = new PathConditionFilter(rule);
assertTrue(filter.match(testObjectList.get(0)));
}
}

View File

@ -14,18 +14,27 @@ public class PathParserTest {
public void parserInitTest() {
Parser parser = new PathParser("kek.tsss.qwe");
assertEquals(parser.getItem(0), "kek");
assertEquals(parser.getItemPath(0), "kek");
assertEquals(parser.getItem(1), "tsss");
assertEquals(parser.getItemPath(1), "kek.tsss");
assertEquals(parser.getItem(2), "qwe");
assertEquals(parser.getItemPath(2), "kek.tsss.qwe");
assertEquals(parser.size(), 3);
assertEquals("kek", parser.getItem(0));
assertEquals("kek", parser.getItemPath(0));
assertEquals("tsss", parser.getItem(1));
assertEquals("kek.tsss", parser.getItemPath(1));
assertEquals("qwe", parser.getItem(2));
assertEquals("kek.tsss.qwe", parser.getItemPath(2));
assertEquals(3, parser.size());
parser = new PathParser("kek..kek...");
assertEquals(parser.getItem(1), "");
assertEquals(parser.getItemPath(1), "kek.");
assertEquals(parser.size(), 6);
assertEquals("kek", parser.getItem(1));
assertEquals("kek.kek", parser.getItemPath(1));
assertEquals(2, parser.size());
}
@Test
public void subParserTest() {
Parser parser = new PathParser("1.2.3.4.5");
assertEquals(5, parser.size());
parser = parser.getSubParser(2);
assertEquals(3, parser.size());
assertEquals("3.4.5", parser.getItemPath(parser.size() - 1));
}
}

View File

@ -7,6 +7,8 @@ struct TestObject {
4: required Type type
5: optional slist words
6: optional list<i64> numbers
7: optional list<Ids> list_ids
8: optional list<list<Status>> statuses
}
struct Ids {

View File

@ -12,7 +12,7 @@
<groupId>com.rbkmoney.geck</groupId>
<artifactId>parent</artifactId>
<version>0.4.0</version>
<version>0.5.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>