Source filtering: only accept array items if the previous include pattern matches (#22593)
Source filtering was always accepting array items even if the include pattern did not match. Closes #22557
This commit is contained in:
parent
baed02bbe2
commit
568e655fdb
|
@ -263,7 +263,7 @@ public class XContentMapValues {
|
||||||
|
|
||||||
List<Object> filteredValue = filter((Iterable<?>) value,
|
List<Object> filteredValue = filter((Iterable<?>) value,
|
||||||
subIncludeAutomaton, subIncludeState, excludeAutomaton, excludeState, matchAllAutomaton);
|
subIncludeAutomaton, subIncludeState, excludeAutomaton, excludeState, matchAllAutomaton);
|
||||||
if (includeAutomaton.isAccept(includeState) || filteredValue.isEmpty() == false) {
|
if (filteredValue.isEmpty() == false) {
|
||||||
filtered.put(key, filteredValue);
|
filtered.put(key, filteredValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,6 +286,7 @@ public class XContentMapValues {
|
||||||
CharacterRunAutomaton excludeAutomaton, int initialExcludeState,
|
CharacterRunAutomaton excludeAutomaton, int initialExcludeState,
|
||||||
CharacterRunAutomaton matchAllAutomaton) {
|
CharacterRunAutomaton matchAllAutomaton) {
|
||||||
List<Object> filtered = new ArrayList<>();
|
List<Object> filtered = new ArrayList<>();
|
||||||
|
boolean isInclude = includeAutomaton.isAccept(initialIncludeState);
|
||||||
for (Object value : iterable) {
|
for (Object value : iterable) {
|
||||||
if (value instanceof Map) {
|
if (value instanceof Map) {
|
||||||
int includeState = includeAutomaton.step(initialIncludeState, '.');
|
int includeState = includeAutomaton.step(initialIncludeState, '.');
|
||||||
|
@ -304,9 +305,8 @@ public class XContentMapValues {
|
||||||
if (filteredValue.isEmpty() == false) {
|
if (filteredValue.isEmpty() == false) {
|
||||||
filtered.add(filteredValue);
|
filtered.add(filteredValue);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (isInclude) {
|
||||||
// TODO: we have tests relying on this behavior on arrays even
|
// #22557: only accept this array value if the key we are on is accepted:
|
||||||
// if the path does not match, but this looks like a bug?
|
|
||||||
filtered.add(value);
|
filtered.add(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import static java.util.Collections.emptyMap;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static org.hamcrest.Matchers.hasEntry;
|
import static org.hamcrest.Matchers.hasEntry;
|
||||||
import static org.hamcrest.Matchers.hasKey;
|
import static org.hamcrest.Matchers.hasKey;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.hamcrest.core.IsEqual.equalTo;
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
@ -148,8 +149,8 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
extValue = XContentMapValues.extractValue("path1.test", map);
|
extValue = XContentMapValues.extractValue("path1.test", map);
|
||||||
assertThat(extValue, instanceOf(List.class));
|
assertThat(extValue, instanceOf(List.class));
|
||||||
|
|
||||||
List extListValue = (List) extValue;
|
List<?> extListValue = (List) extValue;
|
||||||
assertThat(extListValue.size(), equalTo(2));
|
assertThat(extListValue, hasSize(2));
|
||||||
|
|
||||||
builder = XContentFactory.jsonBuilder().startObject()
|
builder = XContentFactory.jsonBuilder().startObject()
|
||||||
.startObject("path1")
|
.startObject("path1")
|
||||||
|
@ -168,7 +169,7 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
assertThat(extValue, instanceOf(List.class));
|
assertThat(extValue, instanceOf(List.class));
|
||||||
|
|
||||||
extListValue = (List) extValue;
|
extListValue = (List) extValue;
|
||||||
assertThat(extListValue.size(), equalTo(2));
|
assertThat(extListValue, hasSize(2));
|
||||||
assertThat(extListValue.get(0).toString(), equalTo("value1"));
|
assertThat(extListValue.get(0).toString(), equalTo("value1"));
|
||||||
assertThat(extListValue.get(1).toString(), equalTo("value2"));
|
assertThat(extListValue.get(1).toString(), equalTo("value2"));
|
||||||
|
|
||||||
|
@ -234,9 +235,9 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("obj", "value");
|
map.put("obj", "value");
|
||||||
map.put("obj_name", "value_name");
|
map.put("obj_name", "value_name");
|
||||||
Map<String, Object> filterdMap = XContentMapValues.filter(map, new String[]{"obj_name"}, Strings.EMPTY_ARRAY);
|
Map<String, Object> filteredMap = XContentMapValues.filter(map, new String[]{"obj_name"}, Strings.EMPTY_ARRAY);
|
||||||
assertThat(filterdMap.size(), equalTo(1));
|
assertThat(filteredMap.size(), equalTo(1));
|
||||||
assertThat((String) filterdMap.get("obj_name"), equalTo("value_name"));
|
assertThat((String) filteredMap.get("obj_name"), equalTo("value_name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -251,19 +252,17 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
put("nested", 2);
|
put("nested", 2);
|
||||||
put("nested_2", 3);
|
put("nested_2", 3);
|
||||||
}}));
|
}}));
|
||||||
Map<String, Object> falteredMap = XContentMapValues.filter(map, new String[]{"array.nested"}, Strings.EMPTY_ARRAY);
|
Map<String, Object> filteredMap = XContentMapValues.filter(map, new String[]{"array.nested"}, Strings.EMPTY_ARRAY);
|
||||||
assertThat(falteredMap.size(), equalTo(1));
|
assertThat(filteredMap.size(), equalTo(1));
|
||||||
|
|
||||||
// Selecting members of objects within arrays (ex. [ 1, { nested: "value"} ]) always returns all values in the array (1 in the ex)
|
assertThat(((List<?>) filteredMap.get("array")), hasSize(1));
|
||||||
// this is expected behavior as this types of objects are not supported in ES
|
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(0)).size(), equalTo(1));
|
||||||
assertThat((Integer) ((List) falteredMap.get("array")).get(0), equalTo(1));
|
assertThat((Integer) ((Map<String, Object>) ((List) filteredMap.get("array")).get(0)).get("nested"), equalTo(2));
|
||||||
assertThat(((Map<String, Object>) ((List) falteredMap.get("array")).get(1)).size(), equalTo(1));
|
|
||||||
assertThat((Integer) ((Map<String, Object>) ((List) falteredMap.get("array")).get(1)).get("nested"), equalTo(2));
|
|
||||||
|
|
||||||
falteredMap = XContentMapValues.filter(map, new String[]{"array.*"}, Strings.EMPTY_ARRAY);
|
filteredMap = XContentMapValues.filter(map, new String[]{"array.*"}, Strings.EMPTY_ARRAY);
|
||||||
assertThat(falteredMap.size(), equalTo(1));
|
assertThat(filteredMap.size(), equalTo(1));
|
||||||
assertThat((Integer) ((List) falteredMap.get("array")).get(0), equalTo(1));
|
assertThat(((List<?>) filteredMap.get("array")), hasSize(1));
|
||||||
assertThat(((Map<String, Object>) ((List) falteredMap.get("array")).get(1)).size(), equalTo(2));
|
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(0)).size(), equalTo(2));
|
||||||
|
|
||||||
map.clear();
|
map.clear();
|
||||||
map.put("field", "value");
|
map.put("field", "value");
|
||||||
|
@ -272,16 +271,16 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
put("field", "value");
|
put("field", "value");
|
||||||
put("field2", "value2");
|
put("field2", "value2");
|
||||||
}});
|
}});
|
||||||
falteredMap = XContentMapValues.filter(map, new String[]{"obj.field"}, Strings.EMPTY_ARRAY);
|
filteredMap = XContentMapValues.filter(map, new String[]{"obj.field"}, Strings.EMPTY_ARRAY);
|
||||||
assertThat(falteredMap.size(), equalTo(1));
|
assertThat(filteredMap.size(), equalTo(1));
|
||||||
assertThat(((Map<String, Object>) falteredMap.get("obj")).size(), equalTo(1));
|
assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(1));
|
||||||
assertThat((String) ((Map<String, Object>) falteredMap.get("obj")).get("field"), equalTo("value"));
|
assertThat((String) ((Map<String, Object>) filteredMap.get("obj")).get("field"), equalTo("value"));
|
||||||
|
|
||||||
falteredMap = XContentMapValues.filter(map, new String[]{"obj.*"}, Strings.EMPTY_ARRAY);
|
filteredMap = XContentMapValues.filter(map, new String[]{"obj.*"}, Strings.EMPTY_ARRAY);
|
||||||
assertThat(falteredMap.size(), equalTo(1));
|
assertThat(filteredMap.size(), equalTo(1));
|
||||||
assertThat(((Map<String, Object>) falteredMap.get("obj")).size(), equalTo(2));
|
assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(2));
|
||||||
assertThat((String) ((Map<String, Object>) falteredMap.get("obj")).get("field"), equalTo("value"));
|
assertThat((String) ((Map<String, Object>) filteredMap.get("obj")).get("field"), equalTo("value"));
|
||||||
assertThat((String) ((Map<String, Object>) falteredMap.get("obj")).get("field2"), equalTo("value2"));
|
assertThat((String) ((Map<String, Object>) filteredMap.get("obj")).get("field2"), equalTo("value2"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +322,7 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
|
|
||||||
filteredMap = XContentMapValues.filter(map, new String[]{"array"}, new String[]{"*.field2"});
|
filteredMap = XContentMapValues.filter(map, new String[]{"array"}, new String[]{"*.field2"});
|
||||||
assertThat(filteredMap.size(), equalTo(1));
|
assertThat(filteredMap.size(), equalTo(1));
|
||||||
assertThat(((List) filteredMap.get("array")).size(), equalTo(2));
|
assertThat(((List<?>) filteredMap.get("array")), hasSize(2));
|
||||||
assertThat((Integer) ((List) filteredMap.get("array")).get(0), equalTo(1));
|
assertThat((Integer) ((List) filteredMap.get("array")).get(0), equalTo(1));
|
||||||
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).size(), equalTo(1));
|
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).size(), equalTo(1));
|
||||||
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).get("field").toString(), equalTo("value"));
|
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).get("field").toString(), equalTo("value"));
|
||||||
|
@ -436,20 +435,20 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
|
|
||||||
assertThat(filteredSource.size(), equalTo(1));
|
assertThat(filteredSource.size(), equalTo(1));
|
||||||
assertThat(filteredSource, hasKey("obj1"));
|
assertThat(filteredSource, hasKey("obj1"));
|
||||||
assertThat(((Map) filteredSource.get("obj1")).size(), Matchers.equalTo(0));
|
assertThat(((Map) filteredSource.get("obj1")).size(), equalTo(0));
|
||||||
|
|
||||||
// explicit include
|
// explicit include
|
||||||
filteredSource = XContentMapValues.filter(mapTuple.v2(), new String[]{"obj1"}, new String[]{"*.obj2"});
|
filteredSource = XContentMapValues.filter(mapTuple.v2(), new String[]{"obj1"}, new String[]{"*.obj2"});
|
||||||
assertThat(filteredSource.size(), equalTo(1));
|
assertThat(filteredSource.size(), equalTo(1));
|
||||||
assertThat(filteredSource, hasKey("obj1"));
|
assertThat(filteredSource, hasKey("obj1"));
|
||||||
assertThat(((Map) filteredSource.get("obj1")).size(), Matchers.equalTo(0));
|
assertThat(((Map) filteredSource.get("obj1")).size(), equalTo(0));
|
||||||
|
|
||||||
// wild card include
|
// wild card include
|
||||||
filteredSource = XContentMapValues.filter(mapTuple.v2(), new String[]{"*.obj2"}, new String[]{"*.obj3"});
|
filteredSource = XContentMapValues.filter(mapTuple.v2(), new String[]{"*.obj2"}, new String[]{"*.obj3"});
|
||||||
assertThat(filteredSource.size(), equalTo(1));
|
assertThat(filteredSource.size(), equalTo(1));
|
||||||
assertThat(filteredSource, hasKey("obj1"));
|
assertThat(filteredSource, hasKey("obj1"));
|
||||||
assertThat(((Map<String, Object>) filteredSource.get("obj1")), hasKey("obj2"));
|
assertThat(((Map<String, Object>) filteredSource.get("obj1")), hasKey("obj2"));
|
||||||
assertThat(((Map) ((Map) filteredSource.get("obj1")).get("obj2")).size(), Matchers.equalTo(0));
|
assertThat(((Map) ((Map) filteredSource.get("obj1")).get("obj2")).size(), equalTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked"})
|
@SuppressWarnings({"unchecked"})
|
||||||
|
@ -589,4 +588,15 @@ public class XContentMapValuesTests extends ESTestCase {
|
||||||
assertEquals(Collections.singletonMap("foobar", 2), XContentMapValues.filter(map, new String[] {"foobar"}, new String[0]));
|
assertEquals(Collections.singletonMap("foobar", 2), XContentMapValues.filter(map, new String[] {"foobar"}, new String[0]));
|
||||||
assertEquals(Collections.singletonMap("foobaz", 3), XContentMapValues.filter(map, new String[0], new String[] {"foobar"}));
|
assertEquals(Collections.singletonMap("foobaz", 3), XContentMapValues.filter(map, new String[0], new String[] {"foobar"}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPrefix() {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("photos", Arrays.asList(new String[] {"foo", "bar"}));
|
||||||
|
map.put("photosCount", 2);
|
||||||
|
|
||||||
|
Map<String, Object> filtered = XContentMapValues.filter(map, new String[] {"photosCount"}, new String[0]);
|
||||||
|
Map<String, Object> expected = new HashMap<>();
|
||||||
|
expected.put("photosCount", 2);
|
||||||
|
assertEquals(expected, filtered);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue