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.imgur.com/xzHy9MU.png. Here you can see the ItemType field by the keys "login", "card", "identity" depending on what type they are.