1{-# language DataKinds #-}
2{-# language FlexibleContexts #-}
3{-# language ScopedTypeVariables #-}
4{-# language TypeFamilies #-}
6{-# options_ghc -fno-warn-redundant-constraints #-}
8module Rel8.Expr.Aggregate
9 ( count, countDistinct, countStar, countWhere
16 , array1DAggExpr, listAggExpr, nonEmptyAggExpr
21import Data.Int ( Int64 )
22import Data.List.NonEmpty ( NonEmpty )
23import Prelude hiding ( and, max, min, null, or, sum )
26import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
29import Rel8.Aggregate ( Aggregate, Aggregator(..), unsafeMakeAggregate )
30import Rel8.Expr ( Expr )
31import Rel8.Expr.Bool ( caseExpr )
32import Rel8.Expr.Opaleye
38import Rel8.Expr.Null ( null )
39import Rel8.Expr.Serialize ( litExpr )
40import Rel8.Schema.Null ( Sql )
41import Rel8.Type.Array ( fromPrimArray )
42import Rel8.Type.Array1D ( Array1D, NotArray )
43import Rel8.Type.Eq ( DBEq )
44import Rel8.Type.Num ( DBNum )
45import Rel8.Type.Ord ( DBMax, DBMin )
46import Rel8.Type.String ( DBString )
47import Rel8.Type.Sum ( DBSum )
50-- | Count the occurances of a single column. Corresponds to @COUNT(a)@
51count :: Expr a -> Aggregate (Expr Int64)
52count = unsafeMakeAggregate toPrimExpr fromPrimExpr $
54 { operation = Opaleye.AggrCount
56 , distinction = Opaleye.AggrAll
60-- | Count the number of distinct occurances of a single column. Corresponds to
62countDistinct :: Sql DBEq a => Expr a -> Aggregate (Expr Int64)
63countDistinct = unsafeMakeAggregate toPrimExpr fromPrimExpr $
65 { operation = Opaleye.AggrCount
67 , distinction = Opaleye.AggrDistinct
71-- | Corresponds to @COUNT(*)@.
72countStar :: Aggregate (Expr Int64)
73countStar = count (litExpr True)
76-- | A count of the number of times a given expression is @true@.
77countWhere :: Expr Bool -> Aggregate (Expr Int64)
78countWhere condition = count (caseExpr [(condition, litExpr (Just True))] null)
81-- | Corresponds to @bool_and@.
82and :: Expr Bool -> Aggregate (Expr Bool)
83and = unsafeMakeAggregate toPrimExpr fromPrimExpr $
85 { operation = Opaleye.AggrBoolAnd
87 , distinction = Opaleye.AggrAll
91-- | Corresponds to @bool_or@.
92or :: Expr Bool -> Aggregate (Expr Bool)
93or = unsafeMakeAggregate toPrimExpr fromPrimExpr $
95 { operation = Opaleye.AggrBoolOr
97 , distinction = Opaleye.AggrAll
101-- | Produce an aggregation for @Expr a@ using the @max@ function.
102max :: Sql DBMax a => Expr a -> Aggregate (Expr a)
103max = unsafeMakeAggregate toPrimExpr fromPrimExpr $
105 { operation = Opaleye.AggrMax
107 , distinction = Opaleye.AggrAll
111-- | Produce an aggregation for @Expr a@ using the @max@ function.
112min :: Sql DBMin a => Expr a -> Aggregate (Expr a)
113min = unsafeMakeAggregate toPrimExpr fromPrimExpr $
115 { operation = Opaleye.AggrMin
117 , distinction = Opaleye.AggrAll
120-- | Corresponds to @sum@. Note that in SQL, @sum@ is type changing - for
121-- example the @sum@ of @integer@ returns a @bigint@. Rel8 doesn't support
122-- this, and will add explicit cast back to the original input type. This can
123-- lead to overflows, and if you anticipate very large sums, you should upcast
125sum :: Sql DBSum a => Expr a -> Aggregate (Expr a)
126sum = unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
128 { operation = Opaleye.AggrSum
130 , distinction = Opaleye.AggrAll
134-- | Take the sum of all expressions that satisfy a predicate.
135sumWhere :: (Sql DBNum a, Sql DBSum a)
136 => Expr Bool -> Expr a -> Aggregate (Expr a)
137sumWhere condition a = sum (caseExpr [(condition, a)] 0)
140-- | Corresponds to @string_agg()@.
141stringAgg :: Sql DBString a
142 => Expr db -> Expr a -> Aggregate (Expr a)
144 unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
146 { operation = Opaleye.AggrStringAggr (toPrimExpr delimiter)
148 , distinction = Opaleye.AggrAll
152-- | Aggregate a value by grouping by it.
153groupByExpr :: Sql DBEq a => Expr a -> Aggregate (Expr a)
154groupByExpr = unsafeMakeAggregate toPrimExpr fromPrimExpr Nothing
157-- | Keep only the first value.
158headAggExpr :: Expr a -> Aggregate (Expr a)
159headAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
161 { operation = Opaleye.AggrArr
163 , distinction = Opaleye.AggrAll
166 from = fromPrimExpr . flip Opaleye.ArrayIndex one
168 one = Opaleye.ConstExpr (Opaleye.NumericLit 1)
171-- | Collect expressions values as an array.
172array1DAggExpr :: NotArray a => Expr a -> Aggregate (Expr (Array1D a))
173array1DAggExpr = unsafeMakeAggregate toPrimExpr fromPrimExpr $ Just
175 { operation = Opaleye.AggrArr
177 , distinction = Opaleye.AggrAll
181-- | Collect expressions values as a list.
182listAggExpr :: Expr a -> Aggregate (Expr [a])
183listAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
185 { operation = Opaleye.AggrArr
187 , distinction = Opaleye.AggrAll
190 from = fromPrimExpr . fromPrimArray
193-- | Collect expressions values as a non-empty list.
194nonEmptyAggExpr :: Expr a -> Aggregate (Expr (NonEmpty a))
195nonEmptyAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
197 { operation = Opaleye.AggrArr
199 , distinction = Opaleye.AggrAll
202 from = fromPrimExpr . fromPrimArray
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list