-- | Perform aggregations on query results.
module Opaleye.SQLite.Aggregate (module Opaleye.SQLite.Aggregate, Aggregator) where

import qualified Opaleye.SQLite.Internal.Aggregate as A
import           Opaleye.SQLite.Internal.Aggregate (Aggregator)
import qualified Opaleye.SQLite.Internal.Column as IC
import           Opaleye.SQLite.QueryArr (Query)
import qualified Opaleye.SQLite.Internal.QueryArr as Q
import qualified Opaleye.SQLite.Column as C
import qualified Opaleye.SQLite.Order as Ord
import qualified Opaleye.SQLite.PGTypes as T
import qualified Opaleye.SQLite.Internal.HaskellDB.PrimQuery as HPQ

-- This page of Postgres documentation tell us what aggregate
-- functions are available
--
--   http://www.postgresql.org/docs/9.3/static/functions-aggregate.html

{-|
Given a 'Query' producing rows of type @a@ and an 'Aggregator' accepting rows of
type @a@, apply the aggregator to the results of the query.

-}
aggregate :: Aggregator a b -> Query a -> Query b
aggregate :: Aggregator a b -> Query a -> Query b
aggregate Aggregator a b
agg Query a
q = (((), Tag) -> (b, PrimQuery, Tag)) -> Query b
forall a b. ((a, Tag) -> (b, PrimQuery, Tag)) -> QueryArr a b
Q.simpleQueryArr (Aggregator a b -> (a, PrimQuery, Tag) -> (b, PrimQuery, Tag)
forall a b.
Aggregator a b -> (a, PrimQuery, Tag) -> (b, PrimQuery, Tag)
A.aggregateU Aggregator a b
agg ((a, PrimQuery, Tag) -> (b, PrimQuery, Tag))
-> (((), Tag) -> (a, PrimQuery, Tag))
-> ((), Tag)
-> (b, PrimQuery, Tag)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Query a -> ((), Tag) -> (a, PrimQuery, Tag)
forall a b. QueryArr a b -> (a, Tag) -> (b, PrimQuery, Tag)
Q.runSimpleQueryArr Query a
q)

-- | Group the aggregation by equality on the input to 'groupBy'.
groupBy :: Aggregator (C.Column a) (C.Column a)
groupBy :: Aggregator (Column a) (Column a)
groupBy = Maybe AggrOp -> Aggregator (Column a) (Column a)
forall a b. Maybe AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr' Maybe AggrOp
forall a. Maybe a
Nothing

-- | Sum all rows in a group.
sum :: Aggregator (C.Column a) (C.Column a)
sum :: Aggregator (Column a) (Column a)
sum = AggrOp -> Aggregator (Column a) (Column a)
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrSum

-- | Count the number of non-null rows in a group.
count :: Aggregator (C.Column a) (C.Column T.PGInt8)
count :: Aggregator (Column a) (Column PGInt8)
count = AggrOp -> Aggregator (Column a) (Column PGInt8)
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrCount

-- | Average of a group
avg :: Aggregator (C.Column T.PGFloat8) (C.Column T.PGFloat8)
avg :: Aggregator (Column PGFloat8) (Column PGFloat8)
avg = AggrOp -> Aggregator (Column PGFloat8) (Column PGFloat8)
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrAvg

-- | Maximum of a group
max :: Ord.PGOrd a => Aggregator (C.Column a) (C.Column a)
max :: Aggregator (Column a) (Column a)
max = AggrOp -> Aggregator (Column a) (Column a)
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrMax

-- | Maximum of a group
min :: Ord.PGOrd a => Aggregator (C.Column a) (C.Column a)
min :: Aggregator (Column a) (Column a)
min = AggrOp -> Aggregator (Column a) (Column a)
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrMin

boolOr :: Aggregator (C.Column T.PGBool) (C.Column T.PGBool)
boolOr :: Aggregator (Column PGBool) (Column PGBool)
boolOr = AggrOp -> Aggregator (Column PGBool) (Column PGBool)
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrBoolOr

boolAnd :: Aggregator (C.Column T.PGBool) (C.Column T.PGBool)
boolAnd :: Aggregator (Column PGBool) (Column PGBool)
boolAnd = AggrOp -> Aggregator (Column PGBool) (Column PGBool)
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrBoolAnd

arrayAgg :: Aggregator (C.Column a) (C.Column (T.PGArray a))
arrayAgg :: Aggregator (Column a) (Column (PGArray a))
arrayAgg = AggrOp -> Aggregator (Column a) (Column (PGArray a))
forall a b. AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr AggrOp
HPQ.AggrArr

stringAgg :: C.Column T.PGText -> Aggregator (C.Column T.PGText) (C.Column T.PGText)
stringAgg :: Column PGText -> Aggregator (Column PGText) (Column PGText)
stringAgg = Maybe AggrOp -> Aggregator (Column PGText) (Column PGText)
forall a b. Maybe AggrOp -> Aggregator (Column a) (Column b)
A.makeAggr' (Maybe AggrOp -> Aggregator (Column PGText) (Column PGText))
-> (Column PGText -> Maybe AggrOp)
-> Column PGText
-> Aggregator (Column PGText) (Column PGText)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AggrOp -> Maybe AggrOp
forall a. a -> Maybe a
Just (AggrOp -> Maybe AggrOp)
-> (Column PGText -> AggrOp) -> Column PGText -> Maybe AggrOp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrimExpr -> AggrOp
HPQ.AggrStringAggr (PrimExpr -> AggrOp)
-> (Column PGText -> PrimExpr) -> Column PGText -> AggrOp
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Column PGText -> PrimExpr
forall a. Column a -> PrimExpr
IC.unColumn