hssqlppp-0.1.0: Database/HsSqlPpp/Tests/ParserTests.lhs
Copyright 2009 Jake Wheat
The automated tests, uses hunit to check a bunch of text expressions
and sql statements parse to the correct tree, and then checks pretty
printing and then reparsing gives the same tree. The code was mostly
written in a tdd style, which the coverage of the tests reflects.
There are no tests for invalid sql at the moment.
temporarily disabled because of haddock issue:
{-# LANGUAGE QuasiQuotes #-}
> module Database.HsSqlPpp.Tests.ParserTests (parserTests) where
> import Test.HUnit
> import Test.Framework
> import Test.Framework.Providers.HUnit
> import Data.Char
> import Data.Generics
> -- import Database.HsSqlPpp.Here
> import Database.HsSqlPpp.Ast.Ast
> import Database.HsSqlPpp.Ast.Annotation
> import Database.HsSqlPpp.Parsing.Parser
> import Database.HsSqlPpp.PrettyPrinter.PrettyPrinter
> data Item = Expressions [(String, Expression)]
> | Statements [(String, [Statement])]
> | PlpgsqlStatements [(String, [Statement])]
> | Group String [Item]
> parserTests :: [Test.Framework.Test]
> parserTests = itemToTft parserTestData
> parserTestData :: Item
> parserTestData =
> Group "parserTests" [
================================================================================
expressions
> Group "parse expressions" [
> Group "basic expressions" [Expressions [
> p "1" (IntegerLit [] 1)
> ,p "-1" (FunCall [] "u-" [IntegerLit [] 1])
> ,p "1.1" (FloatLit [] 1.1)
> ,p "-1.1" (FunCall [] "u-" [FloatLit [] 1.1])
> ,p " 1 + 1 " (FunCall [] "+" [IntegerLit [] 1
> ,IntegerLit [] 1])
> ,p "1+1+1" (FunCall [] "+" [FunCall [] "+" [IntegerLit [] 1
> ,IntegerLit [] 1]
> ,IntegerLit [] 1])
> ]]
> ,Group "parens" [Expressions [
check some basic parens use wrt naked values and row constructors
these tests reflect how pg seems to interpret the variants.
> p "(1)" (IntegerLit [] 1)
> ,p "row ()" (FunCall [] "!rowctor" [])
> ,p "row (1)" (FunCall [] "!rowctor" [IntegerLit [] 1])
> ,p "row (1,2)" (FunCall [] "!rowctor" [IntegerLit [] 1,IntegerLit [] 2])
> ,p "(1,2)" (FunCall [] "!rowctor" [IntegerLit [] 1,IntegerLit [] 2])
> ]]
> ,Group "more basic expressions" [Expressions [
test some more really basic expressions
> p "'test'" (stringQ "test")
> ,p "''" (stringQ "")
> ,p "hello" (Identifier [] "hello")
> ,p "helloTest" (Identifier [] "helloTest")
> ,p "hello_test" (Identifier [] "hello_test")
> ,p "\"this is an identifier\"" (Identifier [] "this is an identifier")
> ,p "hello1234" (Identifier [] "hello1234")
> ,p "true" (BooleanLit [] True)
> ,p "false" (BooleanLit [] False)
> ,p "null" (NullLit [])
> ]]
> ,Group "array ctor and selector" [Expressions [
> p "array[1,2]" (FunCall [] "!arrayctor" [IntegerLit [] 1, IntegerLit [] 2])
> ,p "a[1]" (FunCall [] "!arraysub" [Identifier [] "a", IntegerLit [] 1])
> ]]
> ,Group "simple operators" [Expressions [
> p "1 + tst1" (FunCall [] "+" [IntegerLit [] 1
> ,Identifier [] "tst1"])
> ,p "tst1 + 1" (FunCall [] "+" [Identifier [] "tst1"
> ,IntegerLit [] 1])
> ,p "tst + tst1" (FunCall [] "+" [Identifier [] "tst"
> ,Identifier [] "tst1"])
> ,p "'a' || 'b'" (FunCall [] "||" [stringQ "a"
> ,stringQ "b"])
> ,p "'stuff'::text" (Cast [] (stringQ "stuff") (SimpleTypeName [] "text"))
> ,p "245::float(24)" (Cast [] (IntegerLit [] 245) (PrecTypeName [] "float" 24))
> ,p "245::double precision" (Cast [] (IntegerLit [] 245) (SimpleTypeName [] "double precision"))
> ,p "a between 1 and 3"
> (FunCall [] "!between" [Identifier [] "a", IntegerLit [] 1, IntegerLit [] 3])
> ,p "cast(a as text)"
> (Cast [] (Identifier [] "a") (SimpleTypeName [] "text"))
> ,p "@ a"
> (FunCall [] "@" [Identifier [] "a"])
> ,p "substring(a from 0 for 3)"
> (FunCall [] "!substring" [Identifier [] "a", IntegerLit [] 0, IntegerLit [] 3])
> ,p "substring(a from 0 for (5 - 3))"
> (FunCall [] "!substring" [Identifier [] "a",IntegerLit [] 0,
> FunCall [] "-" [IntegerLit [] 5,IntegerLit [] 3]])
> ,p "a like b"
> (FunCall [] "!like" [Identifier [] "a", Identifier [] "b"])
> ]]
> ,Group "function calls" [Expressions [
> p "fn()" (FunCall [] "fn" [])
> ,p "fn(1)" (FunCall [] "fn" [IntegerLit [] 1])
> ,p "fn('test')" (FunCall [] "fn" [stringQ "test"])
> ,p "fn(1,'test')" (FunCall [] "fn" [IntegerLit [] 1, stringQ "test"])
> ,p "fn('test')" (FunCall [] "fn" [stringQ "test"])
> ]]
> ,Group "simple whitespace sanity checks" [Expressions [
> p "fn (1)" (FunCall [] "fn" [IntegerLit [] 1])
> ,p "fn( 1)" (FunCall [] "fn" [IntegerLit [] 1])
> ,p "fn(1 )" (FunCall [] "fn" [IntegerLit [] 1])
> ,p "fn(1) " (FunCall [] "fn" [IntegerLit [] 1])
> ]]
> ,Group "null stuff" [Expressions [
> p "not null" (FunCall [] "!not" [NullLit []])
> ,p "a is null" (FunCall [] "!isnull" [Identifier [] "a"])
> ,p "a is not null" (FunCall [] "!isnotnull" [Identifier [] "a"])
> ,p "not not true" (FunCall [] "!not"
> [FunCall [] "!not"
> [BooleanLit [] True]])
> ]]
> ,Group "case expressions" [Expressions [
> p -- [$here|
> "case when a,b then 3\n\
> \ when c then 4\n\
> \ else 5\n\
> \end"
> -- |]
> (Case [] [([Identifier [] "a", Identifier [] "b"], IntegerLit [] 3)
> ,([Identifier [] "c"], IntegerLit [] 4)]
> (Just $ IntegerLit [] 5))
> ,p "case 1 when 2 then 3 else 4 end"
> (CaseSimple [] (IntegerLit [] 1)
> [([IntegerLit [] 2], IntegerLit [] 3)]
> (Just $ IntegerLit [] 4))
> ]]
> ,Group "positional args" [Expressions [
> p "$1" (PositionalArg [] 1)
> ,p "?" (Placeholder [])
> ,p "a = ?" (FunCall [] "=" [Identifier [] "a",Placeholder []])
> ]]
> ,Group "exists" [Expressions [
> p "exists (select 1 from a)"
> (Exists [] (selectFrom [SelExp [] (IntegerLit [] 1)] (Tref [] "a" NoAlias)))
> ]]
> ,Group "in variants" [Expressions [
> p "t in (1,2)"
> (InPredicate [] (Identifier [] "t") True (InList [] [IntegerLit [] 1,IntegerLit [] 2]))
> ,p "t not in (1,2)"
> (InPredicate [] (Identifier [] "t") False (InList [] [IntegerLit [] 1,IntegerLit [] 2]))
> ,p "(t,u) in (1,2)"
> (InPredicate [] (FunCall [] "!rowctor" [Identifier [] "t",Identifier [] "u"]) True
> (InList [] [IntegerLit [] 1,IntegerLit [] 2]))
> ,p "3 = any (array[1,2])"
> (LiftOperator [] "=" LiftAny [IntegerLit [] 3
> ,FunCall [] "!arrayctor" [IntegerLit [] 1
> ,IntegerLit [] 2]])
> ,p "3 = all (array[1,2,4])"
> (LiftOperator [] "=" LiftAll [IntegerLit [] 3
> ,FunCall [] "!arrayctor" [IntegerLit [] 1
> ,IntegerLit [] 2
> ,IntegerLit [] 4]])
> ]]
> ,Group "comparison operators" [Expressions [
> p "a < b"
> (FunCall [] "<" [Identifier [] "a", Identifier [] "b"])
> ,p "a <> b"
> (FunCall [] "<>" [Identifier [] "a", Identifier [] "b"])
> ,p "a != b"
> (FunCall [] "<>" [Identifier [] "a", Identifier [] "b"])
> ]]
test some string parsing, want to check single quote behaviour,
and dollar quoting, including nesting.
> ,Group "string parsing" [Expressions [
> p "''" (stringQ "")
> ,p "''''" (stringQ "'")
> ,p "'test'''" (stringQ "test'")
> ,p "'''test'" (stringQ "'test")
> ,p "'te''st'" (stringQ "te'st")
> ,p "$$test$$" (StringLit [] "$$" "test")
> ,p "$$te'st$$" (StringLit [] "$$" "te'st")
> ,p "$st$test$st$" (StringLit [] "$st$" "test")
> ,p "$outer$te$$yup$$st$outer$" (StringLit [] "$outer$" "te$$yup$$st")
> ,p "'spl$$it'" (stringQ "spl$$it")
> ]]
> ]
================================================================================
select statements
> ,Group "simple select statements" [
> Group "select no table" [Statements [
> p "select 1;" [SelectStatement [] $ selectE (SelectList [] [SelExp [] (IntegerLit [] 1)] [])]
> ]]
> ,Group "select from table" [Statements [
> p "select * from tbl;"
> [SelectStatement [] $ selectFrom (selIL ["*"]) (Tref [] "tbl" NoAlias)]
> ,p "select a,b from tbl;"
> [SelectStatement [] $ selectFrom (selIL ["a", "b"]) (Tref [] "tbl" NoAlias)]
> ,p "select a,b from inf.tbl;"
> [SelectStatement [] $ selectFrom (selIL ["a", "b"]) (Tref [] "inf.tbl" NoAlias)]
> ,p "select distinct * from tbl;"
> [SelectStatement [] $ Select [] Distinct (SelectList [] (selIL ["*"]) []) [Tref [] "tbl" NoAlias]
> Nothing [] Nothing [] Nothing Nothing]
> ,p "select a from tbl where b=2;"
> [SelectStatement [] $ selectFromWhere
> (selIL ["a"])
> (Tref [] "tbl" NoAlias)
> (FunCall [] "="
> [Identifier [] "b", IntegerLit [] 2])]
> ,p "select a from tbl where b=2 and c=3;"
> [SelectStatement [] $ selectFromWhere
> (selIL ["a"])
> (Tref [] "tbl" NoAlias)
> (FunCall [] "!and"
> [FunCall [] "=" [Identifier [] "b", IntegerLit [] 2]
> ,FunCall [] "=" [Identifier [] "c", IntegerLit [] 3]])]
> ]]
> ,Group "more select statements" [Statements [
> p "select a from tbl\n\
> \except\n\
> \select a from tbl1;"
> [SelectStatement [] $ CombineSelect [] Except
> (selectFrom (selIL ["a"]) (Tref [] "tbl" NoAlias))
> (selectFrom (selIL ["a"]) (Tref [] "tbl1" NoAlias))]
> ,p "select a from tbl where true\n\
> \except\n\
> \select a from tbl1 where true;"
> [SelectStatement [] $ CombineSelect [] Except
> (selectFromWhere (selIL ["a"]) (Tref [] "tbl" NoAlias) (BooleanLit [] True))
> (selectFromWhere (selIL ["a"]) (Tref [] "tbl1" NoAlias) (BooleanLit [] True))]
> ,p "select a from tbl\n\
> \union\n\
> \select a from tbl1;"
> [SelectStatement [] $ CombineSelect [] Union
> (selectFrom (selIL ["a"]) (Tref [] "tbl" NoAlias))
> (selectFrom (selIL ["a"]) (Tref [] "tbl1" NoAlias))]
> ,p "select a from tbl\n\
> \union all\n\
> \select a from tbl1;"
> [SelectStatement [] $ CombineSelect [] UnionAll
> (selectFrom (selIL ["a"]) (Tref [] "tbl" NoAlias))
> (selectFrom (selIL ["a"]) (Tref [] "tbl1" NoAlias))]
> ,p "(select 1 union select 2) union select 3;"
> [SelectStatement []
> (CombineSelect [] Union
> (CombineSelect [] Union
> (selectE (SelectList [] [SelExp [] (IntegerLit [] 1)] []))
> (selectE (SelectList [] [SelExp [] (IntegerLit [] 2)] [])))
> (selectE (SelectList [] [SelExp [] (IntegerLit [] 3)] [])))]
> ,p "select 1 union (select 2 union select 3);"
> [SelectStatement []
> (CombineSelect [] Union
> (selectE (SelectList [] [SelExp [] (IntegerLit [] 1)] []))
> (CombineSelect [] Union
> (selectE (SelectList [] [SelExp [] (IntegerLit [] 2)] []))
> (selectE (SelectList [] [SelExp [] (IntegerLit [] 3)] []))))]
> ,p "select a as b from tbl;"
> [SelectStatement [] $ selectFrom [SelectItem [] (Identifier [] "a") "b"] (Tref [] "tbl" NoAlias)]
> ,p "select a + b as b from tbl;"
> [SelectStatement [] $ selectFrom
> [SelectItem []
> (FunCall [] "+"
> [Identifier [] "a", Identifier [] "b"]) "b"]
> (Tref [] "tbl" NoAlias)]
> ,p "select a.* from tbl a;"
> [SelectStatement [] $ selectFrom (selIL ["a.*"]) (Tref [] "tbl" (TableAlias "a"))]
> ,p "select a.* from tbl a(b,c);"
> [SelectStatement [] $ selectFrom (selIL ["a.*"]) (Tref [] "tbl" (FullAlias "a" ["b","c"]))]
> ,p "select * from t1 a, t2 b;"
> [SelectStatement []
> (Select [] Dupes
> (SelectList []
> [SelExp [] (Identifier [] "*")] [])
> [Tref [] "t1" (TableAlias "a"),Tref [] "t2" (TableAlias "b")]
> Nothing [] Nothing [] Nothing Nothing)]
> ,p "select a from b inner join c on b.a=c.a;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural Inner (Tref [] "c" NoAlias)
> (Just (JoinOn []
> (FunCall [] "=" [Identifier [] "b.a", Identifier [] "c.a"]))) NoAlias)]
> ,p "select a from b inner join c as d on b.a=d.a;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural Inner (Tref [] "c" (TableAlias "d"))
> (Just (JoinOn []
> (FunCall [] "=" [Identifier [] "b.a", Identifier [] "d.a"]))) NoAlias)]
> ,p "select a from b inner join c using(d,e);"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural Inner (Tref [] "c" NoAlias)
> (Just (JoinUsing [] ["d","e"])) NoAlias)]
> ,p "select a from b natural inner join c;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Natural Inner (Tref [] "c" NoAlias) Nothing NoAlias)]
> ,p "select a from b left outer join c;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural LeftOuter (Tref [] "c" NoAlias) Nothing NoAlias)]
> ,p "select a from b full outer join c;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural FullOuter (Tref [] "c" NoAlias) Nothing NoAlias)]
> ,p "select a from b right outer join c;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural RightOuter (Tref [] "c" NoAlias) Nothing NoAlias)]
> ,p "select a from b cross join c;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural Cross (Tref [] "c" NoAlias) Nothing NoAlias)]
> ,p "select a from (b natural join c);"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (JoinedTref [] (Tref [] "b" NoAlias) Natural Inner (Tref [] "c" NoAlias) Nothing NoAlias)]
> ,p "select x from ((a cross join b) cross join c);"
> [SelectStatement []
> (selectFrom (selIL ["x"])
> (JoinedTref []
> (JoinedTref []
> (Tref [] "a" NoAlias)
> Unnatural Cross
> (Tref [] "b" NoAlias)
> Nothing NoAlias)
> Unnatural Cross
> (Tref [] "c" NoAlias)
> Nothing NoAlias))]
> ,p "select x from (a cross join (b cross join c));"
> [SelectStatement []
> (selectFrom (selIL ["x"])
> (JoinedTref []
> (Tref [] "a" NoAlias)
> Unnatural Cross
> (JoinedTref []
> (Tref [] "b" NoAlias)
> Unnatural Cross
> (Tref [] "c" NoAlias)
> Nothing NoAlias)
> Nothing NoAlias))]
> ,p "select x from ((a cross join b) cross join c);"
> [SelectStatement []
> (selectFrom (selIL ["x"])
> (JoinedTref []
> (JoinedTref []
> (Tref [] "a" NoAlias)
> Unnatural Cross
> (Tref [] "b" NoAlias)
> Nothing NoAlias)
> Unnatural Cross
> (Tref [] "c" NoAlias)
> Nothing NoAlias))]
> ,p "select x from (a cross join b) cross join c;"
> [SelectStatement []
> (selectFrom (selIL ["x"])
> (JoinedTref []
> (JoinedTref []
> (Tref [] "a" NoAlias)
> Unnatural Cross
> (Tref [] "b" NoAlias)
> Nothing NoAlias)
> Unnatural Cross
> (Tref [] "c" NoAlias)
> Nothing NoAlias))]
> ,p "select x from ((a cross join b) cross join c) cross join d;"
> [SelectStatement []
> (selectFrom (selIL ["x"])
> (JoinedTref []
> (JoinedTref []
> (JoinedTref []
> (Tref [] "a" NoAlias)
> Unnatural Cross
> (Tref [] "b" NoAlias)
> Nothing NoAlias)
> Unnatural Cross
> (Tref [] "c" NoAlias)
> Nothing NoAlias)
> Unnatural Cross
> (Tref [] "d" NoAlias)
> Nothing NoAlias))]
> ,p "select a from b\n\
> \ inner join c\n\
> \ on true\n\
> \ inner join d\n\
> \ on 1=1;"
> [SelectStatement [] $ selectFrom
> [SelExp [] (Identifier [] "a")]
> (JoinedTref []
> (JoinedTref [] (Tref [] "b" NoAlias) Unnatural Inner (Tref [] "c" NoAlias)
> (Just $ JoinOn [] (BooleanLit [] True)) NoAlias)
> Unnatural Inner (Tref [] "d" NoAlias)
> (Just $ JoinOn [] (FunCall [] "="
> [IntegerLit [] 1, IntegerLit [] 1])) NoAlias)]
> ,p "select row_number() over(order by a) as place from tbl;"
> [SelectStatement [] $ selectFrom [SelectItem []
> (WindowFn []
> (FunCall [] "row_number" [])
> []
> [Identifier [] "a"] Asc FrameUnboundedPreceding)
> "place"]
> (Tref [] "tbl" NoAlias)]
> ,p "select row_number() over(order by a asc) as place from tbl;"
> [SelectStatement [] $ selectFrom [SelectItem []
> (WindowFn []
> (FunCall [] "row_number" [])
> []
> [Identifier [] "a"] Asc FrameUnboundedPreceding)
> "place"]
> (Tref [] "tbl" NoAlias)]
> ,p "select row_number() over(order by a desc) as place from tbl;"
> [SelectStatement [] $ selectFrom [SelectItem []
> (WindowFn []
> (FunCall [] "row_number" [])
> []
> [Identifier [] "a"] Desc FrameUnboundedPreceding)
> "place"]
> (Tref [] "tbl" NoAlias)]
> ,p "select row_number()\n\
> \over(partition by (a,b) order by c) as place\n\
> \from tbl;"
> [SelectStatement [] $ selectFrom [SelectItem []
> (WindowFn []
> (FunCall [] "row_number" [])
> [FunCall [] "!rowctor" [Identifier [] "a",Identifier [] "b"]]
> [Identifier [] "c"] Asc FrameUnboundedPreceding)
> "place"]
> (Tref [] "tbl" NoAlias)]
> ,p "select * from a natural inner join (select * from b) as a;"
> [SelectStatement [] $ selectFrom
> (selIL ["*"])
> (JoinedTref [] (Tref [] "a" NoAlias) Natural
> Inner (SubTref [] (selectFrom
> (selIL ["*"])
> (Tref [] "b" NoAlias)) (TableAlias "a"))
> Nothing NoAlias)]
> ,p "select * from a order by c;"
> [SelectStatement [] $ Select [] Dupes
> (sl (selIL ["*"]))
> [Tref [] "a" NoAlias]
> Nothing [] Nothing [(Identifier [] "c",Asc)] Nothing Nothing]
> ,p "select *\n\
> \from Adventure\n\
> \order by Clicks desc, AdventureID;"
> [SelectStatement [] $ Select [] Dupes
> (sl (selIL ["*"]))
> [Tref [] "Adventure" NoAlias]
> Nothing [] Nothing [(Identifier [] "Clicks",Desc)
> ,(Identifier [] "AdventureID",Asc)] Nothing Nothing]
> ,p "select * from a order by c,d asc;"
> [SelectStatement [] $ Select [] Dupes
> (sl (selIL ["*"]))
> [Tref [] "a" NoAlias]
> Nothing [] Nothing [(Identifier [] "c", Asc)
> ,(Identifier [] "d", Asc)] Nothing Nothing]
> ,p "select * from a order by c,d desc;"
> [SelectStatement [] $ Select [] Dupes
> (sl (selIL ["*"]))
> [Tref [] "a" NoAlias]
> Nothing [] Nothing [(Identifier [] "c", Asc)
> ,(Identifier [] "d", Desc)] Nothing Nothing]
> ,p "select * from a order by c limit 1;"
> [SelectStatement [] $ Select [] Dupes
> (sl (selIL ["*"]))
> [Tref [] "a" NoAlias]
> Nothing [] Nothing [(Identifier [] "c",Asc)] (Just (IntegerLit [] 1)) Nothing]
> ,p "select * from a order by c offset 3;"
> [SelectStatement [] $ Select [] Dupes
> (sl (selIL ["*"]))
> [Tref [] "a" NoAlias]
> Nothing [] Nothing [(Identifier [] "c",Asc)] Nothing (Just $ IntegerLit [] 3)]
> ,p "select a from (select b from c) as d;"
> [SelectStatement [] $ selectFrom
> (selIL ["a"])
> (SubTref [] (selectFrom
> (selIL ["b"])
> (Tref [] "c" NoAlias))
> (TableAlias "d"))]
> ,p "select * from gen();"
> [SelectStatement [] $ selectFrom (selIL ["*"]) (TrefFun [] (FunCall [] "gen" []) NoAlias)]
> ,p "select * from gen() as t;"
> [SelectStatement [] $ selectFrom
> (selIL ["*"])
> (TrefFun [] (FunCall [] "gen" [])(TableAlias "t"))]
> ,p "select a, count(b) from c group by a;"
> [SelectStatement [] $ Select [] Dupes
> (sl [selI "a", SelExp [] (FunCall [] "count" [Identifier [] "b"])])
> [Tref [] "c" NoAlias] Nothing [Identifier [] "a"]
> Nothing [] Nothing Nothing]
> ,p "select a, count(b) as cnt from c group by a having cnt > 4;"
> [SelectStatement [] $ Select [] Dupes
> (sl [selI "a", SelectItem [] (FunCall [] "count" [Identifier [] "b"]) "cnt"])
> [Tref [] "c" NoAlias] Nothing [Identifier [] "a"]
> (Just $ FunCall [] ">" [Identifier [] "cnt", IntegerLit [] 4])
> [] Nothing Nothing]
> ,p "select a from (select 1 as a, 2 as b) x;"
> [SelectStatement [] $ selectFrom
> [selI "a"]
> (SubTref [] (selectE $ SelectList []
> [SelectItem [] (IntegerLit [] 1) "a"
> ,SelectItem [] (IntegerLit [] 2) "b"] [])
> (TableAlias "x"))]
> ]]
> ,Group "multiple statements" [Statements [
> p "select 1;\nselect 2;" [SelectStatement [] $ selectE $ sl [SelExp [] (IntegerLit [] 1)]
> ,SelectStatement [] $ selectE $ sl [SelExp [] (IntegerLit [] 2)]]
> ]]
> ,Group "comments" [Statements [
> p "" []
> ,p "-- this is a test" []
> ,p "/* this is\n\
> \a test*/" []
> ,p "select 1;\n\
> \-- this is a test\n\
> \select -- this is a test\n\
> \2;" [SelectStatement [] $ selectE $ sl [SelExp [] (IntegerLit [] 1)]
> ,SelectStatement [] $ selectE $ sl [SelExp [] (IntegerLit [] 2)]
> ]
> ,p "select 1;\n\
> \/* this is\n\
> \a test*/\n\
> \select /* this is a test*/2;"
> [SelectStatement [] $ selectE $ sl [SelExp [] (IntegerLit [] 1)]
> ,SelectStatement [] $ selectE $ sl [SelExp [] (IntegerLit [] 2)]
> ]
> ]]
> ]
================================================================================
dml statements
> ,Group "dml" [
> Group "insert" [Statements [
> p "insert into testtable\n\
> \(columna,columnb)\n\
> \values (1,2);\n"
> [Insert []
> "testtable"
> ["columna", "columnb"]
> (Values [] [[IntegerLit [] 1, IntegerLit [] 2]])
> Nothing]
multi row insert, test the stand alone values statement first, maybe
that should be in the select section?
> ,p "values (1,2), (3,4);"
> [SelectStatement [] $ Values [] [[IntegerLit [] 1, IntegerLit [] 2]
> ,[IntegerLit [] 3, IntegerLit [] 4]]]
> ,p "insert into testtable\n\
> \(columna,columnb)\n\
> \values (1,2), (3,4);\n"
> [Insert []
> "testtable"
> ["columna", "columnb"]
> (Values [] [[IntegerLit [] 1, IntegerLit [] 2]
> ,[IntegerLit [] 3, IntegerLit [] 4]])
> Nothing]
insert from select
> ,p "insert into a\n\
> \ select b from c;"
> [Insert [] "a" []
> (selectFrom [selI "b"] (Tref [] "c" NoAlias))
> Nothing]
> ,p "insert into testtable\n\
> \(columna,columnb)\n\
> \values (1,2) returning id;\n"
> [Insert []
> "testtable"
> ["columna", "columnb"]
> (Values [] [[IntegerLit [] 1, IntegerLit [] 2]])
> (Just $ sl [selI "id"])]
> ]]
> ,Group "update" [Statements [
> p "update tb\n\
> \ set x = 1, y = 2;"
> [Update [] "tb" [SetClause [] "x" (IntegerLit [] 1)
> ,SetClause [] "y" (IntegerLit [] 2)]
> Nothing Nothing]
> ,p "update tb\n\
> \ set x = 1, y = 2 where z = true;"
> [Update [] "tb" [SetClause [] "x" (IntegerLit [] 1)
> ,SetClause [] "y" (IntegerLit [] 2)]
> (Just $ FunCall [] "="
> [Identifier [] "z", BooleanLit [] True])
> Nothing]
> ,p "update tb\n\
> \ set x = 1, y = 2 returning id;"
> [Update [] "tb" [SetClause [] "x" (IntegerLit [] 1)
> ,SetClause [] "y" (IntegerLit [] 2)]
> Nothing (Just $ sl [selI "id"])]
> ,p "update pieces\n\
> \set a=b returning tag into r.tag;"
> [Update [] "pieces" [SetClause [] "a" (Identifier [] "b")]
> Nothing (Just (SelectList []
> [SelExp [] (Identifier [] "tag")]
> ["r.tag"]))]
> ,p "update tb\n\
> \ set (x,y) = (1,2);"
> [Update [] "tb" [RowSetClause []
> ["x","y"]
> [IntegerLit [] 1,IntegerLit [] 2]]
> Nothing Nothing]
> ]]
> ,Group "delete" [Statements [
> p "delete from tbl1 where x = true;"
> [Delete [] "tbl1" (Just $ FunCall [] "="
> [Identifier [] "x", BooleanLit [] True])
> Nothing]
> ,p "delete from tbl1 where x = true returning id;"
> [Delete [] "tbl1" (Just $ FunCall [] "="
> [Identifier [] "x", BooleanLit [] True])
> (Just $ sl [selI "id"])]
> ]]
> ,Group "truncate" [Statements [
> p "truncate test;"
> [Truncate [] ["test"] ContinueIdentity Restrict]
> ,p "truncate table test, test2 restart identity cascade;"
> [Truncate [] ["test","test2"] RestartIdentity Cascade]
> ]]
copy, bit crap at the moment
> ,Group "copy" [Statements [
> p "copy tbl(a,b) from stdin;\n\
> \bat\tt\n\
> \bear\tf\n\
> \\\.\n"
> [Copy [] "tbl" ["a", "b"] Stdin
> ,CopyData [] "\
> \bat\tt\n\
> \bear\tf\n"]
> ]]
================================================================================
ddl statements
> ,Group "ddl" [
> Group "simple tables" [Statements [
> p "create table test (\n\
> \ fielda text,\n\
> \ fieldb int\n\
> \);"
> [CreateTable []
> "test"
> [att "fielda" "text"
> ,att "fieldb" "int"
> ]
> []]
> ,p "create table tbl (\n\
> \ fld boolean default false);"
> [CreateTable [] "tbl" [AttributeDef [] "fld" (SimpleTypeName [] "boolean")
> (Just $ BooleanLit [] False) []][]]
> ,p "create table tbl as select 1;"
> [CreateTableAs [] "tbl"
> (selectE (SelectList [] [SelExp [] (IntegerLit [] 1)] []))]
> ,p "alter table a alter column b set default 1;"
> [AlterTable [] "a" [AlterColumnDefault [] "b" (IntegerLit [] 1)]]
> ,p "alter table a add constraint unique(b);"
> [AlterTable [] "a" [AddConstraint [] (UniqueConstraint [] "" ["b"])]]
> ]]
> ,Group "others" [Statements [
> p "create view v1 as\n\
> \select a,b from t;"
> [CreateView []
> "v1"
> (selectFrom [selI "a", selI "b"] (Tref [] "t" NoAlias))]
> ,p "create domain td as text check (value in ('t1', 't2'));"
> [CreateDomain [] "td" (SimpleTypeName [] "text") ""
> (Just (InPredicate [] (Identifier [] "value") True
> (InList [] [stringQ "t1" ,stringQ "t2"])))]
> ,p "create type tp1 as (\n\
> \ f1 text,\n\
> \ f2 text\n\
> \);"
> [CreateType [] "tp1" [TypeAttDef [] "f1" (SimpleTypeName [] "text")
> ,TypeAttDef [] "f2" (SimpleTypeName [] "text")]]
> ,p "create sequence s start with 5 increment by 4 no maxvalue no minvalue cache 1;"
> [CreateSequence [] "s" 4 1 ((2::Integer) ^ (63::Integer) - 1) 5 1]
> ,p "alter sequence s owned by a.b;"
> [AlterSequence [] "s" "a.b"]
> ,p "create trigger tr\n\
> \after insert or delete on tb\n\
> \for each statement\n\
> \execute procedure fb();"
> [CreateTrigger [] "tr" TriggerAfter [TInsert,TDelete] "tb" EachStatement "fb" []]
> ]]
> ,Group "drops" [Statements [
> p "drop domain t;"
> [DropSomething [] Domain Require ["t"] Restrict]
> ,p "drop domain if exists t,u cascade;"
> [DropSomething [] Domain IfExists ["t", "u"] Cascade]
> ,p "drop domain t restrict;"
> [DropSomething [] Domain Require ["t"] Restrict]
> ,p "drop type t;"
> [DropSomething [] Type Require ["t"] Restrict]
> ,p "drop table t;"
> [DropSomething [] Table Require ["t"] Restrict]
> ,p "drop view t;"
> [DropSomething [] View Require ["t"] Restrict]
> ]]
> ,Group "constraints" [
> Group "nulls" [Statements [
> p "create table t1 (\n\
> \ a text null\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "a" (SimpleTypeName [] "text")
> Nothing [NullConstraint [] ""]]
> []]
> ,p "create table t1 (\n\
> \ a text not null\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "a" (SimpleTypeName [] "text")
> Nothing [NotNullConstraint [] ""]]
> []]
> ]]
> ,Group "unique" [Statements [
> p "create table t1 (\n\
> \ x int,\n\
> \ y int,\n\
> \ unique (x,y)\n\
> \);"
> [CreateTable [] "t1" [att "x" "int"
> ,att "y" "int"]
> [UniqueConstraint [] "" ["x","y"]]]
test arbitrary ordering
> ,p "create table t1 (\n\
> \ x int,\n\
> \ unique (x),\n\
> \ y int\n\
> \);"
> [CreateTable [] "t1" [att "x" "int"
> ,att "y" "int"]
> [UniqueConstraint [] "" ["x"]]]
unique row
> ,p "create table t1 (\n\
> \ x int unique\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [RowUniqueConstraint [] ""]][]]
> ,p "create table t1 (\n\
> \ x int unique not null\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [RowUniqueConstraint [] ""
> ,NotNullConstraint [] ""]][]]
quick sanity check
> ,p "create table t1 (\n\
> \ x int not null unique\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [NotNullConstraint [] ""
> ,RowUniqueConstraint [] ""]][]]
> ]]
> ,Group "primary key" [Statements [
> p "create table t1 (\n\
> \ x int primary key\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [RowPrimaryKeyConstraint [] ""]][]]
> ,p "create table t1 (\n\
> \ x int,\n\
> \ y int,\n\
> \ primary key (x,y)\n\
> \);"
> [CreateTable [] "t1" [att "x" "int"
> ,att "y" "int"]
> [PrimaryKeyConstraint [] "" ["x", "y"]]]
> ]]
> ,Group "check" [Statements [
> p "create table t (\n\
> \f text check (f in('a', 'b'))\n\
> \);"
> [CreateTable [] "t"
> [AttributeDef [] "f" (SimpleTypeName [] "text") Nothing
> [RowCheckConstraint [] "" (InPredicate []
> (Identifier [] "f") True
> (InList [] [stringQ "a", stringQ "b"]))]] []]
> ,p "create table t1 (\n\
> \ x int,\n\
> \ y int,\n\
> \ check (x>y)\n\
> \);"
> [CreateTable [] "t1" [att "x" "int"
> ,att "y" "int"]
> [CheckConstraint [] "" (FunCall [] ">" [Identifier [] "x", Identifier [] "y"])]]
> ]]
> ,Group "misc" [Statements [
> p "create table t (\n\
> \f text not null unique check (f in('a', 'b'))\n\
> \);"
> [CreateTable [] "t"
> [AttributeDef [] "f" (SimpleTypeName [] "text") Nothing
> [NotNullConstraint [] ""
> ,RowUniqueConstraint [] ""
> ,RowCheckConstraint [] "" (InPredicate []
> (Identifier [] "f") True
> (InList [] [stringQ "a"
> ,stringQ "b"]))]] []]
> ]]
> ,Group "references" [Statements [
> p "create table t1 (\n\
> \ x int references t2\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [RowReferenceConstraint [] "" "t2" Nothing
> Restrict Restrict]][]]
> ,p "create table t1 (\n\
> \ x int references t2(y)\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [RowReferenceConstraint [] "" "t2" (Just "y")
> Restrict Restrict]][]]
> ,p "create table t1 (\n\
> \ x int,\n\
> \ y int,\n\
> \ foreign key (x,y) references t2\n\
> \);"
> [CreateTable [] "t1" [att "x" "int"
> ,att "y" "int"]
> [ReferenceConstraint [] "" ["x", "y"] "t2" []
> Restrict Restrict]]
> ,p "create table t1 (\n\
> \ x int,\n\
> \ y int,\n\
> \ foreign key (x,y) references t2(z,w)\n\
> \);"
> [CreateTable [] "t1" [att "x" "int"
> ,att "y" "int"]
> [ReferenceConstraint [] "" ["x", "y"] "t2" ["z", "w"]
> Restrict Restrict]]
> ,p "create table t1 (\n\
> \ x int references t2 on delete cascade\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [RowReferenceConstraint [] "" "t2" Nothing
> Cascade Restrict]][]]
> ,p "create table t1 (\n\
> \ x int references t2 on update cascade\n\
> \);"
> [CreateTable [] "t1" [AttributeDef [] "x" (SimpleTypeName [] "int") Nothing
> [RowReferenceConstraint [] "" "t2" Nothing
> Restrict Cascade]][]]
> ,p "create table t1 (\n\
> \ x int,\n\
> \ y int,\n\
> \ foreign key (x,y) references t2 on update cascade on delete cascade\n\
> \);"
> [CreateTable [] "t1" [att "x" "int"
> ,att "y" "int"]
> [ReferenceConstraint [] "" ["x", "y"] "t2" []
> Cascade Cascade]]
> ]]
> ]]
> ,Group "functions" [
> Group "basics" [Statements [
> p "create function t1(text) returns text as $$\n\
> \select a from t1 where b = $1;\n\
> \$$ language sql stable;"
> [CreateFunction [] "t1" [ParamDefTp [] $ SimpleTypeName [] "text"]
> (SimpleTypeName [] "text") Sql "$$"
> (SqlFnBody []
> [SelectStatement [] $ selectFromWhere [SelExp [] (Identifier [] "a")] (Tref [] "t1" NoAlias)
> (FunCall [] "="
> [Identifier [] "b", PositionalArg [] 1])])
> Stable]
> ,p "create function fn() returns void as $$\n\
> \declare\n\
> \ a int;\n\
> \ b text;\n\
> \begin\n\
> \ null;\n\
> \end;\n\
> \$$ language plpgsql volatile;"
> [CreateFunction [] "fn" [] (SimpleTypeName [] "void") Plpgsql "$$"
> (PlpgsqlFnBody [] [VarDef [] "a" (SimpleTypeName [] "int") Nothing
> ,VarDef [] "b" (SimpleTypeName [] "text") Nothing]
> [NullStatement []])
> Volatile]
> ,p "create function fn() returns void as $$\n\
> \declare\n\
> \ a int;\n\
> \ b text;\n\
> \begin\n\
> \ null;\n\
> \end;\n\
> \$$ language plpgsql volatile;"
> [CreateFunction [] "fn" [] (SimpleTypeName [] "void") Plpgsql "$$"
> (PlpgsqlFnBody [] [VarDef [] "a" (SimpleTypeName [] "int") Nothing
> ,VarDef [] "b" (SimpleTypeName [] "text") Nothing]
> [NullStatement []])
> Volatile]
> ,p "create function fn(a text[]) returns int[] as $$\n\
> \declare\n\
> \ b xtype[] := '{}';\n\
> \begin\n\
> \ null;\n\
> \end;\n\
> \$$ language plpgsql immutable;"
> [CreateFunction [] "fn"
> [ParamDef [] "a" $ ArrayTypeName [] $ SimpleTypeName [] "text"]
> (ArrayTypeName [] $ SimpleTypeName [] "int") Plpgsql "$$"
> (PlpgsqlFnBody []
> [VarDef [] "b" (ArrayTypeName [] $ SimpleTypeName [] "xtype") (Just $ stringQ "{}")]
> [NullStatement []])
> Immutable]
> ,p "create function fn() returns void as '\n\
> \declare\n\
> \ a int := 3;\n\
> \begin\n\
> \ null;\n\
> \end;\n\
> \' language plpgsql stable;"
> [CreateFunction [] "fn" [] (SimpleTypeName [] "void") Plpgsql "'"
> (PlpgsqlFnBody [] [VarDef [] "a" (SimpleTypeName [] "int") (Just $ IntegerLit [] 3)]
> [NullStatement []])
> Stable]
> ,p "create function fn() returns setof int as $$\n\
> \begin\n\
> \ null;\n\
> \end;\n\
> \$$ language plpgsql stable;"
> [CreateFunction [] "fn" []
> (SetOfTypeName [] $ SimpleTypeName [] "int") Plpgsql "$$"
> (PlpgsqlFnBody [] [] [NullStatement []])
> Stable]
> ,p "create function fn() returns void as $$\n\
> \begin\n\
> \ null;\n\
> \end\n\
> \$$ language plpgsql stable;"
> [CreateFunction [] "fn" []
> (SimpleTypeName [] "void") Plpgsql "$$"
> (PlpgsqlFnBody [] [] [NullStatement []])
> Stable]
> ,p "drop function test(text);"
> [DropFunction [] Require [("test",[SimpleTypeName [] "text"])] Restrict]
> ,p "drop function if exists a(),test(text) cascade;"
> [DropFunction [] IfExists [("a",[])
> ,("test",[SimpleTypeName [] "text"])] Cascade]
> ]]
> ,Group "simple plpgsql statements" [PlpgsqlStatements [
> p "success := true;"
> [Assignment [] "success" (BooleanLit [] True)]
> ,p "success = true;"
> [Assignment [] "success" (BooleanLit [] True)]
> ,p "return true;"
> [Return [] $ Just (BooleanLit [] True)]
> ,p "return;"
> [Return [] Nothing]
> ,p "return next 1;"
> [ReturnNext [] $ IntegerLit [] 1]
> ,p "return query select a from b;"
> [ReturnQuery [] $ selectFrom [selI "a"] (Tref [] "b" NoAlias)]
> ,p "raise notice 'stuff %', 1;"
> [Raise [] RNotice "stuff %" [IntegerLit [] 1]]
> ,p "perform test();"
> [Perform [] $ FunCall [] "test" []]
> ,p "perform test(a,b);"
> [Perform [] $ FunCall [] "test" [Identifier [] "a", Identifier [] "b"]]
> ,p "perform test(r.relvar_name || '_and_stuff');"
> [Perform [] $ FunCall [] "test" [
> FunCall [] "||" [Identifier [] "r.relvar_name"
> ,stringQ "_and_stuff"]]]
> ,p "select into a,b c,d from e;"
> [SelectStatement [] $ Select [] Dupes (SelectList [] [selI "c", selI "d"] ["a", "b"])
> [Tref [] "e" NoAlias] Nothing [] Nothing [] Nothing Nothing]
> ,p "select c,d into a,b from e;"
> [SelectStatement [] $ Select [] Dupes (SelectList [] [selI "c", selI "d"] ["a", "b"])
> [Tref [] "e" NoAlias] Nothing [] Nothing [] Nothing Nothing]
> ,p "execute s;"
> [Execute [] (Identifier [] "s")]
> ,p "execute s into r;"
> [ExecuteInto [] (Identifier [] "s") ["r"]]
> ,p "continue;" [ContinueStatement []]
> ]]
> ,Group "other plpgsql statements" [PlpgsqlStatements [
> p "for r in select a from tbl loop\n\
> \null;\n\
> \end loop;"
> [ForSelectStatement [] "r" (selectFrom [selI "a"] (Tref [] "tbl" NoAlias))
> [NullStatement []]]
> ,p "for r in select a from tbl where true loop\n\
> \null;\n\
> \end loop;"
> [ForSelectStatement [] "r"
> (selectFromWhere [selI "a"] (Tref [] "tbl" NoAlias) (BooleanLit [] True))
> [NullStatement []]]
> ,p "for r in 1 .. 10 loop\n\
> \null;\n\
> \end loop;"
> [ForIntegerStatement [] "r"
> (IntegerLit [] 1) (IntegerLit [] 10)
> [NullStatement []]]
> ,p "if a=b then\n\
> \ update c set d = e;\n\
> \end if;"
> [If [] [((FunCall [] "=" [Identifier [] "a", Identifier [] "b"])
> ,[Update [] "c" [SetClause [] "d" (Identifier [] "e")] Nothing Nothing])]
> []]
> ,p "if true then\n\
> \ null;\n\
> \else\n\
> \ null;\n\
> \end if;"
> [If [] [((BooleanLit [] True),[NullStatement []])]
> [NullStatement []]]
> ,p "if true then\n\
> \ null;\n\
> \elseif false then\n\
> \ return;\n\
> \end if;"
> [If [] [((BooleanLit [] True), [NullStatement []])
> ,((BooleanLit [] False), [Return [] Nothing])]
> []]
> ,p "if true then\n\
> \ null;\n\
> \elseif false then\n\
> \ return;\n\
> \elseif false then\n\
> \ return;\n\
> \else\n\
> \ return;\n\
> \end if;"
> [If [] [((BooleanLit [] True), [NullStatement []])
> ,((BooleanLit [] False), [Return [] Nothing])
> ,((BooleanLit [] False), [Return [] Nothing])]
> [Return [] Nothing]]
> ,p "case a\n\
> \ when b then null;\n\
> \ when c,d then null;\n\
> \ else null;\n\
> \end case;"
> [CaseStatement [] (Identifier [] "a")
> [([Identifier [] "b"], [NullStatement []])
> ,([Identifier [] "c", Identifier [] "d"], [NullStatement []])]
> [NullStatement []]]
> ]]
> ,Group "misc" [Statements [
> p "SET search_path TO my_schema, public;"
> [Set [] "search_path" [SetId [] "my_schema"
> ,SetId [] "public"]]
> ,p "SET t1 = 3;"
> [Set [] "t1" [SetNum [] 3]]
> ,p "SET t1 = 'stuff';"
> [Set [] "t1" [SetStr [] "stuff"]]
> ,p "create language plpgsql;"
> [CreateLanguage [] "plpgsql"]
> ]]
> ]]]
================================================================================
shortcuts for constructing test data and asts
> p :: t -> t1 -> (t, t1)
> p a b = (a,b)
> stringQ :: String -> Expression
> stringQ = StringLit [] "'"
> selectFrom :: SelectItemList
> -> TableRef
> -> SelectExpression
> selectFrom selList frm = Select [] Dupes (SelectList [] selList [])
> [frm] Nothing [] Nothing [] Nothing Nothing
> selectE :: SelectList -> SelectExpression
> selectE selList = Select [] Dupes selList
> [] Nothing [] Nothing [] Nothing Nothing
> selIL :: [String] -> [SelectItem]
> selIL = map selI
> selI :: String -> SelectItem
> selI = SelExp [] . Identifier []
> sl :: SelectItemList -> SelectList
> sl a = SelectList [] a []
> selectFromWhere :: SelectItemList
> -> TableRef
> -> Expression
> -> SelectExpression
> selectFromWhere selList frm whr =
> Select [] Dupes (SelectList [] selList [])
> [frm] (Just whr) [] Nothing [] Nothing Nothing
> att :: String -> String -> AttributeDef
> att n t = AttributeDef [] n (SimpleTypeName [] t) Nothing []
================================================================================
Unit test helpers
> itemToTft :: Item -> [Test.Framework.Test]
> itemToTft (Expressions es) = map (uncurry testParseExpression) es
> itemToTft (PlpgsqlStatements es) = map (uncurry testParsePlpgsqlStatements) es
> itemToTft (Statements es) = map (uncurry testParseStatements) es
> itemToTft (Group s is) = [testGroup s $ concatMap itemToTft is]
> testParseExpression :: String -> Expression -> Test.Framework.Test
> testParseExpression src ast = parseUtil src ast
> (parseExpression "") printExpression
> testParseStatements :: String -> [Statement] -> Test.Framework.Test
> testParseStatements src ast = parseUtil src ast (parseSql "") printSql
> testParsePlpgsqlStatements :: String -> [Statement] -> Test.Framework.Test
> testParsePlpgsqlStatements src ast = parseUtil src ast (parsePlpgsql "") printSql
> parseUtil :: (Show t, Eq b, Show b, Data b) =>
> String
> -> b
> -> (String -> Either t b)
> -> (b -> String)
> -> Test.Framework.Test
> parseUtil src ast parser printer = testCase ("parse " ++ src) $
> case parser src of
> Left er -> assertFailure $ show er
> Right ast' -> do
> assertEqual ("parse " ++ src) ast $ stripAnnotations ast'
> case parser (printer ast) of
> Left er -> assertFailure $ "reparse\n" ++ show er ++ "\n" -- ++ pp ++ "\n"
> Right ast'' -> assertEqual ("reparse " ++ printer ast) ast $ stripAnnotations ast''
TODO
new idea for testing:
parsesql -> ast1
parse, pretty print, parse -> ast2
load into pg, pg_dump, parse -> ast3
parse, pretty print, load into pg, pg_dump, parse -> ast4
check all these asts are the same