-
Notifications
You must be signed in to change notification settings - Fork 106
Description
This is my stream of consciousness thoughts on Window functions.
Window functions should be restricted in use. Therefore they cant be SqlExpr (Value a) since that would allow for their use wherever a Value is allowed.
Solution: SqlExpr (AggregateValue a) This would use a new newtype to support SqlSelect. I am not a fan of the new wrapper type but it is forced on us by the fundeps of SqlSelect. I would much rather Value and AggregateValue disappeared when we go from the SqlExpr language to Haskell.
Currently we have a number of aggregate functions that can also be used with a window. These functions return types of SqlExpr (Value a). This seems wrong since you cant use aggregate functions in a where clause. Rather where_ expressions should only be in terms of SqlExpr (Value a) and having should be in terms of SqlExpr (AggregateValue a). This change would require work on generalizing the comparison operators.
Should there be two different count_(or other aggregate) functions or should we use a type class to overload the function. The typeclass would be.
class SqlCount a where
count_ :: SqlExpr (Value v) -> a
instance SqlCount (SqlExpr (AggregateValue a)) where
count_ = unsafeSqlFunction "COUNT"
instance SqlCount(WindowContext -> SqlExpr (AggregateValue a)) where
count_ = unsafeWindowFunction "COUNT"I am thinking about how to make the best SQL like syntax and my current idea is:
count_ (user ^. UserId) over_ (partitionBy (user ^. UserGroup) <> orderBy (user ^. UserName))to achieve this we could have
data Over = Over
type WindowContext = Over -> Window
over_ = Overoptionally we can just use () instead of the new Over unit type. This is actually how the nice case_ syntax works then_ = ()
The window would be a Monoid
data Window = Window
{ windowPartition :: Monoid.Last WindowPartition
, windowOrder :: Monoid.Last OrderBy
, windowFrame :: Monoid.Last WindowFrame
}so instead of writing
COUNT(*) OVER ()you would have to write
countRows_ over_ memptyMaybe we should make an AsWindow class
class AsWindow a where
asWindow :: a -> Window
instance AsWindow Window where
asWindow = id
instance AsWindow () where
asWindow = const memptywhich could be used to enable
countRows_ over_ ()This update would require a change to the SqlExpr to create a new constructor
EAggregate :: (IdentInfo -> (TLB.Builder, [PersistValue])) -> SqlExpr (AggregateValue a)This is theoretically not required but will increase the type safety without breaking backwards compat. Then unsafeWindowFunction would handle the logic of converting a Window into an EAggregate value.
Need to come up with a good way to generate WindowFrames. We don't need named windows since we have let statements.
Relevant Issues:
#196