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
15 , listAggExpr, nonEmptyAggExpr
16 , slistAggExpr, snonEmptyAggExpr
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, Unnullify )
41import Rel8.Type ( DBType, typeInformation )
42import Rel8.Type.Array ( encodeArrayElement )
43import Rel8.Type.Eq ( DBEq )
44import Rel8.Type.Information ( TypeInformation )
45import Rel8.Type.Num ( DBNum )
46import Rel8.Type.Ord ( DBMax, DBMin )
47import Rel8.Type.String ( DBString )
48import Rel8.Type.Sum ( DBSum )
51-- | Count the occurances of a single column. Corresponds to @COUNT(a)@
52count :: Expr a -> Aggregate Int64
53count = unsafeMakeAggregate toPrimExpr fromPrimExpr $
55 { operation = Opaleye.AggrCount
57 , distinction = Opaleye.AggrAll
61-- | Count the number of distinct occurances of a single column. Corresponds to
63countDistinct :: Sql DBEq a => Expr a -> Aggregate Int64
64countDistinct = unsafeMakeAggregate toPrimExpr fromPrimExpr $
66 { operation = Opaleye.AggrCount
68 , distinction = Opaleye.AggrDistinct
72-- | Corresponds to @COUNT(*)@.
73countStar :: Aggregate Int64
74countStar = count (litExpr True)
77-- | A count of the number of times a given expression is @true@.
78countWhere :: Expr Bool -> Aggregate Int64
79countWhere condition = count (caseExpr [(condition, litExpr (Just True))] null)
82-- | Corresponds to @bool_and@.
83and :: Expr Bool -> Aggregate Bool
84and = unsafeMakeAggregate toPrimExpr fromPrimExpr $
86 { operation = Opaleye.AggrBoolAnd
88 , distinction = Opaleye.AggrAll
92-- | Corresponds to @bool_or@.
93or :: Expr Bool -> Aggregate Bool
94or = unsafeMakeAggregate toPrimExpr fromPrimExpr $
96 { operation = Opaleye.AggrBoolOr
98 , distinction = Opaleye.AggrAll
102-- | Produce an aggregation for @Expr a@ using the @max@ function.
103max :: Sql DBMax a => Expr a -> Aggregate a
104max = unsafeMakeAggregate toPrimExpr fromPrimExpr $
106 { operation = Opaleye.AggrMax
108 , distinction = Opaleye.AggrAll
112-- | Produce an aggregation for @Expr a@ using the @max@ function.
113min :: Sql DBMin a => Expr a -> Aggregate a
114min = unsafeMakeAggregate toPrimExpr fromPrimExpr $
116 { operation = Opaleye.AggrMin
118 , distinction = Opaleye.AggrAll
121-- | Corresponds to @sum@. Note that in SQL, @sum@ is type changing - for
122-- example the @sum@ of @integer@ returns a @bigint@. Rel8 doesn't support
123-- this, and will add explicit cast back to the original input type. This can
124-- lead to overflows, and if you anticipate very large sums, you should upcast
126sum :: Sql DBSum a => Expr a -> Aggregate a
127sum = unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
129 { operation = Opaleye.AggrSum
131 , distinction = Opaleye.AggrAll
135-- | Take the sum of all expressions that satisfy a predicate.
136sumWhere :: (Sql DBNum a, Sql DBSum a)
137 => Expr Bool -> Expr a -> Aggregate a
138sumWhere condition a = sum (caseExpr [(condition, a)] 0)
141-- | Corresponds to @string_agg()@.
142stringAgg :: Sql DBString a
143 => Expr db -> Expr a -> Aggregate a
145 unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
147 { operation = Opaleye.AggrStringAggr (toPrimExpr delimiter)
149 , distinction = Opaleye.AggrAll
153-- | Aggregate a value by grouping by it.
154groupByExpr :: Sql DBEq a => Expr a -> Aggregate a
155groupByExpr = unsafeMakeAggregate toPrimExpr fromPrimExpr Nothing
158-- | Collect expressions values as a list.
159listAggExpr :: Sql DBType a => Expr a -> Aggregate [a]
160listAggExpr = slistAggExpr typeInformation
163-- | Collect expressions values as a non-empty list.
164nonEmptyAggExpr :: Sql DBType a => Expr a -> Aggregate (NonEmpty a)
165nonEmptyAggExpr = snonEmptyAggExpr typeInformation
169 => TypeInformation (Unnullify a) -> Expr a -> Aggregate [a]
170slistAggExpr info = unsafeMakeAggregate to fromPrimExpr $ Just
172 { operation = Opaleye.AggrArr
174 , distinction = Opaleye.AggrAll
177 to = encodeArrayElement info . toPrimExpr
180snonEmptyAggExpr :: ()
181 => TypeInformation (Unnullify a) -> Expr a -> Aggregate (NonEmpty a)
182snonEmptyAggExpr info = unsafeMakeAggregate to fromPrimExpr $ Just
184 { operation = Opaleye.AggrArr
186 , distinction = Opaleye.AggrAll
189 to = encodeArrayElement info . toPrimExpr
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