3 ms·
I've been using Arel directly (with ActiveRecord) for a project. It's 80% of what I want, but then it inexplicably sucks at the last 20%. The whole point of a
by ef4 14y ago
I've been using Arel directly (with ActiveRecord) for a project. It's 80% of what I want, but then it inexplicably sucks at the last 20%.
The whole point of a relational algebra is that it's closed under all the relevant operations. But Arel's implementation mostly ignores this fact, and you get back different types of objects with incompatible APIs depending on what operations you use and even what order you apply them in.
Concrete example one: "foo.union(bar).union(baz)" explodes because the union operation is not composable.
Concrete example two: you can compose joins from the right but not the left. So "(foo.join(bar)).join(baz)" works but baz.join(foo.join(bar))" explodes -- but not until later when you try to dump it to sql, at which point you get an obscure exception.
When you look under the hood, you see that it's having a hard time with this stuff because it doesn't really implement relational algebra. It's mostly just an abstract syntax tree for SQL.
- dkubb 14y agoThe current version of ARel is not a relational algebra library, it's an SQL compiler according to Aaron Patterson [1]. Many of the concepts and names for internals are based on SQL not RA. There's nothing wrong with that, it's a pragmatic choice for Rails given that ActiveRecord is an RDBMS only abstraction. I've been working on a relational algebra library for ruby (tentatively) called veritas [2] where the sets are closed under all operations. Given that it's a higher level abstraction than ARel the trade off is that there's not a 1:1 mapping between it's pure RA ops and SQL operations. I err on the side of producing SQL that will returns the correct results, which means some of the queries are a bit verbose. I consider that only a temporary problem though; I believe I can get to the point where most common queries are identical to what you'd write by hand. I'm focused on correctness before performance. I've also written an optimizer [3] that takes the RA AST and rewrites it to be smaller and more efficient. It handles lots of the low hanging fruit, but there's still room for improvement. The advantage to this approach is that it simplifies the AST for all targets, not just SQL. There's even room to do per-target optimizations, which is nice because there is often multiple ways to form a query, and some approaches may be more efficient than others on different backends. [1] https://github.com/sconover/knit-js#footnotes https://github.com/sconover/knit-js#footnotes [2] https://github.com/dkubb/veritas https://github.com/dkubb/veritas [3] https://github.com/dkubb/veritas-optimizer https://github.com/dkubb/veritas-optimizer