on 0b718ac help sign in
rel8/src/Rel8/Expr/Aggregate.hs
173 lines 4.7 kB history raw
1{-# language DataKinds #-}
2{-# language FlexibleContexts #-}
3{-# language ScopedTypeVariables #-}
4{-# language TypeApplications #-}
5{-# language TypeFamilies #-}
7{-# options_ghc -fno-warn-redundant-constraints #-}
9module Rel8.Expr.Aggregate
10 ( count, countDistinct, countStar, countWhere
11 , and, or
12 , min, max
13 , sum, sumWhere
14 , stringAgg
15 , groupByExpr
16 , listAggExpr, nonEmptyAggExpr
17 , sgroupByExpr
18 )
19where
21-- base
22import Data.Int ( Int64 )
23import Data.List.NonEmpty ( NonEmpty )
24import Prelude hiding ( and, max, min, null, or, sum )
26-- opaleye
27import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
29-- rel8
30import Rel8.Aggregate ( Aggregate, Aggregator(..), unsafeMakeAggregate )
31import Rel8.Expr ( Expr )
32import Rel8.Expr.Bool ( caseExpr )
33import Rel8.Expr.Opaleye
34 ( castExpr
35 , fromPrimExpr
36 , fromPrimExpr
37 , toPrimExpr
38 )
39import Rel8.Expr.Null ( null )
40import Rel8.Expr.Serialize ( litExpr )
41import Rel8.Schema.Nullability ( Nullability, Sql, nullabilization )
42import Rel8.Type.Array ( fromPrimArray )
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 $
53 Just Aggregator
54 { operation = Opaleye.AggrCount
55 , ordering = []
56 , distinction = Opaleye.AggrAll
57 }
60-- | Count the number of distinct occurances of a single column. Corresponds to
61-- @COUNT(DISTINCT a)@
62countDistinct :: DBEq a => Expr a -> Aggregate (Expr Int64)
63countDistinct = unsafeMakeAggregate toPrimExpr fromPrimExpr $
64 Just Aggregator
65 { operation = Opaleye.AggrCount
66 , ordering = []
67 , distinction = Opaleye.AggrDistinct
68 }
71-- | Corresponds to @COUNT(*)@.
72countStar :: Aggregate (Expr Int64)
73countStar = count (litExpr True)
76countWhere :: Expr Bool -> Aggregate (Expr Int64)
77countWhere condition = count (caseExpr [(condition, litExpr (Just True))] null)
80-- | Corresponds to @bool_and@.
81and :: Expr Bool -> Aggregate (Expr Bool)
82and = unsafeMakeAggregate toPrimExpr fromPrimExpr $
83 Just Aggregator
84 { operation = Opaleye.AggrBoolAnd
85 , ordering = []
86 , distinction = Opaleye.AggrAll
87 }
90-- | Corresponds to @bool_or@.
91or :: Expr Bool -> Aggregate (Expr Bool)
92or = unsafeMakeAggregate toPrimExpr fromPrimExpr $
93 Just Aggregator
94 { operation = Opaleye.AggrBoolOr
95 , ordering = []
96 , distinction = Opaleye.AggrAll
97 }
100-- | Produce an aggregation for @Expr a@ using the @max@ function.
101max :: Sql DBMax a => Expr a -> Aggregate (Expr a)
102max = unsafeMakeAggregate toPrimExpr fromPrimExpr $
103 Just Aggregator
104 { operation = Opaleye.AggrSum
105 , ordering = []
106 , distinction = Opaleye.AggrAll
107 }
110-- | Produce an aggregation for @Expr a@ using the @max@ function.
111min :: Sql DBMin a => Expr a -> Aggregate (Expr a)
112min = unsafeMakeAggregate toPrimExpr fromPrimExpr $
113 Just Aggregator
114 { operation = Opaleye.AggrSum
115 , ordering = []
116 , distinction = Opaleye.AggrAll
117 }
119-- | Corresponds to @sum@.
120sum :: Sql DBSum a => Expr a -> Aggregate (Expr a)
121sum = unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
122 Just Aggregator
123 { operation = Opaleye.AggrSum
124 , ordering = []
125 , distinction = Opaleye.AggrAll
126 }
129sumWhere :: (Sql DBNum a, Sql DBSum a)
130 => Expr Bool -> Expr a -> Aggregate (Expr a)
131sumWhere condition a = sum (caseExpr [(condition, a)] 0)
134stringAgg :: Sql DBString a
135 => Expr db -> Expr a -> Aggregate (Expr a)
136stringAgg delimiter =
137 unsafeMakeAggregate toPrimExpr (castExpr . fromPrimExpr) $
138 Just Aggregator
139 { operation = Opaleye.AggrStringAggr (toPrimExpr delimiter)
140 , ordering = []
141 , distinction = Opaleye.AggrAll
142 }
145-- | Aggregate a value by grouping by it.
146groupByExpr :: Sql DBEq a => Expr a -> Aggregate (Expr a)
147groupByExpr = sgroupByExpr nullabilization
150listAggExpr :: Expr a -> Aggregate (Expr [a])
151listAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
152 Aggregator
153 { operation = Opaleye.AggrArr
154 , ordering = []
155 , distinction = Opaleye.AggrAll
156 }
157 where
158 from = fromPrimExpr . fromPrimArray
161nonEmptyAggExpr :: Expr a -> Aggregate (Expr (NonEmpty a))
162nonEmptyAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
163 Aggregator
164 { operation = Opaleye.AggrArr
165 , ordering = []
166 , distinction = Opaleye.AggrAll
167 }
168 where
169 from = fromPrimExpr . fromPrimArray
172sgroupByExpr :: DBEq db => Nullability db a -> Expr a -> Aggregate (Expr a)
173sgroupByExpr _ = unsafeMakeAggregate toPrimExpr fromPrimExpr Nothing