Skip to content
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

Encode None to undefined?! #26

Open
strdr4605 opened this issue Sep 11, 2019 · 7 comments
Open

Encode None to undefined?! #26

strdr4605 opened this issue Sep 11, 2019 · 7 comments

Comments

@strdr4605
Copy link

strdr4605 commented Sep 11, 2019

I have 2 types:

[@decco]
type attachment = {
  title: string,
  text: string,
  pretext: string,
  color: string,
  fallback: string,
};

[@bs.deriving jsConverter]
[@decco]
type slack_command_response = {
  response_type: string,
  text: string,
  attachments: option(array(attachment))
};

and use them like:

let generateSlackJSONResponse = payload_record => {
  let response = {
    response_type: "ephemeral",
    text: "I process the command: " ++ payload_record.command,
    attachments: None,
  };
  slack_command_response_encode(response);
};

// ...

Axios.postData(
        payload_record.response_url,
        {
          slack_command_responseToJs(response);
        },
      )

Type attachment must have almost all fields optional. To not write everywhere field: None ... I want to use @bs.deriving abstract but as I understand I can't have dublicate @bs.deriving.
What should I do if need slack_command_responseToJs for Axios but also want optional fields?!

Update:

To fix first problem I used:

Axios.postData(
        payload_record.response_url,
-        {
-          slack_command_responseToJs(response);
-        },
+       slack_command_response_encode(response) |> Obj.magic,
      )

Also attachments: None, created a json field "attachments": null but I need to not be at all or "attachments": undefined

Is it possible to do it with ppx_decco?
Maybe some new attribute like [@decco.undefined] only for options

@decco] type mytype = {
    s: string,
    i: int,
    o: option(int),
    [@decco.undefined] u: option(int)
};

let encoded = mytype_encode({
    s: "hello",
    i: 12,
    o: None,
    u: None,
});

Js.log(Js.Json.stringifyWithSpace(encoded, 2));
/* {
     "s": "hello",
     "i": 12,
     "o": null,
     "u": undefined,
  } 
or
{
     "s": "hello",
     "i": 12,
     "o": null,
  } 
*/
@thangngoc89
Copy link

Undefined property will be removed in JSON so I don't think this is the desired behavior

@strdr4605
Copy link
Author

How about not including the key in JSON if it's None and prefixed with
[@decco.undefined] u: option(int) ?!

@ryb73
Copy link
Member

ryb73 commented Oct 2, 2019

This is a tricky one. Just omitting the key might make sense. For now, you could do something like this:

let encodeUndefined = (encoder, value) =>
    switch value {
        | None => [%bs.raw "undefined"]
        | Some(v) => encoder(v)
    };

let decodeUndefined = (decoder, json) =>
    (json !== [%bs.raw "undefined"])
        ? Decco.optionFromJson(decoder, json)
        : Ok(None);

[@decco] type mytype = {
    u: [@decco.codec (encodeUndefined, decodeUndefined)] option(int),
};

@strdr4605
Copy link
Author

Thank you, will try #26 (comment) in the near future.
Do you plan to add [@decco.undefined] as a new attribute?!
If no, can you still give me some hints on how to extend ppx_decco and implement [@decco.undefined] to not use [@decco.codec (encodeUndefined, decodeUndefined)] every time.
If yes,

can you still give ...

and I will try to make a pull request?!

@ryb73
Copy link
Member

ryb73 commented Oct 16, 2019

Hey @strdr4605- I don't plan on working on this in the foreseeable future, and considering there's a pretty reasonable workaround, I'm wary about adding new functionality to handle this case unless this issue gets more traction. However, if you'd like to give it a go anyway, my comment in #6 might be helpful.

@ryb73
Copy link
Member

ryb73 commented Oct 16, 2019

BTW, you maybe figured this out already, but if you don't want to repeat encodeUndefined and decodeUndefined everywhere, you can put them in your own module, say "MyCustomCodecs", along with let undefined = (encodeUndefined, decodeUndefined) and use [@decco.codec MyCustomCodecs.undefined] which would be a little more brief and would be about as convenient as using the proposed [@decco.undefined] feature.

@ryb73
Copy link
Member

ryb73 commented Oct 16, 2019

You could also do something like

[@decco]
type undefined('a) = [@decco.codec (encodeUndefined, decodeUndefined)] option('a);

and use the undefined type in place of option whenever you need a field that encodes to undefined

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

No branches or pull requests

3 participants