diff --git a/src/Rel8.hs b/src/Rel8.hs index 16a05ec8..8cae92c8 100644 --- a/src/Rel8.hs +++ b/src/Rel8.hs @@ -169,6 +169,7 @@ module Rel8 , Expr , Sql , litExpr + , coerceExpr , unsafeCastExpr , unsafeCoerceExpr , unsafeLiteral @@ -417,7 +418,7 @@ import Rel8.Expr.Default import Rel8.Expr.Eq import Rel8.Expr.Function import Rel8.Expr.Null -import Rel8.Expr.Opaleye (unsafeCastExpr, unsafeCoerceExpr, unsafeLiteral, unsafePrimExpr) +import Rel8.Expr.Opaleye (coerceExpr, unsafeCastExpr, unsafeCoerceExpr, unsafeLiteral, unsafePrimExpr) import Rel8.Expr.Ord import Rel8.Expr.Order import Rel8.Expr.Serialize diff --git a/src/Rel8/Expr/Opaleye.hs b/src/Rel8/Expr/Opaleye.hs index 983b79b7..466aad25 100644 --- a/src/Rel8/Expr/Opaleye.hs +++ b/src/Rel8/Expr/Opaleye.hs @@ -9,6 +9,7 @@ module Rel8.Expr.Opaleye ( castExpr, unsafeCastExpr , scastExpr, sunsafeCastExpr + , coerceExpr , unsafeCoerceExpr , unsafePrimExpr , unsafeLiteral @@ -19,6 +20,7 @@ where -- base import Prelude +import Data.Coerce ( Coercible ) -- opaleye import qualified Opaleye.Internal.Column as Opaleye @@ -39,6 +41,23 @@ castExpr :: Sql DBType a => Expr a -> Expr a castExpr = scastExpr typeInformation +-- | Change the type of an 'Expr' without using @CAST()@, if the +-- Haskell type can be safely coerced. +-- +-- This is useful for writing function that use @nextval()@ over @newtype@'d IDs: +-- +-- @ +-- newtype AuthorId = AuthorId Int64 +-- deriving newtype (DBType, DBEq) +-- +-- nextId :: Expr AuthorId +-- nextId = coerceExpr $ nextVal "authors_id_seq" +-- @ +-- +coerceExpr :: forall b a. Coercible a b => Expr a -> Expr b +coerceExpr = unsafeCoerceExpr + + -- | Cast an expression to a different type. Corresponds to a @CAST()@ function -- call. unsafeCastExpr :: forall b a. Sql DBType b => Expr a -> Expr b