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

Field Merging [4/x] Disable SelectionSetInitializers when field merging is enabled #343

Closed
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 @@ -22,7 +22,7 @@ public class IRBuilderTestWrapper {

public func build(
operation operationDefinition: CompilationResult.OperationDefinition,
mergingStrategy: IR.MergedSelections.MergingStrategy = .all
mergingStrategy: MergedSelections.MergingStrategy = .all
) async -> IRTestWrapper<IR.Operation> {
let operation = await irBuilder.build(operation: operationDefinition)
return IRTestWrapper(
Expand All @@ -36,7 +36,7 @@ public class IRBuilderTestWrapper {

public func build(
fragment fragmentDefinition: CompilationResult.FragmentDefinition,
mergingStrategy: IR.MergedSelections.MergingStrategy = .all
mergingStrategy: MergedSelections.MergingStrategy = .all
) async -> IRTestWrapper<IR.NamedFragment> {
let fragment = await irBuilder.build(fragment: fragmentDefinition)
return IRTestWrapper(
Expand Down
23 changes: 13 additions & 10 deletions Tests/ApolloCodegenInternalTestHelpers/IRTestWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,9 @@ public class SelectionSetTestWrapper: IRTestWrapper<IR.SelectionSet> {
)
}

override func childSelectionSet(
with conditions: ScopeCondition
) -> SelectionSetTestWrapper? {
override func childSelectionSet(with conditions: ScopeCondition) -> SelectionSetTestWrapper? {
self.computed.childSelectionSet(
with: conditions,
with: conditions,
computedSelectionSetCache: computedSelectionSetCache
)
}
Expand All @@ -91,7 +89,9 @@ public class SelectionSetTestWrapper: IRTestWrapper<IR.SelectionSet> {
// MARK: -
extension IRTestWrapper {

public subscript(as typeCase: String) -> SelectionSetTestWrapper? {
public subscript(
as typeCase: String
) -> SelectionSetTestWrapper? {
guard let scope = self.scopeCondition(type: typeCase, conditions: nil) else {
return nil
}
Expand Down Expand Up @@ -259,10 +259,13 @@ extension SelectionSetTestWrapper {
}

public subscript(fragment fragment: String) -> IRTestWrapper<IR.NamedFragmentSpread>? {
IRTestWrapper<IR.NamedFragmentSpread>(
irObject:
computed.direct?.namedFragments[fragment] ?? computed.merged[mergingStrategy]!.namedFragments[fragment],
computedSelectionSetCache: computedSelectionSetCache
guard let fragment = computed.direct?.namedFragments[fragment] ?? computed.merged.namedFragments[fragment] else { return nil }
return IRTestWrapper<IR.NamedFragmentSpread>(
irObject: fragment,
computedSelectionSetCache: .init(
mergingStrategy: self.mergingStrategy,
entityStorage: fragment.fragment.entityStorage
)
)
}
}
Expand Down Expand Up @@ -290,7 +293,7 @@ class ComputedSelectionSetCache {
let selectionSet = ComputedSelectionSet.Builder(
directSelections: selectionSet.selections?.readOnlyView,
typeInfo: selectionSet.typeInfo,
mergingStrategies: [mergingStrategy],
mergingStrategy: mergingStrategy,
entityStorage: entityStorage
).build()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ extension ComputedSelectionSet: ScopedChildSelectionSetAccessible {
direct?
.inlineFragments[conditions]?
.selectionSet ??
merged[computedSelectionSetCache.mergingStrategy]!
merged
.inlineFragments[conditions]?
.selectionSet

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,50 @@ class FragmentTemplateTests: XCTestCase {
expect(actual).to(equalLineByLine(expected, atLine: 20, ignoringExtraLines: true))
}

func test__render_givenOperationSelectionSet_initializerConfig_all_fieldMergingConfig_notAll_doesNotRenderInitializer() async throws {
let tests: [ApolloCodegenConfiguration.FieldMerging] = [
.none,
.ancestors,
.namedFragments,
.siblings,
[.ancestors, .namedFragments],
[.siblings, .ancestors],
[.siblings, .namedFragments]
]

for test in tests {
// given
schemaSDL = """
type Query {
allAnimals: [Animal!]
}

type Animal {
species: String!
}
"""

document = """
fragment TestFragment on Animal {
species
}
"""

// when
try await buildSubjectAndFragment(config: .mock(
options: .init(
selectionSetInitializers: [.all],
fieldMerging: test
)
))

let actual = renderSubject()

// then
expect(actual).to(equalLineByLine("}", atLine: 16, ignoringExtraLines: true))
}
}

// MARK: Local Cache Mutation Tests
func test__render__givenFragment__asLocalCacheMutation_generatesFragmentDeclarationDefinitionAsMutableSelectionSetAndBoilerplate() async throws {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,54 @@ class OperationDefinitionTemplateTests: XCTestCase {
expect(actual).to(equalLineByLine(" }", atLine: 35, ignoringExtraLines: true))
}

func test__render_givenOperationSelectionSet_initializerConfig_all_fieldMergingConfig_notAll_doesNotRenderInitializer() async throws {
let tests: [ApolloCodegenConfiguration.FieldMerging] = [
.none,
.ancestors,
.namedFragments,
.siblings,
[.ancestors, .namedFragments],
[.siblings, .ancestors],
[.siblings, .namedFragments]
]

for test in tests {
// given
schemaSDL = """
type Query {
allAnimals: [Animal!]
}

type Animal {
species: String!
}
"""

document = """
query TestOperation {
allAnimals {
species
}
}
"""

config = .mock(
options: .init(
selectionSetInitializers: [.all],
fieldMerging: test
)
)

// when
try await buildSubjectAndOperation()

let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(" }", atLine: 35, ignoringExtraLines: true))
}
}

// MARK: - Variables

func test__generate__givenQueryWithScalarVariable_generatesQueryOperationWithVariable() async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class SelectionSetTemplate_FieldMerging_Tests: XCTestCase {
) 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,
mergingStrategy: fieldMerging.options
Expand Down Expand Up @@ -542,7 +543,7 @@ class SelectionSetTemplate_FieldMerging_Tests: XCTestCase {
allAnimals {
predator {
species
}
}
... on Dog {
species
}
Expand Down Expand Up @@ -1217,84 +1218,4 @@ class SelectionSetTemplate_FieldMerging_Tests: XCTestCase {
expect(actual).to(equalLineByLine(expected, atLine: 12, ignoringExtraLines: true))
}

// MARK: - SelectionSetInitializers

func test__render_selectionSetInitializer__givenFieldMerging_none_withMergedSelections_rendersInitializerWithAllMergedSelections() async throws {
// given
schemaSDL = """
type Query {
allAnimals: [Animal!]
}

interface Animal {
species: String!
age: Int!
}

interface Pet implements Animal {
species: String!
age: Int!
}

type Dog implements Animal & Pet {
species: String!
age: Int!
bark: Boolean!
}
"""

document = """
query TestOperation {
allAnimals {
age
... on Pet {
species
}
... on Dog {
bark
}
}
}
"""

let expected =
"""
public init(
bark: Bool,
age: Int,
species: String
) {
self.init(_dataDict: DataDict(
data: [
"__typename": TestSchema.Objects.Dog.typename,
"bark": bark,
"age": age,
"species": species,
],
fulfilledFragments: [
ObjectIdentifier(TestOperationQuery.Data.AllAnimal.self),
ObjectIdentifier(TestOperationQuery.Data.AllAnimal.AsDog.self),
ObjectIdentifier(TestOperationQuery.Data.AllAnimal.AsPet.self)
]
))
}
"""

// when
try await buildSubjectAndOperation(
fieldMerging: .none,
selectionSetInitializers: true
)

/*
We only want to test the initializer for TestOperationQuery.Data.AllAnimal.AsDog. But we must
render the entire operation because the IRTestWrappers only allow one merge strategy to be
used at a time. However the `SelectionSetTemplate` is actually determining which merge
strategy to use for each child selection set dynamically. We need to test this behavior.
*/
let actual = subject.renderBody().description

// then
expect(actual).to(equalLineByLine(expected, atLine: 103, ignoringExtraLines: true))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1189,6 +1189,8 @@ extension ApolloCodegenConfiguration.OperationsFileOutput {
extension ApolloCodegenConfiguration.OutputOptions {
/// 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 }

switch operation.definition.isLocalCacheMutation {
case true where selectionSetInitializers.contains(.localCacheMutations):
return true
Expand All @@ -1203,6 +1205,8 @@ extension ApolloCodegenConfiguration.OutputOptions {

/// 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 }

if fragment.definition.isLocalCacheMutation &&
Expand Down
Loading