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

Relax oneof set fields validation #43

Merged
merged 4 commits into from
Apr 13, 2022
Merged

Conversation

adriansmares
Copy link
Contributor

@adriansmares adriansmares commented Mar 28, 2022

Summary

References TheThingsNetwork/lorawan-stack#5326

Changes

  • Do not check if the source or destination oneof fields have the correct type, but instead behave as if they are nil on mismatch.
    • Note that this is allowed only if no subfields are provided

Notes for Reviewers

This is motivated by the ADR settings PR. Before this PR, it would be impossible to change the oneof field without clearing the field in between uses. This 'clear' operation (setting to nil) was required because the generated code would complain that the source and the destination oneof type are mismatching.

The effect on TTS can be seen at TheThingsNetwork/lorawan-stack@453b835

@adriansmares adriansmares added this to the 2022 Q1 milestone Mar 28, 2022
@adriansmares adriansmares self-assigned this Mar 28, 2022
@@ -70,11 +62,19 @@ if !dstOk && dst.%s != nil {
fPath = m.ctx.Name(f.OneOf()).String()
}

buildIndented(buf, tabCount, fmt.Sprintf(`if src != nil {
if f.InOneOf() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to check if the source type actually matches, not only that it is present.

newDst = &%s{}
dst.%s = &%s{%s: newDst}
} else {
Copy link
Contributor Author

@adriansmares adriansmares Mar 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point !srcTypeOk && !dstTypeOk (which is the original check) - we empty the destination in order to make sure that it matches the source.

@adriansmares adriansmares force-pushed the feature/relax-oneof branch 2 times, most recently from e2ffa70 to e06448e Compare March 28, 2022 16:48
Copy link
Contributor

@htdvisser htdvisser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not completely sure about this one. If I want to change the type of the oneof, I should replace the entire thing. Changing a subfield of the wrong "branch" should result in an error. Replacing the thing should only happen if the field mask contains (exactly) the oneof field itself, or (exactly) one of its "branches".

@adriansmares
Copy link
Contributor Author

adriansmares commented Apr 11, 2022

Just to make sure that I understood this: partial patches (so the ones which do have subfields) should require that the source and destination types match, but full replaces may change the type freely ?

I understand the reasoning to a certain extent but keep in mind that the client does not know what is stored on the server side - It is hard to know when I need to do a replace and when I need to do a patch as a client, so requiring that I use the top level field complicates things. We require that the client fully retrieves the entity before the update if we require that the top level field is used, which is inconsistent with the rest of the API design.

Note that this PR does not allow you to provide two oneof branches at once - that one is still banned - you cannot give both oneof_field.oneof_branch_a and oneof_field.oneof_branch_b at the same time for an update.

@htdvisser
Copy link
Contributor

htdvisser commented Apr 11, 2022

Just to make sure that I understood this: partial patches (so the ones which do have subfields) should require that the source and destination types match, but full replaces may change the type freely?

Exactly. And to give a clear example, let's look at the ApplicationPubSub message. If the stored PubSub has nats in the provider oneof, I should not be able to set only the mqtt.password. Instead, I need to replace the entire provider by setting the entire mqtt object, so that we can also validate the entire thing.

keep in mind that the client does not know what is stored on the server side

I think it's not unreasonable to expect that clients know the state of the entity (or at least the relevant fields) before they can make changes to those fields.

@NicolasMrad NicolasMrad modified the milestones: 2022 Q1, 2022 Q2 Apr 12, 2022
@adriansmares adriansmares requested a review from htdvisser April 12, 2022 11:23
@adriansmares
Copy link
Contributor Author

I've implemented the requested change and added two test cases that should cover this.

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