packages feed

rel8-1.5.0.0: src/Rel8/Query/Aggregate.hs

{-# language FlexibleContexts #-}
{-# language MonoLocalBinds #-}
{-# language ScopedTypeVariables #-}

module Rel8.Query.Aggregate
  ( aggregate
  , aggregate1
  , aggregateU
  , countRows
  )
where

-- base
import Control.Applicative (liftA2)
import Data.Int ( Int64 )
import Prelude

-- opaleye
import qualified Opaleye.Adaptors as Opaleye
import qualified Opaleye.Aggregate as Opaleye

-- rel8
import Rel8.Aggregate (Aggregator' (Aggregator), Aggregator)
import Rel8.Aggregate.Fold (Fallback (Fallback))
import Rel8.Expr ( Expr )
import Rel8.Expr.Aggregate ( countStar )
import Rel8.Expr.Bool (true)
import Rel8.Query ( Query )
import Rel8.Query.Maybe ( optional )
import Rel8.Query.Opaleye ( mapOpaleye )
import Rel8.Table (Table)
import Rel8.Table.Maybe (fromMaybeTable)
import Rel8.Table.Opaleye (unpackspec)


-- | Apply an 'Aggregator' to all rows returned by a 'Query'. If the 'Query'
-- is empty, then a single \"fallback\" row is returned, composed of the
-- identity elements of the constituent aggregation functions.
aggregate :: (Table Expr i, Table Expr a) => Aggregator i a -> Query i -> Query a
aggregate aggregator@(Aggregator (Fallback fallback) _) =
  fmap (fromMaybeTable fallback) . optional . aggregate1 aggregator


-- | Apply an 'Rel8.Aggregator1' to all rows returned by a 'Query'. If
-- the 'Query' is empty, then zero rows are returned.
aggregate1 :: Table Expr i => Aggregator' fold i a -> Query i -> Query a
aggregate1 = aggregateU unpackspec


aggregateU :: Opaleye.Unpackspec i i -> Aggregator' fold i a -> Query i -> Query a
aggregateU unpack (Aggregator _ aggregator) =
  mapOpaleye (Opaleye.aggregateExplicit unpack aggregator)


-- | Count the number of rows returned by a query. Note that this is different
-- from @countStar@, as even if the given query yields no rows, @countRows@
-- will return @0@.
countRows :: Query a -> Query (Expr Int64)
countRows = aggregate countStar . (true <$)