Author builds a Rust query library (rust-rel8) using CROSS JOIN LATERAL as the backbone for a composable, type-safe SQL eDSL, modeled after Haskell’s Rel8.
Key Takeaways
CROSS JOIN LATERAL with an inner filter produces the same query plan as INNER JOIN but unlocks subquery composability impossible with standard join syntax.
Haskell’s Rel8 uses the Query monad so each do-block line adds a CROSS JOIN LATERAL; the Rust port replicates this with closures and PhantomData<'scope> lifetimes.
Rust lifetimes enforce expression scope at compile time: an Expr<'scope, T> cannot escape the Query that introduced it, preventing invalid SQL generation.
The same struct serves dual roles via a Mode::T<'scope, U> ADT: field types swap between Expr<U> (query-building) and U (decoded result), eliminating separate ORM mapping boilerplate.
.many() aggregates a Query<T> into Query<ListTable<T>> (Vec output); .optional() promotes a subquery to a left outer join returning Option<T>, all without touching raw SQL.
Hacker News Comment Review
Practitioners who have built composable query layers independently arrived at the same lateral-join pattern; CTEs were a prior attempt but forced awkward differentiation between CTE clauses and regular clauses in the query DSL layer.
Commenters note that lateral joins already see real-world use for JSONB unnesting via jsonb_to_recordset, suggesting the primitive is underused more broadly, not just for eDSLs.
Raw-SQL partisans pushed back on the ORM framing; the author’s ORM critique (M2M load-before-mutate footguns, macro-summoned With<Foo, Bar> types) resonates with that crowd even if they reject the eDSL conclusion.
Notable Comments
@brikym: Points out the article never defines “eDSL” (embedded domain-specific language) upfront, a gap for readers unfamiliar with the term.