Skip to content

Commit

Permalink
Fix parsing of nested arrays
Browse files Browse the repository at this point in the history
Fixes #43.
  • Loading branch information
martijnwalraven committed Jan 27, 2017
1 parent 92a00b8 commit 775285d
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 18 deletions.
2 changes: 2 additions & 0 deletions Apollo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@
9F295E301E27534800A24949 /* NormalizeQueryResults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NormalizeQueryResults.swift; sourceTree = "<group>"; };
9F295E341E2773D900A24949 /* SameHeroTwice.graphql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SameHeroTwice.graphql; sourceTree = "<group>"; };
9F295E371E277B2A00A24949 /* GraphQLResultNormalizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GraphQLResultNormalizer.swift; sourceTree = "<group>"; };
9F4352A61E3ACB1700FA1B11 /* Starship.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = Starship.graphql; sourceTree = "<group>"; };
9F5534731DDDF59400E54264 /* HeroParentTypeDependentField.graphql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HeroParentTypeDependentField.graphql; sourceTree = "<group>"; };
9F5534761DDDF5C700E54264 /* HeroTypeDependentAliasedField.graphql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HeroTypeDependentAliasedField.graphql; sourceTree = "<group>"; };
9F55347A1DE1DB2100E54264 /* ApolloStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloStore.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -322,6 +323,7 @@
9F5534731DDDF59400E54264 /* HeroParentTypeDependentField.graphql */,
9FF1F2351DB318250011DE94 /* CreateReviewForEpisode.graphql */,
9F20CBC11DAF03F900A139BB /* API.swift */,
9F4352A61E3ACB1700FA1B11 /* Starship.graphql */,
);
path = StarWars;
sourceTree = "<group>";
Expand Down
117 changes: 114 additions & 3 deletions Sources/GraphQLResultReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ public final class GraphQLResultReader {
return try resolve(field: field) { try parse(array: $0) }
}

public func list<T: JSONDecodable>(for field: Field) throws -> [[T]] {
return try resolve(field: field) { try parse(array: $0) }
}

public func list<T: JSONDecodable>(for field: Field) throws -> [[T?]] {
return try resolve(field: field) { try parse(array: $0) }
}

public func optionalList<T: JSONDecodable>(for field: Field) throws -> [T]? {
return try resolve(field: field) { try parse(array: $0) }
}
Expand All @@ -69,6 +77,14 @@ public final class GraphQLResultReader {
return try resolve(field: field) { try parse(array: $0) }
}

public func optionalList<T: JSONDecodable>(for field: Field) throws -> [[T]]? {
return try resolve(field: field) { try parse(array: $0) }
}

public func optionalList<T: JSONDecodable>(for field: Field) throws -> [[T?]]? {
return try resolve(field: field) { try parse(array: $0) }
}

public func list<T: GraphQLMappable>(for field: Field) throws -> [T] {
return try resolve(field: field) { try parse(array: $0) }
}
Expand All @@ -77,13 +93,30 @@ public final class GraphQLResultReader {
return try resolve(field: field) { try parse(array: $0) }
}

public func list<T: GraphQLMappable>(for field: Field) throws -> [[T]] {
return try resolve(field: field) { try parse(array: $0) }
}

public func list<T: GraphQLMappable>(for field: Field) throws -> [[T?]] {
return try resolve(field: field) { try parse(array: $0) }
}

public func optionalList<T: GraphQLMappable>(for field: Field) throws -> [T]? {
return try resolve(field: field) { try parse(array: $0) }
}

public func optionalList<T: GraphQLMappable>(for field: Field) throws -> [T?]? {
return try resolve(field: field) { try parse(array: $0) }
}

public func optionalList<T: GraphQLMappable>(for field: Field) throws -> [[T]]? {
return try resolve(field: field) { try parse(array: $0) }
}

public func optionalList<T: GraphQLMappable>(for field: Field) throws -> [[T?]]? {
return try resolve(field: field) { try parse(array: $0) }
}


// MARK: -

Expand Down Expand Up @@ -136,15 +169,41 @@ public final class GraphQLResultReader {
}

private func parse<T: JSONDecodable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [T]? {
return try optional(array).map { try parse(array: cast($0), elementType: elementType) }
return try optional(array).map {
try parse(array: cast($0), elementType: elementType)
}
}

private func parse<T: JSONDecodable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [T?]? {
return try optional(array).map { try parse(array: cast($0), elementType: elementType) }
return try optional(array).map {
try parse(array: cast($0), elementType: elementType)
}
}

private func parse<T: JSONDecodable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T]] {
return try parse(array: cast(required(array)), elementType: elementType)
}

private func parse<T: JSONDecodable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T?]] {
return try parse(array: cast(required(array)), elementType: elementType)
}

private func parse<T: JSONDecodable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T]]? {
return try optional(array).map {
return try parse(array: cast(required($0)), elementType: elementType)
}
}

private func parse<T: JSONDecodable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T?]]? {
return try optional(array).map {
return try parse(array: cast(required($0)), elementType: elementType)
}
}

private func parse<T: JSONDecodable>(array: [JSONValue], elementType: T.Type = T.self) throws -> [T] {
return try map(array: array) { try parse(value: $0, intoType: elementType) }
return try map(array: array) {
try parse(value: $0, intoType: elementType)
}
}

private func parse<T: JSONDecodable>(array: [JSONValue], elementType: T.Type = T.self) throws -> [T?] {
Expand All @@ -155,6 +214,22 @@ public final class GraphQLResultReader {
}
}

