on dev help sign in
window functions - attempt 3
873c511Eitan Chatav
squeal-postgresql/src/Squeal/PostgreSQL/Expression.hs+149
@@ -16,11 +16,13 @@ Squeal expressions are the atoms used to build statements.
16 , FlexibleContexts
16 , FlexibleContexts
17 , FlexibleInstances
17 , FlexibleInstances
18 , FunctionalDependencies
18 , FunctionalDependencies
19+ , GADTs
19 , GeneralizedNewtypeDeriving
20 , GeneralizedNewtypeDeriving
20 , LambdaCase
21 , LambdaCase
21 , MagicHash
22 , MagicHash
22 , OverloadedStrings
23 , OverloadedStrings
23 , ScopedTypeVariables
24 , ScopedTypeVariables
25+ , StandaloneDeriving
24 , TypeApplications
26 , TypeApplications
25 , TypeFamilies
27 , TypeFamilies
26 , TypeInType
28 , TypeInType
@@ -141,6 +143,18 @@ module Squeal.PostgreSQL.Expression
141 , count, countDistinct
143 , count, countDistinct
142 , every, everyDistinct
144 , every, everyDistinct
143 , max_, maxDistinct, min_, minDistinct
145 , max_, maxDistinct, min_, minDistinct
146+ -- * Window Functions
147+ , WindowDefinition (..)
148+ , partitionBy
149+ , WindowFunction (..)
150+ , rank
151+ , rowNumber
152+ , denseRank
153+ , percentRank
154+ , cumeDist
155+ -- * Sorting
156+ , SortExpression (..)
157+ , OrderBy (..)
144 -- * Types
158 -- * Types
145 , TypeExpression (..)
159 , TypeExpression (..)
146 , PGTyped (..)
160 , PGTyped (..)
@@ -1778,3 +1792,138 @@ instance PGTyped schemas ty
1778instance (KnownNat n, PGTyped schemas ty)
1792instance (KnownNat n, PGTyped schemas ty)
1779 => PGTyped schemas (nullity ('PGfixarray n ty)) where
1793 => PGTyped schemas (nullity ('PGfixarray n ty)) where
1780 pgtype = fixarray @n (pgtype @schemas @ty)
1794 pgtype = fixarray @n (pgtype @schemas @ty)
1795+
1796+{-----------------------------------------
1797+Sorting
1798+-----------------------------------------}
1799+
1800+-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1801+-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1802+-- column to ascending or descending. Ascending order puts smaller values
1803+-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1804+-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1805+-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1806+-- determine whether nulls appear before or after non-null values in the sort
1807+-- ordering of a `Null` result column.
1808+data SortExpression commons schemas params grp from where
1809+ Asc
1810+ :: Expression commons schemas params grp from ('NotNull ty)
1811+ -> SortExpression commons schemas params grp from
1812+ Desc
1813+ :: Expression commons schemas params grp from ('NotNull ty)
1814+ -> SortExpression commons schemas params grp from
1815+ AscNullsFirst
1816+ :: Expression commons schemas params grp from ('Null ty)
1817+ -> SortExpression commons schemas params grp from
1818+ AscNullsLast
1819+ :: Expression commons schemas params grp from ('Null ty)
1820+ -> SortExpression commons schemas params grp from
1821+ DescNullsFirst
1822+ :: Expression commons schemas params grp from ('Null ty)
1823+ -> SortExpression commons schemas params grp from
1824+ DescNullsLast
1825+ :: Expression commons schemas params grp from ('Null ty)
1826+ -> SortExpression commons schemas params grp from
1827+deriving instance Show (SortExpression commons schemas params grp from)
1828+
1829+class OrderBy expr where
1830+ orderBy
1831+ :: [SortExpression commons schemas params grp from]
1832+ -> expr commons schemas params grp from
1833+ -> expr commons schemas params grp from
1834+
1835+-- | Render a `SortExpression`.
1836+instance RenderSQL (SortExpression commons schemas params grp from) where
1837+ renderSQL = \case
1838+ Asc expression -> renderSQL expression <+> "ASC"
1839+ Desc expression -> renderSQL expression <+> "DESC"
1840+ AscNullsFirst expression -> renderSQL expression
1841+ <+> "ASC NULLS FIRST"
1842+ DescNullsFirst expression -> renderSQL expression
1843+ <+> "DESC NULLS FIRST"
1844+ AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
1845+ DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
1846+
1847+data WindowDefinition commons schemas params grp from where
1848+ WindowDefinition
1849+ :: SListI bys
1850+ => NP (Expression commons schemas params grp from) bys
1851+ -> [SortExpression commons schemas params grp from]
1852+ -> WindowDefinition commons schemas params grp from
1853+
1854+instance OrderBy WindowDefinition where
1855+ orderBy sortsR (WindowDefinition parts sortsL)
1856+ = WindowDefinition parts (sortsL ++ sortsR)
1857+
1858+instance RenderSQL (WindowDefinition commons schemas from grp params) where
1859+ renderSQL (WindowDefinition part ord) =
1860+ renderPartitionByClause part <> renderOrderByClause ord
1861+ where
1862+ renderPartitionByClause = \case
1863+ Nil -> ""
1864+ parts -> "PARTITION" <+> "BY" <+> renderCommaSeparated renderExpression parts
1865+ renderOrderByClause = \case
1866+ [] -> ""
1867+ srts -> " ORDER" <+> "BY"
1868+ <+> commaSeparated (renderSQL <$> srts)
1869+
1870+partitionBy
1871+ :: SListI bys
1872+ => NP (Expression commons schemas params grp from) bys
1873+ -> WindowDefinition commons schemas params grp from
1874+partitionBy bys = WindowDefinition bys []
1875+
1876+newtype WindowFunction
1877+ (commons :: FromType)
1878+ (schemas :: SchemasType)
1879+ (params :: [NullityType])
1880+ (grp :: Grouping)
1881+ (from :: FromType)
1882+ (ty :: NullityType)
1883+ = UnsafeWindowFunction { renderWindowFunction :: ByteString }
1884+ deriving (GHC.Generic,Show,Eq,Ord,NFData)
1885+
1886+instance RenderSQL (WindowFunction commons schemas params grp from ty) where
1887+ renderSQL = renderWindowFunction
1888+
1889+{- | rank of the current row with gaps; same as `rowNumber` of its first peer
1890+>>> :{
1891+let
1892+ expr :: WindowExpression commons schemas params 'Ungrouped '["tab" ::: '["a" ::: ty]] ('NotNull 'PGint8)
1893+ expr = rank `Over` (partitionBy #a)
1894+in
1895+ printSQL expr
1896+:}
1897+rank() OVER (PARTITION BY "a")
1898+-}
1899+rank :: WindowFunction commons schemas from grp params ('NotNull 'PGint8)
1900+rank = UnsafeWindowFunction "rank()"
1901+
1902+{- | number of the current row within its partition, counting from 1
1903+>>> printSQL rowNumber
1904+row_number()
1905+-}
1906+rowNumber :: WindowFunction commons schemas from grp params ('NotNull 'PGint8)
1907+rowNumber = UnsafeWindowFunction "row_number()"
1908+
1909+{- | rank of the current row without gaps; this function counts peer groups
1910+>>> printSQL denseRank
1911+dense_rank()
1912+-}
1913+denseRank :: WindowFunction commons schemas from grp params ('NotNull 'PGint8)
1914+denseRank = UnsafeWindowFunction "dense_rank()"
1915+
1916+{- | relative rank of the current row: (rank - 1) / (total partition rows - 1)
1917+>>> printSQL percentRank
1918+percent_rank()
1919+-}
1920+percentRank :: WindowFunction commons schemas from grp params ('NotNull 'PGfloat8)
1921+percentRank = UnsafeWindowFunction "percent_rank()"
1922+
1923+{- | cumulative distribution: (number of partition rows
1924+preceding or peer with current row) / total partition rows
1925+>>> printSQL cumeDist
1926+cume_dist()
1927+-}
1928+cumeDist :: WindowFunction commons schemas from grp params ('NotNull 'PGfloat8)
1929+cumeDist = UnsafeWindowFunction "cume_dist()"
squeal-postgresql/src/Squeal/PostgreSQL/Query.hs+16−55
@@ -74,7 +74,6 @@ module Squeal.PostgreSQL.Query
74 , where_
74 , where_
75 , groupBy
75 , groupBy
76 , having
76 , having
77− , orderBy
78 , limit
77 , limit
79 , offset
78 , offset
80 -- * From Clauses
79 -- * From Clauses
@@ -92,8 +91,6 @@ module Squeal.PostgreSQL.Query
92 , By (..)
91 , By (..)
93 , GroupByClause (..)
92 , GroupByClause (..)
94 , HavingClause (..)
93 , HavingClause (..)
95− -- * Sorting
96− , SortExpression (..)
97 -- * Subquery Expressions
94 -- * Subquery Expressions
98 , in_
95 , in_
99 , rowIn
96 , rowIn
@@ -412,6 +409,11 @@ data Selection commons schemas params grp from row where
412 :: Selection commons schemas params grp from right
409 :: Selection commons schemas params grp from right
413 -> Selection commons schemas params grp from left
410 -> Selection commons schemas params grp from left
414 -> Selection commons schemas params grp from (Join left right)
411 -> Selection commons schemas params grp from (Join left right)
412+ Over
413+ :: SListI row
414+ => NP (Aliased (WindowFunction commons schemas params grp from)) row
415+ -> WindowDefinition commons schemas params grp from
416+ -> Selection commons schemas params grp from row
415instance (KnownSymbol col, row ~ '[col ::: ty])
417instance (KnownSymbol col, row ~ '[col ::: ty])
416 => Aliasable col
418 => Aliasable col
417 (Expression commons schemas params grp from ty)
419 (Expression commons schemas params grp from ty)
@@ -444,6 +446,15 @@ instance RenderSQL (Selection commons schemas params grp from row) where
444 Star -> "*"
446 Star -> "*"
445 DotStar tab -> renderSQL tab <> ".*"
447 DotStar tab -> renderSQL tab <> ".*"
446 Also right left -> renderSQL left <> ", " <> renderSQL right
448 Also right left -> renderSQL left <> ", " <> renderSQL right
449+ Over winFns winDef ->
450+ let
451+ renderOver
452+ :: Aliased (WindowFunction commons schemas params grp from) field
453+ -> ByteString
454+ renderOver winFn = renderAliased renderSQL winFn
455+ <+> "OVER" <+> parenthesized (renderSQL winDef)
456+ in
457+ renderCommaSeparated renderOver winFns
447
458
448-- | the `TableExpression` in the `select` command constructs an intermediate
459-- | the `TableExpression` in the `select` command constructs an intermediate
449-- virtual table by possibly combining tables, views, eliminating rows,
460-- virtual table by possibly combining tables, views, eliminating rows,
@@ -662,13 +673,8 @@ having
662having hv rels = rels
673having hv rels = rels
663 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
674 { havingClause = case havingClause rels of Having hvs -> Having (hv:hvs) }
664
675
665−-- | An `orderBy` is an endomorphism of `TableExpression`s which appends an
676+instance OrderBy TableExpression where
666−-- ordering to the right of the `orderByClause`.
667−orderBy
668− :: [SortExpression commons schemas params grp from] -- ^ sort expressions
669− -> TableExpression commons schemas params grp from
670− -> TableExpression commons schemas params grp from
671−orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
677+ orderBy srts rels = rels {orderByClause = orderByClause rels ++ srts}
672
678
673-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
679-- | A `limit` is an endomorphism of `TableExpression`s which adds to the
674-- `limitClause`.
680-- `limitClause`.
@@ -1035,51 +1041,6 @@ instance RenderSQL (HavingClause commons schemas params grp from) where
1035 Having conditions ->
1041 Having conditions ->
1036 " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1042 " HAVING" <+> commaSeparated (renderSQL <$> conditions)
1037
1043
1038−{-----------------------------------------
1039−Sorting
1040−-----------------------------------------}
1041−
1042−-- | `SortExpression`s are used by `sortBy` to optionally sort the results
1043−-- of a `Query`. `Asc` or `Desc` set the sort direction of a `NotNull` result
1044−-- column to ascending or descending. Ascending order puts smaller values
1045−-- first, where "smaller" is defined in terms of the `.<` operator. Similarly,
1046−-- descending order is determined with the `.>` operator. `AscNullsFirst`,
1047−-- `AscNullsLast`, `DescNullsFirst` and `DescNullsLast` options are used to
1048−-- determine whether nulls appear before or after non-null values in the sort
1049−-- ordering of a `Null` result column.
1050−data SortExpression commons schemas params grp from where
1051− Asc
1052− :: Expression commons schemas params grp from ('NotNull ty)
1053− -> SortExpression commons schemas params grp from
1054− Desc
1055− :: Expression commons schemas params grp from ('NotNull ty)
1056− -> SortExpression commons schemas params grp from
1057− AscNullsFirst
1058− :: Expression commons schemas params grp from ('Null ty)
1059− -> SortExpression commons schemas params grp from
1060− AscNullsLast
1061− :: Expression commons schemas params grp from ('Null ty)
1062− -> SortExpression commons schemas params grp from
1063− DescNullsFirst
1064− :: Expression commons schemas params grp from ('Null ty)
1065− -> SortExpression commons schemas params grp from
1066− DescNullsLast
1067− :: Expression commons schemas params grp from ('Null ty)
1068− -> SortExpression commons schemas params grp from
1069−deriving instance Show (SortExpression commons schemas params grp from)
1070−
1071−-- | Render a `SortExpression`.
1072−instance RenderSQL (SortExpression commons schemas params grp from) where
1073− renderSQL = \case
1074− Asc expression -> renderSQL expression <+> "ASC"
1075− Desc expression -> renderSQL expression <+> "DESC"
1076− AscNullsFirst expression -> renderSQL expression
1077− <+> "ASC NULLS FIRST"
1078− DescNullsFirst expression -> renderSQL expression
1079− <+> "DESC NULLS FIRST"
1080− AscNullsLast expression -> renderSQL expression <+> "ASC NULLS LAST"
1081− DescNullsLast expression -> renderSQL expression <+> "DESC NULLS LAST"
1082−
1083unsafeSubqueryExpression
1044unsafeSubqueryExpression
1084 :: ByteString
1045 :: ByteString
1085 -> Expression commons schemas params grp from ty
1046 -> Expression commons schemas params grp from ty