rel8-1.5.0.0: src/Rel8/Expr/Function.hs
{-# language FlexibleContexts #-}
{-# language FlexibleInstances #-}
{-# language MultiParamTypeClasses #-}
{-# language RecordWildCards #-}
{-# language StandaloneKindSignatures #-}
{-# language TypeFamilies #-}
{-# language TypeOperators #-}
{-# language UndecidableInstances #-}
module Rel8.Expr.Function
( Arguments
, function
, primFunction
, binaryOperator
)
where
-- base
import Data.Kind ( Constraint, Type )
import Prelude
-- opaleye
import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
-- pretty
import Text.PrettyPrint (parens, text)
-- rel8
import {-# SOURCE #-} Rel8.Expr (Expr)
import Rel8.Expr.Opaleye
( castExpr
, fromPrimExpr, toPrimExpr, zipPrimExprsWith
)
import Rel8.Schema.Escape (escape)
import Rel8.Schema.HTable (hfoldMap)
import Rel8.Schema.Null ( Sql )
import Rel8.Schema.QualifiedName (QualifiedName (..), showQualifiedName)
import Rel8.Table (Table, toColumns)
import Rel8.Type ( DBType )
-- | This type class is basically @'Table' 'Expr'@, where each column of the
-- 'Table' is an argument to the function, but it also has an additional
-- instance for @()@ for calling functions with no arguments.
type Arguments :: Type -> Constraint
class Arguments a where
arguments :: a -> [Opaleye.PrimExpr]
instance Table Expr a => Arguments a where
arguments = hfoldMap (pure . toPrimExpr) . toColumns
instance {-# OVERLAPS #-} Arguments () where
arguments _ = []
-- | @'function' name arguments@ runs the PostgreSQL function @name@ with
-- the arguments @arguments@ returning an @'Expr' a@.
function :: (Arguments arguments, Sql DBType a)
=> QualifiedName -> arguments -> Expr a
function qualified = castExpr . fromPrimExpr . primFunction qualified
primFunction :: Arguments arguments
=> QualifiedName -> arguments -> Opaleye.PrimExpr
primFunction qualified = Opaleye.FunExpr name . arguments
where
name = showQualifiedName qualified
-- | Construct an expression by applying an infix binary operator to two
-- operands.
binaryOperator :: Sql DBType c => QualifiedName -> Expr a -> Expr b -> Expr c
binaryOperator operator a b =
castExpr $ zipPrimExprsWith (Opaleye.BinExpr (Opaleye.OpOther name)) a b
where
name = showQualifiedOperator operator
showQualifiedOperator :: QualifiedName -> String
showQualifiedOperator QualifiedName {schema = mschema, ..} = case mschema of
Nothing -> name
Just schema ->
show $ text "OPERATOR" <> parens (escape schema <> text "." <> text name)