I have two simple data types in Haskell:
data Ticket = Ticket {
tbody :: String,
tauthor :: String,
tcomments :: [TicketComment]
}
data TicketComment = TicketComment {
tcbody :: String,
tcauthor :: String
}
Ignoring for a moment the lack of timestamps, and the use of strings vs. bytestrings, I simply want to store the comments in MongoDB nested in their tickets.
Up until now I have been using a rather simple instance to store data:
class MongoIO a where
transout :: a -> [Field]
transin :: [Field] -> (Maybe a)
The implementation then looks something like this:
instance MongoIO Ticket where
transout a = [("body" =: tbody a),
("author" =: tauthor a),
("comments" =: tcomments a)]
transin a = case (,,) <$> look "body" a
<*> look "author" a
<*> look "comments" a of
Nothing -> Nothing
Just (bo,au,co) ->
Just $ Ticket (typed bo) (typed au) (typed co)
As would be expected, this breaks down at ("comments" =: tcomments a)
. I'm confident that I'm getting into an area of Haskell types where my own knowledge is lacking so I'm excited to hear about how others would approach this.
You have to translate embedded documents also. So
instance MongoIO Ticket where
transout t = [
"body" =: tbody t,
"author" =: tauthor t,
"comments" =: map transout (tcomments t) ]
transin d = Ticket
<$> lookup "body" d
<*> lookup "author" d
<*> (mapM transin =<< lookup "comments" d)
plus similar instance for TicketComment
.
Also I would use the type synonym Document
for [Field]
.
It looks like you just have the transin
and transout
implementations reversed in your instance. Your transin
takes a Ticket
and returns a list of Field
s; but that's transout
's type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With