diff --git a/Tests/ApolloCodegenInternalTestHelpers/MockApolloCodegenConfiguration.swift b/Tests/ApolloCodegenInternalTestHelpers/MockApolloCodegenConfiguration.swift index 393a7d60e..37e38ca84 100644 --- a/Tests/ApolloCodegenInternalTestHelpers/MockApolloCodegenConfiguration.swift +++ b/Tests/ApolloCodegenInternalTestHelpers/MockApolloCodegenConfiguration.swift @@ -30,6 +30,7 @@ extension ApolloCodegenConfiguration { public static func mock( _ moduleType: ApolloCodegenConfiguration.SchemaTypesFileOutput.ModuleType, options: ApolloCodegenConfiguration.OutputOptions = .init(), + experimentalFeatures: ExperimentalFeatures = .init(), schemaNamespace: String = "TestSchema", to path: String = "MockModulePath" ) -> Self { @@ -42,7 +43,8 @@ extension ApolloCodegenConfiguration { output: .init( schemaTypes: .init(path: path, moduleType: moduleType) ), - options: options + options: options, + experimentalFeatures: experimentalFeatures ) } } diff --git a/Tests/ApolloCodegenTests/ApolloCodegenConfigurationCodableTests.swift b/Tests/ApolloCodegenTests/ApolloCodegenConfigurationCodableTests.swift index 261ce68f0..03ac59199 100644 --- a/Tests/ApolloCodegenTests/ApolloCodegenConfigurationCodableTests.swift +++ b/Tests/ApolloCodegenTests/ApolloCodegenConfigurationCodableTests.swift @@ -43,7 +43,6 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase { ], deprecatedEnumCases: .exclude, schemaDocumentation: .exclude, - fieldMerging: .all, cocoapodsCompatibleImportStatements: true, warningsOnDeprecatedUsage: .exclude, conversionStrategies:.init( @@ -55,6 +54,7 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase { markOperationDefinitionsAsFinal: true ), experimentalFeatures: .init( + fieldMerging: .all, legacySafelistingCompatibleOperations: true ), operationManifest: .init( @@ -69,6 +69,9 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase { """ { "experimentalFeatures" : { + "fieldMerging" : [ + "all" + ], "legacySafelistingCompatibleOperations" : true }, "input" : { @@ -100,9 +103,6 @@ class ApolloCodegenConfigurationCodableTests: XCTestCase { "inputObjects" : "none" }, "deprecatedEnumCases" : "exclude", - "fieldMerging" : [ - "all" - ], "markOperationDefinitionsAsFinal" : true, "operationDocumentFormat" : [ "definition" diff --git a/Tests/ApolloCodegenTests/ApolloCodegenTests.swift b/Tests/ApolloCodegenTests/ApolloCodegenTests.swift index 431c90005..3475527d4 100644 --- a/Tests/ApolloCodegenTests/ApolloCodegenTests.swift +++ b/Tests/ApolloCodegenTests/ApolloCodegenTests.swift @@ -2374,6 +2374,46 @@ class ApolloCodegenTests: XCTestCase { }) } + func test__validation__givenFieldMerging_notAll_andSelectionSetInitializers_enabled_shouldThrowError() throws { + // given + let fieldMergingOptions: [ApolloCodegenConfiguration.FieldMerging] = [ + .none, + .ancestors, + .namedFragments, + .siblings, + [.ancestors, .namedFragments], + [.siblings, .ancestors], + [.siblings, .namedFragments] + ] + let initializerOptions: [ApolloCodegenConfiguration.SelectionSetInitializers] = [ + .all, + .localCacheMutations, + .operations, + .namedFragments, + .fragment(named: "TestFragment"), + [.operations, .localCacheMutations] + ] + + for fieldMergingOption in fieldMergingOptions { + for initializerOption in initializerOptions { + + let config = ApolloCodegenConfiguration.mock( + .other, + options: .init( + selectionSetInitializers: initializerOption + ), + experimentalFeatures: .init( + fieldMerging: fieldMergingOption + ) + ) + + // then + expect(try ApolloCodegen._validate(config: config)) + .to(throwError(ApolloCodegen.Error.fieldMergingIncompatibility)) + } + } + } + // MARK: Path Match Exclusion Tests func test__match__givenFilesInSpecialExcludedPaths_shouldNotReturnExcludedPaths() throws { diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift index 1e182cbc1..7610da920 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift @@ -653,9 +653,9 @@ class FragmentTemplateTests: XCTestCase { // when try await buildSubjectAndFragment(config: .mock( options: .init( - selectionSetInitializers: [.all], - fieldMerging: test - ) + selectionSetInitializers: [.all] + ), + experimentalFeatures: .init(fieldMerging: test) )) let actual = renderSubject() diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift index 80879a6d2..72715c049 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift @@ -669,9 +669,9 @@ class OperationDefinitionTemplateTests: XCTestCase { config = .mock( options: .init( - selectionSetInitializers: [.all], - fieldMerging: test - ) + selectionSetInitializers: [.all] + ), + experimentalFeatures: .init(fieldMerging: test) ) // when diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift index 290f0b836..572ba8382 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_ErrorHandling_Tests.swift @@ -44,7 +44,7 @@ class SelectionSetTemplate_ErrorHandling_Tests: XCTestCase { let config = ApolloCodegenConfiguration.mock( schemaNamespace: "TestSchema", output: .mock(moduleType: .swiftPackageManager, operations: .inSchemaModule), - options: .init( + experimentalFeatures: .init( fieldMerging: fieldMerging ) ) diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift index 010fb7a6f..340832f1d 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplate_FieldMerging_Tests.swift @@ -52,11 +52,11 @@ class SelectionSetTemplate_FieldMerging_Tests: XCTestCase { options: .init( additionalInflectionRules: inflectionRules, schemaDocumentation: schemaDocumentation, - fieldMerging: fieldMerging, cocoapodsCompatibleImportStatements: cocoapodsImportStatements, warningsOnDeprecatedUsage: warningsOnDeprecatedUsage, conversionStrategies: conversionStrategies - ) + ), + experimentalFeatures: .init(fieldMerging: fieldMerging) )) let mockTemplateRenderer = MockTemplateRenderer( target: .operationFile(), diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegen+Errors.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegen+Errors.swift index 0c6b0ce79..ed20dd488 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegen+Errors.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegen+Errors.swift @@ -17,6 +17,7 @@ extension ApolloCodegen { case invalidConfiguration(message: String) case invalidSchemaName(_ name: String, message: String) case targetNameConflict(name: String) + case fieldMergingIncompatibility public var errorDescription: String? { switch self { @@ -52,6 +53,13 @@ extension ApolloCodegen { Target name '\(name)' conflicts with a reserved library name. Please choose a different \ target name. """ + case .fieldMergingIncompatibility: + return """ + Options for disabling 'fieldMerging' and enabling 'selectionSetInitializers' are + incompatible. + + Please set either 'fieldMerging' to 'all' or 'selectionSetInitializers' to be empty. + """ } } } diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegenConfiguration.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegenConfiguration.swift index cff16aa86..c0b6b171a 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegenConfiguration.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/ApolloCodegenConfiguration.swift @@ -466,8 +466,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { public let schemaDocumentation: Composition /// Which generated selection sets should include generated initializers. public let selectionSetInitializers: SelectionSetInitializers - /// Which merged fields and named fragment accessors are generated. Defaults to `.all`. - public let fieldMerging: FieldMerging /// How to generate the operation documents for your generated operations. public let operationDocumentFormat: OperationDocumentFormat /// Generate import statements that are compatible with including `Apollo` via Cocoapods. @@ -515,7 +513,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { public static let deprecatedEnumCases: Composition = .include public static let schemaDocumentation: Composition = .include public static let selectionSetInitializers: SelectionSetInitializers = [.localCacheMutations] - public static let fieldMerging: FieldMerging = [.all] public static let operationDocumentFormat: OperationDocumentFormat = .definition public static let cocoapodsCompatibleImportStatements: Bool = false public static let warningsOnDeprecatedUsage: Composition = .include @@ -533,7 +530,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { /// - schemaDocumentation: Whether schema documentation is added to the generated files. /// - selectionSetInitializers: Which generated selection sets should include /// generated initializers. - /// - fieldMerging: Which merged fields and named fragment accessors are generated. /// - operationDocumentFormat: How to generate the operation documents for your generated operations. /// - cocoapodsCompatibleImportStatements: Generate import statements that are compatible with /// including `Apollo` via Cocoapods. @@ -549,7 +545,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { deprecatedEnumCases: Composition = Default.deprecatedEnumCases, schemaDocumentation: Composition = Default.schemaDocumentation, selectionSetInitializers: SelectionSetInitializers = Default.selectionSetInitializers, - fieldMerging: FieldMerging = Default.fieldMerging, operationDocumentFormat: OperationDocumentFormat = Default.operationDocumentFormat, cocoapodsCompatibleImportStatements: Bool = Default.cocoapodsCompatibleImportStatements, warningsOnDeprecatedUsage: Composition = Default.warningsOnDeprecatedUsage, @@ -561,7 +556,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { self.deprecatedEnumCases = deprecatedEnumCases self.schemaDocumentation = schemaDocumentation self.selectionSetInitializers = selectionSetInitializers - self.fieldMerging = fieldMerging self.operationDocumentFormat = operationDocumentFormat self.cocoapodsCompatibleImportStatements = cocoapodsCompatibleImportStatements self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage @@ -578,7 +572,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { case deprecatedEnumCases case schemaDocumentation case selectionSetInitializers - case fieldMerging case apqs case operationDocumentFormat case cocoapodsCompatibleImportStatements @@ -612,11 +605,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { forKey: .selectionSetInitializers ) ?? Default.selectionSetInitializers - fieldMerging = try values.decodeIfPresent( - FieldMerging.self, - forKey: .fieldMerging - ) ?? Default.fieldMerging - operationDocumentFormat = try values.decodeIfPresent( OperationDocumentFormat.self, forKey: .operationDocumentFormat @@ -660,7 +648,6 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { try container.encode(self.deprecatedEnumCases, forKey: .deprecatedEnumCases) try container.encode(self.schemaDocumentation, forKey: .schemaDocumentation) try container.encode(self.selectionSetInitializers, forKey: .selectionSetInitializers) - try container.encode(self.fieldMerging, forKey: .fieldMerging) try container.encode(self.operationDocumentFormat, forKey: .operationDocumentFormat) try container.encode(self.cocoapodsCompatibleImportStatements, forKey: .cocoapodsCompatibleImportStatements) try container.encode(self.warningsOnDeprecatedUsage, forKey: .warningsOnDeprecatedUsage) @@ -965,25 +952,41 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { } public struct ExperimentalFeatures: Codable, Equatable { - /** - * **EXPERIMENTAL**: If enabled, the generated operations will be transformed using a method - * that attempts to maintain compatibility with the legacy behavior from - * [`apollo-tooling`](https://github.com/apollographql/apollo-tooling) - * for registering persisted operation to a safelist. - * - * - Note: Safelisting queries is a deprecated feature of Apollo Server that has reduced - * support for legacy use cases. This option may not work as intended in all situations. - */ + + /// **EXPERIMENTAL**: If enabled, the generated operations will be transformed using a method + /// that attempts to maintain compatibility with the legacy behavior from + /// [`apollo-tooling`](https://github.com/apollographql/apollo-tooling) + /// for registering persisted operation to a safelist. + /// + /// - Note: Safelisting queries is a deprecated feature of Apollo Server that has reduced + /// support for legacy use cases. This option may not work as intended in all situations. public let legacySafelistingCompatibleOperations: Bool + /// **EXPERIMENTAL**: Determines which merged fields and named fragment accessors are generated. + /// Defaults to `.all`. + /// + /// - Note: Disabling field merging and `selectionSetInitializers` functionality are + /// incompatible. If using `selectionSetInitializers`, `fieldMerging` must be set to `.all`, + /// otherwise a validation error will be thrown when runnning code generation. + public let fieldMerging: FieldMerging + /// Default property values public struct Default { public static let legacySafelistingCompatibleOperations: Bool = false + public static let fieldMerging: FieldMerging = [.all] } - + + /// Designated Initializer + /// + /// - Parameters: + /// - fieldMerging: Which merged fields and named fragment accessors are generated. + /// - legacySafelistingCompatibleOperations: Generate operations that are compatible with + /// legacy safelisting. public init( + fieldMerging: FieldMerging = Default.fieldMerging, legacySafelistingCompatibleOperations: Bool = Default.legacySafelistingCompatibleOperations ) { + self.fieldMerging = fieldMerging self.legacySafelistingCompatibleOperations = legacySafelistingCompatibleOperations } @@ -991,16 +994,29 @@ public struct ApolloCodegenConfiguration: Codable, Equatable { public enum CodingKeys: CodingKey, CaseIterable { case legacySafelistingCompatibleOperations + case fieldMerging } public init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) + fieldMerging = try values.decodeIfPresent( + FieldMerging.self, + forKey: .fieldMerging + ) ?? Default.fieldMerging + legacySafelistingCompatibleOperations = try values.decodeIfPresent( Bool.self, forKey: .legacySafelistingCompatibleOperations ) ?? Default.legacySafelistingCompatibleOperations } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.fieldMerging, forKey: .fieldMerging) + try container.encode(self.legacySafelistingCompatibleOperations, forKey: .legacySafelistingCompatibleOperations) + } } // MARK: - Properties @@ -1174,35 +1190,35 @@ extension ApolloCodegenConfiguration.OperationsFileOutput { } } -extension ApolloCodegenConfiguration.OutputOptions { +extension ApolloCodegenConfiguration { /// Determine whether the operations files are output to the schema types module. func shouldGenerateSelectionSetInitializers(for operation: IR.Operation) -> Bool { - guard fieldMerging == .all else { return false } + guard experimentalFeatures.fieldMerging == .all else { return false } switch operation.definition.isLocalCacheMutation { - case true where selectionSetInitializers.contains(.localCacheMutations): + case true where options.selectionSetInitializers.contains(.localCacheMutations): return true - case false where selectionSetInitializers.contains(.operations): + case false where options.selectionSetInitializers.contains(.operations): return true default: - return selectionSetInitializers.contains(definitionNamed: operation.definition.name) + return options.selectionSetInitializers.contains(definitionNamed: operation.definition.name) } } /// Determine whether the operations files are output to the schema types module. func shouldGenerateSelectionSetInitializers(for fragment: IR.NamedFragment) -> Bool { - guard fieldMerging == .all else { return false } - - if selectionSetInitializers.contains(.namedFragments) { return true } + guard experimentalFeatures.fieldMerging == .all else { return false } + + if options.selectionSetInitializers.contains(.namedFragments) { return true } if fragment.definition.isLocalCacheMutation && - selectionSetInitializers.contains(.localCacheMutations) { + options.selectionSetInitializers.contains(.localCacheMutations) { return true } - return selectionSetInitializers.contains(definitionNamed: fragment.definition.name) + return options.selectionSetInitializers.contains(definitionNamed: fragment.definition.name) } } @@ -1466,8 +1482,7 @@ extension ApolloCodegenConfiguration.OutputOptions { /// - deprecatedEnumCases: How deprecated enum cases from the schema should be handled. /// - schemaDocumentation: Whether schema documentation is added to the generated files. /// - selectionSetInitializers: Which generated selection sets should include - /// generated initializers. - /// - fieldMerging: Which merged fields and named fragment accessors are generated. + /// generated initializers. /// - apqs: Whether the generated operations should use Automatic Persisted Queries. /// - cocoapodsCompatibleImportStatements: Generate import statements that are compatible with /// including `Apollo` via Cocoapods. @@ -1487,7 +1502,6 @@ extension ApolloCodegenConfiguration.OutputOptions { deprecatedEnumCases: ApolloCodegenConfiguration.Composition = Default.deprecatedEnumCases, schemaDocumentation: ApolloCodegenConfiguration.Composition = Default.schemaDocumentation, selectionSetInitializers: ApolloCodegenConfiguration.SelectionSetInitializers = Default.selectionSetInitializers, - fieldMerging: ApolloCodegenConfiguration.FieldMerging = Default.fieldMerging, apqs: ApolloCodegenConfiguration.APQConfig, cocoapodsCompatibleImportStatements: Bool = Default.cocoapodsCompatibleImportStatements, warningsOnDeprecatedUsage: ApolloCodegenConfiguration.Composition = Default.warningsOnDeprecatedUsage, @@ -1499,7 +1513,6 @@ extension ApolloCodegenConfiguration.OutputOptions { self.deprecatedEnumCases = deprecatedEnumCases self.schemaDocumentation = schemaDocumentation self.selectionSetInitializers = selectionSetInitializers - self.fieldMerging = fieldMerging self.operationDocumentFormat = apqs.operationDocumentFormat self.cocoapodsCompatibleImportStatements = cocoapodsCompatibleImportStatements self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage @@ -1519,7 +1532,6 @@ extension ApolloCodegenConfiguration.OutputOptions { /// - schemaDocumentation: Whether schema documentation is added to the generated files. /// - selectionSetInitializers: Which generated selection sets should include /// generated initializers. - /// - fieldMerging: Which merged fields and named fragment accessors are generated. /// - operationDocumentFormat: How to generate the operation documents for your generated operations. /// - cocoapodsCompatibleImportStatements: Generate import statements that are compatible with /// including `Apollo` via Cocoapods. @@ -1539,7 +1551,6 @@ extension ApolloCodegenConfiguration.OutputOptions { deprecatedEnumCases: ApolloCodegenConfiguration.Composition = Default.deprecatedEnumCases, schemaDocumentation: ApolloCodegenConfiguration.Composition = Default.schemaDocumentation, selectionSetInitializers: ApolloCodegenConfiguration.SelectionSetInitializers = Default.selectionSetInitializers, - fieldMerging: ApolloCodegenConfiguration.FieldMerging = Default.fieldMerging, operationDocumentFormat: ApolloCodegenConfiguration.OperationDocumentFormat = Default.operationDocumentFormat, cocoapodsCompatibleImportStatements: Bool = Default.cocoapodsCompatibleImportStatements, warningsOnDeprecatedUsage: ApolloCodegenConfiguration.Composition = Default.warningsOnDeprecatedUsage, @@ -1551,7 +1562,6 @@ extension ApolloCodegenConfiguration.OutputOptions { self.deprecatedEnumCases = deprecatedEnumCases self.schemaDocumentation = schemaDocumentation self.selectionSetInitializers = selectionSetInitializers - self.fieldMerging = fieldMerging self.operationDocumentFormat = operationDocumentFormat self.cocoapodsCompatibleImportStatements = cocoapodsCompatibleImportStatements self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/ConfigurationValidation.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/ConfigurationValidation.swift index 00281f825..dc35746a0 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/ConfigurationValidation.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/ConfigurationValidation.swift @@ -21,6 +21,12 @@ extension ApolloCodegen.ConfigurationContext { """) } + guard self.experimentalFeatures.fieldMerging == .all || + self.options.selectionSetInitializers == [] + else { + throw ApolloCodegen.Error.fieldMergingIncompatibility + } + guard !SwiftKeywords.DisallowedSchemaNamespaceNames.contains(self.schemaNamespace.lowercased()) else { diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift index 73a930f24..ab0b72e5d 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/SelectionSetValidationContext.swift @@ -30,9 +30,7 @@ struct SelectionSetValidationContext { // Check for type conflicts resulting from singularization/pluralization of fields var typeNamesForEntityFields = [String: String]() - let entityFields = selections.makeFieldIterator( - mergingStrategy: config.options.fieldMerging.options - ) { field in + let entityFields = selections.makeFieldIterator() { field in field is IR.EntityField } @@ -56,9 +54,7 @@ struct SelectionSetValidationContext { // pass into recursive function calls referencedTypeNames.merge(typeNamesForEntityFields) { (current, _) in current } - IteratorSequence(selections.makeNamedFragmentIterator( - mergingStrategy: config.options.fieldMerging.options - )).forEach { fragmentSpread in + IteratorSequence(selections.makeNamedFragmentIterator()).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/FragmentTemplate.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/FragmentTemplate.swift index 62f0d4839..b5a683657 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/FragmentTemplate.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/FragmentTemplate.swift @@ -33,7 +33,7 @@ struct FragmentTemplate: TemplateRenderer { """) \(SelectionSetTemplate( definition: fragment, - generateInitializers: config.options.shouldGenerateSelectionSetInitializers(for: fragment), + generateInitializers: config.config.shouldGenerateSelectionSetInitializers(for: fragment), config: config, nonFatalErrorRecorder: nonFatalErrorRecorder, renderAccessControl: { accessControlModifier(for: .member) }() diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LocalCacheMutationDefinitionTemplate.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LocalCacheMutationDefinitionTemplate.swift index 0698f2d99..8f0483c15 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LocalCacheMutationDefinitionTemplate.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LocalCacheMutationDefinitionTemplate.swift @@ -32,7 +32,7 @@ struct LocalCacheMutationDefinitionTemplate: OperationTemplateRenderer { \(memberAccessControl)struct Data: \(operation.renderedSelectionSetType(config)) { \(SelectionSetTemplate( definition: operation, - generateInitializers: config.options.shouldGenerateSelectionSetInitializers(for: operation), + generateInitializers: config.config.shouldGenerateSelectionSetInitializers(for: operation), config: config, nonFatalErrorRecorder: nonFatalErrorRecorder, renderAccessControl: { accessControlModifier(for: .member) }() diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/OperationDefinitionTemplate.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/OperationDefinitionTemplate.swift index eb4877c9f..8fc04217c 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/OperationDefinitionTemplate.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/OperationDefinitionTemplate.swift @@ -37,7 +37,7 @@ struct OperationDefinitionTemplate: OperationTemplateRenderer { \(accessControlModifier(for: .member))struct Data: \(operation.renderedSelectionSetType(config)) { \(SelectionSetTemplate( definition: operation, - generateInitializers: config.options.shouldGenerateSelectionSetInitializers(for: operation), + generateInitializers: config.config.shouldGenerateSelectionSetInitializers(for: operation), config: config, nonFatalErrorRecorder: nonFatalErrorRecorder, renderAccessControl: { accessControlModifier(for: .member) }() diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift index 212490ef0..efd083353 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift @@ -64,33 +64,6 @@ struct SelectionSetTemplate { ) } - func mergingStrategies( - for selectionSet: IR.SelectionSet - ) -> Set { - if self.config.options.fieldMerging.options == .all { - return [.all] - } - - /* - There are a number of situations in which we will need to calculate all merged - fields, even if the `fieldMerging` option is not set to `.all`. - - 1. When using `selectionSetInitializers`, the initializers must include all merged fields - for the type in order to initialize a fully valid and functional object. - 2. When a selection set is a CompositeInlineFragment, we use all merged fields to calculate - the `__mergedSources` of the fragment. - - In these situations, we should calculate both strategies. We still use the strategy provided - by the `fieldMerging` configuration option for generating property accessors. We only use the - `.all` merged fields in the necessary areas. - */ - if self.generateInitializers || selectionSet.isCompositeInlineFragment { - return [.all, config.options.fieldMerging.options] - } - - return [config.options.fieldMerging.options] - } - /// MARK: - Render Body /// Renders the body of the SelectionSet template for the entire `definition` including all @@ -189,10 +162,7 @@ struct SelectionSetTemplate { // MARK: - Body func BodyTemplate(_ context: SelectionSetContext) -> TemplateString { lazy var computedChildSelectionSets: [SelectionSetContext] = { - IteratorSequence(context.selectionSet.makeInlineFragmentIterator( - mergingStrategy: config.options.fieldMerging.options - )) - .map { + IteratorSequence(context.selectionSet.makeInlineFragmentIterator()).map { createSelectionSetContext(for: $0.selectionSet, inParent: context) } }() @@ -453,12 +423,7 @@ struct SelectionSetTemplate { \(ifLet: selectionSet.direct?.fields.values, { "\($0.map { FieldAccessorTemplate($0, in: scope) }, separator: "\n")" }) - \(selectionSet - .merged[config.options.fieldMerging.options].unsafelyUnwrapped - .fields.values - .map { FieldAccessorTemplate($0, in: scope) }, - separator: "\n" - ) + \(selectionSet.merged.fields.values.map { FieldAccessorTemplate($0, in: scope) }, separator: "\n") """ } @@ -515,10 +480,7 @@ struct SelectionSetTemplate { ) -> TemplateString { guard !(selectionSet.direct?.namedFragments.isEmpty ?? true) - || !selectionSet - .merged[config.options.fieldMerging.options].unsafelyUnwrapped - .namedFragments - .isEmpty + || !selectionSet.merged.namedFragments.isEmpty || (selectionSet.direct?.inlineFragments.containsDeferredFragment ?? false) else { return "" @@ -534,13 +496,9 @@ struct SelectionSetTemplate { \(ifLet: selectionSet.direct?.namedFragments.values, { "\($0.map { NamedFragmentAccessorTemplate($0, in: scope) }, separator: "\n")" }) - \(selectionSet - .merged[config.options.fieldMerging.options] - .unsafelyUnwrapped - .namedFragments.values - .map { NamedFragmentAccessorTemplate($0, in: scope) }, - separator: "\n" - ) + \(selectionSet.merged.namedFragments.values.map { + NamedFragmentAccessorTemplate($0, in: scope) + }, separator: "\n") \(forEachIn: selectionSet.direct?.inlineFragments.values.elements ?? [], { "\(ifLet: $0.typeInfo.deferCondition, DeferredFragmentAccessorTemplate)" }) @@ -735,9 +693,7 @@ struct SelectionSetTemplate { _ context: SelectionSetContext ) -> TemplateString { let selectionSet = context.selectionSet - let allFields = selectionSet.makeFieldIterator( - mergingStrategy: config.options.fieldMerging.options - ) { field in + let allFields = selectionSet.makeFieldIterator { field in field is IR.EntityField } @@ -806,11 +762,8 @@ extension IR.ComputedSelectionSet { return !self.isEntityRoot && !self.isUserDefined && (direct?.isEmpty ?? true) } - fileprivate func shouldBeRendered( - _ config: ApolloCodegen.ConfigurationContext - ) -> Bool { - return direct != nil || - merged[config.options.fieldMerging.options].unsafelyUnwrapped.mergedSources.count >= 1 + fileprivate var shouldBeRendered: Bool { + return direct != nil || merged.mergedSources.count > 1 } /// If the SelectionSet is a reference to another rendered SelectionSet, returns the qualified @@ -823,15 +776,11 @@ extension IR.ComputedSelectionSet { fileprivate func nameForReferencedSelectionSet( config: ApolloCodegen.ConfigurationContext ) -> String? { - guard direct == nil && - merged[config.options.fieldMerging.options].unsafelyUnwrapped.mergedSources.count == 1 - else { + guard direct == nil && merged.mergedSources.count == 1 else { return nil } - return merged[config.options.fieldMerging.options] - .unsafelyUnwrapped - .mergedSources + return merged.mergedSources .first.unsafelyUnwrapped .generatedSelectionSetNamePath( from: typeInfo,