Skip to content

Commit

Permalink
feature: Emit Identifiable conformance on SelectionSets
Browse files Browse the repository at this point in the history
  • Loading branch information
x-sheep committed Jan 23, 2025
1 parent b68a95d commit 28ca985
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,117 @@ class SelectionSetTemplateTests: XCTestCase {
// then
expect(String(actual.reversed())).to(equalLineByLine("}", ignoringExtraLines: true))
}

// MARK: Protocol conformance

func test__render_selectionSet__givenTypeWithKeyFieldID_rendersIdentifiableConformance() async throws {
// given
schemaSDL = """
type Query {
allAnimals: [Animal!]
}
type Animal @typePolicy(keyFields: "id") {
id: ID!
}
"""

document = """
query TestOperation {
allAnimals {
id
}
}
"""

let expected = """
public struct AllAnimal: TestSchema.SelectionSet, Identifiable {
"""

// when
try await buildSubjectAndOperation()
let allAnimals = try XCTUnwrap(
operation[field: "query"]?[field: "allAnimals"]?.selectionSet
)

let actual = subject.test_render(childEntity: allAnimals.computed)

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

func test__render_selectionSet__givenInterfaceWithKeyFieldID_rendersIdentifiableConformance() async throws {
// given
schemaSDL = """
type Query {
allAnimals: [Animal!]
}
interface Animal @typePolicy(keyFields: "id") {
id: ID!
species: String!
}
"""

document = """
query TestOperation {
allAnimals {
id
}
}
"""

let expected = """
public struct AllAnimal: TestSchema.SelectionSet, Identifiable {
"""

// when
try await buildSubjectAndOperation()
let allAnimals = try XCTUnwrap(
operation[field: "query"]?[field: "allAnimals"]?.selectionSet
)

let actual = subject.test_render(childEntity: allAnimals.computed)

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

func test__render_selectionSet__givenTypeWithOtherKeyField_doesNotRenderIdentifiableConformance() async throws {
// given
schemaSDL = """
type Query {
allAnimals: [Animal!]
}
type Animal @typePolicy(keyFields: "species") {
species: String!
}
"""

document = """
query TestOperation {
allAnimals {
species
}
}
"""

let expected = """
public struct AllAnimal: TestSchema.SelectionSet {
"""

// when
try await buildSubjectAndOperation()
let allAnimals = try XCTUnwrap(
operation[field: "query"]?[field: "allAnimals"]?.selectionSet
)

let actual = subject.test_render(childEntity: allAnimals.computed)

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

// MARK: Parent Type

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ struct SelectionSetTemplate {
"""
\(SelectionSetNameDocumentation(selectionSet))
\(renderAccessControl())\
struct \(fieldSelectionSetName): \(SelectionSetType()) {
struct \(fieldSelectionSetName): \(SelectionSetType())\
\(if: selectionSet.isIdentifiable, ", Identifiable")\
{
\(BodyTemplate(context))
}
"""
Expand All @@ -118,6 +120,7 @@ struct SelectionSetTemplate {
\(renderAccessControl())\
struct \(inlineFragment.renderedTypeName): \(SelectionSetType(asInlineFragment: true))\
\(if: inlineFragment.isCompositeInlineFragment, ", \(config.ApolloAPITargetName).CompositeInlineFragment")\
\(if: inlineFragment.isIdentifiable, ", Identifiable")\
{
\(BodyTemplate(context))
}
Expand Down
16 changes: 16 additions & 0 deletions apollo-ios-codegen/Sources/IR/IR+ComputedSelectionSet.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import GraphQLCompiler
import OrderedCollections
import Utilities

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

/// The `TypeInfo` for the selection set of the computed selections
public let typeInfo: IR.SelectionSet.TypeInfo

/// Indicates if the parent type has a single keyField named `id`.
public var isIdentifiable: Bool {
if let type = typeInfo.parentType as? GraphQLObjectType,
type.keyFields == ["id"] {
return true
}

if let type = typeInfo.parentType as? GraphQLInterfaceType,
type.keyFields == ["id"] {
return true
}

return false
}

// MARK: Dynamic Member Subscript

Expand Down

0 comments on commit 28ca985

Please sign in to comment.