Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Identifiable conformance for Named Fragments #595

Merged
merged 4 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

@_exported import ApolloAPI

public struct PetDetails: AnimalKingdomAPI.SelectionSet, Fragment {
public struct PetDetails: AnimalKingdomAPI.SelectionSet, Fragment, Identifiable {
public static var fragmentDefinition: StaticString {
#"fragment PetDetails on Pet { __typename humanName favoriteToy owner { __typename firstName } }"#
#"fragment PetDetails on Pet { __typename id humanName favoriteToy owner { __typename firstName } }"#
}

public let __data: DataDict
Expand All @@ -14,24 +14,28 @@ public struct PetDetails: AnimalKingdomAPI.SelectionSet, Fragment {
public static var __parentType: any ApolloAPI.ParentType { AnimalKingdomAPI.Interfaces.Pet }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AnimalKingdomAPI.ID.self),
.field("humanName", String?.self),
.field("favoriteToy", String.self),
.field("owner", Owner?.self),
] }

public var id: AnimalKingdomAPI.ID { __data["id"] }
public var humanName: String? { __data["humanName"] }
public var favoriteToy: String { __data["favoriteToy"] }
public var owner: Owner? { __data["owner"] }

public init(
__typename: String,
id: AnimalKingdomAPI.ID,
humanName: String? = nil,
favoriteToy: String,
owner: Owner? = nil
) {
self.init(_dataDict: DataDict(
data: [
"__typename": __typename,
"id": id,
"humanName": humanName,
"favoriteToy": favoriteToy,
"owner": owner._fieldData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public class PetSearchLocalCacheMutation: LocalCacheMutation {
/// Pet
///
/// Parent Type: `Pet`
public struct Pet: AnimalKingdomAPI.MutableSelectionSet {
public struct Pet: AnimalKingdomAPI.MutableSelectionSet, Identifiable {
public var __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class PetAdoptionMutation: GraphQLMutation {
/// AdoptPet
///
/// Parent Type: `Pet`
public struct AdoptPet: AnimalKingdomAPI.SelectionSet {
public struct AdoptPet: AnimalKingdomAPI.SelectionSet, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
/// AllAnimal.AsPet
///
/// Parent Type: `Pet`
public struct AsPet: AnimalKingdomAPI.InlineFragment {
public struct AsPet: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand All @@ -437,6 +437,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
public var species: String? { __data["species"] }
public var skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? { __data["skinCovering"] }
public var predators: [Predator] { __data["predators"] }
public var id: AnimalKingdomAPI.ID { __data["id"] }
public var humanName: String? { __data["humanName"] }
public var favoriteToy: String { __data["favoriteToy"] }
public var owner: Owner? { __data["owner"] }
Expand All @@ -457,6 +458,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
species: String? = nil,
skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? = nil,
predators: [Predator],
id: AnimalKingdomAPI.ID,
humanName: String? = nil,
favoriteToy: String,
owner: Owner? = nil
Expand All @@ -468,6 +470,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
"species": species,
"skinCovering": skinCovering,
"predators": predators._fieldData,
"id": id,
"humanName": humanName,
"favoriteToy": favoriteToy,
"owner": owner._fieldData,
Expand Down Expand Up @@ -528,7 +531,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
/// AllAnimal.AsPet.AsWarmBlooded
///
/// Parent Type: `WarmBlooded`
public struct AsWarmBlooded: AnimalKingdomAPI.InlineFragment {
public struct AsWarmBlooded: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand All @@ -543,6 +546,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
public var skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? { __data["skinCovering"] }
public var predators: [Predator] { __data["predators"] }
public var bodyTemperature: Int { __data["bodyTemperature"] }
public var id: AnimalKingdomAPI.ID { __data["id"] }
public var humanName: String? { __data["humanName"] }
public var favoriteToy: String { __data["favoriteToy"] }
public var owner: Owner? { __data["owner"] }
Expand All @@ -563,6 +567,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? = nil,
predators: [Predator],
bodyTemperature: Int,
id: AnimalKingdomAPI.ID,
humanName: String? = nil,
favoriteToy: String,
owner: Owner? = nil
Expand All @@ -575,6 +580,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
"skinCovering": skinCovering,
"predators": predators._fieldData,
"bodyTemperature": bodyTemperature,
"id": id,
"humanName": humanName,
"favoriteToy": favoriteToy,
"owner": owner._fieldData,
Expand Down Expand Up @@ -638,7 +644,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
/// AllAnimal.AsCatIfGetCat
///
/// Parent Type: `Cat`
public struct AsCatIfGetCat: AnimalKingdomAPI.InlineFragment {
public struct AsCatIfGetCat: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand All @@ -654,6 +660,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
public var skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? { __data["skinCovering"] }
public var predators: [Predator] { __data["predators"] }
public var bodyTemperature: Int { __data["bodyTemperature"] }
public var id: AnimalKingdomAPI.ID { __data["id"] }
public var humanName: String? { __data["humanName"] }
public var favoriteToy: String { __data["favoriteToy"] }
public var owner: Owner? { __data["owner"] }
Expand All @@ -674,6 +681,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? = nil,
predators: [Predator],
bodyTemperature: Int,
id: AnimalKingdomAPI.ID,
humanName: String? = nil,
favoriteToy: String,
owner: Owner? = nil
Expand All @@ -687,6 +695,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
"skinCovering": skinCovering,
"predators": predators._fieldData,
"bodyTemperature": bodyTemperature,
"id": id,
"humanName": humanName,
"favoriteToy": favoriteToy,
"owner": owner._fieldData,
Expand Down Expand Up @@ -799,7 +808,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
/// AllAnimal.AsClassroomPet.AsBird
///
/// Parent Type: `Bird`
public struct AsBird: AnimalKingdomAPI.InlineFragment {
public struct AsBird: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand All @@ -815,6 +824,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
public var skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? { __data["skinCovering"] }
public var predators: [Predator] { __data["predators"] }
public var bodyTemperature: Int { __data["bodyTemperature"] }
public var id: AnimalKingdomAPI.ID { __data["id"] }
public var humanName: String? { __data["humanName"] }
public var favoriteToy: String { __data["favoriteToy"] }
public var owner: Owner? { __data["owner"] }
Expand All @@ -835,6 +845,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
skinCovering: GraphQLEnum<AnimalKingdomAPI.SkinCovering>? = nil,
predators: [Predator],
bodyTemperature: Int,
id: AnimalKingdomAPI.ID,
humanName: String? = nil,
favoriteToy: String,
owner: Owner? = nil
Expand All @@ -848,6 +859,7 @@ public class AllAnimalsIncludeSkipQuery: GraphQLQuery {
"skinCovering": skinCovering,
"predators": predators._fieldData,
"bodyTemperature": bodyTemperature,
"id": id,
"humanName": humanName,
"favoriteToy": favoriteToy,
"owner": owner._fieldData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class AllAnimalsQuery: GraphQLQuery {
/// AllAnimal
///
/// Parent Type: `Animal`
public struct AllAnimal: AnimalKingdomAPI.SelectionSet {
public struct AllAnimal: AnimalKingdomAPI.SelectionSet, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down Expand Up @@ -267,7 +267,7 @@ public class AllAnimalsQuery: GraphQLQuery {
/// AllAnimal.AsWarmBlooded
///
/// Parent Type: `WarmBlooded`
public struct AsWarmBlooded: AnimalKingdomAPI.InlineFragment {
public struct AsWarmBlooded: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down Expand Up @@ -358,7 +358,7 @@ public class AllAnimalsQuery: GraphQLQuery {
/// AllAnimal.AsPet
///
/// Parent Type: `Pet`
public struct AsPet: AnimalKingdomAPI.InlineFragment {
public struct AsPet: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down Expand Up @@ -470,7 +470,7 @@ public class AllAnimalsQuery: GraphQLQuery {
/// AllAnimal.AsPet.AsWarmBlooded
///
/// Parent Type: `WarmBlooded`
public struct AsWarmBlooded: AnimalKingdomAPI.InlineFragment {
public struct AsWarmBlooded: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down Expand Up @@ -583,7 +583,7 @@ public class AllAnimalsQuery: GraphQLQuery {
/// AllAnimal.AsCat
///
/// Parent Type: `Cat`
public struct AsCat: AnimalKingdomAPI.InlineFragment {
public struct AsCat: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down Expand Up @@ -786,7 +786,7 @@ public class AllAnimalsQuery: GraphQLQuery {
/// AllAnimal.AsClassroomPet.AsBird
///
/// Parent Type: `Bird`
public struct AsBird: AnimalKingdomAPI.InlineFragment {
public struct AsBird: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down Expand Up @@ -904,7 +904,7 @@ public class AllAnimalsQuery: GraphQLQuery {
/// AllAnimal.AsDog
///
/// Parent Type: `Dog`
public struct AsDog: AnimalKingdomAPI.InlineFragment {
public struct AsDog: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class DogQuery: GraphQLQuery {
/// AllAnimal
///
/// Parent Type: `Animal`
public struct AllAnimal: AnimalKingdomAPI.SelectionSet {
public struct AllAnimal: AnimalKingdomAPI.SelectionSet, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down Expand Up @@ -78,7 +78,7 @@ public class DogQuery: GraphQLQuery {
/// AllAnimal.AsDog
///
/// Parent Type: `Dog`
public struct AsDog: AnimalKingdomAPI.InlineFragment {
public struct AsDog: AnimalKingdomAPI.InlineFragment, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public class FindPetQuery: GraphQLQuery {
/// FindPet
///
/// Parent Type: `Pet`
public struct FindPet: AnimalKingdomAPI.SelectionSet {
public struct FindPet: AnimalKingdomAPI.SelectionSet, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class PetSearchQuery: GraphQLQuery {
/// Pet
///
/// Parent Type: `Pet`
public struct Pet: AnimalKingdomAPI.SelectionSet {
public struct Pet: AnimalKingdomAPI.SelectionSet, Identifiable {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
fragment PetDetails on Pet {
id
humanName
favoriteToy
owner {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -834,5 +834,68 @@ class FragmentTemplateTests: XCTestCase {
expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true))
}
}

// MARK: - Protocol conformance

func test__render__givenFragmentWithIdKeyField_rendersIdentifiableConformance() async throws {
// given
schemaSDL = """
type Query {
getUser(id: String): User
}

type User @typePolicy(keyFields: "id") {
id: String!
name: String!
}
"""

document = """
fragment NodeFragment on User {
id
}
"""

let expected = """
struct NodeFragment: TestSchema.SelectionSet, Fragment, Identifiable {
"""

// when
try await buildSubjectAndFragment(named: "NodeFragment")
let actual = renderSubject()

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

func test__render_givenFragment_withoutUsingIDField_doesNotRenderIdentifiableConformance() async throws {
// given
schemaSDL = """
type Query {
getUser(id: String): User
}

type User @typePolicy(keyFields: "id") {
id: String!
name: String!
}
"""

document = """
fragment UserFragment on User {
name
}
"""

let expected = """
struct UserFragment: TestSchema.SelectionSet, Fragment {
"""

// when
try await buildSubjectAndFragment(named: "UserFragment")
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ struct FragmentTemplate: TemplateRenderer {
"""
\(accessControlModifier(for: .parent))\
struct \(fragment.generatedDefinitionName.asFragmentName): \
\(fragment.renderedSelectionSetType(config)), Fragment {
\(fragment.renderedSelectionSetType(config)), Fragment\
\(if: fragment.isIdentifiable, ", Identifiable")\
{
\(if: includeDefinition, """
\(accessControlModifier(for: .member))\
static var fragmentDefinition: StaticString {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import GraphQLCompiler

extension GraphQLCompositeType {
/// Indicates if the type has a single keyField named `id`.
var isIdentifiable: Bool {
switch(self) {
case let interface as GraphQLInterfaceType:
return interface.keyFields == ["id"]

case let object as GraphQLObjectType:
return object.keyFields == ["id"]

default:
return false
}
}
}
Loading
Loading