Add Decode.listLength, Decode.arrayLength
Closed this issue · 5 comments
When you are storing varying elements in an array, it would be nicer if we can also discriminate using their length, So subsequently you could use Decode.andThen
followed by sets of valid Decode.index
patterns.
Hello @Swoorup,
To be sure, I understand could you please provide an example (JSON + F# code) of what you are trying to do?
Don't have an F# code at the moment but for example.
You could store notes as an array instead of object for compression.
[
[1, "first note", "2016-08-14 15:34:32Z", ... more properties],
[2, "second note", "2016-08-14 16:03:12Z", ... more properties],
[1, "delete"]
]
Here the third is actually a command to delete the first note identified by its length of 2.
Which roughly translate to
type Note =
| Note of id: int * string * DateTime
| DeleteCommand of id: int
This should work, although there may be potential for efficiency gains by not decoding the whole list:
module Decode =
let listLength : Decoder<int> =
Decode.list Decode.value
|> Decode.map List.length
But perhaps this is better?
module Decode =
let note : Decoder<Note> =
Decode.oneOf
[
Decode.tuple3 Decode.int Decode.string Decode.datetime
|> Decode.map Note
Decode.index 0 Decode.int
|> Decode.map DeleteCommand
]
Note that order of the oneOf
elements is significant here, since a valid Note
can also decode as a valid DeleteCommand
@njlr I am using this for now, I got it from somewhere in the source code which was doing something similar.
let arrayLength: Decoder<int> =
fun path value ->
if Decode.Helpers.isArray value then
let vArray = Decode.Helpers.asArray value
Ok vArray.Length
else
(path, BadPrimitive("an array", value)) |> Error
I am closing this issue because I think this is a specific use case.
If more people show interest in it, I will reconsider including it in the core library.
Another solution is to create a packages or gist to extends Thoth.Json and make it available to others.