-
Notifications
You must be signed in to change notification settings - Fork 478
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
Parameter binding in InfluxQL (influxdata/influxdb-java#274) #429
Changes from 10 commits
2ea9ec6
658fa1d
d71f316
929cfde
7eb0b5a
f03fa37
966d781
be08bcd
58cd9eb
f761e61
2fc928e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package org.influxdb.dto; | ||
|
||
import com.squareup.moshi.JsonWriter; | ||
import java.io.IOException; | ||
import java.nio.charset.Charset; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
|
||
import org.influxdb.InfluxDBIOException; | ||
|
||
import okio.Buffer; | ||
|
||
public final class BoundParameterQuery extends Query { | ||
|
||
private final Map<String, Object> params = new HashMap<>(); | ||
|
||
private BoundParameterQuery(final String command, final String database) { | ||
super(command, database, true); | ||
} | ||
|
||
public String getParameterJsonWithUrlEncoded() { | ||
try { | ||
String jsonParameterObject = createJsonObject(params); | ||
String urlEncodedJsonParameterObject = encode(jsonParameterObject); | ||
return urlEncodedJsonParameterObject; | ||
} catch (IOException e) { | ||
throw new InfluxDBIOException(e); | ||
} | ||
} | ||
|
||
private String createJsonObject(final Map<String, Object> parameterMap) throws IOException { | ||
Buffer b = new Buffer(); | ||
JsonWriter writer = JsonWriter.of(b); | ||
writer.beginObject(); | ||
for (Entry<String, Object> pair : parameterMap.entrySet()) { | ||
String name = pair.getKey(); | ||
Object value = pair.getValue(); | ||
if (value instanceof Number) { | ||
Number number = (Number) value; | ||
writer.name(name).value(number); | ||
} else if (value instanceof String) { | ||
writer.name(name).value((String) value); | ||
} else if (value instanceof Boolean) { | ||
writer.name(name).value((Boolean) value); | ||
} else { | ||
writer.name(name).value(String.valueOf(value)); | ||
} | ||
} | ||
writer.endObject(); | ||
return b.readString(Charset.forName("utf-8")); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
final int prime = 31; | ||
int result = super.hashCode(); | ||
result = prime * result + params.hashCode(); | ||
return result; | ||
} | ||
|
||
@Override | ||
public boolean equals(final Object obj) { | ||
if (this == obj) { | ||
return true; | ||
} | ||
if (!super.equals(obj)) { | ||
return false; | ||
} | ||
BoundParameterQuery other = (BoundParameterQuery) obj; | ||
if (!params.equals(other.params)) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
public static class QueryBuilder { | ||
private BoundParameterQuery query; | ||
private String influxQL; | ||
|
||
public static QueryBuilder newQuery(final String influxQL) { | ||
QueryBuilder instance = new QueryBuilder(); | ||
instance.influxQL = influxQL; | ||
return instance; | ||
} | ||
|
||
public QueryBuilder forDatabase(final String database) { | ||
query = new BoundParameterQuery(influxQL, database); | ||
return this; | ||
} | ||
|
||
public QueryBuilder bind(final String placeholder, final Object value) { | ||
query.params.put(placeholder, value); | ||
return this; | ||
} | ||
|
||
public BoundParameterQuery create() { | ||
return query; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package org.influxdb.dto; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.io.IOException; | ||
import java.io.UnsupportedEncodingException; | ||
import java.net.URLDecoder; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
import org.influxdb.dto.BoundParameterQuery.QueryBuilder; | ||
import org.junit.Assert; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.platform.runner.JUnitPlatform; | ||
import org.junit.runner.RunWith; | ||
|
||
import com.squareup.moshi.JsonAdapter; | ||
import com.squareup.moshi.Moshi; | ||
|
||
/** | ||
* Test for the BoundParameterQuery DTO. | ||
*/ | ||
@RunWith(JUnitPlatform.class) | ||
public class BoundParameterQueryTest { | ||
|
||
@Test | ||
public void testGetParameterJsonWithUrlEncoded() throws IOException { | ||
BoundParameterQuery query = QueryBuilder.newQuery("SELECT * FROM abc WHERE integer > $i" | ||
+ "AND double = $d AND bool = $bool AND string = $string AND other = $object") | ||
.forDatabase("foobar") | ||
.bind("i", 0) | ||
.bind("d", 1.0) | ||
.bind("bool", true) | ||
.bind("string", "test") | ||
.bind("object", new Object()) | ||
.create(); | ||
|
||
Moshi moshi = new Moshi.Builder().build(); | ||
JsonAdapter<Point> adapter = moshi.adapter(Point.class); | ||
Point point = adapter.fromJson(decode(query.getParameterJsonWithUrlEncoded())); | ||
Assert.assertEquals(0, point.i); | ||
Assert.assertEquals(1.0, point.d, 0.0); | ||
Assert.assertEquals(true, point.bool); | ||
Assert.assertEquals("test", point.string); | ||
Assert.assertTrue(point.object.matches("java.lang.Object@[a-z0-9]+")); | ||
} | ||
|
||
@Test | ||
public void testEqualsAndHashCode() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this really necessary? Did you create your own hashcode/equals implementation or you are using the one provided by your IDE? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a test for hashcode and equals in Query. So I just did it for BoundParameterQuery, too. |
||
String stringA0 = "SELECT * FROM foobar WHERE a = $a"; | ||
String stringA1 = "SELECT * FROM foobar WHERE a = $a"; | ||
String stringB0 = "SELECT * FROM foobar WHERE b = $b"; | ||
|
||
Query queryA0 = QueryBuilder.newQuery(stringA0) | ||
.forDatabase(stringA0) | ||
.bind("a", 0) | ||
.create(); | ||
Query queryA1 = QueryBuilder.newQuery(stringA1) | ||
.forDatabase(stringA1) | ||
.bind("a", 0) | ||
.create(); | ||
Query queryA2 = QueryBuilder.newQuery(stringA1) | ||
.forDatabase(stringA1) | ||
.bind("a", 10) | ||
.create(); | ||
Query queryB0 = QueryBuilder.newQuery(stringB0) | ||
.forDatabase(stringB0) | ||
.bind("b", 10) | ||
.create(); | ||
|
||
assertThat(queryA0).isEqualTo(queryA0); | ||
assertThat(queryA0).isEqualTo(queryA1); | ||
assertThat(queryA0).isNotEqualTo(queryA2); | ||
assertThat(queryA0).isNotEqualTo(queryB0); | ||
assertThat(queryA0).isNotEqualTo("foobar"); | ||
|
||
assertThat(queryA0.hashCode()).isEqualTo(queryA1.hashCode()); | ||
assertThat(queryA0.hashCode()).isNotEqualTo(queryB0.hashCode()); | ||
} | ||
|
||
private static String decode(String str) throws UnsupportedEncodingException { | ||
return URLDecoder.decode(str, StandardCharsets.UTF_8.toString()); | ||
} | ||
|
||
private static class Point { | ||
int i; | ||
double d; | ||
String string; | ||
Boolean bool; | ||
String object; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The moshi library has a specific behavior when deserializing numbers: #153 (comment)
I hope casting to
Number
is enough to keep the data type on the JSON object being created here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a look at the moshi code and tested it. This works as intended.