-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Customize encode/decode of variants with arguments #35
Comments
Not sure I understand correctly, If you mean this: {
"files": [{"type": "file", "size": 1}, ... ]
} decoded to the variant with arguement? |
Yeah, maybe it's clearer to split it into two topics: The first topic is about customized encode/decode, as the title suggests. For example: type file = { size: int }
type directory = { ... } // ignore it for now
type item = File(file) | Directory(directory)
@spice
type payload = {
item: item
}
let payload = {
item: File({ size: 1 })
} will be encoded to: {
item: ["File", { size: 0 }]
} While the desired result is: {
item: {
type: "file"
size: 0
}
} |
The second topic is about recursively decoding, for example, |
Did you write a custom codecs for (d)encode? Can you share your codecs? |
Spent some time to try the custom codecs, got errors: module Meta = {
@spice.codec(codecT)
type rec t = File(string, file) | Directory(string, directory)
@spice and file = {size: int}
@spice and directory = {files: array<t>}
let encoderT = t => {
// ignore it for now
Js.Json.parseExn("")
}
let decoderT = json => {
switch json->Js.Json.classify {
| Js.Json.JSONObject(obj) => {
let path = obj->Js.Dict.get("path")->Option.flatMap(Js.Json.decodeString)->Option.getExn
let type_ = obj->Js.Dict.get("type")->Option.flatMap(Js.Json.decodeString)->Option.getExn
switch type_ {
| "file" => File(path, json->file_decode->Result.getExn)->Ok
| "directory" => Directory(path, json->directory_decode->Result.getExn)->Ok
| _ => assert false
}
}
| _ => assert false
}
}
let codecT: Spice.codec<t> = (encoderT, decoderT)
} JSON Examples: {
type: "directory",
path: "/directory",
files: [
{
type: "file",
path: "/file-1",
size: 1
},
{
type: "file",
path: "/file-2",
size: 2
},
]
} |
c@pd4d10 Isn't there another parent-level field of JSON example? If it does, such as "data" in module Meta = {
@spice
type rec t = File(string, file) | Directory(string, directory)
@spice and file = {size: int}
@spice and directory = {files: array<t>}
let encoderT = t => {
// ignore it for now
let _ = t
Js.Json.parseExn("")
}
let decoderT = json => {
switch json->Js.Json.classify {
| Js.Json.JSONObject(obj) => {
let path = obj->Js.Dict.get("path")->Option.flatMap(Js.Json.decodeString)->Option.getExn
let type_ = obj->Js.Dict.get("type")->Option.flatMap(Js.Json.decodeString)->Option.getExn
switch type_ {
| "file" => File(path, json->file_decode->Result.getExn)->Ok
| "directory" => Directory(path, json->directory_decode->Result.getExn)->Ok
| _ => assert false
}
}
| _ => assert false
}
}
let codecT: Spice.codec<t> = (encoderT, decoderT)
@spice
type data = {data: @spice.codec(codecT) t}
} |
I think it is a recursive reference issue between type definition and value binding. |
Unfortunately, there isn't
Get it. It seems to be a language limitation that the |
I don't know about the required spec, but maybe it is a matter of data modeling. Maybe we can model the data as: @spice
type type_ = @spice.as("file") File | @spice.as("directory") Directory
@spice
type file = {size: int}
@spice
type directory = array<file>
@spice
type t = {
@spice.key("type") type_,
path: string,
files?: directory,
file?: file
} |
Hi, thanks for the work! Saves a lot of boilerplate code.
In my case, there is a little problem that the JSON's structure is more like this (described as TypeScript):
The
type
key indicates the variant type, and the other fields are treated as arguments.While the default encode/decode strategy is to convert to an array, as this example shows:
ppx_spice/examples/src/Variants2.res
Line 19 in eab7239
Is it possible to support this pattern?
The text was updated successfully, but these errors were encountered: