-
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
Add flatten
attribute to derive SerializeRow
#1144
base: main
Are you sure you want to change the base?
Conversation
|
0de5bb0
to
dc2a19e
Compare
I apologize about the multiple force pushes yesterday, I was chewing on it yesterday a bit more since it wasn't reviewed yet and decided to move some stuff around to make it more clear that all the new structs are internal to the macro implementation only (by moving it to that sub-module). All that should be done by now. I have also started work on adding the flatten attribute for the |
I have finished the work to also support flattening when serializing with |
@wprzytula would you mind taking a look at this PR and tell me if you would like me to keep it as-is or add the flatten support to the |
Currently only the `match_by_name` flavor is supported. All the needed structs/traits to make this work are marked as `#[doc(hidden)]` to not increase the public API surface. Effort was done to not change any of the existing API.
this was causing a compile time error when trying to use it in my own project. Usure why there wasn't a compile time error in the test
c03bf5b
to
4184a7b
Compare
@Lorak-mmk , could you take a look and let me know if there are any concerns holding this PR? |
@nrxus We're sorry for poor responsivity on our side. We're busy with next year planning; we'll be able to look at your PR later. |
This is a significant but breaking change, so we most likely won't be able to attend to it before releasing 1.0. We are quite busy with other work :( |
Are you sure?
|
I made especially sure not to change any existing API, and to hide all of the new types/traits in the existing internal module to not increase the public API surface area other the new attribute. |
In such case, we will technically be able to release it in, say, 1.1, when we find time to review and accept this after we release 1.0. Does it sound OK to you, @nrxus ? |
Yep sounds good! I'll just keep pointing to my branch for now. I also have a branch to do this same support but when serializing with order enforced. Should I just merge it here so you all only have to review it as one complete feature? It'd make the overall size of the PR bigger which is why I had kept it separate |
IMO let's have it in a single PR, separate commits. |
I made a typo. I definitely meant that this is NOT a breaking change, and thus we will not prioritise the review before releasing 1.0. |
This is similar to the
flatten
attribute in serde.For now I've only added support when using
match_by_name
flavor, largely because that's the way I am using scylla. I'd assume that extending it to support theenforce_ordering
flavor would actually be easier but it might also need new traits similar to how I had to add some formatch_by_name
. Both the parent struct and the flattened struct need to bematch_by_name
, if the parent struct isn't then there is a clear compiler error, if the flattened struct isn't then there is also a compiler error but it'd be a little more opaque because it'd be produced by lack of implementation of a doc hidden trait. If this was ever extended toenforce_ordering
, then it will also work similarly that you cannot mix and match flavors when flattening.I have only added this attribute to
SerializeRow
because it was easier thanDeserializeRow
but I also want to add it to that macro in a future PR next chance I get to dig into this code. However, I have done enough digging to know that implementing this attribute onDeserializeRow
will require a breaking change in theDeserializeRow
trait. Realistically I doubt many people are manually implementing that trait so I don't think it'd actually be a breaking change in practice, but by semver rules alone it would be.All the new traits/structs/enums needed for this change are inside the
_macro_internal
subdmodule such that no new public API is exposed. Maybe in the future those could be made public but it felt too early to know if all the signatures were exactly how we wanted to expose them or not.For context, I am currently dealing with an issue that if I have different insert queries where one sets N columns and another one sets the same N and one extra, then I have two make two structs with N repeated fields. With this PR I'd be able to to instead flatten the struct with N fields inside the other struct to make my code more maintainable.
General Strategy
ser::row::ByName
A new internal-only type
ser::row::ByName
is added that wraps a struct that implements a new trait:SerializeRowByName
. This new type has a single functionser::row::ByName::serialize
and attempts to serialize an entireRowSerializationContext
, returning an error if any of the columns in the context were not serialized or do not belong to the struct. This is basically the implementation ofSerializeRow::serialize
for any struct that implementsSerializeRowByName
but split into its own internal-type so that the macro doesn't have to create this shared code. This couldn't be added as a default implementation in one of our traits because we need to call for some functions usingSelf
as a generic parameter which caused some compilation errors.SerializeRowByName
When deriving
SerializeRow
using thematch_by_name
flavor the struct will also implement a new internal-only trait:SerializeRowByName
. This trait has a single type associated typePartial
, and a functionpartial()
that creates it. The partial struct has 3 main parts:SerializeRowByName
such thatpartial()
can be called on it.The partial struct is required to implement a new trait
PartialSerializeRowByName
PartialSerializeRowByName
PartialSerializeRowByName
has two required functions:serialize_field
: takes the spec of a single column and attempts to serialize the corresponding field to it. If this column does not belong to this partial struct then the caller is told that the column is unused so that the caller can instead try to use a different field for this same column (i.e., when testing to see if any nested structs can serialize to that column). If the column is used, then a check is done to see if that column has completed the serialization of this field so that it can remove it out of itsmissing
set. The caller is informed if that column has finished the serialization of this partial struct or not.check_missing
: consumes the partial struct while checking if all the fields in this struct were serialized, returning an error if not. This is used insideser::row::ByName::serialize
to verify that the a struct has been fully serialized. If a field has not finished serializing and the field is a nested struct (i.e., not just a column) then we should get the error from the nested struct instead for better error messaging.To do this signaling, a new internal-only enum
ser::row::FieldStatus
was added that returns whether a column was used for the field, was used and completed the field, or was used by the field is still missing more columns.Pre-review checklist