private func parse<T: JSONDecodable>(array: [JSONValue], elementType: T.Type = T.self) throws -> [[T]] {
return try map(array: array) {
try map(array: cast(required($0))) {
try parse(value: required($0), intoType: elementType)
}
}
}

private func parse<T: JSONDecodable>(array: [JSONValue], elementType: T.Type = T.self) throws -> [[T?]] {
return try map(array: array) {
try map(array: cast(required($0))) {
try parse(value: optional($0), intoType: elementType)
}
}
}

// MARK: Parsing object arrays

private func parse<T: GraphQLMappable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [T] {
Expand All @@ -173,6 +248,26 @@ public final class GraphQLResultReader {
return try optional(array).map { try parse(array: cast($0), elementType: elementType) }
}

private func parse<T: GraphQLMappable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T]] {
return try parse(array: cast(required(array)), elementType: elementType)
}

private func parse<T: GraphQLMappable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T?]] {
return try parse(array: cast(required(array)), elementType: elementType)
}

private func parse<T: GraphQLMappable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T]]? {
return try optional(array).map {
return try parse(array: cast(required($0)), elementType: elementType)
}
}

private func parse<T: GraphQLMappable>(array: JSONValue?, elementType: T.Type = T.self) throws -> [[T?]]? {
return try optional(array).map {
return try parse(array: cast(required($0)), elementType: elementType)
}
}

private func parse<T: GraphQLMappable>(array: [JSONObject], elementType: T.Type) throws -> [T] {
return try map(array: array) { try parse(object: $0, intoType: elementType) }
}
Expand All @@ -185,6 +280,22 @@ public final class GraphQLResultReader {
}
}

private func parse<T: GraphQLMappable>(array: [JSONObject], elementType: T.Type = T.self) throws -> [[T]] {
return try map(array: array) {
try map(array: cast(required($0))) {
try parse(object: required($0), intoType: elementType)
}
}
}

private func parse<T: GraphQLMappable>(array: [JSONObject], elementType: T.Type = T.self) throws -> [[T?]] {
return try map(array: array) {
try map(array: cast(required($0))) {
try parse(object: optional($0), intoType: elementType)
}
}
}

// MARK: Helpers

private func resolve<T>(field: Field, _ parse: (JSONValue?) throws -> T) throws -> T {
Expand Down
47 changes: 33 additions & 14 deletions Tests/ApolloTests/StarWars/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,12 @@ extension Episode: JSONDecodable, JSONEncodable {}
public struct ReviewInput: GraphQLMapConvertible {
public var graphQLMap: GraphQLMap

public init(stars: Int) {
graphQLMap = ["stars": stars]
}

public init(stars: Int, favoriteColor: ColorInput?) {
graphQLMap = ["stars": stars, "favoriteColor": favoriteColor]
}

public init(stars: Int, commentary: String?) {
graphQLMap = ["stars": stars, "commentary": commentary]
}

public init(stars: Int, commentary: String?, favoriteColor: ColorInput?) {
public init(stars: Int, commentary: String? = nil, favoriteColor: ColorInput? = nil) {
graphQLMap = ["stars": stars, "commentary": commentary, "favoriteColor": favoriteColor]
}
}

/// The input object sent when passing a color
/// The input object sent when passing in a color
public struct ColorInput: GraphQLMapConvertible {
public var graphQLMap: GraphQLMap

Expand Down Expand Up @@ -883,6 +871,37 @@ public final class SameHeroTwiceQuery: GraphQLQuery {
}
}

public final class StarshipQuery: GraphQLQuery {
public static let operationDefinition =
"query Starship {" +
" starship(id: 3000) {" +
" name" +
" coordinates" +
" }" +
"}"
public init() {
}

public struct Data: GraphQLMappable {
public let starship: Starship?

public init(reader: GraphQLResultReader) throws {
starship = try reader.optionalValue(for: Field(responseName: "starship", arguments: ["id": 3000]))
}

public struct Starship: GraphQLMappable {
public let __typename = "Starship"
public let name: String
public let coordinates: [[Double]]?

public init(reader: GraphQLResultReader) throws {
name = try reader.value(for: Field(responseName: "name"))
coordinates = try reader.optionalList(for: Field(responseName: "coordinates"))
}
}
}
}

public final class TwoHeroesQuery: GraphQLQuery {
public static let operationDefinition =
"query TwoHeroes {" +
Expand Down
6 changes: 6 additions & 0 deletions Tests/ApolloTests/StarWars/Starship.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
query Starship {
starship(id: 3000) {
name
coordinates
}
}
30 changes: 29 additions & 1 deletion Tests/ApolloTests/StarWars/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,34 @@
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "coordinates",
"description": "",
"args": [],
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
Expand Down Expand Up @@ -1145,7 +1173,7 @@
{
"kind": "INPUT_OBJECT",
"name": "ColorInput",
"description": "The input object sent when passing a color",
"description": "The input object sent when passing in a color",
"fields": null,
"inputFields": [
{
Expand Down
7 changes: 7 additions & 0 deletions Tests/ApolloTests/StarWarsServerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ class StarWarsServerTests: XCTestCase {
XCTAssertEqual(data.hero?.asHuman?.friends?.first??.asHuman?.height, 5.905512)
}
}

func testStarshipCoordinates() {
fetch(query: StarshipQuery()) { data in
XCTAssertEqual(data.starship?.coordinates?[0], [1, 2])
XCTAssertEqual(data.starship?.coordinates?[1], [3, 4])
}
}

// MARK: Mutations

Expand Down

0 comments on commit 775285d

Please sign in to comment.