nont
nont

Reputation: 9519

how do I get yesod-persistent to recognize the type of my aeson parsed entity array?

I've got a yesod handler that can accept some json with an array of objects. I'd like to insert all the objects into the database.

newtype NodeList = NodeList [Node]

instance FromJSON NodeList where
    parseJSON (Object o) = NodeList <$> o .: "nodes"
    parseJSON _ = mzero

postMoreNodesR :: Handler ()
postMoreNodesR = do
        nodes::NodeList <- requireJsonBody
        runDB $ mapM_ insert nodes
        return ()

But some how, its not recognizing my entity type. (although other POST and GET handlers in the same module work great.) I can tell I'm pretty close, but I'm not sure what to do, since "a0" is not a type I've declared anywhere. Here's the error:

Handler/Node.hs:46:30:
    Couldn't match expected type `[a0]' with actual type `NodeList'
    In the second argument of `mapM_', namely `nodes'
    In the second argument of `($)', namely `mapM_ insert nodes'
    In a stmt of a 'do' block: runDB $ mapM_ insert nodes

Upvotes: 2

Views: 286

Answers (2)

pbrisbin
pbrisbin

Reputation: 151

You can also pattern match directly in the bind:

postMoreNodesR :: Handler ()
postMoreNodesR = do
  NodeList nodes <- requireJsonBody

  runDB $ mapM_ insert nodes

  return ()

This obviates the need for the type annotation as well.

It works because the do expression is de-sugared to a lambda:

requireJsonBody >>= \NodeList nodes -> runDB -- ...

Upvotes: 3

nont
nont

Reputation: 9519

I figured it out! I followed the types and realized I needed a helper function to extract the Nodes from the newtyped NodeList:

getNodesFromList :: NodeList -> [Node]
getNodesFromList (NodeList l) = l

Then my handler function became:

postMoreNodesR :: Handler ()
postMoreNodesR = do
        nodes::NodeList <- requireJsonBody
        runDB $ mapM_ insert $ getNodesFromList nodes
        return ()

This stuff is really starting to click!

Upvotes: 1

Related Questions