Skip to content

Commit

Permalink
fix: Type case with only reserved fields is not composite inline frag…
Browse files Browse the repository at this point in the history
  • Loading branch information
calvincestari authored and gh-action-runner committed Feb 9, 2024
1 parent c844d74 commit 240aded
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 25 deletions.
39 changes: 21 additions & 18 deletions Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ struct SelectionSetTemplate {
\(SelectionSetNameDocumentation(inlineFragment))
\(renderAccessControl())\
struct \(inlineFragment.renderedTypeName): \(SelectionSetType(asInlineFragment: true))\
\(if: inlineFragment.isCompositeSelectionSet, ", \(config.ApolloAPITargetName).CompositeInlineFragment")\
\(if: inlineFragment.isCompositeInlineFragment, ", \(config.ApolloAPITargetName).CompositeInlineFragment")\
\(if: inlineFragment.isDeferred, ", \(config.ApolloAPITargetName).Deferrable")\
{
\(BodyTemplate(context))
Expand Down Expand Up @@ -274,18 +274,25 @@ struct SelectionSetTemplate {
var deprecatedArguments: [DeprecatedArgument]? =
config.options.warningsOnDeprecatedUsage == .include ? [] : nil

let selectionsTemplate = TemplateString(
"""
\(renderAccessControl())\
static var __selections: [\(config.ApolloAPITargetName).Selection] { [
\(if: shouldIncludeTypenameSelection(for: scope), ".field(\"__typename\", String.self),")
\(renderedSelections(groupedSelections.unconditionalSelections, &deprecatedArguments), terminator: ",")
\(groupedSelections.inclusionConditionGroups.map {
renderedConditionalSelectionGroup($0, $1, in: scope, &deprecatedArguments)
}, terminator: ",")
] }
"""
)
let shouldIncludeTypenameSelection = shouldIncludeTypenameSelection(for: scope)
let selectionsTemplate: TemplateString

if !groupedSelections.isEmpty || shouldIncludeTypenameSelection {
selectionsTemplate = TemplateString("""
\(renderAccessControl())\
static var __selections: [\(config.ApolloAPITargetName).Selection] { [
\(if: shouldIncludeTypenameSelection, ".field(\"__typename\", String.self),")
\(renderedSelections(groupedSelections.unconditionalSelections, &deprecatedArguments), terminator: ",")
\(groupedSelections.inclusionConditionGroups.map {
renderedConditionalSelectionGroup($0, $1, in: scope, &deprecatedArguments)
}, terminator: ",")
] }
"""
)
} else {
selectionsTemplate = ""
}

return """
\(if: deprecatedArguments != nil && !deprecatedArguments.unsafelyUnwrapped.isEmpty, """
\(deprecatedArguments.unsafelyUnwrapped.map { """
Expand Down Expand Up @@ -752,12 +759,8 @@ private class SelectionSetNameCache {

extension IR.ComputedSelectionSet {

fileprivate var isCompositeSelectionSet: Bool {
return direct?.isEmpty ?? true
}

fileprivate var isCompositeInlineFragment: Bool {
return !self.isEntityRoot && isCompositeSelectionSet
return !self.isEntityRoot && !self.isUserDefined && (direct?.isEmpty ?? true)
}

fileprivate var shouldBeRendered: Bool {
Expand Down
6 changes: 4 additions & 2 deletions Sources/IR/IR+ComputedSelectionSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ extension ComputedSelectionSet {
private func createShallowlyMergedNestedEntityField(from field: EntityField) -> EntityField {
let typeInfo = SelectionSet.TypeInfo(
entity: entityStorage.entity(for: field.underlyingField, on: typeInfo.entity),
scopePath: self.typeInfo.scopePath.appending(field.selectionSet.typeInfo.scope)
scopePath: self.typeInfo.scopePath.appending(field.selectionSet.typeInfo.scope),
isUserDefined: false
)

let newSelectionSet = SelectionSet(
Expand Down Expand Up @@ -149,7 +150,8 @@ extension ComputedSelectionSet {

let typeInfo = SelectionSet.TypeInfo(
entity: self.typeInfo.entity,
scopePath: self.typeInfo.scopePath.mutatingLast { $0.appending(condition) }
scopePath: self.typeInfo.scopePath.mutatingLast { $0.appending(condition) },
isUserDefined: false
)

let selectionSet = SelectionSet(
Expand Down
10 changes: 8 additions & 2 deletions Sources/IR/IR+DirectSelections.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ public class DirectSelections: Equatable, CustomDebugStringConvertible {

let typeInfo = SelectionSet.TypeInfo(
entity: existingField.entity,
scopePath: wrapperScope
scopePath: wrapperScope,
isUserDefined: true
)

let selectionSet = SelectionSet(
Expand All @@ -111,7 +112,8 @@ public class DirectSelections: Equatable, CustomDebugStringConvertible {
entity: newField.entity,
scopePath: wrapperField.selectionSet.scopePath.mutatingLast {
$0.appending(newFieldConditions)
}
},
isUserDefined: true
)

let newFieldSelectionSet = SelectionSet(
Expand Down Expand Up @@ -209,6 +211,10 @@ public class DirectSelections: Equatable, CustomDebugStringConvertible {
public private(set) var inclusionConditionGroups:
OrderedDictionary<AnyOf<InclusionConditions>, DirectSelections.ReadOnly> = [:]

public var isEmpty: Bool {
unconditionalSelections.isEmpty && inclusionConditionGroups.isEmpty
}

init(_ directSelections: DirectSelections.ReadOnly) {
for selection in directSelections.fields {
if let condition = selection.value.inclusionConditions {
Expand Down
6 changes: 4 additions & 2 deletions Sources/IR/IR+RootFieldBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ class RootFieldBuilder {
) async -> SelectionSet {
let typeInfo = SelectionSet.TypeInfo(
entity: entity,
scopePath: scopePath
scopePath: scopePath,
isUserDefined: true
)

var directSelections: DirectSelections? = nil
Expand Down Expand Up @@ -420,7 +421,8 @@ class RootFieldBuilder {

let typeInfo = SelectionSet.TypeInfo(
entity: parentTypeInfo.entity,
scopePath: scopePath
scopePath: scopePath,
isUserDefined: true
)

let fragmentSpread = NamedFragmentSpread(
Expand Down
12 changes: 11 additions & 1 deletion Sources/IR/IR+SelectionSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ public class SelectionSet: Hashable, CustomDebugStringConvertible {
/// The selection set's `scope` is the last element in the list.
public let scopePath: LinkedList<ScopeDescriptor>

/// Indicates if the `SelectionSet` was created directly due to a selection set in the user defined `.graphql` definition file.
///
/// If `false`, the selection set was artificially created by the IR. Currently, the only reason for this is a `CompositeInlineFragment` created during calculation of merged selections for field merging.
public var isUserDefined: Bool

// MARK: - Computed Properties

/// Describes all of the types and inclusion conditions the selection set matches.
/// Derived from all the selection set's parents.
public var scope: ScopeDescriptor { scopePath.last.value }
Expand All @@ -28,6 +35,7 @@ public class SelectionSet: Hashable, CustomDebugStringConvertible {
public var deferCondition: CompilationResult.DeferCondition? {
scope.scopePath.last.value.deferCondition
}

public var isDeferred: Bool { deferCondition != nil }

/// Indicates if the `SelectionSet` represents a root selection set.
Expand All @@ -38,10 +46,12 @@ public class SelectionSet: Hashable, CustomDebugStringConvertible {

init(
entity: Entity,
scopePath: LinkedList<ScopeDescriptor>
scopePath: LinkedList<ScopeDescriptor>,
isUserDefined: Bool
) {
self.entity = entity
self.scopePath = scopePath
self.isUserDefined = isUserDefined
}

public static func == (lhs: TypeInfo, rhs: TypeInfo) -> Bool {
Expand Down

0 comments on commit 240aded

Please sign in to comment.