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

Allow manually specifying nil on input objects #8

Merged
merged 1 commit into from
Aug 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions codegen/lib/graphql_swift_gen/templates/type.swift.erb
Original file line number Diff line number Diff line change
Expand Up @@ -210,33 +210,54 @@ extension <%= schema_name %> {
}
<% when 'INPUT_OBJECT' %>
open class <%= type.name %> {
<% type.input_fields.each do |field| %>
<% type.required_input_fields.each do |field| %>
open var <%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %>
<% end %>
<% type.optional_input_fields.each do |field| %>
open var <%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %> {
didSet {
<%= escape_reserved_word(field.camelize_name) %>Seen = true
}
}
private var <%= escape_reserved_word(field.camelize_name) %>Seen: Bool = false
<% end %>

public init(
<% input_fields = type.required_input_fields + type.optional_input_fields %>
<% input_fields = type.required_input_fields + type.optional_input_fields # manually ordered with required fields first %>
<% input_fields.each do |field| %>
<% default = field.type.non_null? ? "" : " = nil" %>
<% seperator = field == input_fields.last ? "" : "," %>
<%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %><%= default %><%= seperator %>
<% if field.type.non_null? %>
<%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %><%= seperator %>
<% else %>
<%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %>? = nil<%= seperator %>
<% end %>
<% end %>
) {
<% type.input_fields.each do |field| %>
<% type.required_input_fields.each do |field| %>
self.<%= escape_reserved_word(field.camelize_name) %> = <%= escape_reserved_word(field.camelize_name) %>
<% end %>
<% type.optional_input_fields.each do |field| %>
<% field_name = escape_reserved_word(field.camelize_name) %>
if let <%= field_name %> = <%= field_name %> {
self.<%= field_name %>Seen = true
self.<%= field_name %> = <%= field_name %>
}
<% end %>
}

func serialize() -> String {
var fields: [String] = []
<% type.input_fields.each do |field| %>
<% unless field.type.non_null? %>
<% type.required_input_fields.each do |field| %>
fields.append("<%= field.name %>:<%= generate_build_input_code(field.camelize_name, field.type.unwrap_non_null) %>")
<% end %>
<% type.optional_input_fields.each do |field| %>
if <%= escape_reserved_word(field.camelize_name) %>Seen {
if let <%= escape_reserved_word(field.camelize_name) %> = <%= escape_reserved_word(field.camelize_name) %> {
<% end %>
fields.append("<%= field.name %>:<%= generate_build_input_code(field.camelize_name, field.type.unwrap_non_null) %>")
<% unless field.type.non_null? %>
} else {
fields.append("<%= field.name %>:null")
}
<% end %>
}
<% end %>
return "{\(fields.joined(separator: ","))}"
}
Expand Down
18 changes: 18 additions & 0 deletions support/Tests/GraphQLSupportTests/IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ class IntegrationTests: XCTestCase {
XCTAssertEqual(queryString, "mutation{set_integer(input:{key:\"answer\",value:42,negate:true})}")
}

func testInputObjectExplictNilConstructor() {
let query = Generated.buildMutation { $0
.setInteger(input: Generated.SetIntegerInput(key: "answer", value: 42, negate: .some(nil)))
Copy link
Contributor

@raulriera raulriera Aug 2, 2017

Choose a reason for hiding this comment

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

This needs .none instead of .some

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so? I need a way to distinguish between an optional argument being set to it's default value (which is nil) and the user trying to tell me they want a property to be nil, hence the .some(nil)

Because it unwraps to nil, I can try to unwrap each of the optional arguments and then just use the value inside if it's there as the property's value

Copy link
Contributor

Choose a reason for hiding this comment

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

Optional.none is an optional with nil, Optional.some(nil) is saying that the optional has a value, but when you unwrap it is nil. That would be making it a double optional like your description Optional(Optional(value))

var a: String? = .none
print(a)

var b: String?? = ""
print(b)

// output
nil
Optional(Optional(""))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I want something that you unwrap to nil. The problem is distinguishing between: foo(optinal: nil) and foo() which I can't do at a language level because within foo, optional will have a value of nil regardless of whether the caller provided the nil explicitly or not.

}
let queryString = String(describing: query)
XCTAssertEqual(queryString, "mutation{set_integer(input:{key:\"answer\",value:42,negate:null})}")
}

func testInputObjectExplictNilSetLater() {
let input = Generated.SetIntegerInput(key: "answer", value: 42)
input.negate = nil
let query = Generated.buildMutation { $0
.setInteger(input: input)
}
let queryString = String(describing: query)
XCTAssertEqual(queryString, "mutation{set_integer(input:{key:\"answer\",value:42,negate:null})}")
}

func testScalarInput() {
let ttl = date(year: 2017, month: 1, day: 31, hour: 10, minute: 9, second: 48)
let query = Generated.buildMutation { $0
Expand Down