Hacker News new | ask | show | jobs
by army 4077 days ago
'When you query with ReQL you tack on functions and “compose” your data, with SQL you tell the query engine the steps necessary (aka prescribe) to return your data:'

... what? ReQL and SQL are both declarative query languages: I don't really see the author is getting at. Is there an implication that SQL isn't declarative?

The only real difference is that the API is based around chaining function calls rather than expressing what is needed as a string - there are many SQL query builder APIs that will let you build SQL queries by chaining together function calls.

3 comments

One real difference is that you get most of the benefits of an ORM framework right in the driver, without depending on other packages or frameworks. And the API is very consistent across different languages.

The biggest problem with composing SQL strings is that you have to be very very careful about SQL injections, and if you deal with that in a slightly sophisticated, reusable manner you are half-way to an ORM already. As far as I can determine, the ReQL drivers make injection attacks very difficult.

The biggest problem with a different query language for every project is that when they get around to implementing some of the more esoteric (but extremely useful) SQL features it may not match well with what they've designed so far, and it may be hard to implement for the devs, conceptualize for the users, or just be plain weirdly tacked on causing a cognitive mismatch in how it's used (some side channel, for instance).

Using a query builder (or ORM) of some sort still allows the escape hatch of raw SQL to do those really crazy things that are sometimes needed for performance, or just because what you are trying to do is rather weird. SQL is a very mature language, it's unlikely you are going to run into something someone else hasn't before.

Datomic uses datalog but also exposes lower levels of the data accses api. This allows people with special needs to drop down and do there own thing, while others can use datalog.

It seams like a good idea to allow diffrent layers of data access.

Raw SQL still needs to be parsed and converted into some data structure. The difference I think is that in RQL you are just making the data structure on the client side then sending it to the server.
Another point of ORMs is to make queries reusable. In Django for example, you can reuse the same queryset in views, forms, templating and the admin. You can process and edit the queryset much easier than composed SQL strings.

This should also be possible to build on top of ReQL, though I don't know any examples.

Composing SQL strings at runtime should be the very last resort in my opinion.

This is what stored procedures and parameterized queries are for. Even if I am going to do dynamic SQL, I do it in a stored procedure if I can.

Then you are one of the rare SQL-englightened beings.

I still don't see how you can pass user input from, say, a python string into a stored procedure call without worrying about injections. Or converting between your app's data structures and whatever string is necessary for your stored procedure.

Your driver should be able to handle parameterized queries for you.

    query('SELECT * FROM users WHERE id = ANY ($1::int[])', [1, 2, 3]);
    query('SELECT * FROM users WHERE lower(uname) = lower($1)', 'foo');
Where's the injection vulnerability?
So I may not be an SQL expert, but why would it be difficult to produce an injection string for $1? Of course, if you supply it "guaranteed" integers, then you can't. Injections normally happen with user inputs, not constants.
Because SQL query compilers generally don't execute the parameters. They do not just concatenate the given parameter strings into the query template and then run that. Instead, parameters are always treated as parameters, the query template is compiled and the parameters are passed into that compiled representation of the query where they are simply regarded as variables, not eval'd.
lookup prepared statements.
> The only real difference is that the API is based around chaining function calls rather than expressing what is needed as a string

The query in RethinkDB is very much an expression. In the JavaScript driver you build this expression with function calls. There are other drivers which let you build the expression in a much more declarative way (like my Haskell driver).

Let me give you an arbitrary, unknown sql string in a variable `s`, and I'll do the same with a ReQL query.

The challenge is to make sure the column/field `age` is more than 20.

My code is:

   query.filter(r.row['age'] > 20)
What's yours? (Hint: start by writing a compliant SQL parser)
Let us compare this newfangled "auto-mobile" invention to my favorite form of transportation, the horse: Where would you mount your favorite riding saddle on an auto-mobile?

(Hint: start by learning metalworking)

This is nice, and as others have noted there are similar APIs that can be used with SQL. But I find it bad practice to extend arbitrary queries with additional conditions. This is very likely to lead to poor performance and perhaps correctness problems. In practice you need to have more semantic understanding of your query, so having an opaque 'query' object is no more helpful than a SQL string.
using ActiveRecord:

    query.where('age > ?', 20)
