[squeal-posgresql] Decoding JSONB to Aeson.Value

I have a query with the following type

sql :: Query '[] with MySchema '[ 'NotNull 'PGint4] '["id" ::: 'NotNull 'PGint4, "vals" ::: 'NotNull 'PGjsonb]

that I then want to turn into a Statement

getValues :: Statement MySchema Int32 (Int32, Aeson.Value)
getValues = Query encode decode sql
  where
    encode = (\x -> x) .* nilParams
    decode = (,) <$> #id <*> #vals

This gives me the following error though

* Couldn't match type `PGjsonb' with `PGjson'
    arising from the overloaded label `#vals'
* In the second argument of `(<*>)', namely `#vals'
  In the expression: (,) <$> #id <*> #vals
  In an equation for `decode': decode = (,) <$> #id <*> #vals

which confuses me. The schema says the field is PGjsonb, the query typechecks and the value is PGjsonb, so where does PGjson come in? How do I convert a PGjsonb field to an Aeson.Value? I’m clearly missing something here, but what?

(I originally posted this question here, but thought I’d widen the audience a bit.)

I think this is not quite enough context to properly trouble shoot the issue but my hunch is that a fundep (or type family, for that matter) associates PGjson with Aeson and you would need to wrap Value in a newtype wrapper s.t. it works with the overloaded labels.

Hmm, so would that be necessary to make my own type (something implementing ToJSON/FromJSON) be required to make it work with JSONB too?

I’ll be happy to provide a more complete context if you think it’ll help.

As I said, I would try a newtype wrapper for Value. Call it BValue?

Ah, doing that made me go look at FromPG, which in turn lead me to the newtypes Json and Jsonb. So if I change the type of getValues to

getValues :: Statement MySchema Int32 (Int32, Jsonb Aeson.Value)

then everything typechecks successfully. I just have to use getJsonb to extract the actual Value.

If I want to avoid having to deal with the Jsonb wrapper outside of getValues I can modify the decoder, thus I end up with

getValues :: Statement MySchema Int32 (Int32, Aeson.Value)
getValues = Query encode decode sql
  where
    encode = (\x -> x) .* nilParams
    decode = mkResult <$> #id <*> #vals
    mkResult id_ vals = (id_, getJsonb vals)
1 Like

ah yes, that’s what I expected :slight_smile:

2 Likes