1
Fork 0

add names/docs to some of the scalar expr constuctor fields, add partial support for explicit window frames

This commit is contained in:
Jake Wheat 2013-12-17 17:29:49 +02:00
parent bfe07dce53
commit e85ab8b831
5 changed files with 131 additions and 25 deletions

View file

@ -87,9 +87,9 @@ the fixity code.
> $ HSE.List [str $ show (d,map snd od) > $ HSE.List [str $ show (d,map snd od)
> ,HSE.List $ map toHaskell es > ,HSE.List $ map toHaskell es
> ,HSE.List $ map (toHaskell . fst) od] > ,HSE.List $ map (toHaskell . fst) od]
> WindowApp nm es pb od -> > WindowApp nm es pb od r ->
> HSE.App (var ('w':name nm)) > HSE.App (var ('w':name nm))
> $ HSE.List [str $ show (map snd od) > $ HSE.List [str $ show (map snd od, r)
> ,HSE.List $ map toHaskell es > ,HSE.List $ map toHaskell es
> ,HSE.List $ map toHaskell pb > ,HSE.List $ map toHaskell pb
> ,HSE.List $ map (toHaskell . fst) od] > ,HSE.List $ map (toHaskell . fst) od]
@ -143,9 +143,9 @@ the fixity code.
> ,HSE.List es > ,HSE.List es
> ,HSE.List pb > ,HSE.List pb
> ,HSE.List od]) -> > ,HSE.List od]) ->
> let dir = read vs > let (dir,r) = read vs
> in WindowApp (unname i) (map toSql es) (map toSql pb) > in WindowApp (unname i) (map toSql es) (map toSql pb)
> $ zip (map toSql od) dir > (zip (map toSql od) dir) r
> HSE.App (HSE.Var (HSE.UnQual (HSE.Symbol ('p':nm)))) e0 -> > HSE.App (HSE.Var (HSE.UnQual (HSE.Symbol ('p':nm)))) e0 ->
> PostfixOp (unname nm) $ toSql e0 > PostfixOp (unname nm) $ toSql e0
> HSE.App (HSE.Var (HSE.UnQual (HSE.Symbol nm))) e0 -> > HSE.App (HSE.Var (HSE.UnQual (HSE.Symbol nm))) e0 ->

View file

@ -177,10 +177,36 @@ always used with the optionSuffix combinator.
> try (keyword_ "over") > try (keyword_ "over")
> *> parens (WindowApp f es > *> parens (WindowApp f es
> <$> option [] partitionBy > <$> option [] partitionBy
> <*> option [] orderBy) > <*> option [] orderBy
> <*> optionMaybe frameClause)
> where > where
> partitionBy = try (keyword_ "partition") >> > partitionBy = try (keyword_ "partition") >>
> keyword_ "by" >> commaSep1 scalarExpr' > keyword_ "by" >> commaSep1 scalarExpr'
> frameClause =
> mkFrame <$> (choice [FrameRows <$ keyword_ "rows"
> ,FrameRange <$ keyword_ "range"])
> <*> frameStartEnd
> frameStartEnd =
> choice
> [try (keyword_ "between") >>
> mkFrameBetween <$> frameLimit True
> <*> (keyword_ "and" *> frameLimit True)
> ,mkFrameFrom <$> frameLimit False]
> -- use the bexpression style from the between parsing for frame between
> frameLimit useB =
> choice
> [Current <$ try (keyword_ "current") <* keyword_ "row"
> ,try (keyword_ "unbounded") >>
> choice [UnboundedPreceding <$ keyword_ "preceding"
> ,UnboundedFollowing <$ keyword_ "following"]
> ,do
> e <- if useB then scalarExprB else scalarExpr
> choice [Preceding e <$ keyword_ "preceding"
> ,Following e <$ keyword_ "following"]
> ]
> mkFrameBetween s e rs = FrameBetween rs s e
> mkFrameFrom s rs = FrameFrom rs s
> mkFrame rs c = c rs
> windowSuffix _ = fail "" > windowSuffix _ = fail ""
> app :: P ScalarExpr > app :: P ScalarExpr
@ -486,6 +512,12 @@ expression tree (for efficiency and code clarity).
> scalarExpr :: P ScalarExpr > scalarExpr :: P ScalarExpr
> scalarExpr = fixFixities sqlFixities <$> scalarExpr' > scalarExpr = fixFixities sqlFixities <$> scalarExpr'
expose the b expression for window frame clause range between
> scalarExprB :: P ScalarExpr
> scalarExprB = fixFixities sqlFixities <$> scalarExpr'' True
------------------------------------------------- -------------------------------------------------
= query expressions = query expressions

View file

