Reputation: 2049
What is the best way to convert a string "[\"id\"=:5977, \"brandId\"=:87]"
to a field for mongoDB ["id"=:5977, "brandId"=:87]
or even better if I have a datatype
data Body = Body
{ body_id :: int
brandId :: Int } deriving (Show)
giving
Body {body_id = 5977, brandId = 87}
What is the best way to convert that to
["id"=:5977, "brandId"=:87]
Thanks.
Upvotes: 0
Views: 284
Reputation: 15959
If I understand this correctly you are using hackage: mongoDB to interact with a database.
So the only thing to do is convert a haskell value to a BSON-value this is what hackage: bson provides, notably in the typeclass Val
class (Typeable a, Show a, Eq a) => Val a where Haskell types of this class correspond to BSON value types Minimal complete definition val, cast' Methods val :: a -> Value ... cast' :: Value -> Maybe a ...
so it remains to implement val
and cast'
but first of all we need to derive a few more properties than you have:
Body.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE OverloadedStrings #-}
module Body where
import Data.Bson
import Data.Typeable
data Body = Body { bodyID :: Int
, brandID :: Int }
deriving (Show,Typeable,Eq)
instance Val Body where
val (Body body brand) = Doc [ "bodyID" := (Int64 $ fromIntegral body)
, "brandID" := (Int64 $ fromIntegral brand)]
cast' (Doc bson) = case (bson !? "bodyID") of
Just (Int64 x) ->
case (bson !? "brandID") of
Just (Int64 y) -> Just (Body (fromIntegral x)
(fromIntegral y))
Just _ -> Nothing
Nothing -> Nothing
Just _ -> Nothing
Nothing -> Nothing
cast' (Array x) = undefined
cast' _ = Nothing
this is a bit clustered but rather straightforward.
Now I gave this thing a bit more thought - the previous cast'
is really clustered and haskell having nice abstractions should do better
val (Body body brand) = Doc [ "bodyID" := (val body)
, "brandID" := (val brand)]
cast' (Doc bson) = do body <- (bson !? "bodyID")
brand <- (bson !? "brandID")
Body <$> cast' body <*> cast' brand
cast' _ = Nothing
So you really could write this a bit shorter accepting that <$>
(called fmap
) and <*>
(called ap
do the "right" thing.
Moreover I used do
notation to simplify the job, now using this
> cast' $ val (Body 30 4) :: Maybe Body
Just (Body {bodyID = 30, brandID = 4})
Note in the last example you really need the annotation :: Maybe Body
otherwise the compiler cannot figure out what to cast and you'll get a Nothing
.
Upvotes: 4