on bdb75e6 help sign in
rel8/src/Rel8/Table/Aggregate.hs
78 lines 2.5 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 )
12where
14-- base
15import Data.Functor.Identity ( Identity( Identity ) )
16import Prelude
18-- rel8
19import Rel8.Aggregate ( Aggregate, Col( A ) )
20import Rel8.Expr ( Expr, Col( E ) )
21import Rel8.Expr.Aggregate
22 ( groupByExpr
23 , headAggExpr
24 , listAggExpr
25 , nonEmptyAggExpr
26 )
27import Rel8.Schema.Dict ( Dict( Dict ) )
28import Rel8.Schema.HTable ( hfield, hmap, htabulate )
29import Rel8.Schema.HTable.Vectorize ( hvectorize )
30import Rel8.Table ( Table, toColumns, fromColumns )
31import Rel8.Table.Eq ( EqTable, eqTable )
32import Rel8.Table.List ( ListTable )
33import Rel8.Table.NonEmpty ( NonEmptyTable )
36-- | Group equal tables together. This works by aggregating each column in the
37-- given table with 'groupByExpr'.
38groupBy :: forall exprs. EqTable exprs => exprs -> Aggregate exprs
39groupBy (toColumns -> exprs) = fromColumns $ htabulate $ \field ->
40 case hfield (eqTable @exprs) field of
41 Dict -> case hfield exprs field of
42 E expr -> A $ groupByExpr expr
45-- | Keep only the first row.
46headAgg :: Table Expr a => a -> Aggregate a
47headAgg = fromColumns . hmap (\(E a) -> A $ headAggExpr a) . toColumns
50-- | Aggregate rows into a single row containing an array of all aggregated
51-- rows. This can be used to associate multiple rows with a single row, without
52-- changing the over cardinality of the query. This allows you to essentially
53-- return a tree-like structure from queries.
54--
55-- For example, if we have a table of orders and each orders contains multiple
56-- items, we could aggregate the table of orders, pairing each order with its
57-- items:
58--
59-- @
60-- ordersWithItems :: Query (Order Expr, ListTable (Item Expr))
61-- ordersWithItems = do
62-- order <- each orderSchema
63-- items <- aggregate $ listAgg <$> itemsFromOrder order
64-- return (order, items)
65-- @
66listAgg :: Table Expr a => a -> Aggregate (ListTable a)
67listAgg (toColumns -> exprs) = fromColumns $
68 hvectorize
69 (\_ (Identity (E a)) -> A $ listAggExpr a)
70 (pure exprs)
73-- | Like 'listAgg', but the result is guaranteed to be a non-empty list.
74nonEmptyAgg :: Table Expr a => a -> Aggregate (NonEmptyTable a)
75nonEmptyAgg (toColumns -> exprs) = fromColumns $
76 hvectorize
77 (\_ (Identity (E a)) -> A $ nonEmptyAggExpr a)
78 (pure exprs)