Skip to content

Commit ac4c312

Browse files
committed
Add support for @key and @value for Map filtering
Introduce 2 synthetic variables in Expression Language: - @key - @value to reference directly key or value when filtering on a map (filter, any, all) on top of existing @it variable. fix pretty print for filtering expression to add curly braces
1 parent d8de104 commit ac4c312

File tree

8 files changed

+167
-77
lines changed

8 files changed

+167
-77
lines changed

dd-java-agent/agent-debugger/debugger-bootstrap/src/main/java/datadog/trace/bootstrap/debugger/el/ValueReferences.java

+4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ public final class ValueReferences {
1414
public static String RETURN_EXTENSION_NAME = "return";
1515
public static String ITERATOR_EXTENSION_NAME = "it";
1616
public static String EXCEPTION_EXTENSION_NAME = "exception";
17+
public static String KEY_EXTENSION_NAME = "key";
18+
public static String VALUE_EXTENSION_NAME = "value";
1719
public static String DURATION_REF = SYNTHETIC_PREFIX + DURATION_EXTENSION_NAME;
1820
public static String RETURN_REF = SYNTHETIC_PREFIX + RETURN_EXTENSION_NAME;
1921
public static String ITERATOR_REF = SYNTHETIC_PREFIX + ITERATOR_EXTENSION_NAME;
2022
public static String EXCEPTION_REF = SYNTHETIC_PREFIX + EXCEPTION_EXTENSION_NAME;
23+
public static String KEY_REF = SYNTHETIC_PREFIX + KEY_EXTENSION_NAME;
24+
public static String VALUE_REF = SYNTHETIC_PREFIX + VALUE_EXTENSION_NAME;
2125

2226
public static String synthetic(String name) {
2327
return SYNTHETIC_PREFIX + name;

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/PrettyPrintVisitor.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -89,27 +89,27 @@ public String visit(EndsWithExpression endsWithExpression) {
8989
public String visit(FilterCollectionExpression filterCollectionExpression) {
9090
return "filter("
9191
+ nullSafeAccept(filterCollectionExpression.getSource())
92-
+ ", "
92+
+ ", {"
9393
+ nullSafeAccept(filterCollectionExpression.getFilterExpression())
94-
+ ")";
94+
+ "})";
9595
}
9696

9797
@Override
9898
public String visit(HasAllExpression hasAllExpression) {
9999
return "all("
100100
+ nullSafeAccept(hasAllExpression.getValueExpression())
101-
+ ", "
101+
+ ", {"
102102
+ nullSafeAccept(hasAllExpression.getFilterPredicateExpression())
103-
+ ")";
103+
+ "})";
104104
}
105105

106106
@Override
107107
public String visit(HasAnyExpression hasAnyExpression) {
108108
return "any("
109109
+ nullSafeAccept(hasAnyExpression.getValueExpression())
110-
+ ", "
110+
+ ", {"
111111
+ nullSafeAccept(hasAnyExpression.getFilterPredicateExpression())
112-
+ ")";
112+
+ "})";
113113
}
114114

115115
@Override

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/FilterCollectionExpression.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ public CollectionValue<?> evaluate(ValueReferenceResolver valueRefResolver) {
5858
} else if (collectionValue instanceof MapValue) {
5959
MapValue materialized = (MapValue) collectionValue;
6060
Map<Object, Object> filtered = new HashMap<>();
61-
6261
for (Value<?> key : materialized.getKeys()) {
6362
Value<?> value = key.isUndefined() ? Value.undefinedValue() : materialized.get(key);
64-
if (filterExpression.evaluate(
65-
valueRefResolver.withExtensions(
66-
Collections.singletonMap(
67-
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, value))))) {
63+
Map<String, Object> valueRefExtensions = new HashMap<>();
64+
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
65+
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, value);
66+
valueRefExtensions.put(
67+
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, value));
68+
if (filterExpression.evaluate(valueRefResolver.withExtensions(valueRefExtensions))) {
6869
filtered.put(key.getValue(), value.getValue());
6970
}
7071
}

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAllExpression.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import datadog.trace.bootstrap.debugger.el.ValueReferences;
1212
import datadog.trace.bootstrap.debugger.util.WellKnownClasses;
1313
import java.util.Collections;
14+
import java.util.HashMap;
15+
import java.util.Map;
1416
import java.util.Set;
1517

1618
/**
@@ -65,10 +67,13 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
6567
}
6668
for (Value<?> key : map.getKeys()) {
6769
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);
70+
Map<String, Object> valueRefExtensions = new HashMap<>();
71+
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
72+
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, val);
73+
valueRefExtensions.put(
74+
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
6875
if (!filterPredicateExpression.evaluate(
69-
valueRefResolver.withExtensions(
70-
Collections.singletonMap(
71-
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val))))) {
76+
valueRefResolver.withExtensions(valueRefExtensions))) {
7277
return Boolean.FALSE;
7378
}
7479
}

dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/expressions/HasAnyExpression.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import datadog.trace.bootstrap.debugger.el.ValueReferences;
1212
import datadog.trace.bootstrap.debugger.util.WellKnownClasses;
1313
import java.util.Collections;
14+
import java.util.HashMap;
15+
import java.util.Map;
1416
import java.util.Set;
1517

1618
/**
@@ -65,11 +67,13 @@ public Boolean evaluate(ValueReferenceResolver valueRefResolver) {
6567
}
6668
for (Value<?> key : map.getKeys()) {
6769
Value<?> val = key.isUndefined() ? Value.undefinedValue() : map.get(key);
68-
70+
Map<String, Object> valueRefExtensions = new HashMap<>();
71+
valueRefExtensions.put(ValueReferences.KEY_EXTENSION_NAME, key);
72+
valueRefExtensions.put(ValueReferences.VALUE_EXTENSION_NAME, val);
73+
valueRefExtensions.put(
74+
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val));
6975
if (filterPredicateExpression.evaluate(
70-
valueRefResolver.withExtensions(
71-
Collections.singletonMap(
72-
ValueReferences.ITERATOR_EXTENSION_NAME, new MapValue.Entry(key, val))))) {
76+
valueRefResolver.withExtensions(valueRefExtensions))) {
7377
return Boolean.TRUE;
7478
}
7579
}

dd-java-agent/agent-debugger/debugger-el/src/test/java/com/datadog/debugger/el/expressions/FilterCollectionExpressionTest.java

+33-10
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ void testMatchingList() {
2828
assertFalse(filtered.isEmpty());
2929
assertFalse(filtered.isNull());
3030
assertFalse(filtered.isUndefined());
31-
assertEquals("filter(int[], @it < 2)", print(expression));
31+
assertEquals("filter(int[], {@it < 2})", print(expression));
3232
}
3333

3434
@Test
@@ -41,7 +41,7 @@ void testEmptyList() {
4141
assertTrue(filtered.isEmpty());
4242
assertFalse(filtered.isNull());
4343
assertFalse(filtered.isUndefined());
44-
assertEquals("filter(int[], @it < 2)", print(expression));
44+
assertEquals("filter(int[], {@it < 2})", print(expression));
4545
}
4646

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

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

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

8080
@Test
@@ -104,7 +104,7 @@ void testMatchingMap() {
104104
assertFalse(filtered.isEmpty());
105105
assertFalse(filtered.isNull());
106106
assertFalse(filtered.isUndefined());
107-
assertEquals("filter(Map, @it.value < 2)", print(expression));
107+
assertEquals("filter(Map, {@it.value < 2})", print(expression));
108108
}
109109

110110
@Test
@@ -117,7 +117,7 @@ void testEmptyMap() {
117117
assertTrue(filtered.isEmpty());
118118
assertFalse(filtered.isNull());
119119
assertFalse(filtered.isUndefined());
120-
assertEquals("filter(Map, @it < 2)", print(expression));
120+
assertEquals("filter(Map, {@it < 2})", print(expression));
121121
}
122122

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

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

145145
@Test
@@ -150,6 +150,29 @@ void testUndefinedMap() {
150150
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
151151
assertEquals(collection, filtered);
152152
assertTrue(filtered.isUndefined());
153-
assertEquals("filter(null, @it < 2)", print(expression));
153+
assertEquals("filter(null, {@it < 2})", print(expression));
154+
}
155+
156+
@Test
157+
void keyValueMap() {
158+
Map<String, Integer> map = new HashMap<>();
159+
map.put("a", 1);
160+
map.put("b", 2);
161+
map.put("c", 3);
162+
MapValue collection = new MapValue(map);
163+
164+
FilterCollectionExpression expression =
165+
new FilterCollectionExpression(collection, eq(ref(ValueReferences.KEY_REF), value("b")));
166+
CollectionValue<?> filtered = expression.evaluate(RefResolverHelper.createResolver(this));
167+
assertNotEquals(collection, filtered);
168+
assertEquals(1, filtered.count());
169+
assertEquals("filter(Map, {@key == \"b\"})", print(expression));
170+
171+
expression =
172+
new FilterCollectionExpression(collection, eq(ref(ValueReferences.VALUE_REF), value(2)));
173+
filtered = expression.evaluate(RefResolverHelper.createResolver(this));
174+
assertNotEquals(collection, filtered);
175+
assertEquals(1, filtered.count());
176+
assertEquals("filter(Map, {@value == 2})", print(expression));
154177
}
155178
}

0 commit comments

Comments
 (0)