on master help sign in
Added test cases for matrix parameters. Added some missing cases in the IsElem type family (QueryParams and QueryFlag)
commit0b2f2ae4907e183682fd12e96f3d1e5a29de56da authorDaniel Larsson <daniel.j.larsson@gmail.com> dateSun 4 Jan 2015, 18:14 (12 years ago) parent0b29d1d
4 files changed+64−16
src/Servant/QQ.hs+30−16 src/Servant/Utils/Links.hs+6 test/Servant/QQSpec.hs+22 test/Servant/Utils/LinksSpec.hs+6
src/Servant/QQ.hs+30−16
@@ -58,6 +58,7 @@ import Servant.API.Post ( Post )
5858import Servant.API.Put ( Put )
5959import Servant.API.Delete ( Delete )
6060import Servant.API.QueryParam ( QueryParam )
61+import Servant.API.MatrixParam ( MatrixParam )
6162import Servant.API.ReqBody ( ReqBody )
6263import Servant.API.Sub ( (:>) )
6364import Servant.API.Alternative ( (:<|>) )
@@ -68,15 +69,16 @@ import Servant.API.Alternative ( (:<|>) )
6869-- only one of 'get', 'post', 'put', and 'delete' in a value), but
6970-- sometimes requires a little more work.
7071class ExpSYM repr' repr | repr -> repr', repr' -> repr where
71− lit :: String -> repr' -> repr
72− capture :: String -> String -> repr -> repr
73− reqBody :: String -> repr -> repr
74− queryParam :: String -> String -> repr -> repr
75− conj :: repr' -> repr -> repr
76− get :: String -> repr
77− post :: String -> repr
78− put :: String -> repr
79− delete :: String -> repr
72+ lit :: String -> repr' -> repr
73+ capture :: String -> String -> repr -> repr
74+ reqBody :: String -> repr -> repr
75+ queryParam :: String -> String -> repr -> repr
76+ matrixParam :: String -> String -> repr -> repr
77+ conj :: repr' -> repr -> repr
78+ get :: String -> repr
79+ post :: String -> repr
80+ put :: String -> repr
81+ delete :: String -> repr
8082
8183
8284infixr 6 >:
@@ -90,7 +92,9 @@ instance ExpSYM Type Type where
9092 capture name typ r = AppT (AppT (ConT ''Capture) (LitT (StrTyLit name)))
9193 (ConT $ mkName typ) >: r
9294 reqBody typ r = AppT (ConT ''ReqBody) (ConT $ mkName typ) >: r
93− queryParam name typ r = AppT (AppT (ConT ''QueryParam) (LitT (StrTyLit name)))
95+ queryParam name typ r = AppT (AppT (ConT ''QueryParam) (LitT (StrTyLit name)))
96+ (ConT $ mkName typ) >: r
97+ matrixParam name typ r = AppT (AppT (ConT ''MatrixParam) (LitT (StrTyLit name)))
9498 (ConT $ mkName typ) >: r
9599 conj x = AppT (AppT (ConT ''(:>)) x)
96100 get typ = AppT (ConT ''Get) (ConT $ mkName typ)
@@ -111,17 +115,27 @@ parseUrlSegment = try parseCapture
111115 <|> try parseLit
112116 where
113117 parseCapture = do
114− cname <- many (noneOf " ?/:")
118+ cname <- many (noneOf " ?/:;")
115119 char ':'
116− ctyp <- many (noneOf " ?/:")
117− return $ capture cname ctyp
120+ ctyp <- many (noneOf " ?/:;")
121+ mx <- many parseMatrixParam
122+ return $ capture cname ctyp . foldr (.) id mx
118123 parseQueryParam = do
119124 char '?'
120− cname <- many (noneOf " ?/:")
125+ cname <- many (noneOf " ?/:;")
121126 char ':'
122− ctyp <- many (noneOf " ?/:")
127+ ctyp <- many (noneOf " ?/:;")
123128 return $ queryParam cname ctyp
124− parseLit = lit <$> many (noneOf " ?/:")
129+ parseLit = do
130+ lt <- many (noneOf " ?/:;")
131+ mx <- many parseMatrixParam
132+ return $ lit lt . foldr (.) id mx
133+ parseMatrixParam = do
134+ char ';'
135+ cname <- many (noneOf " ?/:;")
136+ char ':'
137+ ctyp <- many (noneOf " ?/:;")
138+ return $ matrixParam cname ctyp
125139
126140parseUrl :: ExpSYM repr repr => Parser (repr -> repr)
127141parseUrl = do
src/Servant/Utils/Links.hs+6
@@ -54,6 +54,7 @@ import GHC.TypeLits ( KnownSymbol, Symbol, symbolVal )
5454import Servant.API.Capture ( Capture )
5555import Servant.API.ReqBody ( ReqBody )
5656import Servant.API.QueryParam ( QueryParam )
57+import Servant.API.MatrixParam ( MatrixParam )
5758import Servant.API.Get ( Get )
5859import Servant.API.Post ( Post )
5960import Servant.API.Put ( Put )
@@ -78,6 +79,11 @@ type family IsElem a s where
7879 IsElem (e :> sa) (Capture x y :> sb) = IsElem sa sb
7980 IsElem sa (ReqBody x :> sb) = IsElem sa sb
8081 IsElem sa (QueryParam x y :> sb) = IsElem sa sb
82+ IsElem sa (QueryParams x y :> sb) = IsElem sa sb
83+ IsElem sa (QueryFlag x :> sb) = IsElem sa sb
84+ IsElem sa (MatrixParam x y :> sb) = IsElem sa sb
85+ IsElem sa (MatrixParams x y :> sb) = IsElem sa sb
86+ IsElem sa (MatrixFlag x :> sb) = IsElem sa sb
8187 IsElem e e = 'True
8288 IsElem e a = 'False
8389
test/Servant/QQSpec.hs+22
@@ -85,6 +85,20 @@ type SimpleQueryParam' = "hello" :> QueryParam "p" Int :> Post Bool
8585type SimpleQueryParam'' = "hello" :> QueryParam "r" Int :> Post Bool
8686type SimpleQueryParam''' = "hello" :> QueryParam "p" Bool :> Post Bool
8787
88+type SimpleMatrixParam = [sitemap|
89+POST hello;p:Int Bool
90+|]
91+type SimpleMatrixParam' = "hello" :> MatrixParam "p" Int :> Post Bool
92+type SimpleMatrixParam'' = "hello" :> MatrixParam "r" Int :> Post Bool
93+type SimpleMatrixParam''' = "hello" :> MatrixParam "p" Bool :> Post Bool
94+
95+type ComplexMatrixParam = [sitemap|
96+POST hello;p:Int;q:String/world;r:Int Bool
97+|]
98+type ComplexMatrixParam' = "hello" :> MatrixParam "p" Int :> MatrixParam "q" String :> "world" :> MatrixParam "r" Int :> Post Bool
99+type ComplexMatrixParam'' = "hello" :> MatrixParam "p" Int :> MatrixParam "q" String :> "world" :> MatrixParam "s" Int :> Post Bool
100+type ComplexMatrixParam''' = "hello" :> MatrixParam "p" Int :> MatrixParam "q" String :> "world" :> MatrixParam "r" Bool :> Post Bool
101+
88102-- Combinations ----------------------------------------------------------
89103
90104type TwoPaths = [sitemap|
@@ -153,6 +167,14 @@ spec = do
153167 (u::SimpleQueryParam) ~= (u::SimpleQueryParam' ) ~> True
154168 (u::SimpleQueryParam) ~= (u::SimpleQueryParam'') ~> False
155169 (u::SimpleQueryParam) ~= (u::SimpleQueryParam''') ~> False
170+ it "Handles simple matrix parameters" $ do
171+ (u::SimpleMatrixParam) ~= (u::SimpleMatrixParam' ) ~> True
172+ (u::SimpleMatrixParam) ~= (u::SimpleMatrixParam'') ~> False
173+ (u::SimpleMatrixParam) ~= (u::SimpleMatrixParam''') ~> False
174+ it "Handles more complex matrix parameters" $ do
175+ (u::ComplexMatrixParam) ~= (u::ComplexMatrixParam' ) ~> True
176+ (u::ComplexMatrixParam) ~= (u::ComplexMatrixParam'') ~> False
177+ (u::ComplexMatrixParam) ~= (u::ComplexMatrixParam''') ~> False
156178 it "Handles multiples paths" $ do
157179 (u::TwoPaths) ~= (u::TwoPaths') ~> True
158180 it "Ignores inline comments" $ do
test/Servant/Utils/LinksSpec.hs+6
@@ -14,12 +14,15 @@ import Servant.Utils.Links ( IsElem, IsLink )
1414type TestApi =
1515 "hello" :> Capture "name" String :> QueryParam "capital" Bool :> Get Bool
1616 :<|> "greet" :> ReqBody 'True :> Post Bool
17+ :<|> "parent" :> MatrixParams "name" String :> "child" :> MatrixParam "gender" String :> Get String
1718
1819type TestLink = "hello" :> "hi" :> Get Bool
1920type TestLink2 = "greet" :> Post Bool
21+type TestLink3 = "parent" :> "child" :> Get String
2022
2123type BadTestLink = "hallo" :> "hi" :> Get Bool
2224type BadTestLink2 = "greet" :> Get Bool
25+type BadTestLink3 = "parent" :> "child" :> MatrixFlag "male" :> Get String
2326
2427type NotALink = "hello" :> Capture "x" Bool :> Get Bool
2528type NotALink2 = "hello" :> ReqBody 'True :> Get Bool
@@ -39,15 +42,18 @@ isElem = describe "IsElem" $ do
3942 it "is True when the first argument is an url within the second" $ do
4043 reflected (Proxy::Proxy (IsElem TestLink TestApi)) ~> True
4144 reflected (Proxy::Proxy (IsElem TestLink2 TestApi)) ~> True
45+ reflected (Proxy::Proxy (IsElem TestLink3 TestApi)) ~> True
4246 it "is False when the first argument is not an url within the second" $ do
4347 reflected (Proxy::Proxy (IsElem BadTestLink TestApi)) ~> False
4448 reflected (Proxy::Proxy (IsElem BadTestLink2 TestApi)) ~> False
49+ reflected (Proxy::Proxy (IsElem BadTestLink3 TestApi)) ~> False
4550
4651isLink :: Spec
4752isLink = describe "IsLink" $ do
4853 it "is True when all Subs are paths and the last is a method" $ do
4954 reflected (Proxy::Proxy (IsLink TestLink)) ~> True
5055 reflected (Proxy::Proxy (IsLink TestLink2)) ~> True
56+ reflected (Proxy::Proxy (IsLink TestLink3)) ~> True
5157 it "is False of anything with captures" $ do
5258 reflected (Proxy::Proxy (IsLink NotALink)) ~> False
5359 reflected (Proxy::Proxy (IsLink NotALink2)) ~> False