Postgres's lateral joins allow for quite the good eDSL

· databases · Source ↗

TLDR

  • 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.

Original | Discuss on HN