Question

I'm writing a data record to marshall a JIRA JSON object. The problem is, multiple objects have the same labels for name/value pairs. For example :

(returned from curl and formatted)

{"expand":"schema,names"
,"startAt":0
,"maxResults":2
,"total":74
,"issues":[
           {"expand":"editmeta,renderedFields,transitions,changelog,operations"
           ,"id":"183614"
           ,"self":"https://10.64.16.44/rest/api/latest/issue/183614"
           ,"key":"BNAP-339"
           ,"fields":{"versions":[
                                  {"self":"https://10.64.16.44/rest/api/2/version/28240"  
                                  ,"id":"28240"
                                  ,"name":"2012-12-07"
                                  ,"archived":false
                                  ,"released":false
                                  }
                                 ]
                     ,"status":{"self":"https://10.64.16.44/rest/api/2/status/1"
                               ,"description":"The issue is open and ready for the assignee to start work on it."
                               ,"iconUrl":"https://10.64.16.44/images/icons/status_open.gif"
                               ,"name":"Open"
                               ,"id":"1"
                               }
                     ,"description":"Do Re Mi Fa"
                     ,"resolution":null
                     }
           }
          ]

when I construct the problematic corresponding Haskell data records I get:

data Issue = Issue {expand :: String
                   ,id :: String
                   ,self :: String
                   ,key :: String
                   ,fields :: Fields
                   } deriving Generic


data Version = Version {self :: String
                       ,id :: String
                       ,name :: String
                       ,archived :: Bool
                       ,released :: Bool
                       } deriving Generic

and 'id' and 'self' will clash. It occured to me I could solve this by just changing the names in the records and fixing it with a manually-created FromJSON instance. Any alternative solutions would be welcome.

Was it helpful?

Solution

I solve this in protocol buffers by putting things like Issue and Version in separate files in the same hierarchy.

Haskell only uses separate modules to control namespaces, so this is the orthodox solution.

Much much fancier: use type classes to define available name:

class Has'self a b | a -> bwhere
   get'self :: a -> b
   set'self :: b -> a -> b

instance Has'self Issue String where ...
instance Has'self Version String where ....

EDIT: The comments below remind me to give more verbose advice. Do not use Has'self like solutions -- those that have gone that road report it gets ugly. I can vouch for the path of separate modules.

PS: Perhaps you can use the lens library for your fields!

OTHER TIPS

Another alternative that should work is to use a single data type that contains the distinct records. For example, the following data type is capable of representing your value without field conflicts:

import Prelude hiding (id)

data JIRA = JIRA
  { expand :: String
  , startAt :: Int
  , maxResults :: Int
  , total :: Int
  , issues :: [JIRA]
  } | Issue 
  { expand :: String
  , id :: Int
  , self :: String
  , key :: String
  , fields :: JIRA
  } | Field
  { versions :: [JIRA]
  , status :: JIRA
  , description :: String
  , resolution :: Maybe String
  } | Version
  { self :: String
  , id :: Int
  , name :: String
  , archived :: Bool
  , released :: Bool
  } | Status
  { self :: String
  , description :: String
  , iconUrl :: String
  , name :: String
  , id :: Int
  }


yourExample = JIRA
  { expand = "schema, names"
  , startAt = 0
  , maxResults = 2
  , total = 74
  , issues = [ Issue
               { expand = "editmeta, etc..."
               , id = 12345
               , self = "https://xyz"
               , key = "BLAH"
               , fields = Field
                          { versions = [ Version
                                          { self = "https://foobar"
                                          , id = 1234
                                          , name = "quux"
                                          , archived = False
                                          , released = False
                                          }
                                       ]
                          , status = Status
                                     { self = "https://etc"
                                     , description = "issue"
                                     , iconUrl = "https://iconurl"
                                     , name = "open"
                                     , id = 1
                                     }
                          , description = "another description"
                          , resolution = Nothing
                          }
                 }
               ]
  }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top