The 4th official driver from RethinkDB • The current official drivers are for Ruby, Python and JavaScript • The first official driver in a statically typed language
implementing only some terms • So we decided to build our own • The official driver is heavily based on npiv’s driver, since it was written with Java 8 lambdas in mind
language that handles connecting to RethinkDB and serializing queries • They're very integrated with the language itself • r.table('users') .map(lambda user: user['age'] / 2 + 7)
a tree structure • So r.expr(1) + r.expr(2) * 3 • turns into something like: Add(Datum(1), Mul(Datum(2), Datum(3))) • This is close to how it gets serialized to JSON
do it all the time • We happen to have more Python devs than Java devs at RethinkDB, so it made sense for us to use Python tools • The actual code to do the generation uses Mako templates and outputs all of the classes and methods we need in one shot
from the master JSON file • This says count should show up on ReQL expressions, not the top-level (i.e. there's no r.count()) • It has 3 signatures: stream.count() stream.count("foo") stream.count(x -> x.gt(4)) • Each term also has an id "COUNT": { "include_in": ["T_EXPR"], "signatures": [ ["T_EXPR"], ["T_EXPR", "T_EXPR"], ["T_EXPR", "T_FUNC1"] ], "id": 43 },
more feasible to create a Java driver is the addition of lambdas in Java 8 • Previous to that, the only way we could have implemented ReQL would be with anonymous inner classes
is they create an anonymous class instance for any interface with exactly one method. • This is backwards compatible with existing interfaces, so it fits into Java really well
for application. You can't do something like: Function<Integer, Integer> pred = x -> x + 1; pred(3); // not allowed! • You have to call the method on the object like: pred.apply(3);
that lambdas rely on the type system to be so concise • Consider a method like: public ReQLExpr map(Object…) {…} • This takes any number of any argument type
to give it a lambda as an argument: r.table("foo").map(x -> x) • How can Java know what interface to implement? • It can't. When we implement the methods, we have to know where lambdas can be used, and how many arguments they take.
the full signature. • For instance, count has exactly three signatures: public ReQLExpr count() {…} public ReQLExpr count(Object expr) {…} public ReQLExpr count(ReQLFunction1 func) {…}
little less amenable. • map can take variable numbers of arguments, • the number of arguments it takes is how many arguments affects the type of its lambda argument
r.range().map(r.range(), (x, y) -> x + y) r.range().map(r.range(), r.range(), (x,y,z) -> x+y+z) • Signatures: public ReQLExpr map(ReQLFunction1 f) public ReQLExpr map(Object e, ReQLFunction2 f) public ReQLExpr map(Object e, Object e, ReQLFunction3 f)
shared by Python, Ruby and JavaScript is very concise literals for these data structures. • ReQL sort of expects these to be simple to express, things like pathspecs are convenient when this assumption is true • r.table('foo').filter({nested: {field: "value"}})
language tests to exercise the Java driver • Right now the driver is in "unofficial alpha", available on the branch josh/java-driver • If you want to go through the trouble of checking it out and compiling it, you can try it out now • For everyone else, we should have a packaged beta version soon
• The JSON library should be swappable to work with more frameworks • We want to add asynchronous network IO like the other drivers (probably using Netty)