Closed lontivero closed 1 year ago
The decoder that you propose is too specialised to be inside of Thoth.Json. At least, in the current form.
The decoder is called expect
but only works with string
type where expect
implied that you expect a particular value which could be string, int, object, etc.
You can avoid the use of oneOf
in your decoder by using:
Decode.index 0 Decode.string
|> Decode.andThen (function
| "EVENT" ->
// ...
| "OK" ->
// ...
| unknown ->
sprintf "'%s' is not a supported type for ReplayMessage" unknown
|> Decode.fail
)
Full example code:
type SubscriptionId = SubscriptionId of string
module SubscriptionId =
let decoder : Decoder<SubscriptionId> =
Decode.string
|> Decode.map SubscriptionId
type EventId = EventId of string
module EventId =
let decoder : Decoder<EventId> =
Decode.string
|> Decode.map EventId
type RelayMessage =
| RMEvent of SubscriptionId * int
| RMACK of EventId * bool * string
module ReplayMessage =
let decoder : Decoder<RelayMessage> =
Decode.index 0 Decode.string
|> Decode.andThen (function
| "EVENT" ->
// You can move this decoder in its own function to make the code more readable
Decode.map2
(fun subId value ->
RMEvent (subId, value)
)
(Decode.index 1 SubscriptionId.decoder)
(Decode.index 2 Decode.int)
| "OK" ->
// You can move this decoder in its own function to make the code more readable
Decode.map3
(fun eventId isSuccess message ->
RMACK (eventId, isSuccess, message)
)
(Decode.index 1 EventId.decoder)
(Decode.index 2 Decode.bool)
(Decode.index 3 Decode.string)
| unknown ->
sprintf "'%s' is not a supported type for ReplayMessage" unknown
|> Decode.fail
)
I see. It is completely unnecessary.
Thank you very much for the code, I will do as you say.
In some situations it could be convenient to have a early circuit shortener to use in combination with
oneOf
. For example, the Nostr protocol serializes messages as arrays, here an example:In this case it is the first element ~is~ the one that indicates the type of message and how it should be deserialized so, the
oneOf
decoder can be used but we want to stop immediately if the first element doesn't match. My proposal is to have a decoder like the following:I've used it here: https://github.com/lontivero/Nostra/blob/5c76df4ca8aa18022e4f84202693146aa53438fc/Nostra.Core/Client.fs#L182-L205
Please if this is not the best way to do it I would appreciate your advice. Thanks for the library, it is really really cool.