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

Add special handling for dates behind feature flag #55

Closed
wants to merge 2 commits into from

Conversation

ranile
Copy link

@ranile ranile commented Aug 31, 2023

This PR adds special handling for Dates. All Date objects are deserialized to ISO timestamp strings, prefixed with $::date:. When serializing back to JsValue, strings with that prefix are converted to Date objects.

Currently, Date are deserialized to {}, which is useless. It also silently breaks any expectations that the application may have about the values. This PR introduces a work around for this problem.

This approach is inspired by serde_json, which also uses a special token to encode information about deserialization

Also see #54

@RReverser
Copy link
Owner

Adding special handling for some JS types seems like slippery slope as, once it begins, we might start having to add it for all the other objects that are not representable in serialization (e.g. someone might want RegExp or other types for similar reasons).

Instead, I just merged the long-standing PR that allows to preserve JS values as-is: #40

Could you try it out via

serde-wasm-bindgen = { git = "https://github.com/cloudflare/serde-wasm-bindgen/" }

in your project? It should allow you to preserve a field like

#[derive(Deserialize)]
struct MyStruct {
  #[serde(with = "serde_wasm_bindgen::preserve")]
  date: js_sys::Date,
}

so that after deserializing you can extract and convert dates to whatever you wish.

Let me know how that goes.

@ranile
Copy link
Author

ranile commented Sep 4, 2023

I agree with it being a slippery slope to special case types. But I can't see how else I would handle this situation. If you look at the linked PR, my goal is deserialize the JS object into a serde_json::Value so I can diff it against another object using the json-patch crate. How would that work if I'm deserializing into something like serde_json::Value?

@RReverser
Copy link
Owner

Using the provided "preserve value" functionality, you can create your own function for the serde(deserialize_with = "...") attribute. Your function will call serde_wasm_bindgen::preserve::deserialize and convert the resulting Date to string, object, or whatever is most comfortable for your final representation.

Such function should be relatively straightforward to implement by looking at other deserialize_with Serde examples, but let me know if you run into difficulties.

@ranile
Copy link
Author

ranile commented Sep 4, 2023

Right, I know I can use deserialize_with but it's a problem if I don't control the type, as is the case with serde_json::Value

@RReverser
Copy link
Owner

Ah yeah, you'll need a custom type. OTOH for your particular usecase - if you need serde_json::Value specifically instead of some custom structure for diffing - maybe it's easier to stick with JSON.stringify + serde-json.

@ranile
Copy link
Author

ranile commented Sep 4, 2023

That has the problem of not being able to be converted back to Date. The function takes the inputs, processes it and returns the output. Input has a field in the object that contains a Date. When that field is returned in the output, it is no longer a Date but a string.

That prevents me from being able to use JSON.stringify with serde_json. After processing the date field is the same as any other string and is handled that way. The serializer has no idea it's supposed to convert that string to a date

@RReverser
Copy link
Owner

RReverser commented Sep 4, 2023

That has the problem of not being able to be converted back to Date.

That does give you more flexibility via JSON.parse / JSON.stringify replacer functions. They allow to intercept and convert any types during serialization / deserialization, so you could recognise that special date prefix as you did in this PR but from the JS side.

@RReverser
Copy link
Owner

What I mean is that on the Rust side you can still send $::date:2023-... and then in a JS snippet you'd do

JSON.parse(s, (k, v) => typeof v === 'string' && v.startsWith('$::date:') ? new Date(v.slice(8)) : v)

@RReverser
Copy link
Owner

I'm probably going to close this, sorry. I'm happy to help or discuss other approaches, but for reasons mentioned above not very comfortable with special-casing Date in particular.

@RReverser RReverser closed this Sep 5, 2023
ranile added a commit to formbird/json-patcher that referenced this pull request Sep 26, 2023
Implement suggestions from RReverser/serde-wasm-bindgen#55 of using `replacer` and `reviver` functions in `JSON.parse` and `JSON.stringify`.


* pass args to wasm as JSON strings

* clean up a little

* use serde_json for node as well
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

Successfully merging this pull request may close these issues.

3 participants