Skip to content

Add support for @key and @value for Map filtering #8669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ public final class ValueReferences {
public static String RETURN_EXTENSION_NAME = "return";
public static String ITERATOR_EXTENSION_NAME = "it";
public static String EXCEPTION_EXTENSION_NAME = "exception";
public static String KEY_EXTENSION_NAME = "key";
public static String VALUE_EXTENSION_NAME = "value";
public static String DURATION_REF = SYNTHETIC_PREFIX + DURATION_EXTENSION_NAME;
public static String RETURN_REF = SYNTHETIC_PREFIX + RETURN_EXTENSION_NAME;
public static String ITERATOR_REF = SYNTHETIC_PREFIX + ITERATOR_EXTENSION_NAME;
public static String EXCEPTION_REF = SYNTHETIC_PREFIX + EXCEPTION_EXTENSION_NAME;
public static String KEY_REF = SYNTHETIC_PREFIX + KEY_EXTENSION_NAME;
public static String VALUE_REF = SYNTHETIC_PREFIX + VALUE_EXTENSION_NAME;

public static String synthetic(String name) {
return SYNTHETIC_PREFIX + name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,27 +89,27 @@ public String visit(EndsWithExpression endsWithExpression) {
public String visit(FilterCollectionExpression filterCollectionExpression) {
return "filter("
+ nullSafeAccept(filterCollectionExpression.getSource())
+ ", "
+ ", {"
+ nullSafeAccept(filterCollectionExpression.getFilterExpression())
+ ")";
+ "})";
}

@Override
public String visit(HasAllExpression hasAllExpression) {
return "all("
+ nullSafeAccept(hasAllExpression.getValueExpression())
+ ", "
+ ", {"
+ nullSafeAccept(hasAllExpression.getFilterPredicateExpression())
+ ")";
+ "})";
}

@Override
public String visit(HasAnyExpression hasAnyExpression) {
return "any("
+ nullSafeAccept(hasAnyExpression.getValueExpression())
+ ", "
+ ", {"
+ nullSafeAccept(hasAnyExpression.getFilterPredicateExpression())
+ ")";
+ "})";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ public CollectionValue<?> evaluate(ValueReferenceResolver valueRefResolver) {
} else if (collectionValue instanceof MapValue) {
MapValue materialized = (MapValue) collectionValue;
Map<Object, Object> filtered = new HashMap<>();

for (Value<?> key : materialized.getKeys()) {
Value<?> value = key.isUndefined() ? Value.undefinedValue() : materialized.get(key);
if (filterExpression.evaluate(
valueRefResolver.withExtensions(
Collections.singletonMap(
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, value))))) {
Map<String, Object> valueRefExtensions = new HashMap<>();
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, value);
valueRefExtensions.put(
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, value));
if (filterExpression.evaluate(valueRefResolver.withExtensions(valueRefExtensions))) {
filtered.put(key.getValue(), value.getValue());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import datadog.trace.bootstrap.debugger.el.ValueReferences;
import datadog.trace.bootstrap.debugger.util.WellKnownClasses;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
Expand Down Expand Up @@ -65,10 +67,13 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
}
for (Value<?> key : map.getKeys()) {
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);
Map<String, Object> valueRefExtensions = new HashMap<>();
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, val);
valueRefExtensions.put(
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
if (!filterPredicateExpression.evaluate(
valueRefResolver.withExtensions(
Collections.singletonMap(
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val))))) {
valueRefResolver.withExtensions(valueRefExtensions))) {
return Boolean.FALSE;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import datadog.trace.bootstrap.debugger.el.ValueReferences;
import datadog.trace.bootstrap.debugger.util.WellKnownClasses;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
Expand Down Expand Up @@ -65,11 +67,13 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
}
for (Value<?> key : map.getKeys()) {
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);

Map<String, Object> valueRefExtensions = new HashMap<>();
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, val);
valueRefExtensions.put(
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
if (filterPredicateExpression.evaluate(
valueRefResolver.withExtensions(
Collections.singletonMap(
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val))))) {
valueRefResolver.withExtensions(valueRefExtensions))) {
return Boolean.TRUE;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void testMatchingList() {
assertFalse(filtered.isEmpty());
assertFalse(filtered.isNull());
assertFalse(filtered.isUndefined());
assertEquals("filter(int[], @it < 2)", print(expression));
assertEquals("filter(int[], {@it < 2})", print(expression));
}

@Test
Expand All @@ -41,7 +41,7 @@ void testEmptyList() {
assertTrue(filtered.isEmpty());
assertFalse(filtered.isNull());
assertFalse(filtered.isUndefined());
assertEquals("filter(int[], @it < 2)", print(expression));
assertEquals("filter(int[], {@it < 2})", print(expression));
}

@Test
Expand All @@ -52,7 +52,7 @@ void testNullList() {
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertEquals(collection, filtered);
assertTrue(filtered.isNull());
assertEquals("filter(null, @it < 2)", print(expression));
assertEquals("filter(null, {@it < 2})", print(expression));
}

@Test
Expand All @@ -63,7 +63,7 @@ void testNullObjectList() {
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertEquals(collection, filtered);
assertTrue(filtered.isNull());
assertEquals("filter(null, @it < 2)", print(expression));
assertEquals("filter(null, {@it < 2})", print(expression));
}

@Test
Expand All @@ -74,7 +74,7 @@ void testUndefinedList() {
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertEquals(collection, filtered);
assertTrue(filtered.isUndefined());
assertEquals("filter(null, @it < 2)", print(expression));
assertEquals("filter(null, {@it < 2})", print(expression));
}

@Test
Expand Down Expand Up @@ -104,7 +104,7 @@ void testMatchingMap() {
assertFalse(filtered.isEmpty());
assertFalse(filtered.isNull());
assertFalse(filtered.isUndefined());
assertEquals("filter(Map, @it.value < 2)", print(expression));
assertEquals("filter(Map, {@it.value < 2})", print(expression));
}

@Test
Expand All @@ -117,7 +117,7 @@ void testEmptyMap() {
assertTrue(filtered.isEmpty());
assertFalse(filtered.isNull());
assertFalse(filtered.isUndefined());
assertEquals("filter(Map, @it < 2)", print(expression));
assertEquals("filter(Map, {@it < 2})", print(expression));
}

@Test
Expand All @@ -128,7 +128,7 @@ void testNullMap() {
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertEquals(collection, filtered);
assertTrue(filtered.isNull());
assertEquals("filter(null, @it < 2)", print(expression));
assertEquals("filter(null, {@it < 2})", print(expression));
}

@Test
Expand All @@ -139,7 +139,7 @@ void testNullObjectMap() {
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertEquals(collection, filtered);
assertTrue(filtered.isNull());
assertEquals("filter(null, @it < 2)", print(expression));
assertEquals("filter(null, {@it < 2})", print(expression));
}

@Test
Expand All @@ -150,6 +150,29 @@ void testUndefinedMap() {
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertEquals(collection, filtered);
assertTrue(filtered.isUndefined());
assertEquals("filter(null, @it < 2)", print(expression));
assertEquals("filter(null, {@it < 2})", print(expression));
}

@Test
void keyValueMap() {
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
MapValue collection = new MapValue(map);

FilterCollectionExpression expression =
new FilterCollectionExpression(collection, eq(ref(ValueReferences.KEY_REF), value("b")));
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertNotEquals(collection, filtered);
assertEquals(1, filtered.count());
assertEquals("filter(Map, {@key == \"b\"})", print(expression));

expression =
new FilterCollectionExpression(collection, eq(ref(ValueReferences.VALUE_REF), value(2)));
filtered = expression.evaluate(RefResolverHelper.createResolver(this));
assertNotEquals(collection, filtered);
assertEquals(1, filtered.count());
assertEquals("filter(Map, {@value == 2})", print(expression));
}
}
Loading