Skip to content

Commit

Permalink
Field Merging[1/x] Configuration Options
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyMDev committed Mar 21, 2024
1 parent 3364c10 commit eec8762
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,8 @@ 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.
Expand Down Expand Up @@ -513,6 +515,7 @@ 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
Expand All @@ -530,6 +533,7 @@ 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.
Expand All @@ -545,6 +549,7 @@ 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,
Expand All @@ -556,6 +561,7 @@ 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
Expand All @@ -572,6 +578,7 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
case deprecatedEnumCases
case schemaDocumentation
case selectionSetInitializers
case fieldMerging
case apqs
case operationDocumentFormat
case cocoapodsCompatibleImportStatements
Expand Down Expand Up @@ -605,6 +612,11 @@ 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
Expand Down Expand Up @@ -648,6 +660,7 @@ 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)
Expand Down Expand Up @@ -902,6 +915,43 @@ public struct ApolloCodegenConfiguration: Codable, Equatable {
}
}

/// The `FieldMerging` configuration is used to determine what merged fields and named fragment
/// accessors are present on the generated selection set models. Field merging generates
/// selection set models that are easier to use, but more verbose.
///
/// Property accessors are always generated for each field directly included in a selection
/// set in the GraphQL definition. In addition, the code generation engine can compute which
/// selections from a selection set's parents, sibling inline fragments, and named fragment
/// spreads will also be included on the response object, given the selection set's scope.
///
/// By default, all possible fields and named fragment accessors are merged into each selection
/// set.
public struct FieldMerging: OptionSet, Codable, Equatable {
/// Merges fields and fragment accessors from the selection set's direct ancestors.
public static let ancestors = FieldMerging(rawValue: 1 << 0)

/// Merges fields and fragment accessors from sibling inline fragments that match the selection
/// set's scope.
public static let siblings = FieldMerging(rawValue: 1 << 1)

/// Merges fields and fragment accessors from named fragments that have been spread into the
/// selection set.
public static let namedFragments = FieldMerging(rawValue: 1 << 2)

/// Merges all possible fields and fragment accessors from all sources.
public static let all: FieldMerging = [.ancestors, .siblings, .namedFragments]

/// Disables field merging entirely. Aside from removal of redundant selections, the shape of
/// the generated models will directly mirror the GraphQL definition.
public static let none: FieldMerging = FieldMerging(rawValue: 0)

public let rawValue: Int

public init(rawValue: Int) {
self.rawValue = rawValue
}
}

