Skip to content

Commit

Permalink
feat: Specify caching fields with typePolicy directive
Browse files Browse the repository at this point in the history
  • Loading branch information
x-sheep committed Dec 13, 2024
1 parent c694236 commit c9c78c4
Show file tree
Hide file tree
Showing 14 changed files with 785 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ input PetSearchFilters {
measurements: MeasurementsInput
}

interface Animal {
interface Animal @typePolicy(keyFields: "id") {
id: ID!
species: String!
height: Height!
predators: [Animal!]!
skinCovering: SkinCovering
}

interface Pet {
interface Pet @typePolicy(keyFields: "id") {
id: ID!
humanName: String
favoriteToy: String!
Expand Down Expand Up @@ -198,5 +198,5 @@ enum SkinCovering {
FUR
HAIR
FEATHERS
SCALES
SCALES
}
4 changes: 3 additions & 1 deletion Tests/ApolloCodegenInternalTestHelpers/MockGraphQLType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ public extension GraphQLObjectType {
_ name: String = "",
interfaces: [GraphQLInterfaceType] = [],
fields: [String: GraphQLField] = [:],
keyFields: [String] = [],
documentation: String? = nil
) -> GraphQLObjectType {
GraphQLObjectType(
name: GraphQLName(schemaName: name),
documentation: documentation,
fields: fields,
interfaces: interfaces
interfaces: interfaces,
keyFields: keyFields
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ class ObjectTemplateTests: XCTestCase {
name: String = "Dog",
customName: String? = nil,
interfaces: [GraphQLInterfaceType] = [],
keyFields: [String] = [],
documentation: String? = nil,
config: ApolloCodegenConfiguration = .mock()
) {
let objectType = GraphQLObjectType.mock(
name,
interfaces: interfaces,
keyFields: keyFields,
documentation: documentation
)
objectType.name.customName = customName
Expand Down Expand Up @@ -82,7 +84,7 @@ class ObjectTemplateTests: XCTestCase {
implementedInterfaces: [
TestSchema.Interfaces.Animal.self,
TestSchema.Interfaces.Pet.self
]
],
"""

// when
Expand All @@ -106,7 +108,7 @@ class ObjectTemplateTests: XCTestCase {
implementedInterfaces: [
Interfaces.Animal.self,
Interfaces.Pet.self
]
],
"""

// when
Expand All @@ -121,7 +123,7 @@ class ObjectTemplateTests: XCTestCase {
buildSubject()

let expected = """
implementedInterfaces: []
implementedInterfaces: [],
"""

// when
Expand All @@ -130,6 +132,39 @@ class ObjectTemplateTests: XCTestCase {
// then
expect(actual).to(equalLineByLine(expected, atLine: 3, ignoringExtraLines: true))
}

func test_render_givenKeyField_rendersKeyFieldArray() {
// given
buildSubject(keyFields: ["id"])

let expected = """
keyFields: ["id"]
"""

// when
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, atLine: 4, ignoringExtraLines: true))
}

func test_render_givenMultipleKeyFields_rendersKeyFieldArray() {
// given
buildSubject(keyFields: ["id", "species"])

let expected = """
keyFields: [
"id",
"species"
]
"""

// when
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, atLine: 4, ignoringExtraLines: true))
}

// MARK: Documentation Tests

Expand Down Expand Up @@ -213,7 +248,8 @@ class ObjectTemplateTests: XCTestCase {
// Renamed from GraphQL schema value: 'MyObject'
static let MyCustomObject = ApolloAPI.Object(
typename: "MyObject",
implementedInterfaces: [TestSchema.Interfaces.MyCustomInterface.self]
implementedInterfaces: [TestSchema.Interfaces.MyCustomInterface.self],
keyFields: nil
)
"""

Expand Down
51 changes: 51 additions & 0 deletions Tests/ApolloTests/CacheKeyResolutionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,55 @@ class CacheKeyResolutionTests: XCTestCase {
expect(actual).to(equal("GreekLetters:δ"))
}

func test__schemaConfiguration__givenSingleKeyField_shouldReturnKeyFieldValue() {
let Delta = Object(typename: "Dog", implementedInterfaces: [], keyFields: ["id"])

MockSchemaMetadata.stub_objectTypeForTypeName({ _ in Delta })

let object: JSONObject = [
"__typename": "Dog",
"id": "10",
"name": "Beagle"
]

let objectDict = NetworkResponseExecutionSource().opaqueObjectDataWrapper(for: object)
let actual = MockSchemaMetadata.cacheKey(for: objectDict)

expect(actual).to(equal("Dog:10"))
}

func test__schemaConfiguration__givenMultipleKeyFields_shouldReturnKeyFieldValues() {
let Delta = Object(typename: "Dog", implementedInterfaces: [], keyFields: ["id", "name"])

MockSchemaMetadata.stub_objectTypeForTypeName({ _ in Delta })

let object: JSONObject = [
"__typename": "Dog",
"id": "10",
"name": #"Be\ag+le"#,
"height": 20,
]

let objectDict = NetworkResponseExecutionSource().opaqueObjectDataWrapper(for: object)
let actual = MockSchemaMetadata.cacheKey(for: objectDict)

expect(actual).to(equal(#"Dog:10+Be\\ag\+le"#))
}

func test__schemaConfiguration__givenMissingKeyFields_shouldReturnNil() {
let Delta = Object(typename: "Dog", implementedInterfaces: [], keyFields: ["id", "name"])

MockSchemaMetadata.stub_objectTypeForTypeName({ _ in Delta })

let object: JSONObject = [
"__typename": "Dog",
"id": "10",
]

let objectDict = NetworkResponseExecutionSource().opaqueObjectDataWrapper(for: object)
let actual = MockSchemaMetadata.cacheKey(for: objectDict)

expect(actual).to(beNil())
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,19 @@ struct ObjectTemplate: TemplateRenderer {
\(graphqlObject.name.typeNameDocumentation)
static let \(graphqlObject.render(as: .typename)) = \(config.ApolloAPITargetName).Object(
typename: "\(graphqlObject.name.schemaName)\",
implementedInterfaces: \(ImplementedInterfacesTemplate())
implementedInterfaces: \(ImplementedInterfacesTemplate()),
keyFields: \(KeyFieldsTemplate())
)
"""
}

private func KeyFieldsTemplate() -> TemplateString {
guard let fields = graphqlObject.keyFields, !fields.isEmpty else { return "nil" }

return """
[\(list: fields.map { "\"\($0)\"" })]
"""
}

private func ImplementedInterfacesTemplate() -> TemplateString {
return """
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -239,16 +239,20 @@ public final class GraphQLObjectType: GraphQLCompositeType, GraphQLInterfaceImpl
public private(set) var fields: [String: GraphQLField]!

public private(set) var interfaces: [GraphQLInterfaceType]!

public private(set) var keyFields: [String]!

/// Initializer to be used for creating mock objects in tests only.
init(
name: GraphQLName,
documentation: String?,
fields: [String: GraphQLField],
interfaces: [GraphQLInterfaceType]
interfaces: [GraphQLInterfaceType],
keyFields: [String]
) {
self.fields = fields
self.interfaces = interfaces
self.keyFields = keyFields
super.init(name: name, documentation: documentation)
}

Expand All @@ -259,6 +263,7 @@ public final class GraphQLObjectType: GraphQLCompositeType, GraphQLInterfaceImpl
override func finalize(_ jsValue: JSValue, bridge: isolated JavaScriptBridge) {
self.fields = try! bridge.invokeMethod("getFields", on: jsValue)
self.interfaces = try! bridge.invokeMethod("getInterfaces", on: jsValue)
self.keyFields = jsValue["_apolloKeyFields"]
}

public override var debugDescription: String {
Expand Down
Loading

0 comments on commit c9c78c4

Please sign in to comment.