Skip to content

Commit

Permalink
Alphabetize fragment ordering in source text (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyMDev authored and gh-action-runner committed Nov 9, 2023
1 parent 1755ce3 commit 3f5048f
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
import ApolloAPI

public enum SchemaConfiguration: ApolloAPI.SchemaConfiguration {
public static func cacheKeyInfo(for type: Object, object: ObjectData) -> CacheKeyInfo? {
public static func cacheKeyInfo(
for type: ApolloAPI.Object,
object: ApolloAPI.ObjectData
) -> ApolloAPI.CacheKeyInfo? {
// Implement this function to configure cache key resolution for your schema types.
return nil
}
Expand Down
54 changes: 54 additions & 0 deletions Tests/ApolloCodegenTests/CodeGenIR/IRRootFieldBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4327,6 +4327,60 @@ class IRRootFieldBuilderTests: XCTestCase {
expect(self.computedReferencedFragments).to(equal(expected))
}

func test__referencedFragments__givenMultipleFragments_hasFragmentsInAlphbeticalOrder() async throws {
// given
schemaSDL = """
type Query {
name: String!
}
"""

document =
"""
query NameQuery {
...Fragment4
...Fragment1
}
fragment Fragment4 on Query {
name
...Fragment3
}
fragment Fragment3 on Query {
name
...Fragment2
}
fragment Fragment2 on Query {
name
}
fragment Fragment1 on Query {
name
...Fragment5
}
fragment Fragment5 on Query {
name
}
"""

// when
try await buildSubjectRootField()

let expected: OrderedSet = await [
try ir.builtFragmentStorage.getFragmentIfBuilt(named: "Fragment1").xctUnwrapped(),
try ir.builtFragmentStorage.getFragmentIfBuilt(named: "Fragment2").xctUnwrapped(),
try ir.builtFragmentStorage.getFragmentIfBuilt(named: "Fragment3").xctUnwrapped(),
try ir.builtFragmentStorage.getFragmentIfBuilt(named: "Fragment4").xctUnwrapped(),
try ir.builtFragmentStorage.getFragmentIfBuilt(named: "Fragment5").xctUnwrapped(),
]

// then
expect(self.computedReferencedFragments).to(equal(expected))
}

// MARK: - Deferred Fragments - hasDeferredFragments property

func test__deferredFragments__givenNoDeferredFragment_hasDeferredFragmentsFalse() async throws {
Expand Down
104 changes: 104 additions & 0 deletions Tests/ApolloCodegenTests/OperationDescriptorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import Foundation
import XCTest
import Nimble
import OrderedCollections
import GraphQLCompiler
@testable import IR
import Utilities
@testable import ApolloCodegenLib
import ApolloCodegenInternalTestHelpers

class OperationDescriptorTests: XCTestCase {
var schemaSDL: String!
var document: String!
var ir: IRBuilder!
var subject: OperationDescriptor!

override func setUp() {
super.setUp()
}

override func tearDown() {
subject = nil
schemaSDL = nil
document = nil
ir = nil
super.tearDown()
}

// MARK: - Helpers

func getOperation(
named operationName: String? = nil,
fromJSONSchema json: Bool = false
) async throws {
ir = json ?
try await .mock(schemaJSON: schemaSDL, document: document) :
try await .mock(schema: schemaSDL, document: document)

var operation: CompilationResult.OperationDefinition
if let operationName = operationName {
operation = try XCTUnwrap(ir.compilationResult.operations.first {$0.name == operationName})
} else {
operation = try XCTUnwrap(ir.compilationResult.operations.first)
}

subject = OperationDescriptor(operation)
}

// MARK: - Tests

@available(macOS 13.0, *)
func test__rawSourceText__givenOperationWithDeeplyNestedFragmentsNotInAlphabeticalOrder__hasReferencedFragmentsInSameOrderAsBuiltOperation() async throws {
// given
schemaSDL = """
type Query {
name: String!
}
"""

document =
"""
query NameQuery {
...Fragment4
...Fragment1
}
fragment Fragment4 on Query {
name
...Fragment3
}
fragment Fragment3 on Query {
name
...Fragment2
}
fragment Fragment2 on Query {
name
}
fragment Fragment1 on Query {
name
...Fragment5
}
fragment Fragment5 on Query {
name
}
"""

try await getOperation(named: "NameQuery")

// when
let operationDescriptorReferencedFragments = subject.rawSourceText
.matches(of: /fragment (\S*)\s/)
.map(\.output.1.description)

let operation = await ir.build(operation: subject.underlyingDefinition)
let builtOperationReferencedFragments = operation.referencedFragments.map(\.name)

// then
expect(operationDescriptorReferencedFragments).to(equal(builtOperationReferencedFragments))
}
}
64 changes: 33 additions & 31 deletions Tests/ApolloCodegenTests/OperationIdentifierFactoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ class OperationIdentifierFactoryTests: XCTestCase {
schemaSDL = nil
document = nil
operation = nil
ir = nil
super.tearDown()
}

// MARK: = Helpers
// MARK: - Helpers

func getOperation(
named operationName: String? = nil,
Expand All @@ -47,43 +48,44 @@ class OperationIdentifierFactoryTests: XCTestCase {

// MARK: - Default Operation Identifier Computation Tests

func test__buildOperation__givenOperationWithNoFragments__hasCorrectOperationIdentifier() async throws {
// given
document = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.GraphQLOperation(named: "HeroAndFriendsNames")
)
func test__identifierForOperation__givenOperationWithNoFragments__hasCorrectOperationIdentifier() async throws {
// given
document = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.GraphQLOperation(named: "HeroAndFriendsNames")
)

schemaSDL = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.JSONSchema)
schemaSDL = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.JSONSchema)

let expected = "1e36c3331171b74c012b86caa04fbb01062f37c61227655d9c0729a62c6f7285"
try await getOperation(named: "HeroAndFriendsNames", fromJSONSchema: true)
let expected = "1e36c3331171b74c012b86caa04fbb01062f37c61227655d9c0729a62c6f7285"
try await getOperation(named: "HeroAndFriendsNames", fromJSONSchema: true)

// when
let actual = try await subject.identifier(for: operation)
// when
let actual = try await subject.identifier(for: operation)

// then
expect(actual).to(equal(expected))
}
// then
expect(actual).to(equal(expected))
}

func test__buildOperation__givenOperationWithFragment__hasCorrectOperationIdentifier() async throws {
// given
document = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.GraphQLOperation(named: "HeroAndFriendsNamesWithFragment")
) + "\n" + String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.GraphQLOperation(named: "HeroName")
)
func test__identifierForOperation__givenOperationWithFragment__hasCorrectOperationIdentifier() async throws {
// given
document = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.GraphQLOperation(named: "HeroAndFriendsNamesWithFragment")
) + "\n" + String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.GraphQLOperation(named: "HeroName")
)

