on master help sign in
Rename singularize to distinctTabulation and implement in terms of distinctOn

This also means we can delete `headAgg`.

commitb86f4454e9a464995c500e528c6829824e6def19 authorShane O'Brien <shane.obrien@circuithub.com> dateTue 15 Jun 2021, 01:01 (5 years ago) parente548510
5 files changed+21−43
src/Rel8.hs−1 src/Rel8/Aggregate/Legacy.hs+1−8 src/Rel8/Expr/Aggregate.hs−15 src/Rel8/Table/Aggregate.hs+1−8 src/Rel8/Tabulate.hs+19−11
src/Rel8.hs−1
@@ -221,7 +221,6 @@ module Rel8
221221 , aggregate
222222 , countRows
223223 , groupBy
224− , headAgg
225224 , listAgg, listAggExpr
226225 , nonEmptyAgg, nonEmptyAggExpr
227226 , DBMax, max
src/Rel8/Aggregate/Legacy.hs+1−8
@@ -14,7 +14,6 @@ module Rel8.Aggregate.Legacy
1414 , aggregate
1515 , aggregateTabulation
1616 , groupBy
17− , headAgg
1817 , listAgg
1918 , nonEmptyAgg
2019
@@ -37,7 +36,6 @@ import Rel8.Aggregate ( Aggregate, Aggregates, Col( A ) )
3736import Rel8.Expr ( Col( E ), Expr )
3837import Rel8.Expr.Aggregate
3938 ( groupByExpr
40− , headAggExpr
4139 , slistAggExpr
4240 , snonEmptyAggExpr
4341 )
@@ -47,7 +45,7 @@ import Rel8.Kind.Algebra ( Algebra( Sum ) )
4745import Rel8.Query ( Query )
4846import Rel8.Query.Opaleye ( mapOpaleye )
4947import Rel8.Schema.Dict ( Dict( Dict ) )
50−import Rel8.Schema.HTable ( hmap, hfield, htabulate )
48+import Rel8.Schema.HTable ( hfield, htabulate )
5149import Rel8.Schema.HTable.Vectorize ( hvectorize )
5250import Rel8.Schema.Kind ( Rel8able )
5351import Rel8.Schema.Spec ( SSpec( SSpec, info ) )
@@ -84,11 +82,6 @@ groupBy (toColumns -> exprs) = fromColumns $ htabulate $ \field ->
8482 E expr -> A $ groupByExpr expr
8583
8684
87−-- | Keep only the first row's values.
88−headAgg :: Aggregates aggregates exprs => exprs -> aggregates
89−headAgg = fromColumns . hmap (\(E a) -> A $ headAggExpr a) . toColumns
90−
91−
9285-- | Aggregate rows into a single row containing an array of all aggregated
9386-- rows. This can be used to associate multiple rows with a single row, without
9487-- changing the over cardinality of the query. This allows you to essentially
src/Rel8/Expr/Aggregate.hs−15
@@ -12,7 +12,6 @@ module Rel8.Expr.Aggregate
1212 , sum, sumWhere
1313 , stringAgg
1414 , groupByExpr
15− , headAggExpr
1615 , listAggExpr, nonEmptyAggExpr
1716 , slistAggExpr, snonEmptyAggExpr
1817 )
@@ -156,20 +155,6 @@ groupByExpr :: Sql DBEq a => Expr a -> Aggregate (Expr a)
156155groupByExpr = unsafeMakeAggregate toPrimExpr fromPrimExpr Nothing
157156
158157
159−-- | Keep only the first value.
160−headAggExpr :: Expr a -> Aggregate (Expr a)
161−headAggExpr = unsafeMakeAggregate toPrimExpr from $ Just
162− Aggregator
163− { operation = Opaleye.AggrArr
164− , ordering = []
165− , distinction = Opaleye.AggrAll
166− }
167− where
168− from = fromPrimExpr . flip Opaleye.ArrayIndex one
169− where
170− one = Opaleye.ConstExpr (Opaleye.NumericLit 1)
171−
172−
173158-- | Collect expressions values as a list.
174159listAggExpr :: Sql DBType a => Expr a -> Aggregate (Expr [a])
175160listAggExpr = slistAggExpr typeInformation
src/Rel8/Table/Aggregate.hs+1−8
@@ -7,7 +7,6 @@
77
88module Rel8.Table.Aggregate
99 ( groupBy
10− , headAgg
1110 , listAgg, nonEmptyAgg
1211 )
1312where
@@ -21,12 +20,11 @@ import Rel8.Aggregate ( Aggregate, Col( A ) )
2120import Rel8.Expr ( Expr, Col( E ) )
2221import Rel8.Expr.Aggregate
2322 ( groupByExpr
24− , headAggExpr
2523 , slistAggExpr
2624 , snonEmptyAggExpr
2725 )
2826import Rel8.Schema.Dict ( Dict( Dict ) )
29−import Rel8.Schema.HTable ( hfield, hmap, htabulate )
27+import Rel8.Schema.HTable ( hfield, htabulate )
3028import Rel8.Schema.HTable.Vectorize ( hvectorize )
3129import Rel8.Schema.Spec ( SSpec( SSpec, info ) )
3230import Rel8.Table ( Table, toColumns, fromColumns )
@@ -44,11 +42,6 @@ groupBy (toColumns -> exprs) = fromColumns $ htabulate $ \field ->
4442 E expr -> A $ groupByExpr expr
4543
4644
47−-- | Keep only the first row.
48−headAgg :: Table Expr a => a -> Aggregate a
49−headAgg = fromColumns . hmap (\(E a) -> A $ headAggExpr a) . toColumns
50−
51−
5245-- | Aggregate rows into a single row containing an array of all aggregated
5346-- rows. This can be used to associate multiple rows with a single row, without
5447-- changing the over cardinality of the query. This allows you to essentially
src/Rel8/Tabulate.hs+19−11
@@ -26,7 +26,7 @@ module Rel8.Tabulate
2626 , difference
2727 , aggregateTabulation
2828 , orderTabulation
29− , singularize
29+ , distinctTabulation
3030 , optionalTabulation
3131 , manyTabulation
3232 , someTabulation
@@ -48,13 +48,14 @@ import Rel8.Expr ( Expr )
4848import Rel8.Order ( Order )
4949import Rel8.Query ( Query )
5050import Rel8.Query.Aggregate ( aggregate )
51+import Rel8.Query.Distinct ( distinctOn )
5152import Rel8.Query.Exists ( withBy, withoutBy )
5253import Rel8.Query.Filter ( filter, where_ )
5354import Rel8.Query.Maybe ( optional )
5455import Rel8.Query.Order ( orderBy )
5556import Rel8.Query.These ( alignBy )
5657import Rel8.Table ( Table )
57−import Rel8.Table.Aggregate ( groupBy, headAgg, listAgg, nonEmptyAgg )
58+import Rel8.Table.Aggregate ( groupBy, listAgg, nonEmptyAgg )
5859import Rel8.Table.Alternative
5960 ( AltTable, (<|>:)
6061 , AlternativeTable, emptyTable
@@ -63,6 +64,8 @@ import Rel8.Table.Eq ( EqTable, (==:) )
6364import Rel8.Table.List ( ListTable )
6465import Rel8.Table.Maybe ( MaybeTable, maybeTable )
6566import Rel8.Table.NonEmpty ( NonEmptyTable )
67+import Rel8.Table.Ord ( OrdTable )
68+import Rel8.Table.Order ( ascTable )
6669import Rel8.Table.These ( TheseTable, theseTable )
6770
6871-- semigroupoids
@@ -337,26 +340,26 @@ difference kas kbs = do
337340
338341aggregateTabulation :: EqTable k
339342 => Tabulation k (Aggregate a) -> Tabulation k a
340−aggregateTabulation kas = do
341− as <- toQuery kas
342− fromQuery $ aggregate $ bitraverse1 groupBy id <$> as
343+aggregateTabulation = mapQuery (aggregate . fmap (bitraverse1 groupBy id))
343344
344345
345−-- | 'orderTabulation' orders the /values/ of a 'Tabulation' (not the keys).
346+-- | 'orderTabulation' orders the /values/ of a 'Tabulation' within each key.
347+--
346348-- In general this is meaningless, but if used together with 'manyTabulation'
347349-- or 'someTabulation', the resulting lists will be ordered according to
348350-- ordering given to 'orderTabulation'.
349−orderTabulation :: Order a -> Tabulation k a -> Tabulation k a
350−orderTabulation ordering (Tabulation as) =
351− Tabulation $ orderBy (snd >$< ordering) . as
351+orderTabulation :: OrdTable k => Order a -> Tabulation k a -> Tabulation k a
352+orderTabulation ordering = mapQuery $ orderBy ordering'
353+ where
354+ ordering' = (fst >$< ascTable) <> (snd >$< ordering)
352355
353356
354357-- | Turns the given 'Tabulation' from a \"multimap\" into a \"map\". If there
355358-- is more than one value at a particular key, only the first one is kept.
356359-- \"First\" is in general undefined, but 'orderTabulation' can be used to
357360-- make it deterministic.
358−singularize :: (EqTable k, Table Expr a) => Tabulation k a -> Tabulation k a
359−singularize = aggregateTabulation . fmap headAgg
361+distinctTabulation :: EqTable k => Tabulation k a -> Tabulation k a
362+distinctTabulation = mapQuery (distinctOn fst)
360363
361364
362365optionalTabulation :: EqTable k
@@ -380,6 +383,11 @@ someTabulation :: (EqTable k, Table Expr a)
380383someTabulation = aggregateTabulation . fmap nonEmptyAgg
381384
382385
386+mapQuery :: (Query (k, a) -> Query (k, b)) -> Tabulation k a -> Tabulation k b
387+mapQuery f (Tabulation query) = Tabulation $ \k ->
388+ first Just <$> f (first (fromMaybe k) <$> query k)
389+
390+
383391toQuery :: Tabulation k a -> Tabulation k (Query (k, a))
384392toQuery (Tabulation as) = Tabulation $ \k ->
385393 pure (Nothing, first (fromMaybe k) <$> as k)