diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift index 839139477..290f0b836 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift @@ -31,14 +31,22 @@ class SelectionSetTemplate_ErrorHandling_Tests: XCTestCase { // MARK: - Helpers - func buildSubjectAndOperation(named operationName: String = "ConflictingQuery") async throws { + func buildSubjectAndOperation( + named operationName: String = "ConflictingQuery", + fieldMerging: ApolloCodegenConfiguration.FieldMerging = .all + ) async throws { ir = try await IRBuilderTestWrapper(.mock(schema: schemaSDL, document: document)) let operationDefinition = try XCTUnwrap(ir.compilationResult[operation: operationName]) - operation = await ir.build(operation: operationDefinition) + operation = await ir.build( + operation: operationDefinition, + mergingStrategy: fieldMerging.options + ) let config = ApolloCodegenConfiguration.mock( schemaNamespace: "TestSchema", output: .mock(moduleType: .swiftPackageManager, operations: .inSchemaModule), - options: .init() + options: .init( + fieldMerging: fieldMerging + ) ) let mockTemplateRenderer = MockTemplateRenderer( target: .operationFile(), @@ -251,6 +259,61 @@ class SelectionSetTemplate_ErrorHandling_Tests: XCTestCase { expect(self.errorRecorder.recordedErrors.first).to(equal(expectedError)) } + func + test__validation__selectionSet_typeConflicts_withDirectInlineFragment_withFieldMerging_notIncludingAncestors_shouldNotReturnError() + async throws + { + schemaSDL = """ + type Query { + user: User + } + type User { + containers: [ContainerInterface] + } + interface ContainerInterface { + value: Value + } + type Container implements ContainerInterface{ + value: Value + values: [Value] + } + type Value { + propertyA: String! + propertyB: String! + propertyC: String! + propertyD: String! + } + """ + + document = """ + query ConflictingQuery { + user { + containers { + value { + propertyA + propertyB + propertyC + propertyD + } + ... on Container { + values { + propertyA + propertyC + } + } + } + } + } + """ + + // when + try await buildSubjectAndOperation(fieldMerging: .siblings) + _ = subject.renderBody() + + // then + expect(self.errorRecorder.recordedErrors).to(beEmpty()) + } + func test__validation__selectionSet_typeConflicts_withMergedInlineFragment_shouldReturnNonFatalError() async throws @@ -382,6 +445,61 @@ class SelectionSetTemplate_ErrorHandling_Tests: XCTestCase { expect(self.errorRecorder.recordedErrors.first).to(equal(expectedError)) } + func + test__validation__selectionSet_typeConflicts_withDirectNamedFragment_givenFieldMerging_notIncludingNamedFragments_shouldNotReturnError() + async throws + { + schemaSDL = """ + type Query { + user: User + } + type User { + containers: [Container] + } + + type Container { + value: Value + values: [Value] + } + type Value { + propertyA: String! + propertyB: String! + propertyC: String! + propertyD: String! + } + """ + + document = """ + query ConflictingQuery { + user { + containers { + value { + propertyA + propertyB + propertyC + propertyD + } + ...ContainerFields + } + } + } + + fragment ContainerFields on Container { + values { + propertyA + propertyC + } + } + """ + + // when + try await buildSubjectAndOperation(fieldMerging: [.ancestors, .siblings]) + _ = subject.renderBody() + + // then + expect(self.errorRecorder.recordedErrors).to(beEmpty()) + } + func test__validation__selectionSet_typeConflicts_withNamedFragment_shouldReturnNonFatalError() async throws { diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift index 3b3b5ec9b..ad3d788ad 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift @@ -515,6 +515,708 @@ class SelectionSetTemplate_FieldMerging_Tests: XCTestCase { expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) } + // MARK: - Child Entity Selection Sets + + func test__render_childEntitySelectionSet__givenFieldMerging_none__givenEntityFieldMergedFromAncestor_doesNotRenderMergedChildSelectionSet() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + type Dog implements Animal { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + predator { + species + } + ... on Dog { + species + } + } + } + """ + + let expected = """ + public var species: String? { __data["species"] } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .none + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_childEntitySelectionSet__givenFieldMerging_ancestors__givenEntityFieldMergedFromAncestor_doesNotRenderMergedChildSelectionSet() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + type Dog implements Animal { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + predator { + species + } + ... on Dog { + species + } + } + } + """ + + let expected = """ + public var species: String? { __data["species"] } + public var predator: Predator? { __data["predator"] } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .ancestors + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_childEntitySelectionSet__givenFieldMerging_ancestors__givenEntityFieldMergedFromAncestorAndSibling_doesNotRenderMergedChildSelectionSet() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + predator { + species + } + ... on Pet { + predator { + name + } + } + ... on Dog { + species + } + } + } + """ + + let expected = """ + public var species: String? { __data["species"] } + public var predator: Predator? { __data["predator"] } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .ancestors + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_childEntitySelectionSet__givenFieldMerging_siblings__givenEntityFieldMergedFromAncestorAndSibling_rendersMergedChildSelectionSet() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + predator { + species + } + ... on Pet { + predator { + name + } + } + ... on Dog { + species + } + } + } + """ + + let expected = """ + public var species: String? { __data["species"] } + public var predator: Predator? { __data["predator"] } + + /// AllAnimal.AsDog.Predator + public struct Predator: TestSchema.SelectionSet { + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .siblings + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + // MARK: - Child Entity Selections - From Named Fragments + + func test__render_childEntitySelectionSet__givenFieldMerging_ancestors__givenEntityFieldMergedFromNamedFragmentInAncestor_doesNotRenderChildSelectionSet() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + ...PredatorDetails + ... on Dog { + species + } + } + } + + fragment PredatorDetails on Animal { + predator { + species + } + } + """ + + let expected = """ + public var species: String? { __data["species"] } + + public struct Fragments: FragmentContainer { + public let __data: DataDict + public init(_dataDict: DataDict) { __data = _dataDict } + + public var predatorDetails: PredatorDetails { _toFragment() } + } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .ancestors + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_childEntitySelectionSet__givenFieldMerging_ancestorsAndNamedFragments__givenEntityFieldMergedFromNamedFragmentInAncestor_rendersChildSelectionSet() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + ...PredatorDetails + ... on Dog { + species + } + } + } + + fragment PredatorDetails on Animal { + predator { + species + } + } + """ + + let expected = """ + public var species: String? { __data["species"] } + public var predator: Predator? { __data["predator"] } + + public struct Fragments: FragmentContainer { + public let __data: DataDict + public init(_dataDict: DataDict) { __data = _dataDict } + + public var predatorDetails: PredatorDetails { _toFragment() } + } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: [.ancestors, .namedFragments] + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_childEntitySelectionSet__givenFieldMerging_siblingsAndNamedFragments__givenEntityFieldMergedFromNamedFragmentInAncestor_doesNotRenderChildSelectionSet() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + ...PredatorDetails + ... on Dog { + species + } + } + } + + fragment PredatorDetails on Animal { + predator { + species + } + } + """ + + let expected = """ + public var species: String? { __data["species"] } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: [.siblings, .namedFragments] + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + // MARK: - Named Fragment Accessors + + func test__render_fragmentAccessors__givenFieldMerging_ancestors__givenEntityFieldMergedFromNamedFragmentInAncestor_rendersFragmentAccessor() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + ...AnimalDetails + ... on Dog { + name + } + } + } + + fragment AnimalDetails on Animal { + species + } + """ + + let expected = """ + public var name: String? { __data["name"] } + + public struct Fragments: FragmentContainer { + public let __data: DataDict + public init(_dataDict: DataDict) { __data = _dataDict } + + public var animalDetails: AnimalDetails { _toFragment() } + } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .ancestors + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_fragmentAccessors__givenFieldMerging_siblings__givenEntityFieldMergedFromNamedFragmentInAncestor_doesNotRenderFragmentAccessor() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + ...AnimalDetails + ... on Dog { + name + } + } + } + + fragment AnimalDetails on Animal { + species + } + """ + + let expected = """ + public var name: String? { __data["name"] } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .siblings + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_fragmentAccessors__givenFieldMerging_siblings__givenEntityFieldMergedFromNamedFragmentInSibling_rendersFragmentAccessor() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + ... on Pet { + ...AnimalDetails + } + ... on Dog { + name + } + } + } + + fragment AnimalDetails on Animal { + species + } + """ + + let expected = """ + public var name: String? { __data["name"] } + + public struct Fragments: FragmentContainer { + public let __data: DataDict + public init(_dataDict: DataDict) { __data = _dataDict } + + public var animalDetails: AnimalDetails { _toFragment() } + } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .siblings + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_fragmentAccessors__givenFieldMerging_ancestors__givenEntityFieldMergedFromNamedFragmentInSibling_doesNotRenderFragmentAccessor() async throws { + // given + schemaSDL = """ + type Query { + allAnimals: [Animal!] + } + + interface Animal { + species: String + predator: Animal + name: String + } + + interface Pet implements Animal { + species: String + predator: Animal + } + + type Dog implements Animal & Pet { + species: String + predator: Animal + name: String + } + """ + + document = """ + query TestOperation { + allAnimals { + ... on Pet { + ...AnimalDetails + } + ... on Dog { + name + } + } + } + + fragment AnimalDetails on Animal { + species + } + """ + + let expected = """ + public var name: String? { __data["name"] } + } + """ + + // when + try await buildSubjectAndOperation( + fieldMerging: .ancestors + ) + + let allAnimals_asDog = try XCTUnwrap( + operation[field: "query"]?[field: "allAnimals"]?[as: "Dog"] + ) + + let actual = subject.test_render(childEntity: allAnimals_asDog.computed) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true)) + } + // MARK: - SelectionSetInitializers func test__render_selectionSetInitializer__givenFieldMerging_none_withMergedSelections_rendersInitializerWithAllMergedSelections() async throws { diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift index c66b5c2ff..73a930f24 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift @@ -30,7 +30,9 @@ struct SelectionSetValidationContext { // Check for type conflicts resulting from singularization/pluralization of fields var typeNamesForEntityFields = [String: String]() - let entityFields = selections.makeFieldIterator(mergingStrategy: .all) { field in + let entityFields = selections.makeFieldIterator( + mergingStrategy: config.options.fieldMerging.options + ) { field in field is IR.EntityField } @@ -54,7 +56,9 @@ struct SelectionSetValidationContext { // pass into recursive function calls referencedTypeNames.merge(typeNamesForEntityFields) { (current, _) in current } - IteratorSequence(selections.makeNamedFragmentIterator()).forEach { fragmentSpread in + IteratorSequence(selections.makeNamedFragmentIterator( + mergingStrategy: config.options.fieldMerging.options + )).forEach { fragmentSpread in if let existingTypeName = referencedTypeNames[fragmentSpread.fragment.generatedDefinitionName] { errorRecorder.record(error: ApolloCodegen.NonFatalError.typeNameConflict( diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/RenderingHelpers/ComputedSelectionSet+Iterators.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/RenderingHelpers/ComputedSelectionSet+Iterators.swift index 116399a44..ae147fdf8 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/RenderingHelpers/ComputedSelectionSet+Iterators.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/RenderingHelpers/ComputedSelectionSet+Iterators.swift @@ -17,7 +17,7 @@ extension IR.ComputedSelectionSet { ) -> FieldIterator { SelectionsIterator( direct: direct?.fields.values, - merged: merged[mergingStrategy]?.fields.values, + merged: merged.fields.values, filter: filter ) } @@ -33,7 +33,6 @@ extension IR.ComputedSelectionSet { } func makeNamedFragmentIterator( - mergingStrategy: MergedSelections.MergingStrategy = .all, filter: ((IR.NamedFragmentSpread) -> Bool)? = nil ) -> NamedFragmentIterator { SelectionsIterator( diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift index df39e69cd..c9c228b92 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift @@ -42,7 +42,7 @@ struct SelectionSetTemplate { private func createSelectionSetContext( for selectionSet: IR.SelectionSet, - inParent context: SelectionSetContext + inParent context: SelectionSetContext? ) -> SelectionSetContext { let computedSelectionSet = ComputedSelectionSet.Builder( selectionSet, @@ -50,7 +50,9 @@ struct SelectionSetTemplate { entityStorage: definition.entityStorage ).build() - var validationContext = context.validationContext + var validationContext = context?.validationContext ?? + SelectionSetValidationContext(config: config) + validationContext.runTypeValidationFor( computedSelectionSet, recordingErrorsTo: nonFatalErrorRecorder @@ -101,21 +103,9 @@ struct SelectionSetTemplate { /// /// - Returns: The `TemplateString` for the body of the `SelectionSetTemplate`. func renderBody() -> TemplateString { - let selectionSet = definition.rootField.selectionSet - let computedRootSelectionSet = IR.ComputedSelectionSet.Builder( - selectionSet, - mergingStrategies: self.mergingStrategies(for: selectionSet), - entityStorage: definition.entityStorage - ).build() - - var validationContext = SelectionSetValidationContext(config: config) - validationContext.runTypeValidationFor( - computedRootSelectionSet, - recordingErrorsTo: nonFatalErrorRecorder - ) - let selectionSetContext = SelectionSetContext( - selectionSet: computedRootSelectionSet, - validationContext: validationContext + let selectionSetContext = createSelectionSetContext( + for: definition.rootField.selectionSet, + inParent: nil ) let body = BodyTemplate(selectionSetContext) @@ -126,6 +116,7 @@ struct SelectionSetTemplate { // MARK: - Child Entity func render(childEntity context: SelectionSetContext) -> String? { let selectionSet = context.selectionSet + let fieldSelectionSetName = nameCache.selectionSetName(for: selectionSet.typeInfo) if let referencedSelectionSetName = selectionSet.nameForReferencedSelectionSet(config: config) { @@ -720,7 +711,7 @@ struct SelectionSetTemplate { fulfilledFragments.append(selectionSetName) } - for source in selectionSet.merged[.all]!.mergedSources { + for source in selectionSet.merged.mergedSources { fulfilledFragments .append( contentsOf: source.generatedSelectionSetNamesOfFullfilledFragments( @@ -742,7 +733,9 @@ struct SelectionSetTemplate { _ context: SelectionSetContext ) -> TemplateString { let selectionSet = context.selectionSet - let allFields = selectionSet.makeFieldIterator(mergingStrategy: .all) { field in + let allFields = selectionSet.makeFieldIterator( + mergingStrategy: config.options.fieldMerging.options + ) { field in field is IR.EntityField } @@ -815,7 +808,7 @@ extension IR.ComputedSelectionSet { _ config: ApolloCodegen.ConfigurationContext ) -> Bool { return direct != nil || - merged[config.options.fieldMerging.options].unsafelyUnwrapped.mergedSources.count != 1 + merged[config.options.fieldMerging.options].unsafelyUnwrapped.mergedSources.count >= 1 } /// If the SelectionSet is a reference to another rendered SelectionSet, returns the qualified @@ -828,7 +821,9 @@ extension IR.ComputedSelectionSet { fileprivate func nameForReferencedSelectionSet( config: ApolloCodegen.ConfigurationContext ) -> String? { - guard !shouldBeRendered(config) else { + guard direct == nil && + merged[config.options.fieldMerging.options].unsafelyUnwrapped.mergedSources.count == 1 + else { return nil }