@@ -233,9 +233,14 @@ instance ToHttpApiData v => ToForm (IntMap [v]) where
233 toForm = fromEntriesByKey . IntMap.toList
233 toForm = fromEntriesByKey . IntMap.toList
235-- | Convert a list of entries groupped by key into a 'Form'.
235-- | Convert a list of entries groupped by key into a 'Form'.
237+-- >>> fromEntriesByKey [("name",["Nick"]),("color",["red","blue"])]
238+-- fromList [("color","red"),("color","blue"),("name","Nick")]
236fromEntriesByKey :: (ToFormKey k, ToHttpApiData v) => [(k, [v])] -> Form
239fromEntriesByKey :: (ToFormKey k, ToHttpApiData v) => [(k, [v])] -> Form
237fromEntriesByKey = Form . HashMap.fromListWith (<>) . map (toFormKey *** map toQueryParam)
240fromEntriesByKey = Form . HashMap.fromListWith (<>) . map (toFormKey *** map toQueryParam)
242+data Proxy3 a b c = Proxy3
239-- | A 'Generic'-based implementation of 'toForm'.
244-- | A 'Generic'-based implementation of 'toForm'.
240-- This is used as a default implementation in 'ToForm'.
245-- This is used as a default implementation in 'ToForm'.
241genericToForm :: (Generic a, GToForm (Rep a)) => a -> Form
246genericToForm :: (Generic a, GToForm (Rep a)) => a -> Form
@@ -314,6 +319,9 @@ instance FromHttpApiData v => FromForm (IntMap [v]) where
314 fromForm = fmap (IntMap.fromListWith (<>)) . toEntriesByKey
319 fromForm = fmap (IntMap.fromListWith (<>)) . toEntriesByKey
316-- | Parse a 'Form' into a list of entries groupped by key.
321-- | Parse a 'Form' into a list of entries groupped by key.
323+-- >>> toEntriesByKey [("name", "Nick"), ("color", "red"), ("color", "white")] :: Either Text [(Text, [Text])]
324+-- Right [("color",["red","white"]),("name",["Nick"])]
317toEntriesByKey :: (FromFormKey k, FromHttpApiData v) => Form -> Either Text [(k, [v])]
325toEntriesByKey :: (FromFormKey k, FromHttpApiData v) => Form -> Either Text [(k, [v])]
318toEntriesByKey = traverse parseGroup . HashMap.toList . unForm
326toEntriesByKey = traverse parseGroup . HashMap.toList . unForm
@@ -422,8 +430,6 @@ urlDecodeForm bs = toForm <$> traverse parsePair pairs
422 [k] -> return (k, "")
430 [k] -> return (k, "")
423 xs -> Left $ "not a valid pair: " <> Text.intercalate "=" xs
431 xs -> Left $ "not a valid pair: " <> Text.intercalate "=" xs
425−data Proxy3 a b c = Proxy3
427-- | This is a convenience function for decoding a
433-- | This is a convenience function for decoding a
428-- @application/x-www-form-urlencoded@ 'BSL.ByteString' directly to a datatype
434-- @application/x-www-form-urlencoded@ 'BSL.ByteString' directly to a datatype
429-- that has an instance of 'FromForm'.
435-- that has an instance of 'FromForm'.
@@ -448,14 +454,14 @@ urlEncodeAsForm = urlEncodeForm . toForm
449-- | Find all values corresponding to a given key in a 'Form'.
455-- | Find all values corresponding to a given key in a 'Form'.
451−-- >>> lookupKey "name" []
457+-- >>> lookupAll "name" []
453−-- >>> lookupKey "name" [("name", "Oleg")]
459+-- >>> lookupAll "name" [("name", "Oleg")]
454-- ["Oleg"]
460-- ["Oleg"]
455−-- >>> lookupKey "name" [("name", "Oleg"), ("name", "David")]
461+-- >>> lookupAll "name" [("name", "Oleg"), ("name", "David")]
456-- ["Oleg","David"]
462-- ["Oleg","David"]
457−lookupKey :: Text -> Form -> [Text]
463+lookupAll :: Text -> Form -> [Text]
458−lookupKey key = F.concat . HashMap.lookup key . unForm
464+lookupAll key = F.concat . HashMap.lookup key . unForm
460-- | Lookup a unique value for a key.
466-- | Lookup a unique value for a key.
461-- Fail if there is zero or more than one value.
467-- Fail if there is zero or more than one value.
@@ -468,12 +474,26 @@ lookupKey key = F.concat . HashMap.lookup key . unForm
468-- Left "Duplicate key \"name\""
474-- Left "Duplicate key \"name\""
469lookupUnique :: Text -> Form -> Either Text Text
475lookupUnique :: Text -> Form -> Either Text Text
470lookupUnique key form =
476lookupUnique key form =
471− case lookupKey key form of
477+ case lookupAll key form of
472 [v] -> pure v
478 [v] -> pure v
473 [] -> Left $ "Could not find key " <> Text.pack (show key)
479 [] -> Left $ "Could not find key " <> Text.pack (show key)
474 _ -> Left $ "Duplicate key " <> Text.pack (show key)
480 _ -> Left $ "Duplicate key " <> Text.pack (show key)
482+-- | Lookup all values for a given key in a 'Form' and parse them with 'parseQueryParams'.
484+-- >>> parseAll "age" [] :: Either Text [Word8]
486+-- >>> parseAll "age" [("age", "8"), ("age", "seven")] :: Either Text [Word8]
487+-- Left "could not parse: `seven' (input does not start with a digit)"
488+-- >>> parseAll "age" [("age", "8"), ("age", "777")] :: Either Text [Word8]
489+-- Left "out of bounds: `777' (should be between 0 and 255)"
490+-- >>> parseAll "age" [("age", "12"), ("age", "25")] :: Either Text [Word8]
492+parseAll :: FromHttpApiData v => Text -> Form -> Either Text [v]
493+parseAll key = parseQueryParams . lookupAll key
476-- | Lookup a unique value for a given key and parse it with 'parseQueryParam'.
495-- | Lookup a unique value for a given key and parse it with 'parseQueryParam'.
496+-- Fail if there is zero or more than one value for the key.
478-- >>> parseUnique "age" [] :: Either Text Word8
498-- >>> parseUnique "age" [] :: Either Text Word8
479-- Left "Could not find key \"age\""
499-- Left "Could not find key \"age\""
@@ -488,16 +508,3 @@ lookupUnique key form =
488parseUnique :: FromHttpApiData v => Text -> Form -> Either Text v
508parseUnique :: FromHttpApiData v => Text -> Form -> Either Text v
489parseUnique key form = lookupUnique key form >>= parseQueryParam
509parseUnique key form = lookupUnique key form >>= parseQueryParam
491−-- | Lookup all values for a given key in a 'Form' and parse them with 'parseQueryParams'.
493−-- >>> parseAll "age" [] :: Either Text [Word8]
495−-- >>> parseAll "age" [("age", "8"), ("age", "seven")] :: Either Text [Word8]
496−-- Left "could not parse: `seven' (input does not start with a digit)"
497−-- >>> parseAll "age" [("age", "8"), ("age", "777")] :: Either Text [Word8]
498−-- Left "out of bounds: `777' (should be between 0 and 255)"
499−-- >>> parseAll "age" [("age", "12"), ("age", "25")] :: Either Text [Word8]
501−parseAll :: FromHttpApiData v => Text -> Form -> Either Text [v]
502−parseAll key = parseQueryParams . lookupKey key