Hacker News new | ask | show | jobs
by valzam 28 days ago
The big problem is that raw SQL has pretty bad type inference and linting support in most editors. A query builder can still give you a lot of type safety benefits.
5 comments

A query builder is not an ORM.

ORMs build queries for you, but a query builder does not need to be an ORM.

ORMs do not inherently build queries. They only provide data transformations between relations (i.e. rows and columns) and objects. Hence the literal name: Object relation mapping. You can absolutely have ORM without query building just as much as you can have query building without ORM.

Sometimes ORMs and query builders are combined into a higher order system, such as what is described by the active record pattern. This might be what you are actually thinking of instead?

Okay, so I have an object like:

    User {
        name
        friends: List<Friend>
        posts: List<Post>
    }
Let's say we have a "MappedUser" which is derived from this type by this ORM.

I now do:

    user = get_mapped_user()
    for post in user.friends[0].friends[0].posts {
        ...
    }
Ignoring "get_mapped_user()" how does our user object work?

What happens when I access `.friends`?

Does it give me an empty list, because I didn't ask for it?

I am not aware of anything that calls itself an ORM which merely does:

    user: User = map_from_relational_to_user(query_user())
Not only is it difficult to conceptualise how this operation would ever meaningfully work for any non-trivial query, it's also difficult to see how it would even work for trivial queries.

ORMs, at their core, try to abstract away something like `user.friends[0].friends[0].posts` more or less into some underlying queries against a relational database. The main distinction between them being in the availability and first-class nature of the escape hatches when this operation inevitably becomes slow.

> Does it give me an empty list, because I didn't ask for it?

That depends on the rest of your code. If you are using something like the active record or data mapper pattern then it would reach out and fetch more results. If you don't have such mechanics in place then an empty list is possible. We don't have enough information here to say what happens.

> I am not aware of anything that calls itself an ORM which merely does

When your code merely does that, what do you call it?

> ORMs, at their core, try to abstract away something like `user.friends[0].friends[0].posts` more or less into some underlying queries against a relational database.

Active record/data mapper tries to abstract that. ORMs are a necessary piece of active record/data mapper, but one part of a larger system. You also need things like a query builder. ORM alone is not sufficient for these patterns.

> into some underlying queries against a relational database.

Unlikely. SQL is mentioned in the headline for a reason. Nobody uses relational databases in the real world. The only remaining relational database engines that are still maintained really only exist for educational purposes. I understand why you might think a relational database is necessary given that ORM stands for Object Relational Mapping, but as ORM operates on data, not databases, the data can be relational even if the backing database isn't. It simply becomes another mapping step to see them become compatible.

> That depends on the rest of your code.

No, I am asking about your hypothetical "bare bones" "ORM" which explicitly _doens't_ have anything beyond "object mapping".

> When your code merely does that, what do you call it?

Certainly not _object_ mapping. It's something between regular "data mapping" and "completely worthless." If the thing you get out of it is not something representing an object from your object model.

> ORM alone is not sufficient for these patterns.

You are talking about a definition of ORM which is at odds with any definition of ORM that I am personally aware of.

Classical ORMs focus almost entirely on providing proxy objects which represent your object model and which back accesses with additional queries.

> Unlikely. SQL is mentioned in the headline for a reason. Nobody uses relational databases in the real world.

SQL is a query language for relational databases. Unless you have another definition for "SQL" or "relational database" which is at odds with common parlance.

> I understand why you might think a relational database is necessary given that ORM stands for Object Relational Mapping, but as ORM operates on data, not databases, the data can be relational even if the backing database isn't. It simply becomes another mapping step to see them become compatible.

While certainly an ORM maps between an object model and a relational model, the fact that this could be done with something other than a relational database seems completely irrelevant to anything in this discussion.

You seem to be taking the term "Object Relational Mapping" splitting it into its constituent parts, looking at the definitions of those terms, and then assuming that the definition for the whole term is just a simple combination of the individual terms.

This is akin to me claiming that OOP doesn't require a programming language or computers, and can merely involve me buying or otherwise procuring a bunch of things (objects) and then setting them up (programming) in the form of a Rube Goldberg machine in order to perform calculations.

My earlier statements regarding the example code existed to point out that the mere act of taking some relational data and somehow converting it to objects in your object model is not "mapping" in any meaningful sense because the resulting objects would be incomplete, and in some cases would not even be able to be constructed from arbitrary relational data.

The mere act of instantiating a partial object graph from relational data is _not_ "ORM", in the same sense that writing and calling functions is not functional programming.

> I am asking about your hypothetical "bare bones" "ORM"

What does "bare bones ORM" mean? That seems like saying "bare bones sort", but like sort it seems to me like it is either something that happens or something that doesn't happen. You either map objects and relations or you don't. Are you imagining that there is some way to partially map relations and objects but somehow not go all the way? I admittedly cannot picture what that would look like. What would the purpose be?

> SQL is a query language for relational databases.

No. SQL is not for relational databases. This is most obviously observed by the fact that SQL is centred around tables instead of relations. That naming isn't just a marketing gimmick. Tables are technically different from relations. Codd, inventor of the relational model, spent a lot of time writing about why SQL isn't relational if you want a more in-depth technical explanation, but suffice to say that ORMs and SQL are not directly compatible. Although obviously they can work together if you layer in additional functionality. You can make any data shape work with another if you provide some kind of mapping between them.

Autocomplete is making me lazy. If I don't see what I'm about to type within two or three characters, I feel like the IDE isn't doing its job of helping me. So being able to type `db.Cust` and autocomplete Customers is really nice. I do know SQL, but yes, the language servers usually have a harder time connecting the SQL to my backend code, whatever language it's in, without quite a lot of config fiddling that pretty much obviates any time savings I would have gained from autocomplete.
In my database[0] you get an SDK generated from your schema. Typescript is the default and man, the autocomplete works so well.

I recently added support for SDK generation in Rust and Go, just do `disc codegen —rust` (double dash, my iPad is autocompleting the wrong dash) and you’re good to go.

[0]: https://disc.sh

I'm firmly on the ORM side of things, despite knowing SQL very well -- but your IDE/editor can fix this with bare sql. Try using Jetbrains Datagrip or the DB integration in Idea or one of the other language-specific IDEs.
Use testcontainers and make sure you have an integration test for every query..
I think the bigger problem is that SQL is in almost every language a second-class citizen. And even calling it second-class can be seen as a stretch.
I’m a SQL-lover and ORM-hater but I don’t see why any language would support another wholly different language as a first-class citizen.
Ideally, SQL wouldn’t be a wholly different language, but a library with bindings for various languages.
Time to start using plsql, ADA with first class support for embedded SQL.
That's why it's called SQL aka String Query Language. The queries are just strings.
Are you being cheeky? The S stands for Structured.
Which is why one is better off using IDEs, especially those from DB vendors.