3 ms·
> But that's what RethinkDB's query builder is. You construct a free-standing AST, let's call it x, then call x.run(conn) or (IIRC) conn.run(x) to run it. That
by ssmoot 11y ago
> But that's what RethinkDB's query builder is. You construct a free-standing AST, let's call it x, then call x.run(conn) or (IIRC) conn.run(x) to run it.
That's not what http://rethinkdb.com/docs/quickstart/ http://rethinkdb.com/docs/quickstart/ says. It shows a connection that exposes context-bound Builder methods with trigger (insert, changes, run, etc) methods.
Though that is a little more high-level than I thought at first. You're right that not everything is a `run`.
It feels like a stretch to call it an AST but maybe that's just a question of taking a closer look at the wire protocol.
> An SQL query building API can easily be understood by developers that know SQL
It can, but it's more complex with more mental overhead. It's the difference between Active Record scopes and HQL. Where HQL is a flavor of SQL with extensions for object notation that can feel pretty similar to qualified database.table.column syntax, AR scopes are (I feel) objectively more complex.
> you don't need to syntax check it
You actually do. It's just your interpreter or compiler that does so. A compiler plugin (for native support) or embedded DSL such as LINQ or the Slick DSL can accomplish the same for SQL though.
> it's hard not to need to dynamically construct queries anyway
True, but IME a Builder based API is a poor choice for that unless the scope of the Builder usage is private to a single class. Once you start passing around a mutable builder you can easily end up with unintentional side-effects.
In SQL builders it's easy for example to override a sort clause to be incompatible with a previous aggregation if the builder doesn't go to a lot of care to make that impossible. And then you might well also end up in a situation where you need to discard previously defined scopes (such as the problematic aggregation). How do you do that?
IME once you let a builder escape a very narrow scope (class-level at the most) you create a great maintenance burden and create a new category of very difficult to avoid bugs.
Interpolation/materialization of terms into an AST is a much simpler, and encourages simpler designs (IME). IOW: Writing builders should be up to the user. If the "driver" provides it, it's too easy to fall into anti-pattern traps with unintended consequences.
That's just my opinion. But bottom line, the API is much too high-level for my taste. I'd prefer something much closer to Cloudant, with a well defined syntax (if you imagined the HTTP end-points query-parameters folded into the request body instead; query vs update APIs aren't super consistent on which goes where, eg: _deleted or _rev vs keys or include_docs).
Such a high-level interface for building queries being provided for the driver is fairly unique among the databases I'm familiar with. And while it seems like a nice affordance for JavaScript users, it feels like an anti-pattern for other platforms.
I don't mean to trash RethinkDB though. On the other end of the spectrum you have DynamoDB's very cumbersome API. If I had to pick between the two I'd take RethinkDB's any day. I just think a more formal syntax for other platforms would make it feel less JavaScript centric and more at home on other platforms.
- SamReidHughes 11y ago> That's not what http://rethinkdb.com/docs/quickstart/ http://rethinkdb.com/docs/quickstart/ says. It shows a connection that exposes context-bound Builder methods with trigger (insert, changes, run, etc) methods. There isn't any sort of builder or any sort of context that anything is bound to. insert and changes aren't anything like run -- they build an AST that describes an insert query, and then you have to run them with run.
- danielmewes 11y ago> That's not what http://rethinkdb.com/docs/quickstart/ http://rethinkdb.com/docs/quickstart/ says. It shows a connection that exposes context-bound Builder methods with trigger (insert, changes, run, etc) methods. I think the confusion stems from the fact that the Quickstart guide assumes that you're running queries in the Data Explorer, a web frontend for prototyping queries. In the Data Explorer, clicking the "Run" button is what triggers the execution of the AST. If you wrote something like `r.table("tv_shows").insert(...)` in your application code, it wouldn't do anything except for returning an AST object. You can store that object, or call the `run(conn)` method on it to send it over a RethinkDB connection and execute it. Note that the `r` object in these queries has no state. You can think of it as a namespace that serves as a starting point for building queries.
- ssmoot 11y agoAh. Thank you. Yes, that was definitely unclear to me.