Skip to content

Commit d387119

Browse files
committed
wip
1 parent 5dac462 commit d387119

File tree

4 files changed

+34
-24
lines changed

4 files changed

+34
-24
lines changed

servant-client-core/src/Servant/Client/Core/HasClient.hs

-8
Original file line numberDiff line numberDiff line change
@@ -678,14 +678,6 @@ instance (HasClient m api)
678678
hoistClientMonad pm _ f cl = \b ->
679679
hoistClientMonad pm (Proxy :: Proxy api) f (cl b)
680680

681-
class ToDeepQuery a where
682-
toDeepQuery :: a -> [([T.Text], Maybe T.Text)]
683-
684-
generateDeepParam :: T.Text -> ([T.Text], Maybe T.Text) -> (T.Text, Maybe T.Text)
685-
generateDeepParam name (keys, value) =
686-
let makeKeySegment key = "[" <> key <> "]"
687-
in (name <> foldMap makeKeySegment keys, value)
688-
689681
instance (KnownSymbol sym, ToDeepQuery a, HasClient m api)
690682
=> HasClient m (DeepQuery sym a :> api) where
691683
type Client m (DeepQuery sym a :> api) =

servant-server/src/Servant/Server/Internal.hs

-16
Original file line numberDiff line numberDiff line change
@@ -728,22 +728,6 @@ parseDeepParam (paramname, value) =
728728
_ -> Left $ "Error parsing deep param, missing opening '[': " <> T.unpack remaining
729729
in (, value) <$> parseParam paramname
730730

731-
-- | Extract a deep object from (possibly nested) query parameters.
732-
-- a param like @filter[a][b][c]=d@ will be represented as
733-
-- @'(["a", "b", "c"], Just "d")'@. Note that a parameter with no
734-
-- nested field is possible: @filter=a@ will be represented as
735-
-- @'([], Just "a")'@
736-
class FromDeepQuery a where
737-
fromDeepQuery :: [([T.Text], Maybe T.Text)] -> Either String a
738-
739-
instance FromHttpApiData a => FromDeepQuery (Map.Map T.Text a) where
740-
fromDeepQuery params =
741-
let parseParam ([k], Just rawV) = (k,) <$> first T.unpack (parseQueryParam rawV)
742-
parseParam (_, Nothing) = Left "Empty map value"
743-
parseParam ([], _) = Left "Empty map parameter"
744-
parseParam (_ , Just _) = Left "Nested map values"
745-
in Map.fromList <$> traverse parseParam params
746-
747731
-- | Just pass the request to the underlying application and serve its response.
748732
--
749733
-- Example:

servant/servant.cabal

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ library
8484
base >= 4.9 && < 4.20
8585
, bytestring >= 0.10.8.1 && < 0.13
8686
, constraints >= 0.2
87+
, containers >= 0.6 && < 0.7
8788
, mtl ^>= 2.2.2 || ^>= 2.3.1
8889
, sop-core >= 0.4.0.0 && < 0.6
8990
, transformers >= 0.5.2.0 && < 0.7

servant/src/Servant/API/QueryString.hs

+33
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
{-# OPTIONS_HADDOCK not-home #-}
66
module Servant.API.QueryString (QueryString, DeepQuery) where
77

8+
import Data.Kind (Type)
9+
import Data.Map.Strict (Map)
10+
import Data.Text (Text)
11+
import qualified Data.Text as T
812
import Data.Typeable
913
(Typeable)
1014
import GHC.TypeLits
@@ -37,3 +41,32 @@ data DeepQuery (sym :: Symbol) (a :: Type)
3741
-- >>> data Book
3842
-- >>> data BookQuery
3943
-- >>> instance ToJSON Book where { toJSON = undefined }
44+
45+
-- | Extract a deep object from (possibly nested) query parameters.
46+
-- a param like @filter[a][b][c]=d@ will be represented as
47+
-- @'(["a", "b", "c"], Just "d")'@. Note that a parameter with no
48+
-- nested field is possible: @filter=a@ will be represented as
49+
-- @'([], Just "a")'@
50+
class FromDeepQuery a where
51+
fromDeepQuery :: [([Text], Maybe Text)] -> Either String a
52+
53+
instance FromHttpApiData a => FromDeepQuery (Map.Map Text a) where
54+
fromDeepQuery params =
55+
let parseParam ([k], Just rawV) = (k,) <$> first T.unpack (parseQueryParam rawV)
56+
parseParam (_, Nothing) = Left "Empty map value"
57+
parseParam ([], _) = Left "Empty map parameter"
58+
parseParam (_ , Just _) = Left "Nested map values"
59+
in Map.fromList <$> traverse parseParam params
60+
61+
-- | Generate query parameters from an object, using the deep object syntax.
62+
-- A result of @'(["a", "b", "c"], Just "d")'@ attributed to the @filter@
63+
-- parameter name will result in the following query parameter:
64+
-- @filter[a][b][c]=d@
65+
class ToDeepQuery a where
66+
toDeepQuery :: a -> [([Text], Maybe Text)]
67+
68+
generateDeepParam :: Text -> ([Text], Maybe Text) -> (Text, Maybe Text)
69+
generateDeepParam name (keys, value) =
70+
let makeKeySegment key = "[" <> key <> "]"
71+
in (name <> foldMap makeKeySegment keys, value)
72+

0 commit comments

Comments
 (0)