on 43bf3a4 help sign in
rel8/src/Rel8/Table/Aggregate.hs
98 lines 3.1 kB history raw
1{-# language FlexibleContexts #-}
2{-# language ScopedTypeVariables #-}
3{-# language TypeApplications #-}
4{-# language TypeFamilies #-}
5{-# language ViewPatterns #-}
7module Rel8.Table.Aggregate
8 ( groupBy
9 , headAgg
10 , listAgg, nonEmptyAgg
11 , listAggWithOrder, nonEmptyAggWithOrder
12 )
13where
15-- base
16import Data.Functor.Identity ( Identity( Identity ) )
17import Prelude
19-- rel8
20import Rel8.Aggregate ( Aggregate, Col( A ) )
21import Rel8.Expr ( Expr, Col( E ) )
22import Rel8.Expr.Aggregate
23 ( groupByExpr
24 , headAggExpr
25 , listAggExpr
26 , listAggExprWithOrder
27 , nonEmptyAggExpr
28 , nonEmptyAggExprWithOrder
29 )
30import Rel8.Order ( Order )
31import Rel8.Schema.Dict ( Dict( Dict ) )
32import Rel8.Schema.HTable ( hfield, hmap, htabulate )
33import Rel8.Schema.HTable.Vectorize ( hvectorize )
34import Rel8.Table ( Table, toColumns, fromColumns )
35import Rel8.Table.Eq ( EqTable, eqTable )
36import Rel8.Table.List ( ListTable )
37import Rel8.Table.NonEmpty ( NonEmptyTable )
40-- | Group equal tables together. This works by aggregating each column in the
41-- given table with 'groupByExpr'.
42groupBy :: forall exprs. EqTable exprs => exprs -> Aggregate exprs
43groupBy (toColumns -> exprs) = fromColumns $ htabulate $ \field ->
44 case hfield (eqTable @exprs) field of
45 Dict -> case hfield exprs field of
46 E expr -> A $ groupByExpr expr
49-- | Keep only the first row.
50headAgg :: Table Expr a => a -> Aggregate a
51headAgg = fromColumns . hmap (\(E a) -> A $ headAggExpr a) . toColumns
54-- | Aggregate rows into a single row containing an array of all aggregated
55-- rows. This can be used to associate multiple rows with a single row, without
56-- changing the over cardinality of the query. This allows you to essentially
57-- return a tree-like structure from queries.
58--
59-- For example, if we have a table of orders and each orders contains multiple
60-- items, we could aggregate the table of orders, pairing each order with its
61-- items:
62--
63-- @
64-- ordersWithItems :: Query (Order Expr, ListTable (Item Expr))
65-- ordersWithItems = do
66-- order <- each orderSchema
67-- items <- aggregate $ listAgg <$> itemsFromOrder order
68-- return (order, items)
69-- @
70listAgg :: Table Expr a => a -> Aggregate (ListTable a)
71listAgg (toColumns -> exprs) = fromColumns $
72 hvectorize
73 (\_ (Identity (E a)) -> A $ listAggExpr a)
74 (pure exprs)
77-- | Like 'listAgg', but the result is guaranteed to be a non-empty list.
78nonEmptyAgg :: Table Expr a => a -> Aggregate (NonEmptyTable a)
79nonEmptyAgg (toColumns -> exprs) = fromColumns $
80 hvectorize
81 (\_ (Identity (E a)) -> A $ nonEmptyAggExpr a)
82 (pure exprs)
85listAggWithOrder :: Table Expr a
86 => Order o -> o -> a -> Aggregate (ListTable a)
87listAggWithOrder order o (toColumns -> exprs) = fromColumns $
88 hvectorize
89 (\_ (Identity (E x)) -> A $ listAggExprWithOrder order o x)
90 (pure exprs)
93nonEmptyAggWithOrder :: Table Expr a
94 => Order o -> o -> a -> Aggregate (NonEmptyTable a)
95nonEmptyAggWithOrder order o (toColumns -> exprs) = fromColumns $
96 hvectorize
97 (\_ (Identity (E x)) -> A $ nonEmptyAggExprWithOrder order o x)
98 (pure exprs)