-
Notifications
You must be signed in to change notification settings - Fork 27
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
Make explicit NULL easy – and break less API #12
Conversation
…ing serialized if explicitly called
Given that swift supports unicode in function and variable names, I humbly suggest that |
It seems like the API is kind of confusing with If sending an explicit |
Change {field name}Seen => serialize{field name} Expose serialize{field name} publicly
9e678b7
to
bbc43a0
Compare
Updated the description about the new proposal. Can I get a rereview? |
self.<%= field_name %> = <%= field_name %> | ||
self.serialize<%= escape_reserved_word(field.classify_name) %> = true |
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.
Doesn't the self.<%= field_name %> = <%= field_name %>
line already set the serialize value to true
in the properties didSet
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.
No, didSet
observers arent triggered in initializers
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.
Some questions about what the hell is going on because I'm not too familiar with erb syntax. I like the change from propertySeen
to serializeProperty
- makes the intent much clearer.
<% else %> | ||
<%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %>? = nil<%= seperator %> | ||
<%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %> = nil, | ||
serialize<%= escape_reserved_word(field.classify_name) %>: Bool = false<%= seperator %> |
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.
Spelling: separator
@@ -214,36 +214,41 @@ extension <%= schema_name %> { | |||
<% when 'INPUT_OBJECT' %> | |||
open class <%= type.name %> { | |||
<% type.required_input_fields.each do |field| %> |
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.
What determines the set of required vs optional fields?
Do I understand correctly that optional
means "field can be omitted from the mutation" rather than "field value is nullable", and that required
means "field must be present in the mutation, whether it's nullable or not"?
If that's correct, isn't the change below this forcing all required
fields to be non-nullable as well?
Would love some code documentation around this to clarify the implications.
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.
The GraphQL schema doesn't distinguish between "field can be omitted from the mutation" rather than "field value is nullable". The name optional
used to be more appropriate before graphql allowed a null
input value to be specified. So required
actually means the field is non-null in schema and optional
that it isn't non-null in the schema. So it is correct for a required
field to also no be nullable.
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.
In GraphQL there is no distinction between "the field can be omitted from the mutation" and "the field value is nullable". They are one and the same (in the type system) so there is no way we can tell the difference.
In practice you have fields that are implicitly required but in GraphQL are specified as nullable (not very nice right?). For example in a ProductInput the title
property is nullable in GraphQL but if you tried to update a product with a null title we would send you a userError
.
And yes the change below is forcing all required fields to be non nullable because if you make a mutation without a required field the mutation will always fail.
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 replied saying the same thing as Dylan 😂
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.
For example in a ProductInput the title property is nullable in GraphQL but if you tried to update a product with a null title we would send you a userError.
What about update mutations that omit the title
field altogether? I thought that was allowed, and was what we wanted, so that we wouldn't overwrite fields that we didn't modify ourselves but that might have been changed by another mutation.
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.
That is still possible with this PR. If you want to omit the title field all together you can do it multiple ways.
// init with nil
let input1 = inputType(id: 1, title: nil)
print(input1.serialize) // { id: 1 }
// ☝️ this is because the default value for serializeTitle is false
// init with value but set serialize to false
let input2 = inputType(id: 2, title: "Great thing", serializeTitle: false)
print(input2.serialize) // { id: 2 }
// init with value but set serialize to false later
let input3 = inputType(id: 3, title: "Great thing")
input3.serializeTitle = false
print(input3.serialize) // { id: 3 }
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 thought title
was a required field, and so wasn't generating serializeTitle
at all? 😕
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.
Sorry in the example I was treating title
as a non required field. If Title were a required field it would have to be sent to the server.
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.
OK, after an in-person discussion with @BenEmdon I have a better handle on the rules now:
-
optional fields are nillable and expose
serialize{Field}
. -
required fields are non-nil and do not expose
serialize{Field}
. -
fields can only be required on Input objects that are creation-only.
e.g.FulfillmentInput
-
Input objects that are used for both creation and update need all their fields marked as optional so that we can express minimal changesets.
e.g.ProductInput
-
If a creation mutation omits a field which is optional, but which is implicitly required for creation, the mutation will fail with a user error.
e.g. trying to create a product with aProductInput
that has notitle
-
If an update mutation omits a field which is optional, but which is implicitly required for update, then the mutation will also fail with a user error (even though this is really a programmer error.)
e.g. trying to edit an existing product with aProductInput
that has noid
(This example will be solved once we refactor update mutations to passid
as a separate parameter instead of making it part of the Input object.)
Perhaps we should check the generated code into git as we do in the java gem Shopify/graphql_java_gen#17, since it can sometimes be easier to review the generated code. |
I totally agree. Do we currently have a way of doing that for the swift repo? |
Update:I am going to talk to @dbart01 this afternoon and see how we align on the API |
Closing this in favor of #15 |
This PR
The mirror of Shopify/graphql_java_gen#29
In this PR I am adding a way to unset properties so that they aren't serialized. This change is required because currently there is no way to tell a property to not serialize.This is aimed to help consumers of this generator that were effected by the change #8 that used to reset their input types with
inputType.property = null
so that they can useinputType.unsetProperty()
instead.This PR has pivoted to be about making #8 cause less API breakage.
adds a publicunset{property name}
methodThe new input type looks like this