If I'm understanding you correctly.
That's moving the goalposts. The original challenge was take an arbitrary SQL query stored in a string.
I believe army's point was that when using an SQL query builder API, one does not start with a string, but something which allows them to do a similar check that you showed.

I'm also not sure how your comment replies to army's point. The point, as I understood it, is that it is not accurate to characterize SQL queries as steps that tell the engine what to do. SQL is declarative, and leaves the execution plan up to the database itself. army's comments about the API and strings were trying to point out the only perceived difference, which is not relevant to the question of declarative versus imperative.

Wait what? Not sure what you are asking for

"SELECT * FROM table WHERE age > 20"?

You already have an existing SQL query in a string variable. You need to add the age > 20 condition to that query.

  SELECT * FROM ($S) AS FOO WHERE FOO.age > 20
I think that will work for the specific case but won't generalize.
Consider:

"You already have an existing ReQL query in a string variable. You need to add the age > 20 condition to that query."

Same problem. Comparing apples and oranges, strings and some "live" code. If you put ReQL and SQL into the same category (either as a string or as a thing that represents some "live" running code that you can manipulate at runtime) then it is difficult for me, at least, to really grasp what the differences are between them. SQL is certainly not considered an imperative language, eh?

----

EDIT to respond to the comments below from TylerE and pests:

Oh but you do have ReQL as a string: when you type it into the editor, when it lives on disk as a file of source code. At some point that code becomes live and you can interact with it. The exact same basic transformation happens whether the syntax is ReQL or SQL, just in different ways and at different times depending on how you choose to run it not what syntax it's in. The issues are orthogonal and it certainly fair to demand that we compare the right things.

If you want to say that ReQL is a better syntax than SQL, well, I don't see it (yet.)

If you want to say that the product in question provides a nice way to run ReQL syntax queries in some fashion that is fundamentally better than the way that some other product allows you to run SQL queries, that is a whole different issue (and NOT the one I am addressing in my comment above.)

I hope that makes sense. ;-) Cheers!

No it's not. Because there is no such thing as a ReQL query in a string. It's an object, usually built by chain methods. There is no textual representation.

Edit to your edit: It seems you are fundamentally not getting it. The ReQL is live code in your native programming environment. That means you can inspect it and manipulate it. SQL doesn't get interpreted (or whatever, it's black box) until it hits the server.

Imagine you're in a world where there are no XML parsing libraries. SQL is a string containing XML. ReQL is a DOM object.

One is much more useful than the other.

Your argument is so silly.

You are a comparing a language (SQL is independent to the language you're programming with) to an API.

RethinkDB has API available for three languages: JavaScript, Python & Ruby. If you take look carefully while it tries to be consistent across them, there are still parts that are specific to given language. If you would want to use RethinkDB with a language that is completely different (for example a functional language), assuming RethinkDB would support it, you're guaranteed that the interaction with the DB would be completely different, while you could still use the same SQL language[1].

If you want to compare RethinkDB's API to something similar you should compare it with something like JOOQ[2].

Just to preemptively respond to argument about translating DSL to SQL. Currently modern driver communicates with database using binary protocol, the SQL is compiled on client side. You could actually skip SQL altogether, but then you would lose flexibility of being able to support many other databases.

[1] http://pgocaml.forge.ocamlcore.org/

[2] https://en.wikipedia.org/wiki/Java_Object_Oriented_Querying

Try to understand the context in which what I am saying makes sense, it will blow your mind and make you a better programmer when you do.

(Expanding upon that: We are both correct but not in the same context. There's a context in which what you are saying is true and sensible, and there is another context wherein what I am saying is true and sensible. I can switch between the contexts, so I am not trying to disagree with you, I am trying to give you data to help you to understand this other context and switch between then too. Additionally, this other context is of a higher "logical level" in the mathematical sense than the one we already have in common, and so when you do grok it I can confidently predict both that it with blow you mind and improve your ability to write software.)

You would never have a ReQL query in a string though. I don't think its fair to ask about that case.
Does a string really have the filter method?
A ReQL query does. That's the point, it's a native object you can chain stuff off of.
Then it's not a string, it's a ReQL query object. Same way a Django model instance isn't a string. Your comparison seems way too artificially made up towards Rethink, so much so that it discredits itself.

Imagine me saying "here's a SQL string, let's see which database can execute it more easily, Rethink or Postgres. Hint: Start with writing a parser to convert it to ReQL".

Why would you ever do this?