diff --git a/Language/SQL/SimpleSQL/Parser.lhs b/Language/SQL/SimpleSQL/Parser.lhs index b631cca..3321087 100644 --- a/Language/SQL/SimpleSQL/Parser.lhs +++ b/Language/SQL/SimpleSQL/Parser.lhs @@ -161,6 +161,19 @@ to be. > return $ App i es > _ -> return $ AggregateApp i d es (fromMaybe [] od) +> windowSuffix :: ScalarExpr -> P ScalarExpr +> windowSuffix e@(App f es) = +> choice [try (keyword_ "over") +> *> parens (WindowApp f es +> <$> option [] partitionBy +> <*> option [] orderBy) +> ,return e] +> where +> partitionBy = try (keyword_ "partition") >> +> keyword_ "by" >> +> commaSep1 scalarExpr' + +> windowSuffix e = return e > scase :: P ScalarExpr > scase = @@ -308,7 +321,7 @@ postgresql handles this > ,extract > ,subquery > ,prefixUnaryOp -> ,try app +> ,(try app) >>= windowSuffix > ,try dottedIden > ,identifier > ,sparens] diff --git a/Language/SQL/SimpleSQL/Pretty.lhs b/Language/SQL/SimpleSQL/Pretty.lhs index 8488d7b..8199e54 100644 --- a/Language/SQL/SimpleSQL/Pretty.lhs +++ b/Language/SQL/SimpleSQL/Pretty.lhs @@ -39,6 +39,15 @@ back into SQL source text. It attempts to format the output nicely. > <+> commaSep (map scalarExpr es) > <+> orderBy od) +> scalarExpr (WindowApp f es pb od) = +> text f <> parens (commaSep $ map scalarExpr es) +> <+> text "over" +> <+> parens ((case pb of +> [] -> empty +> _ -> text "partition by" +> <+> nest 4 (commaSep $ map scalarExpr pb)) +> <+> orderBy od) + > scalarExpr (SpecialOp nm [a,b,c]) | nm `elem` ["between", "not between"] = > sep [scalarExpr a > ,text nm <+> scalarExpr b diff --git a/Language/SQL/SimpleSQL/Syntax.lhs b/Language/SQL/SimpleSQL/Syntax.lhs index 0b9aaa2..c0cc67c 100644 --- a/Language/SQL/SimpleSQL/Syntax.lhs +++ b/Language/SQL/SimpleSQL/Syntax.lhs @@ -24,6 +24,7 @@ > | AggregateApp String (Maybe Duplicates) > [ScalarExpr] > [(ScalarExpr,Direction)] +> | WindowApp String [ScalarExpr] [ScalarExpr] [(ScalarExpr,Direction)] > -- the binop, prefixop and postfix op > -- are used for symbol and keyword operators > -- these are used even for the multiple keyword diff --git a/Tests.lhs b/Tests.lhs index 2459177..0a78233 100644 --- a/Tests.lhs +++ b/Tests.lhs @@ -184,14 +184,20 @@ > windowFunctions :: TestItem > windowFunctions = Group "windowFunctions" $ map (uncurry TestScalarExpr) -> [{-("max(a) over ()", NumLit "1") -> ,("count(*) over ()", NumLit "1") -> ,("max(a) over (partition by b)", NumLit "1") -> ,("sum(a) over (order by b)", NumLit "1") -> ,("sum(a) over (partition by b order by c)", NumLit "1") -> ,("sum(a) over (partition by b order by c)", NumLit "1") +> [("max(a) over ()", WindowApp "max" [Iden "a"] [] []) +> ,("count(*) over ()", WindowApp "count" [Star] [] []) +> ,("max(a) over (partition by b)" +> ,WindowApp "max" [Iden "a"] [Iden "b"] []) +> ,("max(a) over (partition by b,c)" +> ,WindowApp "max" [Iden "a"] [Iden "b",Iden "c"] []) +> ,("sum(a) over (order by b)" +> ,WindowApp "sum" [Iden "a"] [] [(Iden "b", Asc)]) +> ,("sum(a) over (order by b desc,c)" +> ,WindowApp "sum" [Iden "a"] [] [(Iden "b", Desc) +> ,(Iden "c", Asc)]) +> ,("sum(a) over (partition by b order by c)" +> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]) > -- todo: check order by options, add frames -> -} > ] > parens :: TestItem