@ -52,21 +52,34 @@
> <+> commaSep (map scalarExpr es) > <+> commaSep (map scalarExpr es)
> <+> orderBy od) > <+> orderBy od)
> scalarExpr (WindowApp f es pb od) = > scalarExpr (WindowApp f es pb od fr) =
> name f <> parens (commaSep $ map scalarExpr es) > name f <> parens (commaSep $ map scalarExpr es)
> <+> text "over" > <+> text "over"
> <+> parens ((case pb of > <+> parens ((case pb of
> [] -> empty > [] -> empty
> _ -> text "partition by" > _ -> text "partition by"
> <+> nest 13 (commaSep $ map scalarExpr pb)) > <+> nest 13 (commaSep $ map scalarExpr pb))
> <+> orderBy od) > <+> orderBy od
> <+> maybe empty frd fr)
> where
> frd (FrameFrom rs fp) = rsd rs <+> fpd fp
> frd (FrameBetween rs fps fpe) =
> rsd rs <+> text "between" <+> fpd fps
> <+> text "and" <+> fpd fpe
> rsd rs = case rs of
> FrameRows -> text "rows"
> FrameRange -> text "range"
> fpd UnboundedPreceding = text "unbounded preceding"
> fpd UnboundedFollowing = text "unbounded following"
> fpd Current = text "current row"
> fpd (Preceding e) = scalarExpr e <+> text "preceding"
> fpd (Following e) = scalarExpr e <+> text "following"
> scalarExpr (SpecialOp nm [a,b,c]) | nm `elem` [Name "between" > scalarExpr (SpecialOp nm [a,b,c]) | nm `elem` [Name "between"
> ,Name "not between"] = > ,Name "not between"] =
> sep [scalarExpr a > sep [scalarExpr a
> ,name nm <+> scalarExpr b > ,name nm <+> scalarExpr b
> ,nest (length (unname nm) + 1) > ,nest (length (unname nm) + 1) $ text "and" <+> scalarExpr c]
> $ text "and" <+> scalarExpr c]
> scalarExpr (SpecialOp (Name "extract") [a,n]) = > scalarExpr (SpecialOp (Name "extract") [a,n]) =
> text "extract" <> parens (scalarExpr a > text "extract" <> parens (scalarExpr a

View file

@ -9,6 +9,9 @@
> ,Direction(..) > ,Direction(..)
> ,InThing(..) > ,InThing(..)
> ,SubQueryExprType(..) > ,SubQueryExprType(..)
> ,Frame(..)
> ,FrameRows(..)
> ,FramePos(..)
> -- * Query expressions > -- * Query expressions
> ,QueryExpr(..) > ,QueryExpr(..)
> ,makeSelect > ,makeSelect
@ -44,7 +47,11 @@
> | StringLit String > | StringLit String
> -- | text of interval literal, units of interval precision, > -- | text of interval literal, units of interval precision,
> -- e.g. interval 3 days (3) > -- e.g. interval 3 days (3)
> | IntervalLit String String (Maybe Int) > | IntervalLit
> {ilLiteral :: String -- ^ literal text
> ,ilUnits :: String -- ^ units
> ,ilPrecision :: Maybe Int -- ^ precision
> }
> -- | identifier without dots > -- | identifier without dots
> | Iden Name > | Iden Name
> -- | star, as in select *, t.*, count(*) > -- | star, as in select *, t.*, count(*)
@ -54,13 +61,22 @@
> | App Name [ScalarExpr] > | App Name [ScalarExpr]
> -- | aggregate application, which adds distinct or all, and > -- | aggregate application, which adds distinct or all, and
> -- order by, to regular function application > -- order by, to regular function application
> | AggregateApp Name (Maybe Duplicates) > | AggregateApp
> [ScalarExpr] > {aggName :: Name -- ^ aggregate function name
> [(ScalarExpr,Direction)] > ,aggDistinct :: (Maybe Duplicates)-- ^ distinct
> ,aggArgs :: [ScalarExpr]-- ^ args
> ,aggOrderBy :: [(ScalarExpr,Direction)] -- ^ order by
> }
> -- | window application, which adds over (partition by a order > -- | window application, which adds over (partition by a order
> -- by b) to regular function application. Explicit frames are > -- by b) to regular function application. Explicit frames are
> -- not currently supported > -- not currently supported
> | WindowApp Name [ScalarExpr] [ScalarExpr] [(ScalarExpr,Direction)] > | WindowApp
> {wnName :: Name -- ^ window function name
> ,wnArgs :: [ScalarExpr] -- ^ args
> ,wnPartition :: [ScalarExpr] -- ^ partition by
> ,wnOrderBy :: [(ScalarExpr,Direction)] -- ^ order by
> ,wnFrame :: Maybe Frame -- ^ frame clause
> }
> -- | Infix binary operators. This is used for symbol operators > -- | Infix binary operators. This is used for symbol operators
> -- (a + b), keyword operators (a and b) and multiple keyword > -- (a + b), keyword operators (a and b) and multiple keyword
> -- operators (a is similar to b) > -- operators (a is similar to b)
@ -79,9 +95,11 @@
> -- | case expression. both flavours supported. Multiple > -- | case expression. both flavours supported. Multiple
> -- condition when branches not currently supported (case when > -- condition when branches not currently supported (case when
> -- a=4,b=5 then x end) > -- a=4,b=5 then x end)
> | Case (Maybe ScalarExpr) -- test value > | Case
> [(ScalarExpr,ScalarExpr)] -- when branches > {caseTest :: Maybe ScalarExpr -- ^ test value
> (Maybe ScalarExpr) -- else value > ,caseWhens :: [(ScalarExpr,ScalarExpr)] -- ^ when branches
> ,caseElse :: Maybe ScalarExpr -- ^ else value
> }
> | Parens ScalarExpr > | Parens ScalarExpr
> -- | cast(a as typename) > -- | cast(a as typename)
> | Cast ScalarExpr TypeName > | Cast ScalarExpr TypeName
@ -123,6 +141,25 @@
> | SqAny > | SqAny
> deriving (Eq,Show,Read) > deriving (Eq,Show,Read)
> -- | Represents the frame clause of a window
> -- this can be [range | rows] frame_start
> -- or [range | rows] between frame_start and frame_end
> data Frame = FrameFrom FrameRows FramePos
> | FrameBetween FrameRows FramePos FramePos
> deriving (Eq,Show,Read)
> -- | Represents whether a window frame clause is over rows or ranges
> data FrameRows = FrameRows | FrameRange
> deriving (Eq,Show,Read)
> -- | represents the start or end of a frame
> data FramePos = UnboundedPreceding
> | Preceding ScalarExpr
> | Current
> | Following ScalarExpr
> | UnboundedFollowing
> deriving (Eq,Show,Read)
> -- | Represents a query expression, which can be: > -- | Represents a query expression, which can be:
> -- > --
> -- * a regular select; > -- * a regular select;

View file

@ -224,25 +224,49 @@ Tests for parsing scalar expressions
> windowFunctions :: TestItem > windowFunctions :: TestItem
> windowFunctions = Group "windowFunctions" $ map (uncurry TestScalarExpr) > windowFunctions = Group "windowFunctions" $ map (uncurry TestScalarExpr)
> [("max(a) over ()", WindowApp "max" [Iden "a"] [] []) > [("max(a) over ()", WindowApp "max" [Iden "a"] [] [] Nothing)
> ,("count(*) over ()", WindowApp "count" [Star] [] []) > ,("count(*) over ()", WindowApp "count" [Star] [] [] Nothing)
> ,("max(a) over (partition by b)" > ,("max(a) over (partition by b)"
> ,WindowApp "max" [Iden "a"] [Iden "b"] []) > ,WindowApp "max" [Iden "a"] [Iden "b"] [] Nothing)
> ,("max(a) over (partition by b,c)" > ,("max(a) over (partition by b,c)"
> ,WindowApp "max" [Iden "a"] [Iden "b",Iden "c"] []) > ,WindowApp "max" [Iden "a"] [Iden "b",Iden "c"] [] Nothing)
> ,("sum(a) over (order by b)" > ,("sum(a) over (order by b)"
> ,WindowApp "sum" [Iden "a"] [] [(Iden "b", Asc)]) > ,WindowApp "sum" [Iden "a"] [] [(Iden "b", Asc)] Nothing)
> ,("sum(a) over (order by b desc,c)" > ,("sum(a) over (order by b desc,c)"
> ,WindowApp "sum" [Iden "a"] [] [(Iden "b", Desc) > ,WindowApp "sum" [Iden "a"] [] [(Iden "b", Desc)
> ,(Iden "c", Asc)]) > ,(Iden "c", Asc)] Nothing)
> ,("sum(a) over (partition by b order by c)" > ,("sum(a) over (partition by b order by c)"
> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]) > ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)] Nothing)
> -- todo: check order by options, add frames
> ,("sum(a) over (partition by b order by c range unbounded preceding)"
> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]
> $ Just $ FrameFrom FrameRange UnboundedPreceding)
> ,("sum(a) over (partition by b order by c range 5 preceding)"
> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]
> $ Just $ FrameFrom FrameRange $ Preceding (NumLit "5"))
> ,("sum(a) over (partition by b order by c range current row)"
> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]
> $ Just $ FrameFrom FrameRange Current)
> ,("sum(a) over (partition by b order by c rows 5 following)"
> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]
> $ Just $ FrameFrom FrameRows $ Following (NumLit "5"))
> ,("sum(a) over (partition by b order by c range unbounded following)"
> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]
> $ Just $ FrameFrom FrameRange UnboundedFollowing)
> ,("sum(a) over (partition by b order by c range between 5 preceding and 5 following)"
> ,WindowApp "sum" [Iden "a"] [Iden "b"] [(Iden "c", Asc)]
> $ Just $ FrameBetween FrameRange (Preceding (NumLit "5")) (Following (NumLit "5")))
> ] > ]
> parens :: TestItem > parens :: TestItem