rethinkdb / docs

RethinkDB documentation
http://rethinkdb.com/docs
Apache License 2.0
117 stars 167 forks source link

Document Java driver #901

Closed chipotle closed 8 years ago

chipotle commented 9 years ago

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.

deontologician commented 9 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))
deontologician commented 9 years ago

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

deontologician commented 9 years ago

Since bracket is such a long name, it's probably more convenient to use nth when we're explicitly dealing with a numeric argument.

danielmewes commented 9 years ago

@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.

deontologician commented 9 years ago

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.

chipotle commented 9 years ago

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.

deontologician commented 9 years ago

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.

deontologician commented 9 years ago

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

deontologician commented 9 years ago

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)
deontologician commented 9 years ago

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

chipotle commented 9 years ago

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.

deontologician commented 9 years ago

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

deontologician commented 9 years ago

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

chipotle commented 9 years ago

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.

deontologician commented 9 years ago

I don't do any camel case conversion for the optargs, they're just snake case

chipotle commented 9 years ago

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 both getField and nth. Instead, use g or nth 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.)

deontologician commented 9 years ago

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.

chipotle commented 9 years ago

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 aMap<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?)

deontologician commented 9 years ago

It returns a GroupedResult

danielmewes commented 9 years ago

@deontologician Is that a list of GroupedResults?

deontologician commented 9 years ago

Ah, yeah sorry it is a List<GroupedResult>

chipotle commented 9 years ago

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.

deontologician commented 9 years ago

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)
danielmewes commented 9 years ago

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.

chipotle commented 9 years ago

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?

deontologician commented 9 years ago

This was a bug in the script, I fixed it late last week

igorlukanin commented 8 years ago

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

chipotle commented 8 years ago

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.

danielmewes commented 8 years ago

Pinging @deontologician for further input on the cursor part. Is there anything special to keep in mind?

deontologician commented 8 years ago

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

deontologician commented 8 years ago

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.

chipotle commented 8 years ago

This has been merged.