Closed thomashoneyman closed 2 years ago
I also frequently want to work with a map that has some type as the key that can be serialized to a string, so it should be represented in JSON as an object, which would perhaps work out to something like this:
strMap :: forall k a. Ord k => String -> (String -> Maybe k) -> (k -> String) -> JsonCodec a -> JsonCodec (Map.Map k a)
strMap ty parse print valueCodec = Codec.basicCodec decode encode
where
encode :: Map k a -> Json
encode m = Codec.encode CA.jobject $ Object.runST do
obj <- Object.ST.new
forWithIndex_ m \k v -> Object.ST.poke (print k) (Codec.encode valueCodec v) obj
pure obj
decode :: Json -> Either CA.JsonDecodeError (Map k a)
decode json = do
array :: Array _ <- Object.toUnfoldable <$> Codec.decode CA.jobject json
parsed <- array # traverse \(Tuple k v) -> do
key <- note (CA.Named k (CA.TypeMismatch ty)) (parse k)
val <- lmap (CA.AtKey k) (Codec.decode valueCodec v)
pure $ Tuple key val
pure $ Map.fromFoldable parsed
unless there's a reasonable way to convert a JsonCodec (Map String a)
to a JsonCodec (Map k a)
?
I thought I was onto something for this that would be more flexible and handle both cases here as well as foreign objects.
The general idea being:
Map
and Object
) - this KVCodec
type would be similar to the existing JPropCodec
but needs a little more flexibility, it would probably replace JPropCodec
for the existing usages also.KVCodec
so you could handle the non-String
-key Map
case you outlined above, where they can still be represented as String
sKVCodec
that dictate the final JSON representation (object being restricted to accepting KVCodec String a
, list of tuples would accommodate KVCodec k a
in general)But I'm not quite satisfied with it yet. If I can't get it figured out tonight I'll just merge this 🙂
No rush! I'm using this strMap
implementation in a codebase for now, but I'll tear it out if we come up with something nicer.
I regularly need to encode a
Map String a
(or, equivalently,Map k a
wherek
can be printed / parsed as a string). There's no easy way to do this right now besides converting to aForeign.Object
, but it's nice to skip the ceremony if I can simply convert the keys to/from strings as needed but retain a map structure.