on da76712 help sign in
rel8/src/Rel8/Query/Aggregate.hs
56 lines 1.7 kB history raw
1{-# language FlexibleContexts #-}
2{-# language MonoLocalBinds #-}
3{-# language ScopedTypeVariables #-}
4{-# language TypeApplications #-}
6module Rel8.Query.Aggregate
7 ( aggregate
8 , countRows
9 , mode
10 )
11where
13-- base
14import Data.Functor.Contravariant ( (>$<) )
15import Data.Int ( Int64 )
16import Prelude
18-- opaleye
19import qualified Opaleye.Aggregate as Opaleye
21-- rel8
22import Rel8.Aggregate ( Aggregates )
23import Rel8.Expr ( Expr )
24import Rel8.Expr.Aggregate ( countStar )
25import Rel8.Expr.Order ( desc )
26import Rel8.Query ( Query )
27import Rel8.Query.Limit ( limit )
28import Rel8.Query.Maybe ( optional )
29import Rel8.Query.Opaleye ( mapOpaleye )
30import Rel8.Query.Order ( orderBy )
31import Rel8.Table ( toColumns )
32import Rel8.Table.Aggregate ( hgroupBy )
33import Rel8.Table.Cols ( Cols( Cols ), fromCols )
34import Rel8.Table.Eq ( EqTable, eqTable )
35import Rel8.Table.Opaleye ( aggregator )
36import Rel8.Table.Maybe ( maybeTable )
39-- | Apply an aggregation to all rows returned by a 'Query'.
40aggregate :: Aggregates aggregates exprs => Query aggregates -> Query exprs
41aggregate = mapOpaleye (Opaleye.aggregate aggregator)
44-- | Count the number of rows returned by a query. Note that this is different
45-- from @countStar@, as even if the given query yields no rows, @countRows@
46-- will return @0@.
47countRows :: Query a -> Query (Expr Int64)
48countRows = fmap (maybeTable 0 id) . optional . aggregate . fmap (const countStar)
51-- | Return the most common row in a query.
52mode :: forall a. EqTable a => Query a -> Query a
53mode rows = limit 1 $ fmap (fromCols . snd) $ orderBy (fst >$< desc) $ do
54 aggregate $ do
55 row <- toColumns <$> rows
56 pure (countStar, Cols $ hgroupBy (eqTable @a) row)