Export materialize (#260)

The main reason I wasn't happy with this before is that there was nothing stopping you from writing `materialize query pure`. This returned query would produce invalid SQL if you actually tried to use it, because it would attempt to reference a common table expression outside the scope of the `WITH` statement.

The "solution" here is just to throw a `rebind` around the result such that `materialize` incurs an extra `Table Expr b` constraint, which means that you can't return `Query (Query a)` because `Query a` can't satisfy a `Table Expr` constraint.
This commit is contained in:
Shane 2023-07-15 12:25:04 +01:00 committed by GitHub
parent 9f372dc649
commit cdf0c761d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 8 additions and 4 deletions

View File

@ -251,6 +251,9 @@ module Rel8
, without
, withoutBy
-- ** @WITH@
, materialize
-- ** @WITH RECURSIVE@
, loop

View File

@ -33,11 +33,12 @@ import Rel8.Table.Opaleye ( unpackspec )
-- 'materialize' to use the newer @WITH foo AS MATERIALIZED bar@ syntax
-- introduced in PostgreSQL 12 in the future. Currently Rel8 does not use
-- @AS MATERIALIZED@ to support earlier PostgreSQL versions.
materialize :: Table Expr a => Query a -> (Query a -> Query b) -> Query b
materialize :: (Table Expr a, Table Expr b)
=> Query a -> (Query a -> Query b) -> Query b
materialize query f =
fromOpaleye $
(>>= rebind "with") . fromOpaleye $
withExplicit unpackspec
(toOpaleye query')
(toOpaleye . f . fromOpaleye)
where
query' = query >>= rebind "with"
query' = query >>= rebind "materialize"

View File

@ -628,7 +628,7 @@ difference a b = a <* absent b
-- | 'Q.materialize' for 'Tabulation's.
materialize :: (Table Expr k, Table Expr a)
materialize :: (Table Expr k, Table Expr a, Table Expr b)
=> Tabulation k a -> (Tabulation k a -> Query b) -> Query b
materialize tabulation f = case peek tabulation of
Tabulation query -> do