Closed chipotle closed 8 years ago
Some differences off the top of my head (these are more notes to myself to expand later than really helpful to others):
r.connection
instead of r.connect
. It returns a builder object, which you then call .connect
on when you've initialized it.
r.hashMap
and r.array
helpers for creating hashmaps and arrays
r.row
is not implemented since lambda syntax is very concise
Some terms (like contains
) don't take a truly variable number of arguments. They are expanded somewhat into a finite number of different signatures.
optargs are added to a term not as a positional argument, but with a method, like:
r.table("foo").getAll("bar").optArg("index", "barVal")
There's no operator overloading, so all math terms are like the javascript driver.
This isn't Java driver specific, but the lambda syntax is like:
expr.map(x -> x.add(2))
expr.reduce((left, right) -> left.add(right))
Also: bracket
is an explicit method in the java driver, since we can't use the same trick as in the javascript driver to overload the constructor.
So:
r.table('foo')('x')
becomes:
r.table("foo").bracket("x")
Also, annoyingly, Java doesn't allow single quotes for strings, those are reserved for characters like in C and C++, so everything has to be double quoted
Since bracket
is such a long name, it's probably more convenient to use nth
when we're explicitly dealing with a numeric argument.
@deontologician Is there getField
as well? I think we shouldn't use the bracket
term in the documentation wherever we can avoid it.
We added the bracket
term specifically because val[idx]
is ambiguous in Python and Ruby, since it can refer to either arrays or objects with slightly different meanings.
If you have to write it out anyway, I think there's rarely a reason to use the bracket
term, and it has a somewhat undescriptive name. Most of the time, using either getField
or nth
explicitly makes the query nicer to read.
Yeah, I was using bracket because it's shorter than getField
, but you're right, it's probably better that the docs use getField
explicitly. I toyed with adding an alias for bracket like .br
since it's such a common operation, it's a shame it's so verbose.
If there's a place with a few bits of example code that'd be useful -- establishing a connection with the builder object (I'm still not clear on what that would look like; the previous Java driver apparently just let you do RethinkDBConnection conn = r.connect();
for that), making a simple query, making a query that requires a lambda function, and a change feed.
Ah I forgot to link the test file: https://github.com/rethinkdb/rethinkdb/blob/josh/java-driver/drivers/java/src/test/java/RethinkDBTest.java
Daniel also mentioned having a tool to do auto-conversion from python -> java. I will build that and send it to you as well. It won't work for r.row, but it should work for the vast majority of snippets.
Also, there is an example of the connection builder here: https://github.com/rethinkdb/rethinkdb/blob/josh/java-driver/drivers/java/src/test/java/TestingFramework.java#L64
Ok, @chipotle if you check out the josh/java-driver
branch, I added the capability to convert snippets from the command line.
The script is: drivers/java/convert_tests.py
You can run it like:
$ ./convert_tests.py -e 'r.table("foo").filter(lambda x: x["bar"][2][baz][1:3] != 12 + 3, error=True)'
r.table("foo").filter(x -> x.g("bar").nth(2).bracket(baz).slice(1, 3).ne(r.add(12, 3))).optArg("error", true)
You'll notice it sends the 12 + 3 to the server, whereas python would evaluate that before sending it. There are other corner cases like that, but in general it assumes all operators are ReQL, so you'll have to probably give the output a once over to see if it makes sense
I'm probably going to need a couple specific examples about cursors, particularly the equivalents of each
, next
, and (since this one seems to be very language-specific) to_array
. In the run
command, for instance, the first example is:
for doc in r.table('marvel').run(conn):
print doc
I don't know the correct way to write this in Java.
for that one, try:
for(Map<String, Object> doc : r.table("marvel").run<Cursor<Map<String,Object>>(conn)) {
System.out.println(doc);
}
I haven't tested this, but I think it should work
This interface might change though, since usually people work with classes instead of Maps. So I'd hold off on this example for the time being, there is a PR I haven't merged that will make this nicer
Here's another question:
r.table('marvel').between(10, 20).optArg('rightBound', 'closed').run(conn);
Or
r.table('marvel').between(10, 20).optArg('right_bound', 'closed').run(conn);
I've been assuming the former, but I've noticed the Python script does the latter.
I don't do any camel case conversion for the optargs, they're just snake case
I see the script converts brackets to either .g()
or .nth()
-- from a user standpoint, is the bracket term useful (or even exposed)? I've tentatively written api/java/bracket/
to only refer to g
and to describe it as a shorthand for getField
, with a little infobox reading:
If you have used other RethinkDB client drivers, the Java driver has no direct equivalent to the "bracket" command (usually
[]
or()
depending on the language), which functions as bothgetField
andnth
. Instead, useg
ornth
explicitly.
Does this seem like a good approach? Even if there's technically a bracket()
term implemented, I don't think we should advise users to use it. (I'm not sure it should even be exposed, if it can be handled by both g
/getField
and nth
.)
The only time bracket might be useful is in very rare situations with complicated queries where you may or may not know what type the index value will be. The conversion script will convert anything like [some_var]
into .bracket(some_var)
, but that's just being conservative, in reality you'll almost always know which kind you want. I'd say it's fine to discourage using .bracket
on the bracket page, but we should probably still document it since the driver does have it implemented.
Next horrible question: group
. JavaScript returns an array whose elements are { group: "name", reduction: <data> }
while Ruby and Python return arrays whose elements are { "group name": <reduction data>" }. How does Java do this? And how should I represent the returned data? I'm guessing in reality it's going to be a
Map<String, Object>`, but I don't know if there's a canonical way to represent that in text the way we can represent documents in Python, Ruby or JS. (Maybe just JSON, assuming people will figure that out?)
It returns a GroupedResult
@deontologician Is that a list of GroupedResult
s?
Ah, yeah sorry it is a List<GroupedResult>
What data types does binary
take and receive in Java? It looks like the "Save an avatar image to an existing user record" is going to be ridiculously more complex.
It'll take a Reql queries (so like r.binary(r.http("some/image_url.jpg"))
) and byte[]
import java.nio.file.*;
Path path = Paths.get("path/to/file");
byte[] data = Files.readAllBytes(path);
r.binary(data).run(conn)
One difference between the Java and other drivers that's relevant for the run
documentation:
Our other drivers accept a noreply=True
option to run
. The Java driver doesn't accept this option. Instead there is a special method runNoReply(conn)
to run noreply queries. runNoReply
works like run(conn)
, but returns void
instead.
With r.error
, I just found that the Python -> Java script converts
r.table('marvel').get('IronMan').do(
lambda ironman: r.branch(ironman['victories'] < ironman['battles'],
r.error('impossible code path'),
ironman)
).run(conn)
Into
r.table("marvel").get("IronMan").do_(
ironman -> r.branch(
ironman.g("victories").lt(ironman.g("battles")),
r.error(),
ironman
)
).run(conn)
-- i.e., it deletes the argument in error()
. Is this a bug in the script or does Java not take arguments here?
This was a bug in the script, I fixed it late last week
Just a quick note—there should be a place in docs for POJO support which was added by this PR: https://github.com/rethinkdb/rethinkdb/pull/4889
I need to get back to the cursor bits, as that's the remaining bit of API documentation...
Basically, I need the equivalents of these, assuming they're all there:
http://rethinkdb.com/api/python/next/ (get the next item in a cursor)
http://rethinkdb.com/api/python/each/ (iterate through a cursor; this is actually just Python for
)
http://rethinkdb.com/api/python/to_array/ (list
in Python, i.e., convert to an array)
I can open up a CR later today with what I have, after converting from JS to Python.
Pinging @deontologician for further input on the cursor part. Is there anything special to keep in mind?
There's no "each" but there's next and toList
(see https://github.com/rethinkdb/rethinkdb/blob/next/drivers/java/src/main/java/com/rethinkdb/net/Cursor.java any methods marked "public")
It implements the iterator interface, so it can be used in for loops
It also implements bufferedSize
and bufferedItems
which give the number of items left before a CONTINUE
will be emitted, and a copy of those buffered items themselves, respectively.
This has been merged.
Since the official Java driver is almost complete, we need to start documenting it.
I'm initially assigning this to @deontologician just for comments and notes on how to go about it. My suspicion is that the best thing to do will be to copy the documentation from one of the existing drivers -- probably JavaScript, just because it uses camelCase for commands already -- into a new folder and then work from there.