Skip to content

Conversation

@garyb
Copy link
Owner

@garyb garyb commented Oct 13, 2025

@m-bock Right before I made the release as per #80 I ran into a case where I found myself wanting a JPropCodec for a sum type so I could combine it with another codec for a surrounding type:

import Prelude

import Data.Codec.Argonaut ((~))
import Data.Codec.Argonaut as CA
import Data.Codec.Argonaut.Sum as CAS
import Data.Generic.Rep (class Generic)
import Data.String as String
import Data.Tuple (Tuple(..), fst, snd)

type Var = Tuple String

codecVar   a. String  CA.JPropCodec a  CA.JsonCodec (Var a)
codecVar name codec =
  CA.object name $ Tuple
    <$> fst ~ CA.prop "name" CA.string
    <*> snd ~ codec

data Typed
  = Str String
  | Bool Boolean
  | Num Number

derive instance Generic Typed _

type Value = Var Typed

codecValue  CA.JsonCodec Value
codecValue = codecVar "Value" $ CAS.sumWith' encoding
  { "Str": CA.string
  , "Bool": CA.boolean
  , "Num": CA.number
  }
  where
  encoding =
    CAS.EncodeTagged
      { tagKey: "type"
      , valuesKey: "value"
      , unwrapSingleArguments: true
      , omitEmptyArguments: true
      , mapTag: String.toLower
      }

This gives us Tuple "foo" (Str "BAR"){ "name": "foo", "type": "str", "value": "BAR" }. The motivating case was a bit more involved, so this looks like a lot of work for something of questionable necessity, but hopefully it illustrates the idea still! Basically, without this, we can't deal with complex sums and would have to match our PS representation to the flat structure of the JSON object (aside from introducing further types and doing a conversion step or something like that).

(Also, isn't it kinda cool the way codecVar worked out? 😄)

@m-bock
Copy link
Contributor

m-bock commented Oct 15, 2025

Nice idea, i see the purpose! Just one thing to consider: Doesn't this imply that Sum.Encoding alway describes encodings to objects? What if we want to extend it with third case that encodes to tuple-Arrays, like e.g. for Typed sample:

["Str", "hello"]
["Bool", true]
["Num", 42]

@m-bock
Copy link
Contributor

m-bock commented Oct 15, 2025

Or maybe one day there's an encoding that encodes constructors without args just as strings.

data Sample = Foo Int | Bar String | Baz
{"type": "Foo", "value": 6}
{"type": "Bar", "value": "abc"}
"Baz"

@garyb
Copy link
Owner Author

garyb commented Oct 15, 2025

Yeah, those are good points. Maybe there's something that could be done for this case that could be constrained to sumFlatWith, since that does imply an object encoding and is somewhat similar to what I wanted to achieve.

If I can't come up with anything for that I might just merge this as it is for now, as I definitely have this use case (and have also had it in the past) and haven't personally encountered cases for those other encodings yet. 😉

@m-bock
Copy link
Contributor

m-bock commented Oct 16, 2025

I might just merge this as it is for now

go for it :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants