rel8-1.4.1.0: src/Rel8/Aggregate.hs
{-# language DataKinds #-}
{-# language FlexibleContexts #-}
{-# language FlexibleInstances #-}
{-# language MultiParamTypeClasses #-}
{-# language RankNTypes #-}
{-# language StandaloneKindSignatures #-}
{-# language TypeFamilies #-}
{-# language UndecidableInstances #-}
module Rel8.Aggregate
( Aggregate(..), zipOutputs
, unsafeMakeAggregate
, Aggregates
)
where
-- base
import Control.Applicative ( liftA2 )
import Data.Functor.Identity ( Identity( Identity ) )
import Data.Kind ( Constraint, Type )
import Prelude
-- profunctors
import Data.Profunctor ( dimap )
-- opaleye
import qualified Opaleye.Aggregate as Opaleye
import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
import qualified Opaleye.Internal.Column as Opaleye
-- rel8
import Rel8.Expr ( Expr )
import Rel8.Schema.HTable.Identity ( HIdentity(..) )
import qualified Rel8.Schema.Kind as K
import Rel8.Schema.Null ( Sql )
import Rel8.Table
( Table, Columns, Context, fromColumns, toColumns
, FromExprs, fromResult, toResult
, Transpose
)
import Rel8.Table.Transpose ( Transposes )
import Rel8.Type ( DBType )
-- | 'Aggregate' is a special context used by 'Rel8.aggregate'.
type Aggregate :: K.Context
newtype Aggregate a = Aggregate (Opaleye.Aggregator () (Expr a))
instance Sql DBType a => Table Aggregate (Aggregate a) where
type Columns (Aggregate a) = HIdentity a
type Context (Aggregate a) = Aggregate
type FromExprs (Aggregate a) = a
type Transpose to (Aggregate a) = to a
toColumns = HIdentity
fromColumns (HIdentity a) = a
toResult = HIdentity . Identity
fromResult (HIdentity (Identity a)) = a
-- | @Aggregates a b@ means that the columns in @a@ are all 'Aggregate's
-- for the 'Expr' columns in @b@.
type Aggregates :: Type -> Type -> Constraint
class Transposes Aggregate Expr aggregates exprs => Aggregates aggregates exprs
instance Transposes Aggregate Expr aggregates exprs => Aggregates aggregates exprs
zipOutputs :: ()
=> (Expr a -> Expr b -> Expr c) -> Aggregate a -> Aggregate b -> Aggregate c
zipOutputs f (Aggregate a) (Aggregate b) = Aggregate (liftA2 f a b)
unsafeMakeAggregate :: forall (input :: Type) (output :: Type) n n' a a'. ()
=> (Expr input -> Opaleye.PrimExpr)
-> (Opaleye.PrimExpr -> Expr output)
-> Opaleye.Aggregator (Opaleye.Field_ n a) (Opaleye.Field_ n' a')
-> Expr input
-> Aggregate output
unsafeMakeAggregate input output aggregator expr =
Aggregate $ dimap in_ out aggregator
where out = output . Opaleye.unColumn
in_ = Opaleye.Column . input . const expr