rel8-1.3.0.0: src/Rel8/Query/Aggregate.hs
{-# language FlexibleContexts #-}
{-# language MonoLocalBinds #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}
module Rel8.Query.Aggregate
( aggregate
, countRows
, mode
)
where
-- base
import Data.Functor.Contravariant ( (>$<) )
import Data.Int ( Int64 )
import Prelude
-- opaleye
import qualified Opaleye.Aggregate as Opaleye
-- rel8
import Rel8.Aggregate ( Aggregates )
import Rel8.Expr ( Expr )
import Rel8.Expr.Aggregate ( countStar )
import Rel8.Expr.Order ( desc )
import Rel8.Query ( Query )
import Rel8.Query.Limit ( limit )
import Rel8.Query.Maybe ( optional )
import Rel8.Query.Opaleye ( mapOpaleye )
import Rel8.Query.Order ( orderBy )
import Rel8.Table ( toColumns )
import Rel8.Table.Aggregate ( hgroupBy )
import Rel8.Table.Cols ( Cols( Cols ), fromCols )
import Rel8.Table.Eq ( EqTable, eqTable )
import Rel8.Table.Opaleye ( aggregator )
import Rel8.Table.Maybe ( maybeTable )
-- | Apply an aggregation to all rows returned by a 'Query'.
aggregate :: Aggregates aggregates exprs => Query aggregates -> Query exprs
aggregate = mapOpaleye (Opaleye.aggregate 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 = fmap (maybeTable 0 id) . optional . aggregate . fmap (const countStar)
-- | Return the most common row in a query.
mode :: forall a. EqTable a => Query a -> Query a
mode rows = limit 1 $ fmap (fromCols . snd) $ orderBy (fst >$< desc) $ do
aggregate $ do
row <- toColumns <$> rows
pure (countStar, Cols $ hgroupBy (eqTable @a) row)