diff --git a/Sources/ApolloSQLite/SQLiteNormalizedCache.swift b/Sources/ApolloSQLite/SQLiteNormalizedCache.swift index 3f819152f7..1474b86578 100644 --- a/Sources/ApolloSQLite/SQLiteNormalizedCache.swift +++ b/Sources/ApolloSQLite/SQLiteNormalizedCache.swift @@ -33,11 +33,24 @@ public final class SQLiteNormalizedCache { } private func recordCacheKey(forFieldCacheKey fieldCacheKey: CacheKey) -> CacheKey { - var components = fieldCacheKey.components(separatedBy: ".") - if components.count > 1 { - components.removeLast() + let components = fieldCacheKey.components(separatedBy: ".") + var updatedComponents = [String]() + if components.first?.contains("_ROOT") == true { + for component in components { + if updatedComponents.last?.last?.isNumber ?? false && component.first?.isNumber ?? false { + updatedComponents[updatedComponents.count - 1].append(".\(component)") + } else { + updatedComponents.append(component) + } + } + } else { + updatedComponents = components + } + + if updatedComponents.count > 1 { + updatedComponents.removeLast() } - return components.joined(separator: ".") + return updatedComponents.joined(separator: ".") } private func createTableIfNeeded() throws { diff --git a/Tests/ApolloCacheDependentTests/LoadQueryFromStoreTests.swift b/Tests/ApolloCacheDependentTests/LoadQueryFromStoreTests.swift index b49b8b6c51..e6860233cf 100644 --- a/Tests/ApolloCacheDependentTests/LoadQueryFromStoreTests.swift +++ b/Tests/ApolloCacheDependentTests/LoadQueryFromStoreTests.swift @@ -319,7 +319,45 @@ class LoadQueryFromStoreTests: XCTestCase { } } } - + + + func testLoadingQueryWithFloats() throws { + let starshipLength = 1234.5 + let coordinates = [[38.857150, -94.798464]] + + let initialRecords: RecordSet = [ + "QUERY_ROOT": ["starshipCoordinates(coordinates:\(coordinates))": Reference(key: "starshipCoordinates(coordinates:\(coordinates))")], + "starshipCoordinates(coordinates:\(coordinates))": ["__typename": "Starship", + "name": "Millennium Falcon", + "length": starshipLength, + "coordinates": coordinates] + ] + + withCache(initialRecords: initialRecords) { (cache) in + store = ApolloStore(cache: cache) + + let query = StarshipCoordinatesQuery(coordinates: coordinates) + + load(query: query) { result in + switch result { + case .success(let graphQLResult): + XCTAssertNil(graphQLResult.errors) + + guard let data = graphQLResult.data else { + XCTFail("No data returned with result") + return + } + + XCTAssertEqual(data.starshipCoordinates?.name, "Millennium Falcon") + XCTAssertEqual(data.starshipCoordinates?.length, starshipLength) + XCTAssertEqual(data.starshipCoordinates?.coordinates, coordinates) + case .failure(let error): + XCTFail("Unexpected error: \(error)") + } + } + } + } + // MARK: - Helpers private func load(query: Query, resultHandler: @escaping GraphQLResultHandler) { diff --git a/Tests/StarWarsAPI/API.swift b/Tests/StarWarsAPI/API.swift index 432b9e9829..908ca35641 100644 --- a/Tests/StarWarsAPI/API.swift +++ b/Tests/StarWarsAPI/API.swift @@ -5548,6 +5548,121 @@ public final class StarshipQuery: GraphQLQuery { } } +public final class StarshipCoordinatesQuery: GraphQLQuery { + /// The raw GraphQL definition of this operation. + public let operationDefinition = + """ + query StarshipCoordinates($coordinates: [[Float!]!]) { + starshipCoordinates(coordinates: $coordinates) { + __typename + name + coordinates + length + } + } + """ + + public let operationName = "StarshipCoordinates" + + public let operationIdentifier: String? = "8dd77d4bc7494c184606da092a665a7c2ca3c2a3f14d3b23fa5e469e207b3406" + + public var coordinates: [[Double]]? + + public init(coordinates: [[Double]]?) { + self.coordinates = coordinates + } + + public var variables: GraphQLMap? { + return ["coordinates": coordinates] + } + + public struct Data: GraphQLSelectionSet { + public static let possibleTypes = ["Query"] + + public static let selections: [GraphQLSelection] = [ + GraphQLField("starshipCoordinates", arguments: ["coordinates": GraphQLVariable("coordinates")], type: .object(StarshipCoordinate.selections)), + ] + + public private(set) var resultMap: ResultMap + + public init(unsafeResultMap: ResultMap) { + self.resultMap = unsafeResultMap + } + + public init(starshipCoordinates: StarshipCoordinate? = nil) { + self.init(unsafeResultMap: ["__typename": "Query", "starshipCoordinates": starshipCoordinates.flatMap { (value: StarshipCoordinate) -> ResultMap in value.resultMap }]) + } + + public var starshipCoordinates: StarshipCoordinate? { + get { + return (resultMap["starshipCoordinates"] as? ResultMap).flatMap { StarshipCoordinate(unsafeResultMap: $0) } + } + set { + resultMap.updateValue(newValue?.resultMap, forKey: "starshipCoordinates") + } + } + + public struct StarshipCoordinate: GraphQLSelectionSet { + public static let possibleTypes = ["Starship"] + + public static let selections: [GraphQLSelection] = [ + GraphQLField("__typename", type: .nonNull(.scalar(String.self))), + GraphQLField("name", type: .nonNull(.scalar(String.self))), + GraphQLField("coordinates", type: .list(.nonNull(.list(.nonNull(.scalar(Double.self)))))), + GraphQLField("length", type: .scalar(Double.self)), + ] + + public private(set) var resultMap: ResultMap + + public init(unsafeResultMap: ResultMap) { + self.resultMap = unsafeResultMap + } + + public init(name: String, coordinates: [[Double]]? = nil, length: Double? = nil) { + self.init(unsafeResultMap: ["__typename": "Starship", "name": name, "coordinates": coordinates, "length": length]) + } + + public var __typename: String { + get { + return resultMap["__typename"]! as! String + } + set { + resultMap.updateValue(newValue, forKey: "__typename") + } + } + + /// The name of the starship + public var name: String { + get { + return resultMap["name"]! as! String + } + set { + resultMap.updateValue(newValue, forKey: "name") + } + } + + public var coordinates: [[Double]]? { + get { + return resultMap["coordinates"] as? [[Double]] + } + set { + resultMap.updateValue(newValue, forKey: "coordinates") + } + } + + /// Length of the starship, along the longest axis + public var length: Double? { + get { + return resultMap["length"] as? Double + } + set { + resultMap.updateValue(newValue, forKey: "length") + } + } + } + } +} + public final class ReviewAddedSubscription: GraphQLSubscription { /// The raw GraphQL definition of this operation. public let operationDefinition = diff --git a/Tests/StarWarsAPI/Starship.graphql b/Tests/StarWarsAPI/Starship.graphql index bb84f13c79..1bfef3a16b 100644 --- a/Tests/StarWarsAPI/Starship.graphql +++ b/Tests/StarWarsAPI/Starship.graphql @@ -4,3 +4,11 @@ query Starship { coordinates } } + +query StarshipCoordinates($coordinates: [[Float!]!]) { + starshipCoordinates(coordinates: $coordinates) { + name + coordinates + length + } +} diff --git a/Tests/StarWarsAPI/operationIdsPath.json b/Tests/StarWarsAPI/operationIdsPath.json index 2a9c3bf0bd..a94b69687b 100644 --- a/Tests/StarWarsAPI/operationIdsPath.json +++ b/Tests/StarWarsAPI/operationIdsPath.json @@ -127,6 +127,10 @@ "name": "Starship", "source": "query Starship {\n starship(id: 3000) {\n __typename\n name\n coordinates\n }\n}" }, + "8dd77d4bc7494c184606da092a665a7c2ca3c2a3f14d3b23fa5e469e207b3406": { + "name": "StarshipCoordinates", + "source": "query StarshipCoordinates($coordinates: [[Float!]!]) {\n starshipCoordinates(coordinates: $coordinates) {\n __typename\n name\n coordinates\n length\n }\n}" + }, "38644c5e7cf4fd506b91d2e7010cabf84e63dfcd33cf1deb443b4b32b55e2cbe": { "name": "ReviewAdded", "source": "subscription ReviewAdded($episode: Episode) {\n reviewAdded(episode: $episode) {\n __typename\n episode\n stars\n commentary\n }\n}" diff --git a/Tests/StarWarsAPI/schema.json b/Tests/StarWarsAPI/schema.json index 11f02ed009..b9a35aa09d 100644 --- a/Tests/StarWarsAPI/schema.json +++ b/Tests/StarWarsAPI/schema.json @@ -204,6 +204,45 @@ }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "starshipCoordinates", + "description": "", + "args": [ + { + "name": "coordinates", + "description": "", + "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 + } + } + } + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Starship", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, @@ -2184,4 +2223,4 @@ ] } } -} \ No newline at end of file +}