Skip to content

Commit

Permalink
add support for contains, starts, and ends (#998)
Browse files Browse the repository at this point in the history
Update to be consistent with recent changes to Atlas
backend to support `:contains`, `:starts`, and `:ends`
query operations. These get mapped to regex so it only
impacts the query parsing.

See: Netflix/atlas#1470 and Netflix/atlas#1471.
  • Loading branch information
brharrington committed Oct 7, 2022
1 parent e816e9a commit 9e7944f
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 14 deletions.
15 changes: 3 additions & 12 deletions codequality/checkstyle.xml
Expand Up @@ -166,17 +166,8 @@
</module>
<module name="UpperEll"/>

<!-- Enable suppression comments -->
<module name="SuppressionCommentFilter">
<property name="offCommentFormat" value="CHECKSTYLE IGNORE\s+(\S+)"/>
<property name="onCommentFormat" value="CHECKSTYLE END IGNORE\s+(\S+)"/>
<property name="checkFormat" value="$1"/>
</module>
<module name="SuppressWithNearbyCommentFilter">
<!-- Syntax is "SUPPRESS CHECKSTYLE name" -->
<property name="commentFormat" value="SUPPRESS CHECKSTYLE (\w+)"/>
<property name="checkFormat" value="$1"/>
<property name="influenceFormat" value="1"/>
</module>
<!-- Enable suppression via annotation -->
<module name="SuppressWarningsHolder"/>
</module>
<module name="SuppressWarningsFilter"/>
</module>
Expand Up @@ -15,6 +15,8 @@
*/
package com.netflix.spectator.atlas.impl;

import com.netflix.spectator.impl.matcher.PatternUtils;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
Expand Down Expand Up @@ -56,7 +58,7 @@ public static Query parseQuery(String expr) {
}
}

@SuppressWarnings({"unchecked", "PMD"})
@SuppressWarnings({"unchecked", "checkstyle:MethodLength", "PMD"})
private static Object parse(String expr) {
DataExpr.AggregateFunction af;
Query q, q1, q2;
Expand Down Expand Up @@ -156,6 +158,21 @@ private static Object parse(String expr) {
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, v, true, ":reic"));
break;
case ":contains":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, ".*" + PatternUtils.escape(v)));
break;
case ":starts":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, PatternUtils.escape(v)));
break;
case ":ends":
v = (String) stack.pop();
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, ".*" + PatternUtils.escape(v) + "$"));
break;
case ":all":
q = (Query) stack.pop();
stack.push(new DataExpr.All(q));
Expand Down
Expand Up @@ -42,7 +42,10 @@ private Query parse(String expr) {
Query q1 = Parser.parseQuery(expr);
Query q2 = Parser.parseQuery(expr);
Assertions.assertEquals(q1, q2);
Assertions.assertEquals(expr, q1.toString());

Query q3 = Parser.parseQuery(q1.toString());
Assertions.assertEquals(q1, q3);
Assertions.assertEquals(q1.toString(), q3.toString());
return q1;
}

Expand Down Expand Up @@ -210,6 +213,63 @@ public void reEqualsContract() {
.verify();
}

@Test
public void containsQuery() {
Query q = parse("name,foo,:contains");
Assertions.assertTrue(q.matches(registry.createId("foo")));
Assertions.assertTrue(q.matches(registry.createId("foo_")));
Assertions.assertTrue(q.matches(registry.createId("_foo_")));
Assertions.assertTrue(q.matches(registry.createId("_foo")));
Assertions.assertFalse(q.matches(registry.createId("_Foo_")));
}

@Test
public void containsQueryEscape() {
Query q = parse("name,^$.?*+[](){}\\#&!%,:contains");
Assertions.assertEquals(
"name,.*\\^\\$\\.\\?\\*\\+\\[\\]\\(\\)\\{\\}\\\\#&!%,:re",
q.toString());
Assertions.assertTrue(q.matches(registry.createId("^$.?*+[](){}\\#&!%")));
}

@Test
public void startsQuery() {
Query q = parse("name,foo,:starts");
Assertions.assertTrue(q.matches(registry.createId("foo")));
Assertions.assertTrue(q.matches(registry.createId("foo_")));
Assertions.assertFalse(q.matches(registry.createId("_foo_")));
Assertions.assertFalse(q.matches(registry.createId("_foo")));
Assertions.assertFalse(q.matches(registry.createId("Foo_")));
}

@Test
public void startsQueryEscape() {
Query q = parse("name,^$.?*+[](){}\\#&!%,:starts");
Assertions.assertEquals(
"name,\\^\\$\\.\\?\\*\\+\\[\\]\\(\\)\\{\\}\\\\#&!%,:re",
q.toString());
Assertions.assertTrue(q.matches(registry.createId("^$.?*+[](){}\\#&!%")));
}

@Test
public void endsQuery() {
Query q = parse("name,foo,:ends");
Assertions.assertTrue(q.matches(registry.createId("foo")));
Assertions.assertFalse(q.matches(registry.createId("foo_")));
Assertions.assertFalse(q.matches(registry.createId("_foo_")));
Assertions.assertTrue(q.matches(registry.createId("_foo")));
Assertions.assertFalse(q.matches(registry.createId("_Foo")));
}

@Test
public void endsQueryEscape() {
Query q = parse("name,^$.?*+[](){}\\#&!%,:ends");
Assertions.assertEquals(
"name,.*\\^\\$\\.\\?\\*\\+\\[\\]\\(\\)\\{\\}\\\\#&!%$,:re",
q.toString());
Assertions.assertTrue(q.matches(registry.createId("^$.?*+[](){}\\#&!%")));
}

@Test
public void andQuery() {
Query q = parse("name,foo,:eq,bar,baz,:eq,:and");
Expand Down

0 comments on commit 9e7944f

Please sign in to comment.