Add source to SqlAggregate, the Over instance uses this to prevent pseudo-aggregates(from groupBy) and already windowed values from being windowed

This commit is contained in:
belevy 2021-02-14 20:18:20 -06:00
parent 8efca2ba05
commit ceab69a4e9
3 changed files with 22 additions and 22 deletions

View File

@ -90,7 +90,7 @@ module Database.Esqueleto.Experimental
, joinV
, withNonNull
, countRows
, countRows_
, count
, countDistinct

View File

@ -55,15 +55,15 @@ instance SqlExprEntity SqlExpr where
(^.) = (I.^.)
(?.) = (I.?.)
newtype SqlAggregate a = SqlAggregate { unsafeSqlAggregate :: SqlExpr a }
deriving via SqlExpr instance SqlExprEntity SqlAggregate
instance forall a. PersistField a => SqlSelect (SqlAggregate a) a where
newtype SqlAggregate source a = SqlAggregate { unsafeSqlAggregate :: SqlExpr a }
deriving via SqlExpr instance SqlExprEntity (SqlAggregate source)
instance forall a source. PersistField a => SqlSelect (SqlAggregate source a) a where
sqlSelectCols info (SqlAggregate e) = sqlSelectCols info e
sqlSelectColCount = const 1
sqlSelectProcessRow _ = sqlSelectProcessRow (Proxy :: Proxy (SqlExpr a))
instance SqlQueryHaving (SqlAggregate Bool) where
instance SqlQueryHaving (SqlAggregate source Bool) where
having expr = Q $ W.tell mempty { sdHavingClause = I.Where (coerce expr) }
instance SqlQueryHaving (SqlAggregate (Maybe Bool)) where
instance SqlQueryHaving (SqlAggregate source (Maybe Bool)) where
having expr = Q $ W.tell mempty { sdHavingClause = I.Where (coerce expr) }
test :: (PersistEntity ent, PersistField a, PersistField b, PersistField c)
@ -76,8 +76,6 @@ test ent field y other = do
groupBy (ent, y) $ \(ent', y') ->
pure (ent' ?. field, y', sum_ other, countRows_)
countRows_ :: (PersistField n, Integral n) => SqlAggregate n
countRows_ = SqlAggregate $ ERaw noMeta $ \_ _ -> ("COUNT(*)", [])
-- Tuple magic, only SqlExprs are on the leaves.
-- The Coercible instance from the SqlExpr a -> SqlExpr b allows 0 cost casting
@ -88,8 +86,9 @@ class Coercible a r => Aggregateable a r | a -> r, r -> a where
fromAggregate :: r -> a
fromAggregate = coerce
data GroupedValue
instance Aggregateable () () where
instance Aggregateable (SqlExpr a) (SqlAggregate a) where
instance Aggregateable (SqlExpr a) (SqlAggregate GroupedValue a) where
instance (Aggregateable a ra, Aggregateable b rb) => Aggregateable (a,b) (ra, rb) where
instance
( Aggregateable a ra
@ -137,9 +136,6 @@ instance
, Aggregateable h rh
) => Aggregateable (a,b,c,d,e,f,g,h) (ra,rb,rc,rd,re,rf,rg,rh) where
sum_ :: (PersistField a, PersistField n, Integral n) => SqlExpr a -> SqlAggregate (Maybe n)
sum_ = coerce . unsafeSqlFunction "SUM"
groupBy :: ( ToSomeValues a
, Aggregateable a a'
, Aggregateable b b'
@ -147,3 +143,11 @@ groupBy :: ( ToSomeValues a
groupBy a f = do
Q $ W.tell $ mempty{sdGroupByClause = GroupBy $ toSomeValues a }
fmap fromAggregate $ f $ toAggregate a
-- Aggregation Functions
countRows_ :: forall n s. (PersistField n, Integral n) => SqlAggregate s n
countRows_ = SqlAggregate $ ERaw noMeta $ \_ _ -> ("COUNT(*)", [])
sum_ :: forall n a w. (PersistField a, PersistField n, Integral n) => SqlExpr a -> SqlAggregate w (Maybe n)
sum_ = coerce . unsafeSqlFunction "SUM"

View File

@ -253,16 +253,9 @@ unboundedFollowing = FrameRangeFollowing FrameRangeUnbounded
currentRow :: FrameRange
currentRow = FrameRangeCurrentRow
data WindowAggregate
class Over expr where
over_ :: RenderWindow window => expr a -> window -> SqlAggregate (WindowedValue a)
data WindowedValue a = WindowedValue { unWindowedValue :: a }
instance PersistField a => SqlSelect (SqlExpr (WindowedValue a)) (WindowedValue a) where
sqlSelectCols info expr = sqlSelectCols info (coerce expr :: SqlExpr a)
sqlSelectColCount = const 1
sqlSelectProcessRow _ [pv] = WindowedValue <$> fromPersistValue pv
sqlSelectProcessRow _ pvs = WindowedValue <$> fromPersistValue (PersistList pvs)
over_ :: RenderWindow window => expr a -> window -> SqlAggregate WindowAggregate a
newtype WindowExpr a = WindowExpr { unsafeWindowExpr :: SqlExpr a }
instance Over WindowExpr where
@ -271,4 +264,7 @@ instance Over WindowExpr where
(w, vw) = renderWindow info window
in (parensM p $ b <> " OVER " <> parens w , v <> vw)
deriving via WindowExpr instance Over SqlAggregate
-- Only universally quantified SqlAggregate's can be used
-- TODO Add nicer type error
data NoWindow
deriving via WindowExpr instance (s ~ NoWindow) => Over (SqlAggregate s)