public struct ExperimentalFeatures: Codable, Equatable {
/**
* **EXPERIMENTAL**: If enabled, the generated operations will be transformed using a method
Expand Down Expand Up @@ -1332,6 +1382,7 @@ 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.
/// - apqs: Whether the generated operations should use Automatic Persisted Queries.
/// - cocoapodsCompatibleImportStatements: Generate import statements that are compatible with
/// including `Apollo` via Cocoapods.
Expand All @@ -1351,6 +1402,7 @@ 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,
Expand All @@ -1362,6 +1414,7 @@ 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
Expand All @@ -1381,6 +1434,7 @@ 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.
Expand All @@ -1400,6 +1454,7 @@ 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,
Expand All @@ -1411,6 +1466,7 @@ extension ApolloCodegenConfiguration.OutputOptions {
self.deprecatedEnumCases = deprecatedEnumCases
self.schemaDocumentation = schemaDocumentation
self.selectionSetInitializers = selectionSetInitializers
self.fieldMerging = fieldMerging
self.operationDocumentFormat = operationDocumentFormat
self.cocoapodsCompatibleImportStatements = cocoapodsCompatibleImportStatements
self.warningsOnDeprecatedUsage = warningsOnDeprecatedUsage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ extension ComputedSelectionSet {
fileprivate func finalize() -> ComputedSelectionSet {
let merged = MergedSelections(
mergedSources: mergedSources,
mergingStrategy: .all,
fields: fields,
inlineFragments: inlineFragments,
namedFragments: namedFragments
Expand Down
56 changes: 47 additions & 9 deletions apollo-ios-codegen/Sources/IR/IR+MergedSelections.swift
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import Foundation
import OrderedCollections

/// Represents the selections that merged into a selection set from other selection sets.
/// This includes all selections from other related `SelectionSet`s on the same entity that match
/// the selection set's type scope.
/// Represents the selections that are merged into a selection set from other selection sets,
/// using the given ``MergingStrategy``. See ``MergingStrategy`` for more information on what is
/// included in the ``MergedSelections`` for a given strategy.
///
/// Combining the `MergedSelections` with the `DirectSelections` for a `SelectionSet` provides all
/// selections that are available to be accessed by the selection set.
///
/// To get the `MergedSelections` for a `SelectionSet` use a `ComputedSelectionSet`.
///
/// Selections in the `mergedSelections` are guaranteed to be selected if this `SelectionSet`'s
/// Selections in the `MergedSelections` are guaranteed to be selected if this `SelectionSet`'s
/// `selections` are selected. This means they can be merged into the generated object
/// representing this `SelectionSet` as field accessors.
///
/// To get the ``MergedSelections`` for a ``SelectionSet`` use a ``ComputedSelectionSet/Builder``.
public struct MergedSelections: Equatable {
public let mergedSources: OrderedSet<MergedSource>
public let mergingStrategy: MergingStrategy
public let fields: OrderedDictionary<String, Field>
public let inlineFragments: OrderedDictionary<ScopeCondition, InlineFragmentSpread>
public let namedFragments: OrderedDictionary<String, NamedFragmentSpread>
Expand All @@ -25,6 +23,7 @@ public struct MergedSelections: Equatable {

public static func == (lhs: MergedSelections, rhs: MergedSelections) -> Bool {
lhs.mergedSources == rhs.mergedSources &&
lhs.mergingStrategy == rhs.mergingStrategy &&
lhs.fields == rhs.fields &&
lhs.inlineFragments == rhs.inlineFragments &&
lhs.namedFragments == rhs.namedFragments
Expand All @@ -45,6 +44,45 @@ extension MergedSelections {
}
}

// MARK: - MergingStrategy

extension MergedSelections {
/// The ``MergingStrategy`` is used to determine what merged fields and named fragment
/// accessors are merged into the ``MergedSelections``.
///
/// ``MergedSelections`` can compute which selections from a selection set's parents, sibling
/// inline fragments, and named fragment spreads will also be included on the response object,
/// given the selection set's ``SelectionSet/TypeInfo``.
public struct MergingStrategy: OptionSet, Equatable {
/// Merges fields and fragment accessors from the selection set's direct ancestors.
public static let ancestors = MergingStrategy(rawValue: 1 << 0)

/// Merges fields and fragment accessors from sibling inline fragments that match the selection
/// set's scope.
public static let siblings = MergingStrategy(rawValue: 1 << 1)

/// Merges fields and fragment accessors from named fragments that have been spread into the
/// selection set.
public static let namedFragments = MergingStrategy(rawValue: 1 << 2)

/// Merges all possible fields and fragment accessors from all sources.
///
/// This includes all selections from other related `SelectionSet`s on the same entity that match
/// the selection set's type scope.
///
/// When using this strategy, combining the ``MergedSelections`` with the ``DirectSelections``
/// for a ``SelectionSet`` provides all selections that are available to be accessed by the
/// selection set.
public static let all: MergingStrategy = [.ancestors, .siblings, .namedFragments]

public let rawValue: Int

public init(rawValue: Int) {
self.rawValue = rawValue
}
}
}

// MARK: - CustomDebugStringConvertible

extension MergedSelections: CustomDebugStringConvertible {
Expand Down

0 comments on commit eec8762

Please sign in to comment.