d005dc1706
add parse function for parsing multiple query expressions separated by semicolon add parser for substring operator tweak the layout for pretty printing binary operators add sql file with tpch queries in it add simple exe to parse and pretty print multiple query expressions
477 lines
17 KiB
Plaintext
477 lines
17 KiB
Plaintext
|
|
> module Tests (testData, runTests) where
|
|
|
|
> import Language.SQL.SimpleSQL.Syntax
|
|
> import Language.SQL.SimpleSQL.Pretty
|
|
> import Language.SQL.SimpleSQL.Parser
|
|
> import qualified Test.HUnit as H
|
|
> import Control.Monad
|
|
> import Tpch
|
|
|
|
> data TestItem = Group String [TestItem]
|
|
> | TestScalarExpr String ScalarExpr
|
|
> | TestQueryExpr String QueryExpr
|
|
> | ParseQueryExpr String
|
|
> deriving (Eq,Show)
|
|
|
|
> scalarExprParserTests :: TestItem
|
|
> scalarExprParserTests = Group "scalarExprParserTests"
|
|
> [literals
|
|
> ,identifiers
|
|
> ,star
|
|
> ,app
|
|
> ,caseexp
|
|
> ,operators
|
|
> ,parens
|
|
> ,subqueries
|
|
> ,aggregates
|
|
> ,windowFunctions
|
|
> ]
|
|
|
|
> literals :: TestItem
|
|
> literals = Group "literals" $ map (uncurry TestScalarExpr)
|
|
> [("3", NumLit "3")
|
|
> ,("3.", NumLit "3.")
|
|
> ,("3.3", NumLit "3.3")
|
|
> ,(".3", NumLit ".3")
|
|
> ,("3.e3", NumLit "3.e3")
|
|
> ,("3.3e3", NumLit "3.3e3")
|
|
> ,(".3e3", NumLit ".3e3")
|
|
> ,("3e3", NumLit "3e3")
|
|
> ,("3e+3", NumLit "3e+3")
|
|
> ,("3e-3", NumLit "3e-3")
|
|
> ,("'string'", StringLit "string")
|
|
> ,("'1'", StringLit "1")
|
|
> ,("interval '3' day", IntervalLit "3" "day" Nothing)
|
|
> ,("interval '3' day (3)", IntervalLit "3" "day" $ Just 3)
|
|
> ]
|
|
|
|
> identifiers :: TestItem
|
|
> identifiers = Group "identifiers" $ map (uncurry TestScalarExpr)
|
|
> [("iden1", Iden "iden1")
|
|
> ,("t.a", Iden2 "t" "a")
|
|
> ]
|
|
|
|
> star :: TestItem
|
|
> star = Group "star" $ map (uncurry TestScalarExpr)
|
|
> [("*", Star)
|
|
> ,("t.*", Star2 "t")
|
|
> ]
|
|
|
|
> app :: TestItem
|
|
> app = Group "app" $ map (uncurry TestScalarExpr)
|
|
> [("f()", App "f" [])
|
|
> ,("f(a)", App "f" [Iden "a"])
|
|
> ,("f(a,b)", App "f" [Iden "a", Iden "b"])
|
|
> ]
|
|
|
|
> caseexp :: TestItem
|
|
> caseexp = Group "caseexp" $ map (uncurry TestScalarExpr)
|
|
> [("case a when 1 then 2 end"
|
|
> ,Case (Just $ Iden "a") [(NumLit "1"
|
|
> ,NumLit "2")] Nothing)
|
|
> ,("case a when 1 then 2 when 3 then 4 end"
|
|
> ,Case (Just $ Iden "a") [(NumLit "1", NumLit "2")
|
|
> ,(NumLit "3", NumLit "4")] Nothing)
|
|
> ,("case a when 1 then 2 when 3 then 4 else 5 end"
|
|
> ,Case (Just $ Iden "a") [(NumLit "1", NumLit "2")
|
|
> ,(NumLit "3", NumLit "4")] (Just $ NumLit "5"))
|
|
> ,("case when a=1 then 2 when a=3 then 4 else 5 end"
|
|
> ,Case Nothing [(BinOp "=" (Iden "a") (NumLit "1"), NumLit "2")
|
|
> ,(BinOp "=" (Iden "a") (NumLit "3"), NumLit "4")]
|
|
> (Just $ NumLit "5"))
|
|
> ]
|
|
|
|
> operators :: TestItem
|
|
> operators = Group "operators"
|
|
> [binaryOperators
|
|
> ,unaryOperators
|
|
> ,casts
|
|
> ,miscOps]
|
|
|
|
> binaryOperators :: TestItem
|
|
> binaryOperators = Group "binaryOperators" $ map (uncurry TestScalarExpr)
|
|
> [("a + b", BinOp "+" (Iden "a") (Iden "b"))
|
|
> -- sanity check fixities
|
|
> -- todo: add more fixity checking
|
|
> {-,("a + b * c"
|
|
> ,Op "+" [Iden "a"
|
|
> ,Op "*" [Iden "b"
|
|
> ,Iden "c"]])
|
|
> ,("a * b + c"
|
|
> ,Op "+" [Op "*" [Iden "a", Iden "b"]
|
|
> ,Iden "c"])-}
|
|
> ]
|
|
|
|
> unaryOperators :: TestItem
|
|
> unaryOperators = Group "unaryOperators" $ map (uncurry TestScalarExpr)
|
|
> [("not a", PrefixOp "not" $ Iden "a")
|
|
> ,("not not a", PrefixOp "not" $ PrefixOp "not" $ Iden "a")
|
|
> ,("+a", PrefixOp "+" $ Iden "a")
|
|
> ,("-a", PrefixOp "-" $ Iden "a")
|
|
> ]
|
|
|
|
|
|
> casts :: TestItem
|
|
> casts = Group "operators" $ map (uncurry TestScalarExpr)
|
|
> [("cast('1' as int)"
|
|
> ,Cast (StringLit "1") $ TypeName "int")
|
|
> ,("int '3'"
|
|
> ,CastOp (TypeName "int") "3")
|
|
> ,("cast('1' as double precision)"
|
|
> ,Cast (StringLit "1") $ TypeName "double precision")
|
|
> ,("double precision '3'"
|
|
> ,CastOp (TypeName "double precision") "3")
|
|
> ]
|
|
|
|
> subqueries :: TestItem
|
|
> subqueries = Group "unaryOperators" $ map (uncurry TestScalarExpr)
|
|
> [("exists (select a from t)", SubQueryExpr SqExists ms)
|
|
> ,("(select a from t)", SubQueryExpr SqSq ms)
|
|
> ,("a in (select a from t)"
|
|
> ,In True (Iden "a") (InQueryExpr ms))
|
|
> ,("a not in (select a from t)"
|
|
> ,In False (Iden "a") (InQueryExpr ms))
|
|
> ,("a > all (select a from t)"
|
|
> ,BinOp ">" (Iden "a") (SubQueryExpr SqAll ms))
|
|
> ,("a = some (select a from t)"
|
|
> ,BinOp "=" (Iden "a") (SubQueryExpr SqSome ms))
|
|
> ,("a <= any (select a from t)"
|
|
> ,BinOp "<=" (Iden "a") (SubQueryExpr SqAny ms))
|
|
> ]
|
|
> where
|
|
> ms = makeSelect
|
|
> {qeSelectList = [(Nothing,Iden "a")]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> }
|
|
|
|
> miscOps :: TestItem
|
|
> miscOps = Group "unaryOperators" $ map (uncurry TestScalarExpr)
|
|
> [("a in (1,2,3)"
|
|
> ,In True (Iden "a") $ InList $ map NumLit ["1","2","3"])
|
|
> ,("a between b and c", SpecialOp "between" [Iden "a"
|
|
> ,Iden "b"
|
|
> ,Iden "c"])
|
|
> ,("a not between b and c", SpecialOp "not between" [Iden "a"
|
|
> ,Iden "b"
|
|
> ,Iden "c"])
|
|
> ,("a is null", PostfixOp "is null" (Iden "a"))
|
|
> ,("a is not null", PostfixOp "is not null" (Iden "a"))
|
|
> ,("a is true", PostfixOp "is true" (Iden "a"))
|
|
> ,("a is not true", PostfixOp "is not true" (Iden "a"))
|
|
> ,("a is false", PostfixOp "is false" (Iden "a"))
|
|
> ,("a is not false", PostfixOp "is not false" (Iden "a"))
|
|
> ,("a is unknown", PostfixOp "is unknown" (Iden "a"))
|
|
> ,("a is not unknown", PostfixOp "is not unknown" (Iden "a"))
|
|
> ,("a is distinct from b", BinOp "is distinct from" (Iden "a") (Iden "b"))
|
|
> ,("a is not distinct from b", BinOp "is not distinct from" (Iden "a") (Iden "b"))
|
|
> ,("a like b", BinOp "like" (Iden "a") (Iden "b"))
|
|
> ,("a not like b", BinOp "not like" (Iden "a") (Iden "b"))
|
|
> ,("a is similar to b", BinOp "is similar to" (Iden "a") (Iden "b"))
|
|
> ,("a is not similar to b", BinOp "is not similar to" (Iden "a") (Iden "b"))
|
|
> ,("a overlaps b", BinOp "overlaps" (Iden "a") (Iden "b"))
|
|
> ,("extract(day from t)", SpecialOp "extract" [Iden "day", Iden "t"])
|
|
> ,("substring(x from 1 for 2)"
|
|
> ,SpecialOp "substring" [Iden "x", NumLit "1", NumLit "2"])
|
|
> ]
|
|
|
|
> aggregates :: TestItem
|
|
> aggregates = Group "aggregates" $ map (uncurry TestScalarExpr)
|
|
> [("count(*)",App "count" [Star])
|
|
> ,("sum(a order by a)"
|
|
> ,AggregateApp "sum" Nothing [Iden "a"] [(Iden "a", Asc)])
|
|
> ,("sum(all a)"
|
|
> ,AggregateApp "sum" (Just All) [Iden "a"] [])
|
|
> ,("count(distinct a)"
|
|
> ,AggregateApp "count" (Just Distinct) [Iden "a"] [])
|
|
> ]
|
|
|
|
> windowFunctions :: TestItem
|
|
> windowFunctions = Group "windowFunctions" $ map (uncurry TestScalarExpr)
|
|
> [("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
|
|
> parens = Group "parens" $ map (uncurry TestScalarExpr)
|
|
> [("(a)", Parens (Iden "a"))
|
|
> ,("(a + b)", Parens (BinOp "+" (Iden "a") (Iden "b")))
|
|
> ]
|
|
|
|
> queryExprParserTests :: TestItem
|
|
> queryExprParserTests = Group "queryExprParserTests"
|
|
> [duplicates
|
|
> ,selectLists
|
|
> ,from
|
|
> ,whereClause
|
|
> ,groupByClause
|
|
> ,having
|
|
> ,orderBy
|
|
> ,limit
|
|
> ,combos
|
|
> ,fullQueries
|
|
> ]
|
|
|
|
|
|
|
|
> duplicates :: TestItem
|
|
> duplicates = Group "duplicates" $ map (uncurry TestQueryExpr)
|
|
> [("select a from t" ,ms All)
|
|
> ,("select all a from t" ,ms All)
|
|
> ,("select distinct a from t", ms Distinct)
|
|
> ]
|
|
> where
|
|
> ms d = makeSelect
|
|
> {qeDuplicates = d
|
|
> ,qeSelectList = [(Nothing,Iden "a")]
|
|
> ,qeFrom = [SimpleTableRef "t"]}
|
|
|
|
> selectLists :: TestItem
|
|
> selectLists = Group "selectLists" $ map (uncurry TestQueryExpr)
|
|
> [("select 1",
|
|
> makeSelect {qeSelectList = [(Nothing,NumLit "1")]})
|
|
> ,("select a"
|
|
> ,makeSelect {qeSelectList = [(Nothing,Iden "a")]})
|
|
> ,("select a,b"
|
|
> ,makeSelect {qeSelectList = [(Nothing,Iden "a")
|
|
> ,(Nothing,Iden "b")]})
|
|
> ,("select 1+2,3+4"
|
|
> ,makeSelect {qeSelectList =
|
|
> [(Nothing,BinOp "+" (NumLit "1") (NumLit "2"))
|
|
> ,(Nothing,BinOp "+" (NumLit "3") (NumLit "4"))]})
|
|
> ,("select a as a, /*comment*/ b as b"
|
|
> ,makeSelect {qeSelectList = [(Just "a", Iden "a")
|
|
> ,(Just "b", Iden "b")]})
|
|
> ,("select a a, b b"
|
|
> ,makeSelect {qeSelectList = [(Just "a", Iden "a")
|
|
> ,(Just "b", Iden "b")]})
|
|
> ]
|
|
|
|
> from :: TestItem
|
|
> from = Group "from" $ map (uncurry TestQueryExpr)
|
|
> [("select a from t"
|
|
> ,ms [SimpleTableRef "t"])
|
|
> ,("select a from t,u"
|
|
> ,ms [SimpleTableRef "t", SimpleTableRef "u"])
|
|
> ,("select a from t inner join u on expr"
|
|
> ,ms [JoinTableRef Inner (SimpleTableRef "t") (SimpleTableRef "u")
|
|
> (Just $ JoinOn $ Iden "expr")])
|
|
> ,("select a from t left join u on expr"
|
|
> ,ms [JoinTableRef JLeft (SimpleTableRef "t") (SimpleTableRef "u")
|
|
> (Just $ JoinOn $ Iden "expr")])
|
|
> ,("select a from t right join u on expr"
|
|
> ,ms [JoinTableRef JRight (SimpleTableRef "t") (SimpleTableRef "u")
|
|
> (Just $ JoinOn $ Iden "expr")])
|
|
> ,("select a from t full join u on expr"
|
|
> ,ms [JoinTableRef Full (SimpleTableRef "t") (SimpleTableRef "u")
|
|
> (Just $ JoinOn $ Iden "expr")])
|
|
> ,("select a from t cross join u"
|
|
> ,ms [JoinTableRef Cross (SimpleTableRef "t")
|
|
> (SimpleTableRef "u") Nothing])
|
|
> ,("select a from t natural inner join u"
|
|
> ,ms [JoinTableRef Inner (SimpleTableRef "t") (SimpleTableRef "u")
|
|
> (Just JoinNatural)])
|
|
> ,("select a from t inner join u using(a,b)"
|
|
> ,ms [JoinTableRef Inner (SimpleTableRef "t") (SimpleTableRef "u")
|
|
> (Just $ JoinUsing ["a", "b"])])
|
|
> ,("select a from (select a from t)"
|
|
> ,ms [JoinQueryExpr $ ms [SimpleTableRef "t"]])
|
|
> ,("select a from t as u"
|
|
> ,ms [JoinAlias (SimpleTableRef "t") "u"])
|
|
> ,("select a from t u"
|
|
> ,ms [JoinAlias (SimpleTableRef "t") "u"])
|
|
> ,("select a from (t cross join u) as u"
|
|
> ,ms [JoinAlias (JoinParens $ JoinTableRef Cross (SimpleTableRef "t")
|
|
> (SimpleTableRef "u") Nothing) "u"])
|
|
> ]
|
|
> where
|
|
> ms f = makeSelect {qeSelectList = [(Nothing,Iden "a")]
|
|
> ,qeFrom = f}
|
|
|
|
> whereClause :: TestItem
|
|
> whereClause = Group "whereClause" $ map (uncurry TestQueryExpr)
|
|
> [("select a from t where a = 5"
|
|
> ,makeSelect {qeSelectList = [(Nothing,Iden "a")]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> ,qeWhere = Just $ BinOp "=" (Iden "a") (NumLit "5")})
|
|
> ]
|
|
|
|
> groupByClause :: TestItem
|
|
> groupByClause = Group "groupByClause" $ map (uncurry TestQueryExpr)
|
|
> [("select a,sum(b) from t group by a"
|
|
> ,makeSelect {qeSelectList = [(Nothing, Iden "a")
|
|
> ,(Nothing, App "sum" [Iden "b"])]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> ,qeGroupBy = [Iden "a"]
|
|
> })
|
|
> ,("select a,b,sum(c) from t group by a,b"
|
|
> ,makeSelect {qeSelectList = [(Nothing, Iden "a")
|
|
> ,(Nothing, Iden "b")
|
|
> ,(Nothing, App "sum" [Iden "c"])]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> ,qeGroupBy = [Iden "a",Iden "b"]
|
|
> })
|
|
> ]
|
|
|
|
> having :: TestItem
|
|
> having = Group "having" $ map (uncurry TestQueryExpr)
|
|
> [("select a,sum(b) from t group by a having sum(b) > 5"
|
|
> ,makeSelect {qeSelectList = [(Nothing, Iden "a")
|
|
> ,(Nothing, App "sum" [Iden "b"])]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> ,qeGroupBy = [Iden "a"]
|
|
> ,qeHaving = Just $ BinOp ">" (App "sum" [Iden "b"]) (NumLit "5")
|
|
> })
|
|
> ]
|
|
|
|
> orderBy :: TestItem
|
|
> orderBy = Group "orderBy" $ map (uncurry TestQueryExpr)
|
|
> [("select a from t order by a"
|
|
> ,ms [(Iden "a", Asc)])
|
|
> ,("select a from t order by a, b"
|
|
> ,ms [(Iden "a", Asc), (Iden "b", Asc)])
|
|
> ,("select a from t order by a asc"
|
|
> ,ms [(Iden "a", Asc)])
|
|
> ,("select a from t order by a desc, b desc"
|
|
> ,ms [(Iden "a", Desc), (Iden "b", Desc)])
|
|
> ]
|
|
> where
|
|
> ms o = makeSelect {qeSelectList = [(Nothing,Iden "a")]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> ,qeOrderBy = o}
|
|
|
|
> limit :: TestItem
|
|
> limit = Group "limit" $ map (uncurry TestQueryExpr)
|
|
> [("select a from t limit 10"
|
|
> ,ms (Just $ NumLit "10") Nothing)
|
|
> ,("select a from t limit 10 offset 10"
|
|
> ,ms (Just $ NumLit "10") (Just $ NumLit "10"))
|
|
> ]
|
|
> where
|
|
> ms l o = makeSelect
|
|
> {qeSelectList = [(Nothing,Iden "a")]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> ,qeLimit = l
|
|
> ,qeOffset = o}
|
|
|
|
> combos :: TestItem
|
|
> combos = Group "combos" $ map (uncurry TestQueryExpr)
|
|
> [("select a from t union select b from u"
|
|
> ,CombineQueryExpr ms1 Union All Respectively ms2)
|
|
> ,("select a from t intersect select b from u"
|
|
> ,CombineQueryExpr ms1 Intersect All Respectively ms2)
|
|
> ,("select a from t except all select b from u"
|
|
> ,CombineQueryExpr ms1 Except All Respectively ms2)
|
|
> ,("select a from t union distinct corresponding \
|
|
> \select b from u"
|
|
> ,CombineQueryExpr ms1 Union Distinct Corresponding ms2)
|
|
> ]
|
|
> where
|
|
> ms1 = makeSelect
|
|
> {qeSelectList = [(Nothing,Iden "a")]
|
|
> ,qeFrom = [SimpleTableRef "t"]}
|
|
> ms2 = makeSelect
|
|
> {qeSelectList = [(Nothing,Iden "b")]
|
|
> ,qeFrom = [SimpleTableRef "u"]}
|
|
|
|
> fullQueries :: TestItem
|
|
> fullQueries = Group "queries" $ map (uncurry TestQueryExpr)
|
|
> [("select count(*) from t"
|
|
> ,makeSelect
|
|
> {qeSelectList = [(Nothing, App "count" [Star])]
|
|
> ,qeFrom = [SimpleTableRef "t"]
|
|
> }
|
|
> )
|
|
> ,("select a, sum(c+d) as s\n\
|
|
> \ from t,u\n\
|
|
> \ where a > 5\n\
|
|
> \ group by a\n\
|
|
> \ having count(1) > 5\n\
|
|
> \ order by s"
|
|
> ,makeSelect
|
|
> {qeSelectList = [(Nothing, Iden "a")
|
|
> ,(Just "s", App "sum" [BinOp "+" (Iden "c")
|
|
> (Iden "d")])]
|
|
> ,qeFrom = [SimpleTableRef "t", SimpleTableRef "u"]
|
|
> ,qeWhere = Just $ BinOp ">" (Iden "a") (NumLit "5")
|
|
> ,qeGroupBy = [Iden "a"]
|
|
> ,qeHaving = Just $ BinOp ">" (App "count" [NumLit "1"])
|
|
> (NumLit "5")
|
|
> ,qeOrderBy = [(Iden "s", Asc)]
|
|
> }
|
|
> )
|
|
> ]
|
|
|
|
> tpchTests :: TestItem
|
|
> tpchTests =
|
|
> Group "parse tpch"
|
|
> $ map (ParseQueryExpr . snd) tpchQueries
|
|
|
|
> testData :: TestItem
|
|
> testData =
|
|
> Group "parserTest"
|
|
> [scalarExprParserTests
|
|
> ,queryExprParserTests
|
|
> ,tpchTests
|
|
> ]
|
|
|
|
|
|
> runTests :: IO ()
|
|
> runTests = void $ H.runTestTT $ itemToTest testData
|
|
|
|
> itemToTest :: TestItem -> H.Test
|
|
> itemToTest (Group nm ts) =
|
|
> H.TestLabel nm $ H.TestList $ map itemToTest ts
|
|
> itemToTest (TestScalarExpr str expected) =
|
|
> toTest parseScalarExpr prettyScalarExpr str expected
|
|
> itemToTest (TestQueryExpr str expected) =
|
|
> toTest parseQueryExpr prettyQueryExpr str expected
|
|
> itemToTest (ParseQueryExpr str) =
|
|
> toPTest parseQueryExpr prettyQueryExpr str
|
|
|
|
> toTest :: (Eq a, Show a) =>
|
|
> (String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
|
> -> (a -> String)
|
|
> -> String
|
|
> -> a
|
|
> -> H.Test
|
|
> toTest parser pp str expected = H.TestLabel str $ H.TestCase $ do
|
|
> let egot = parser "" Nothing str
|
|
> case egot of
|
|
> Left e -> H.assertFailure $ peFormattedError e
|
|
> Right got -> do
|
|
> H.assertEqual "" expected got
|
|
> let str' = pp got
|
|
> let egot' = parser "" Nothing str'
|
|
> case egot' of
|
|
> Left e' -> H.assertFailure $ "pp roundtrip " ++ peFormattedError e'
|
|
> Right got' -> H.assertEqual "pp roundtrip" expected got'
|
|
|
|
> toPTest :: (Eq a, Show a) =>
|
|
> (String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
|
> -> (a -> String)
|
|
> -> String
|
|
> -> H.Test
|
|
> toPTest parser pp str = H.TestLabel str $ H.TestCase $ do
|
|
> let egot = parser "" Nothing str
|
|
> case egot of
|
|
> Left e -> H.assertFailure $ peFormattedError e
|
|
> Right got -> do
|
|
> let str' = pp got
|
|
> let egot' = parser "" Nothing str'
|
|
> case egot' of
|
|
> Left e' -> H.assertFailure $ "pp roundtrip " ++ peFormattedError e'
|
|
> Right _got' -> return ()
|