schemaSDL = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.JSONSchema)
schemaSDL = try String(
contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.JSONSchema)

let expected = "599cd7d91ede7a5508cdb26b424e3b8e99e6c2c5575b799f6090695289ff8e99"
try await getOperation(named: "HeroAndFriendsNamesWithFragment", fromJSONSchema: true)
let expected = "599cd7d91ede7a5508cdb26b424e3b8e99e6c2c5575b799f6090695289ff8e99"
try await getOperation(named: "HeroAndFriendsNamesWithFragment", fromJSONSchema: true)

// when
let actual = try await subject.identifier(for: operation)
// when
let actual = try await subject.identifier(for: operation)

// then
expect(actual).to(equal(expected))
}

// then
expect(actual).to(equal(expected))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,38 @@ public struct OperationDescriptor: Sendable {
}

func sourceText(withFormat format: SourceFormat) -> String {
format.formatted(underlyingDefinition)
format.formatted(self)
}


fileprivate var allReferencedFragments: [CompilationResult.FragmentDefinition] {
func insertAllFragments(
from fragment: CompilationResult.FragmentDefinition,
into set: inout Set<CompilationResult.FragmentDefinition>
) {
set.insert(fragment)
for referencedFragment in fragment.referencedFragments {
insertAllFragments(from: referencedFragment, into: &set)
}
}

var fragmentSet = Set<CompilationResult.FragmentDefinition>()
for fragment in underlyingDefinition.referencedFragments {
insertAllFragments(from: fragment, into: &fragmentSet)
}
return fragmentSet.sorted { $0.name < $1.name }
}

}

// MARK: - Formatting

fileprivate extension OperationDescriptor.SourceFormat {
func formatted(_ operation: CompilationResult.OperationDefinition) -> String {
var source = operation.source.convertedToSingleLine()
var set = Set<String>()
append(
to: &source,
set: &set,
fragments: operation.referencedFragments
)
func formatted(_ operation: OperationDescriptor) -> String {
var source = operation.underlyingDefinition.source.convertedToSingleLine()
for fragment in operation.allReferencedFragments {
source += formatted(fragment)
}

switch self {
case .rawSource:
return source
Expand All @@ -86,20 +102,6 @@ fileprivate extension OperationDescriptor.SourceFormat {
}
}

private func append(
to source: inout String,
set: inout Set<String>,
fragments: [CompilationResult.FragmentDefinition]
) {
for fragment in fragments {
if !set.contains(fragment.name) {
set.insert(fragment.name)
source += formatted(fragment)
append(to: &source, set: &set, fragments: fragment.referencedFragments)
}
}
}

private func formatted(_ fragment: CompilationResult.FragmentDefinition) -> String {
switch self {
case .rawSource:
Expand Down
4 changes: 4 additions & 0 deletions apollo-ios-codegen/Sources/IR/IR+RootFieldBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ class RootFieldBuilder {
from: rootSelectionSet
)

referencedFragments.sort(by: {
$0.name < $1.name
})

return Result(
rootField: EntityField(rootField, selectionSet: rootIrSelectionSet),
referencedFragments: referencedFragments,
Expand Down

0 comments on commit 3f5048f

Please sign in to comment.