Skip to content
This repository has been archived by the owner on May 17, 2024. It is now read-only.

url-encode filter parameter #3

Merged
merged 5 commits into from
Oct 21, 2021
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
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ artifacts {

group = "com.indeed"
archivesBaseName = "consul-api"
version = "1.4.8"
version = "1.4.9"

def doUploadArchives = project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')
if (doUploadArchives) {
Expand Down
25 changes: 24 additions & 1 deletion src/main/java/com/ecwid/consul/v1/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ public enum MatchingOperator {
NOT_MATCHES("not matches", false);

private final String representation;
private final String encoded;
private final boolean unary;

MatchingOperator(final String representation, final boolean unary) {
this.representation = representation;
encoded = representation.replaceAll(" ", SPACE);
this.unary = unary;
}

Expand Down Expand Up @@ -138,7 +140,7 @@ public Filter not() {

@Override
public List<String> toUrlParameters() {
return Collections.singletonList("filter=" + toString());
return Collections.singletonList("filter=" + toEncodedString());
}

@Override
Expand Down Expand Up @@ -181,6 +183,27 @@ public String toString() {
return prefix + "(" + result + ")";
}

private static final String SPACE = "%20";
private static final String DOUBLEQUOTE = "%22";

public String toEncodedString() {
final String prefix = positive ? "" : ("not" + SPACE);
if (leaf == null) {
final String result = children.stream().map(Filter::toEncodedString).collect(Collectors.joining(SPACE + boolOp + SPACE));
if ((parent == null) && positive) {
return result;
}
return prefix + "(" + result + ")";
}
if (leaf.value == null) {
return prefix + leaf.selector + SPACE + leaf.matchingOperator.encoded;
}
if ((leaf.matchingOperator == MatchingOperator.IN) || (leaf.matchingOperator == MatchingOperator.NOT_IN)) {
return prefix + DOUBLEQUOTE + leaf.value + DOUBLEQUOTE + SPACE + leaf.matchingOperator.encoded + SPACE + leaf.selector;
}
return prefix + leaf.selector + SPACE + leaf.matchingOperator.encoded + SPACE + DOUBLEQUOTE + leaf.value + DOUBLEQUOTE;
}

private enum BoolOp {
OR("or"),
AND("and");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public String getNear() {

/**
* @deprecated use {@link HealthServicesRequest.Builder#setFilter(Filter)} to filter by tags
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.tags")))}
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.Tags")))}
*/
@Deprecated
public String getTag() {
Expand All @@ -89,7 +89,7 @@ public String getTag() {

/**
* @deprecated use {@link HealthServicesRequest.Builder#setFilter(Filter)} to filter by tags
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.tags")))}
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.Tags")))}
*/
@Deprecated
public String[] getTags() {
Expand Down Expand Up @@ -146,7 +146,7 @@ public Builder setNear(String near) {

/**
* @deprecated use {@link #setFilter(Filter)}
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.tags")))}
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.Tags")))}
*/
@Deprecated
public Builder setTag(String tag) {
Expand All @@ -156,7 +156,7 @@ public Builder setTag(String tag) {

/**
* @deprecated use {@link #setFilter(Filter)}
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.tags")))}
* e.g {@code * setFilter(Filter.in(tag, Filter.Selector.of("Service.Tags")))}
*/
@Deprecated
public Builder setTags(String[] tags) {
Expand Down
62 changes: 34 additions & 28 deletions src/test/java/com/ecwid/consul/v1/FilterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,60 +32,60 @@ void shouldVerify() {
@Test
public void of() {
Filter actual = Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo"), "bar");
assertEquals("foo = \"bar\"", actual.toString());
assertFilter("foo = \"bar\"", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo")));

actual = Filter.of(Filter.MatchingOperator.NOT_EQUAL, Selector.of("foo"), "bar");
assertEquals("foo != \"bar\"", actual.toString());
assertFilter("foo != \"bar\"", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.NOT_EQUAL, Selector.of("foo")));

actual = Filter.of(Filter.MatchingOperator.IS_EMPTY, Selector.of("foo"), null);
assertEquals("foo is empty", actual.toString());
assertFilter("foo is empty", actual);
actual = Filter.of(Filter.MatchingOperator.IS_EMPTY, Selector.of("foo"));
assertEquals("foo is empty", actual.toString());
assertFilter("foo is empty", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.IS_EMPTY, Selector.of("foo"), "bar"));

actual = Filter.of(Filter.MatchingOperator.IS_NOT_EMPTY, Selector.of("foo"), null);
assertEquals("foo is not empty", actual.toString());
assertFilter("foo is not empty", actual);
actual = Filter.of(Filter.MatchingOperator.IS_NOT_EMPTY, Selector.of("foo"));
assertEquals("foo is not empty", actual.toString());
assertFilter("foo is not empty", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.IS_NOT_EMPTY, Selector.of("foo"), "bar"));

actual = Filter.of(Filter.MatchingOperator.IN, Selector.of("foo"), "bar");
assertEquals("\"bar\" in foo", actual.toString());
assertFilter("\"bar\" in foo", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.IN, Selector.of("foo")));

actual = Filter.of(Filter.MatchingOperator.NOT_IN, Selector.of("foo"), "bar");
assertEquals("\"bar\" not in foo", actual.toString());
assertFilter("\"bar\" not in foo", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.NOT_IN, Selector.of("foo")));

actual = Filter.of(Filter.MatchingOperator.CONTAINS, Selector.of("foo"), "bar");
assertEquals("foo contains \"bar\"", actual.toString());
assertFilter("foo contains \"bar\"", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.CONTAINS, Selector.of("foo")));

actual = Filter.of(Filter.MatchingOperator.NOT_CONTAINS, Selector.of("foo"), "bar");
assertEquals("foo not contains \"bar\"", actual.toString());
assertFilter("foo not contains \"bar\"", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.NOT_CONTAINS, Selector.of("foo")));

actual = Filter.of(Filter.MatchingOperator.MATCHES, Selector.of("foo"), "bar");
assertEquals("foo matches \"bar\"", actual.toString());
assertFilter("foo matches \"bar\"", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.MATCHES, Selector.of("foo")));

actual = Filter.of(Filter.MatchingOperator.NOT_MATCHES, Selector.of("foo"), "bar");
assertEquals("foo not matches \"bar\"", actual.toString());
assertFilter("foo not matches \"bar\"", actual);
assertThrows(IllegalArgumentException.class, ()-> Filter.of(Filter.MatchingOperator.NOT_MATCHES, Selector.of("foo")));
}

@Test
public void in() {
final Filter actual = Filter.in("bar", Selector.of("foo"));
assertEquals("\"bar\" in foo", actual.toString());
assertFilter("\"bar\" in foo", actual);
}

@Test
public void notIn() {
final Filter actual = Filter.notIn("bar", Selector.of("foo"));
assertEquals("\"bar\" not in foo", actual.toString());
assertFilter("\"bar\" not in foo", actual);
}

@Test
Expand All @@ -96,15 +96,15 @@ public void and() {
Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo2"), "bar2")
);

assertEquals("foo = \"bar\" and foo1 = \"bar1\" and foo2 = \"bar2\"", actual.toString());
assertFilter("foo = \"bar\" and foo1 = \"bar1\" and foo2 = \"bar2\"", actual);

final Filter actual2 = f
.or(Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo1"), "bar1"))
.and(Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo3"), "bar3"));
assertEquals("(foo = \"bar\" or foo1 = \"bar1\") and foo3 = \"bar3\"", actual2.toString());
assertFilter("(foo = \"bar\" or foo1 = \"bar1\") and foo3 = \"bar3\"", actual2);

final Filter actual3 = f.and();
assertEquals("foo = \"bar\"", actual3.toString());
assertFilter("foo = \"bar\"", actual3);
}

@Test
Expand All @@ -114,7 +114,7 @@ public void addAll() {
Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo1"), "bar1")
}
));
assertEquals("foo = \"bar\" and foo1 = \"bar1\"", actual.toString());
assertFilter("foo = \"bar\" and foo1 = \"bar1\"", actual);
}

@Test
Expand All @@ -125,15 +125,15 @@ public void or() {
Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo2"), "bar2")
);

assertEquals("foo = \"bar\" or foo1 = \"bar1\" or foo2 = \"bar2\"", actual.toString());
assertFilter("foo = \"bar\" or foo1 = \"bar1\" or foo2 = \"bar2\"", actual);

final Filter actual2 = f
.and(Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo1"), "bar1"))
.or(Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo3"), "bar3"));
assertEquals("(foo = \"bar\" and foo1 = \"bar1\") or foo3 = \"bar3\"", actual2.toString());
assertFilter("(foo = \"bar\" and foo1 = \"bar1\") or foo3 = \"bar3\"", actual2);

final Filter actual3 = f.or();
assertEquals("foo = \"bar\"", actual3.toString());
assertFilter("foo = \"bar\"", actual3);
}

@Test
Expand All @@ -143,25 +143,31 @@ public void orAll() {
Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo1"), "bar1")
}
));
assertEquals("foo = \"bar\" or foo1 = \"bar1\"", actual.toString());
assertFilter("foo = \"bar\" or foo1 = \"bar1\"", actual);
}

@Test
public void not() {
final Filter f = Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo"), "bar");
assertEquals("foo = \"bar\"", f.toString());
assertEquals("not foo = \"bar\"", f.not().toString());
assertEquals("foo = \"bar\"", f.not().not().toString());
assertFilter("foo = \"bar\"", f);
assertFilter("not foo = \"bar\"", f.not());
assertFilter("foo = \"bar\"", f.not().not());

final Filter f2 = f.and(Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo1"), "bar2"));
assertEquals("foo = \"bar\" and foo1 = \"bar2\"", f2.toString());
assertEquals("not (foo = \"bar\" and foo1 = \"bar2\")", f2.not().toString());
assertFilter("foo = \"bar\" and foo1 = \"bar2\"", f2);
assertFilter("not (foo = \"bar\" and foo1 = \"bar2\")", f2.not());
}

@Test
public void toUrlParameters() {
final Filter subject = Filter.of(Filter.MatchingOperator.EQUAL, Selector.of("foo"), "bar");
final List<String> actual = subject.toUrlParameters();
assertEquals(Collections.singletonList("filter=foo = \"bar\""), actual);
assertEquals(Collections.singletonList("filter=foo%20=%20%22bar%22"), actual);
}

private void assertFilter(final String expected, final Filter subject) {
assertEquals(expected, subject.toString());
final String encoded = expected.replaceAll(" ", "%20").replaceAll("\"", "%22");
assertEquals(encoded, subject.toEncodedString());
}
}