-
Notifications
You must be signed in to change notification settings - Fork 110
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
Unify macro attributes between serialization and deserialization derive macros #1119
Unify macro attributes between serialization and deserialization derive macros #1119
Conversation
|
a504b58
to
3711afc
Compare
b6a7b6d
to
d9e0c6b
Compare
Rebased on main after #1117 was merged. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I stopped review at: macros: SerializeValue supports #[allow_missing]
. Will continue later.
Also a small request: could you please add missing comments for fields of Attributes
and FieldAttributes
? I remembered what each attribute is responsible for when I reviewed your PR for deserialization macros. I managed to forget it since then, thus such comments would be helpful during review.
This unifies the name of the attribute across SerializeValue and DeserializeValue. `forbid_excess_udt_fields` is arguably a better name for what it does than `force_exact_match`.
607cc78
to
7d4d91d
Compare
Rebased on main. |
They are taken from DeserializeValue.
They are taken from DeserializeRow.
Instead of taking `enforce_order` as boolean flag, DeserializeValue now takes a string (e.g., `flavor = "enforce_order"`) and converts it to a variant of the Flavor enum. This way DeserializeValue is unified with SerializeValue wrt flavor selection.
Instead of taking `enforce_order` as boolean flag, DeserializeRow now takes a string (e.g., `flavor = "enforce_order"`) and converts it to a variant of the Flavor enum. This way DeserializeRow is unified with SerializeRow wrt flavor selection.
The `#[allow_missing]` attibute is intented to allow a flexible transition period when schema is altered. Namely, if a UDT is extended with a new field and the transition begins with migrating clients to the new schema (extending the Rust struct with a new field), then server may still have the old schema and provide metadata that is missing the new field. In such case, `#[allow_missing]` can be attached to the new Rust struct's field and this way handle the situation: - in deserialization, the field missing from DB metadata will be default-initialized, - in serialization, such a field will be ignored and not serialized. This commit adds support for this attribute: for parsing it using `darling`, and for its semantics in both `match_by_name` and `enforce_order` flavors. Also, corresponding (doc)tests for attribute sanity verification are added, fully based on those from DeserializeValue.
The `#[default_when_null]` attibute is intented to allow a flexible transition period when schema is altered. Namely, if a UDT is extended with a new field, then server will populate the new column with NULLs. If the data model does not abstractly permit NULLs in that column, one may not want to represent the field with `Option<T>`, not to have to handle the case of `None`. In such case, `#[default_when_null]` can be attached to the new Rust struct's field and this way handle the situation: - in deserialization, the NULL field received from the DB will be default-initialized, - in serialization, there is no corresponding situation, so this attribute does nothing. This commit adds support for this attribute: for parsing it using `darling`, and that's it - because it's a no-op. Also, a corresponding (doc)test is added to confirm that the attibute is parsed correctly.
As those macros are complex and feature many switches and flavors, tests are added that verify that when a UDT struct is derived both SerializeValue and DeserializeValue: - attributes are parsed correctly and trait impls are generated without errors, - after serialization and deserialization, the result is what is expected.
Even though these macros are less complex and feature fewer switches and flavors than their {Ser,De}Value counterparts, tests are added that verify that when a row struct is derived both SerializeRow and DeserializeRow: - attributes are parsed correctly and trait impls are generated without errors, - after serialization and deserialization, the result is what is expected.
Also, no longer mention the limitations of old derive macros. The new macros have no limitations compared to Serialize macros.
Some comments were missing, so I imported them from DeserializeValue.
7d4d91d
to
0c9a8cc
Compare
Addressed @muzarski comments:
|
Motivation
When deserialization macros were introduced in #1024, their attributes differed in naming and usage from those introduced in #851 for serialization derive macros.
This PR aims to unify attributes between
SerializeValue
andDeserializeValue
, and betweenSerializeRow
andDeserializeRow
, so that both traits can be derived for a struct without a clash in attribute parsing.Fixes: #462
FINALLY!
What's done
SerializeValue
:force_exact_match
->forbid_excess_udt_fields
(attribute renamed for consistency withDeserializeValue
);Flavor
is shared between serialization and deserialization derive macros, and both have the same syntax for choosing the flavor:flavor = "enforce_order"
;allow_missing
is supported forSerializeValue
, as it is inDeserializeValue
;default_when_null
is parsed and ignored inSerializeValue
, as it's a no-op for serialization (it's only useful for deserialization, as it says: "If I got NULL for a non-Option Rust field, let's fill it with Default::default()"; currently, it would cause a parse error inSerializeValue
.Deserialize{Value,Row}
) for sanity verification of provided attributes.Pre-review checklist
./docs/source/
.[ ] I added appropriateFixes:
annotations to PR description.