stratosphere-0.22.2: library/Stratosphere/Helpers.hs
module Stratosphere.Helpers
( maybeField
, prefixNamer
, prefixFieldRules
, modTemplateJSONField
, NamedItem (..)
, namedItemToJSON
, namedItemFromJSON
) where
import Control.Lens (set)
import Control.Lens.TH
import Data.Aeson
import Data.Aeson.Types (Parser)
import Data.Char (isUpper, toLower)
import qualified Data.HashMap.Strict as HM
import Data.List (stripPrefix)
import Data.Maybe (maybeToList)
import qualified Data.Text as T
import Language.Haskell.TH
-- | Might create an aeson pair from a Maybe value.
maybeField :: ToJSON a => T.Text -> Maybe a -> Maybe (T.Text, Value)
maybeField field = fmap ((field .=) . toJSON)
-- | Similar to `camelCaseNamer`, except we specify the prefix exactly. We use
-- this because camelCaseNamer is terrible with names that start in all caps,
-- like EC2. We would like to start the field names with "ec2...", but
-- camelCaseNamer wants "eC2...".
prefixNamer :: String -> Name -> [Name] -> Name -> [DefName]
prefixNamer prefix _ _ field = maybeToList $
do
fieldPart <- stripPrefix prefix (nameBase field)
method <- computeMethod fieldPart
let cls = "Has" ++ fieldPart
return (MethodName (mkName cls) (mkName method))
where computeMethod (x:xs) | isUpper x = Just (toLower x : xs)
computeMethod _ = Nothing
-- | See `prefixNamer`
prefixFieldRules :: String -> LensRules
prefixFieldRules prefix = set lensField (prefixNamer prefix) defaultFieldRules
-- | Used for the JSON instances in Template. It is put here because it must be
-- in a separate module.
modTemplateJSONField :: String -> String
modTemplateJSONField "_templateFormatVersion" = "AWSTemplateFormatVersion"
modTemplateJSONField s = drop 9 s
-- | This class defines items with names in them. It is used to extract the
-- name from JSON fields so we can get an Object with the names as keys instead
-- of just an array.
class NamedItem a where
itemName :: a -> T.Text
nameToJSON :: a -> Value
nameParseJSON :: T.Text -> Object -> Parser a
namedItemToJSON :: (NamedItem a) => [a] -> Value
namedItemToJSON xs =
object $ fmap (\x -> itemName x .= nameToJSON x) xs
namedItemFromJSON :: (NamedItem a) => Value -> Parser [a]
namedItemFromJSON v = do
objs <- parseJSON v :: Parser (HM.HashMap T.Text Value)
sequence [withObject "NamedItem" (nameParseJSON n) obj |
(n, obj) <- HM.toList objs]