Skip to content

Explicit nulls on input types using InputValue wrapper #15

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

Merged
merged 2 commits into from
Sep 13, 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
29 changes: 20 additions & 9 deletions codegen/lib/graphql_swift_gen/templates/type.swift.erb
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,22 @@ extension <%= schema_name %> {
}
<% when 'INPUT_OBJECT' %>
open class <%= type.name %> {
<% type.input_fields.each do |field| %>
open var <%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type) %>
<% type.required_input_fields.each do |field| %>
open var <%= escape_reserved_word(field.camelize_name) %>: <%= swift_input_type(field.type, non_null: true) %>
<% end %>
<% type.optional_input_fields.each do |field| %>
open var <%= escape_reserved_word(field.camelize_name) %>: Input<<%= swift_input_type(field.type, non_null: true) %>>
<% end %>

public init(
<% input_fields = type.required_input_fields + type.optional_input_fields %>
<% 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, non_null: true) %><%= seperator %>
<% else %>
<%= escape_reserved_word(field.camelize_name) %>: Input<<%= swift_input_type(field.type, non_null: true) %>> = .undefined<%= seperator %>
<% end %>
<% end %>
) {
<% type.input_fields.each do |field| %>
Expand All @@ -232,14 +238,19 @@ extension <%= schema_name %> {

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| %>
switch <%= escape_reserved_word(field.camelize_name) %> {
case .value(let <%= escape_reserved_word(field.camelize_name) %>):
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 %>
case .undefined: break
}
<% end %>
return "{\(fields.joined(separator: ","))}"
}
Expand Down
15 changes: 15 additions & 0 deletions support/Sources/GraphQL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,21 @@ public struct SchemaViolationError: Error {
}
}

public enum Input<T> {
// Serialzeable value
case value(T?)
// Not serializable
case undefined

public init(orUndefined optional: Optional<T>) {
if let value = optional {
self = .value(value)
} else {
self = .undefined
}
}
}

extension GraphQL.Selection: Equatable {}
public func ==(lhs: GraphQL.Selection, rhs: GraphQL.Selection) -> Bool {
return (lhs === rhs) || (lhs.field == rhs.field && lhs.alias == rhs.alias && lhs.args == rhs.args && lhs.subfields == rhs.subfields)
Expand Down
36 changes: 12 additions & 24 deletions support/Tests/GraphQLSupportTests/Generated/SetIntegerInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,26 @@ extension Generated {

open var value: Int32

open var ttl: Date? {
didSet {
ttlSeen = true
}
}
private var ttlSeen: Bool = false
open var ttl: Input<Date>

open var negate: Bool? {
didSet {
negateSeen = true
}
}
private var negateSeen: Bool = false
open var negate: Input<Bool>

public init(
key: String,

value: Int32,

ttl: Date?? = nil,
ttl: Input<Date> = .undefined,

negate: Bool?? = nil
negate: Input<Bool> = .undefined
) {
self.key = key

self.value = value

if let ttl = ttl {
self.ttlSeen = true
self.ttl = ttl
}
self.ttl = ttl

if let negate = negate {
self.negateSeen = true
self.negate = negate
}
self.negate = negate
}

func serialize() -> String {
Expand All @@ -54,20 +38,24 @@ extension Generated {

fields.append("value:\(value)")

if ttlSeen {
switch ttl {
case .value(let ttl):
if let ttl = ttl {
fields.append("ttl:\(GraphQL.quoteString(input: "\(iso8601DateParser.string(from: ttl))"))")
} else {
fields.append("ttl:null")
}
case .undefined: break
}

if negateSeen {
switch negate {
case .value(let negate):
if let negate = negate {
fields.append("negate:\(negate)")
} else {
fields.append("negate:null")
}
case .undefined: break
}

return "{\(fields.joined(separator: ","))}"
Expand Down
38 changes: 36 additions & 2 deletions support/Tests/GraphQLSupportTests/IntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,50 @@ class IntegrationTests: XCTestCase {

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

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

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

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

func testInputObjectExplictNullSetLater() {
let input = Generated.SetIntegerInput(key: "answer", value: 42)
input.negate = .value(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
.setInteger(input: Generated.SetIntegerInput(key: "answer", value: 42, ttl: ttl))
.setInteger(input: Generated.SetIntegerInput(key: "answer", value: 42, ttl: .value(ttl)))
}
let queryString = String(describing: query)
XCTAssertEqual(queryString, "mutation{set_integer(input:{key:\"answer\",value:42,ttl:\"2017-01-31T10:09:48Z\"})}")
Expand Down