Skip to content

Commit 28ca985

Browse files
committed
feature: Emit Identifiable conformance on SelectionSets
1 parent b68a95d commit 28ca985

File tree

3 files changed

+131
-1
lines changed

3 files changed

+131
-1
lines changed

Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplateTests.swift

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,117 @@ class SelectionSetTemplateTests: XCTestCase {
125125
// then
126126
expect(String(actual.reversed())).to(equalLineByLine("}", ignoringExtraLines: true))
127127
}
128+
129+
// MARK: Protocol conformance
130+
131+
func test__render_selectionSet__givenTypeWithKeyFieldID_rendersIdentifiableConformance() async throws {
132+
// given
133+
schemaSDL = """
134+
type Query {
135+
allAnimals: [Animal!]
136+
}
137+
138+
type Animal @typePolicy(keyFields: "id") {
139+
id: ID!
140+
}
141+
"""
142+
143+
document = """
144+
query TestOperation {
145+
allAnimals {
146+
id
147+
}
148+
}
149+
"""
150+
151+
let expected = """
152+
public struct AllAnimal: TestSchema.SelectionSet, Identifiable {
153+
"""
154+
155+
// when
156+
try await buildSubjectAndOperation()
157+
let allAnimals = try XCTUnwrap(
158+
operation[field: "query"]?[field: "allAnimals"]?.selectionSet
159+
)
160+
161+
let actual = subject.test_render(childEntity: allAnimals.computed)
162+
163+
// then
164+
expect(actual).to(equalLineByLine(expected, atLine: 2, ignoringExtraLines: true))
165+
}
166+
167+
func test__render_selectionSet__givenInterfaceWithKeyFieldID_rendersIdentifiableConformance() async throws {
168+
// given
169+
schemaSDL = """
170+
type Query {
171+
allAnimals: [Animal!]
172+
}
173+
174+
interface Animal @typePolicy(keyFields: "id") {
175+
id: ID!
176+
species: String!
177+
}
178+
"""
179+
180+
document = """
181+
query TestOperation {
182+
allAnimals {
183+
id
184+
}
185+
}
186+
"""
187+
188+
let expected = """
189+
public struct AllAnimal: TestSchema.SelectionSet, Identifiable {
190+
"""
191+
192+
// when
193+
try await buildSubjectAndOperation()
194+
let allAnimals = try XCTUnwrap(
195+
operation[field: "query"]?[field: "allAnimals"]?.selectionSet
196+
)
197+
198+
let actual = subject.test_render(childEntity: allAnimals.computed)
199+
200+
// then
201+
expect(actual).to(equalLineByLine(expected, atLine: 2, ignoringExtraLines: true))
202+
}
203+
204+
func test__render_selectionSet__givenTypeWithOtherKeyField_doesNotRenderIdentifiableConformance() async throws {
205+
// given
206+
schemaSDL = """
207+
type Query {
208+
allAnimals: [Animal!]
209+
}
210+
211+
type Animal @typePolicy(keyFields: "species") {
212+
species: String!
213+
}
214+
"""
215+
216+
document = """
217+
query TestOperation {
218+
allAnimals {
219+
species
220+
}
221+
}
222+
"""
223+
224+
let expected = """
225+
public struct AllAnimal: TestSchema.SelectionSet {
226+
"""
227+
228+
// when
229+
try await buildSubjectAndOperation()
230+
let allAnimals = try XCTUnwrap(
231+
operation[field: "query"]?[field: "allAnimals"]?.selectionSet
232+
)
233+
234+
let actual = subject.test_render(childEntity: allAnimals.computed)
235+
236+
// then
237+
expect(actual).to(equalLineByLine(expected, atLine: 2, ignoringExtraLines: true))
238+
}
128239

129240
// MARK: Parent Type
130241

apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ struct SelectionSetTemplate {
102102
"""
103103
\(SelectionSetNameDocumentation(selectionSet))
104104
\(renderAccessControl())\
105-
struct \(fieldSelectionSetName): \(SelectionSetType()) {
105+
struct \(fieldSelectionSetName): \(SelectionSetType())\
106+
\(if: selectionSet.isIdentifiable, ", Identifiable")\
107+
{
106108
\(BodyTemplate(context))
107109
}
108110
"""
@@ -118,6 +120,7 @@ struct SelectionSetTemplate {
118120
\(renderAccessControl())\
119121
struct \(inlineFragment.renderedTypeName): \(SelectionSetType(asInlineFragment: true))\
120122
\(if: inlineFragment.isCompositeInlineFragment, ", \(config.ApolloAPITargetName).CompositeInlineFragment")\
123+
\(if: inlineFragment.isIdentifiable, ", Identifiable")\
121124
{
122125
\(BodyTemplate(context))
123126
}

apollo-ios-codegen/Sources/IR/IR+ComputedSelectionSet.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Foundation
2+
import GraphQLCompiler
23
import OrderedCollections
34
import Utilities
45

@@ -18,6 +19,21 @@ public struct ComputedSelectionSet {
1819

1920
/// The `TypeInfo` for the selection set of the computed selections
2021
public let typeInfo: IR.SelectionSet.TypeInfo
22+
23+
/// Indicates if the parent type has a single keyField named `id`.
24+
public var isIdentifiable: Bool {
25+
if let type = typeInfo.parentType as? GraphQLObjectType,
26+
type.keyFields == ["id"] {
27+
return true
28+
}
29+
30+
if let type = typeInfo.parentType as? GraphQLInterfaceType,
31+
type.keyFields == ["id"] {
32+
return true
33+
}
34+
35+
return false
36+
}
2137

2238
// MARK: Dynamic Member Subscript
2339

0 commit comments

Comments
 (0)