So I have this data type ItemType
which is decoded using its data constructor name (see the FromJSON instance).
import Data.Aeson
import Data.Aeson.Types
import Data.Char (toLower)
import GHC.Generics
data ItemType =
MkLogin Login
| MkCard Card
| MkIdentity Identity
| MkSecureNote Note
deriving (Generic, Show)
lowercase :: String -> String
lowercase "" = ""
lowercase (s:ss) = toLower s : ss
stripPrefix :: String -> String
stripPrefix ('M':'k':ss) = ss
stripPrefix str = str
-- | Decode value using ItemType data constructor names
instance FromJSON ItemType where
parseJSON = genericParseJSON defaultOptions
{ constructorTagModifier = lowercase . stripPrefix
, sumEncoding = ObjectWithSingleField }
and what I want to do is add this type as a field to a larger record type called Item
data Item =
Item { _object :: String
, _id :: String
, _organizationId :: Maybe Int
, _folderId :: Maybe Int
, _type :: Int
, _name :: String
, _notes :: String
, _favorite :: Bool
, ??? :: ItemType -- don't know how to add this without a different field name
, _collectionIds :: [Int]
, _revisionDate :: Maybe String
} deriving (Generic, Show)
instance FromJSON Item where
parseJSON =
genericParseJSON defaultOptions { fieldLabelModifier = stripUnderscore }
However I don't want to create a new field name for the type. Instead I want to use the data constructor which aeson matched on ItemType
as the field name because the key of the ItemType
field in the JSON object I'm trying to model changes depending upon what ItemType
it is. So in this case the key is either "login", "card", "identity", "secureNote". Perhaps I should be using TaggedObject
for the sumEncoding
, but I'm not totally sure how it works.
Example JSON list of Item
objects: https://i.stack.imgur.com/JQmH0.png. Here you can see the ItemType
field by the keys "login", "card", "identity" depending on what type they are.