Make SqlAggregate selectable, window now returns a SqlAggregate since the results are legal in a grouped query. Added SqlQueryHaving to allow use of SqlAggregate in the having clause.

This commit is contained in:
belevy 2021-02-14 19:31:53 -06:00
parent 1fd1d64d6d
commit 8efca2ba05
4 changed files with 24 additions and 11 deletions

View File

@ -53,8 +53,6 @@ module Database.Esqueleto.Experimental
, with
, withRecursive
, agg
-- ** Internals
, From(..)
, ToMaybe(..)

View File

@ -16,11 +16,13 @@ module Database.Esqueleto.Experimental.Aggregates
import Control.Monad.IO.Class
import qualified Control.Monad.Trans.Writer as W
import Data.Coerce (Coercible, coerce)
import Data.Proxy
import Database.Esqueleto.Internal.Internal
( GroupByClause(..)
, SideData(..)
, SqlExpr(..)
, SqlQuery(..)
, SqlQueryHaving(..)
, SqlSelect(..)
, ToSomeValues(..)
, noMeta
@ -53,8 +55,16 @@ instance SqlExprEntity SqlExpr where
(^.) = (I.^.)
(?.) = (I.?.)
newtype SqlAggregate a = SqlAggregate { agg :: SqlExpr a }
newtype SqlAggregate a = SqlAggregate { unsafeSqlAggregate :: SqlExpr a }
deriving via SqlExpr instance SqlExprEntity SqlAggregate
instance forall a. PersistField a => SqlSelect (SqlAggregate a) a where
sqlSelectCols info (SqlAggregate e) = sqlSelectCols info e
sqlSelectColCount = const 1
sqlSelectProcessRow _ = sqlSelectProcessRow (Proxy :: Proxy (SqlExpr a))
instance SqlQueryHaving (SqlAggregate Bool) where
having expr = Q $ W.tell mempty { sdHavingClause = I.Where (coerce expr) }
instance SqlQueryHaving (SqlAggregate (Maybe Bool)) where
having expr = Q $ W.tell mempty { sdHavingClause = I.Where (coerce expr) }
test :: (PersistEntity ent, PersistField a, PersistField b, PersistField c)
=> SqlExpr (Maybe (Entity ent))

View File

@ -62,7 +62,7 @@ example =
<> orderBy_ [asc (val @Int64 10)]
)
data NeedsWindow a
example2 = countRows_ @Int64 `over_` ()
lag :: SqlExpr (Value a) -> WindowExpr a
lag v = lag_ v Nothing Nothing
@ -254,7 +254,7 @@ currentRow :: FrameRange
currentRow = FrameRangeCurrentRow
class Over expr where
over_ :: RenderWindow window => expr a -> window -> SqlExpr (WindowedValue a)
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
@ -266,7 +266,7 @@ instance PersistField a => SqlSelect (SqlExpr (WindowedValue a)) (WindowedValue
newtype WindowExpr a = WindowExpr { unsafeWindowExpr :: SqlExpr a }
instance Over WindowExpr where
(WindowExpr (ERaw _ f)) `over_` window = ERaw noMeta $ \p info ->
(WindowExpr (ERaw _ f)) `over_` window = SqlAggregate $ ERaw noMeta $ \p info ->
let (b, v) = f Never info
(w, vw) = renderWindow info window
in (parensM p $ b <> " OVER " <> parens w , v <> vw)

View File

@ -377,11 +377,16 @@ distinctOnOrderBy exprs act =
rand :: SqlExpr OrderBy
rand = ERaw noMeta $ \_ _ -> ("RANDOM()", [])
-- | @HAVING@.
--
-- @since 1.2.2
having :: SqlExpr Bool -> SqlQuery ()
having expr = Q $ W.tell mempty { sdHavingClause = Where expr }
class SqlQueryHaving expr where
-- | @HAVING@.
--
-- @since 1.2.2
having :: expr -> SqlQuery ()
instance SqlQueryHaving (SqlExpr Bool) where
having expr = Q $ W.tell mempty { sdHavingClause = Where expr }
instance SqlQueryHaving (SqlExpr (Maybe Bool)) where
having expr = Q $ W.tell mempty { sdHavingClause = Where (coerce expr) }
-- | Add a locking clause to the query. Please read
-- 'LockingKind' documentation and your RDBMS manual.