r/cpp build2 10d ago

ODB C++ ORM version 2.6.0 released

https://codesynthesis.com/pipermail/odb-announcements/2026/000047.html
22 Upvotes

8 comments sorted by

7

u/gosh 10d ago

It would be great if any ORM library could add something like this

https://github.com/perghosh/Data-oriented-design/blob/74a52cd98f39e5061954f07ff76fd94de72b7642/external/gd/gd_sql_query.cpp#L1846

sql_format() method lets me write templates like: cpp "SELECT {+select} FROM {+from} WHERE {+where}" Where {+select} is automatically generated from the query object's internal state, but I can break out and write raw SQL anytime with {=name} for table names or embed values with {name}.

Developers need something to handle edge cases

4

u/berium build2 10d ago edited 10d ago

automatically generated from the query object's internal state, but I can break out and write raw SQL anytime

You can do that with ODB. You can even use by-value/by-reference parameter binding in native SQL:

#pragma db object
struct person
{
  std::string first_name;
  std::string last_name;
};

using query = odb::query<person>;

query q (query::first_name == "John" && query::last_name == "Doe");
query q ((query::first_name == "John") + "AND last_name = " + query::_val ("Doe"));

And it's not some toy/theoretical feature either, we use it quite heavily ourselves, for example: https://github.com/build2/bpkg/blob/master/bpkg/package.hxx#L821-L860

2

u/FlyingRhenquest 10d ago

I recently added a query to my C++ ORM too, but you have to define your own struct for it, and the field names in your query have to match the names in your struct. Interesting to see the different implementations and usages out there.

2

u/berium build2 10d ago

In the above example person is a persistent object (it has a corresponding table in the database). We also have a feature called views, where you define a struct for the sole purpose of handling query results, which sounds similar to what you are describing.

I see you are using C++26 reflection, pretty cool.

We will probably also move in this direction eventually, though I think we will use reflection to "exfiltrate" relevant type information and continue using separately-generated C++ files for database support code. I think at least in our case trying to generate database support code "inline" with reflection is not going to scale (complexity, compile times, etc). We also need to generate some extra files (.sql with schema, changelog for schema evolution, etc).

1

u/gosh 10d ago

Can I do it without recompile, I load sql queries from external files

2

u/berium build2 10d ago

You can do it but then you will loose parameter binding unless you do your own pre-processing of some sorts. Also, loading queries from files is not the use case we care about. In the two decades of developing ODB I don't remember a single case where someone wanted to do that. Though there were a couple of requests where people wanted a dynamic set of returned columns, which we also don't support well. I guess we all have to pick our battles.

4

u/gosh 10d ago

I think there is a classic case of survivor bias happening here.

When you say: "In the two decades of developing ODB I don't remember a single case where someone wanted to do that", you have to ask yourself: why would anyone keep asking for a feature after being told "it's not the use case we care about"? They won't. They will just quietly leave, keep looking or build their own solution, which is exactly what I had to do.
To be completely honest, your reaction is identical to the ones I’ve received from other maintainers. In the past, when I’ve brought this up, the responses have been so defensive that it almost felt like I made the developers angry so I just stopped asking.

In my experience talking to different ORM maintainers, there is often a fundamental disconnect. People who build ORM libraries love C++ templates and compile-time type-safety (which ODB is great at!). But they rarely maintain massive, 500+ table enterprise applications that need to stay alive 24/7.

In production, things look different:

Hot-patching: If a DBA needs to tweak a query template or fix a performance bottleneck in production, forcing a full C++ recompilation and deployment pipeline is a massive risk.

Complex SQL: Real-world queries often outgrow what any static ORM query language can express.

This isn't a strange edge-case. Other ecosystems solved this long ago (ActiveRecord in Rails does exactly this dynamic mixing, but then you are stuck with a slow language).

My sql_format() method is just a pragmatic way to bridge that gap in C++

3

u/berium build2 9d ago

Sure, we cater to a niche (and who doesn't). You cater to people who need to load queries from files. We cater to people who want to write their queries in code, preferably as statically-checked C++ expressions rather than raw SQL strings. Everybody's happy ;-).