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

SelectionSet Codegen __typename fix - Closes #2955 #2983

Merged
merged 2 commits into from
Apr 26, 2023
Merged
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,6 @@ SwiftScripts/.build-**
# Local generated packages we don't need in the main project
Sources/AnimalKingdomAPI/Generated/Package.swift
Sources/AnimalKingdomAPI/Generated/Package.resolved

# Generated js files we don't need committed
Sources/ApolloCodegenLib/Frontend/dist/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions Sources/ApolloCodegenLib/Frontend/CompilationResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ public class CompilationResult: JavaScriptObject {
private enum Constants {
static let LocalCacheMutationDirectiveName = "apollo_client_ios_localCacheMutation"
}
lazy var rootTypes: RootTypeDefinition = self["rootTypes"]

lazy var referencedTypes: [GraphQLNamedType] = self["referencedTypes"]

lazy var operations: [OperationDefinition] = self["operations"]
Expand All @@ -13,6 +15,14 @@ public class CompilationResult: JavaScriptObject {

lazy var schemaDocumentation: String? = self["schemaDocumentation"]

public class RootTypeDefinition: JavaScriptObject {
lazy var queryType: GraphQLNamedType = self["queryType"]

lazy var mutationType: GraphQLNamedType? = self["mutationType"]

lazy var subscriptionType: GraphQLNamedType? = self["subscriptionType"]
}

public class OperationDefinition: JavaScriptObject, Equatable {
lazy var name: String = self["name"]

Expand Down
5 changes: 2 additions & 3 deletions Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,8 @@ public class GraphQLCompositeType: GraphQLNamedType {
"Type - \(name)"
}

var isRootFieldType: Bool {
["Query", "Mutation", "Subscription"].contains(name)
}
var isRootFieldType: Bool = false

}

protocol GraphQLInterfaceImplementingType: GraphQLCompositeType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function filePathForNode(node: ASTNode): string | undefined {
}

export interface CompilationResult {
rootTypes: ir.RootTypeDefinition;
operations: ir.OperationDefinition[];
fragments: ir.FragmentDefinition[];
referencedTypes: GraphQLNamedType[];
Expand All @@ -71,6 +72,17 @@ export function compileToIR(
const fragmentMap = new Map<String, ir.FragmentDefinition>();
const referencedTypes = new Set<GraphQLNamedType>();

const queryType = schema.getQueryType() as GraphQLNamedType;
if (queryType === undefined) {
throw new GraphQLError("GraphQL Schema must contain a 'query' root type definition.", { });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this we'd ever reach this stage. Since this is a spec violation it'll likely get caught by graphql-js validation before we start compiling the IR.

}

const rootTypes: ir.RootTypeDefinition = {
queryType: queryType,
mutationType: schema.getMutationType() ?? undefined,
subscriptionType: schema.getSubscriptionType() ?? undefined
};

for (const definitionNode of document.definitions) {
if (definitionNode.kind !== Kind.OPERATION_DEFINITION) continue;

Expand All @@ -86,7 +98,8 @@ export function compileToIR(
}

return {
operations,
rootTypes: rootTypes,
operations: operations,
fragments: Array.from(fragmentMap.values()),
referencedTypes: Array.from(referencedTypes.values()),
schemaDocumentation: schema.description ?? undefined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import {
GraphQLCompositeType,
GraphQLInputType,
GraphQLNamedType,
GraphQLObjectType,
GraphQLOutputType,
GraphQLType,
} from "graphql";
import { GraphQLValue } from "./values";

export interface RootTypeDefinition {
queryType: GraphQLNamedType;
mutationType: GraphQLNamedType | undefined;
subscriptionType: GraphQLNamedType | undefined;
}

export interface OperationDefinition {
name: string;
operationType: OperationType;
Expand Down
7 changes: 7 additions & 0 deletions Sources/ApolloCodegenLib/Frontend/auto_rollup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
output_file="$SCRIPT_DIR/ApolloCodegenFrontendBundle.swift"
$( cd "$SCRIPT_DIR/Javascript" && rollup -c )
minJS=$(cat "$SCRIPT_DIR/dist/ApolloCodegenFrontend.bundle.js")
printf "%s%s%s" "let ApolloCodegenFrontendBundle: String = #\"" "$minJS" "\"#" > $output_file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done!

14 changes: 14 additions & 0 deletions Sources/ApolloCodegenLib/IR/IR.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ class IR {
referencedTypes: .init(compilationResult.referencedTypes),
documentation: compilationResult.schemaDocumentation
)
self.processRootTypes()
}

private func processRootTypes() {
let rootTypes = compilationResult.rootTypes
let typeList = [rootTypes.queryType.name, rootTypes.mutationType?.name, rootTypes.subscriptionType?.name].compactMap { $0 }

compilationResult.operations.forEach { op in
op.rootType.isRootFieldType = typeList.contains(op.rootType.name)
}

compilationResult.fragments.forEach { fragment in
fragment.type.isRootFieldType = typeList.contains(fragment.type.name)
}
}

/// A top level GraphQL definition, which can be an operation or a named fragment.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

public extension CompilationResult {

class func mock() -> Self {
class func mock(
rootTypes: RootTypeDefinition = RootTypeDefinition.mock()
) -> Self {
let mock = Self.emptyMockObject()
mock.rootTypes = rootTypes
mock.referencedTypes = []
mock.fragments = []
mock.operations = []
Expand All @@ -12,6 +15,22 @@ public extension CompilationResult {

}

public extension CompilationResult.RootTypeDefinition {

class func mock(
queryName: String = "Query",
mutationName: String = "Mutation",
subscriptionName: String = "Subscription"
) -> Self {
let mock = Self.emptyMockObject()
mock.queryType = GraphQLCompositeType.mock(queryName)
mock.mutationType = GraphQLCompositeType.mock(mutationName)
mock.subscriptionType = GraphQLCompositeType.mock(subscriptionName)
return mock
}

}

public extension CompilationResult.OperationDefinition {

class func mock(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public extension GraphQLCompositeType {
}
}


public extension GraphQLObjectType {
class override func mock(
_ name: String = ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,53 @@ class SelectionSetTemplateTests: XCTestCase {
// then
expect(actual).to(equalLineByLine(expected, atLine: 6, ignoringExtraLines: true))
}

func test__render_selections__givenCustomRootTypes_doesNotGenerateTypenameField() throws {
// given
schemaSDL = """
schema {
query: RootQueryType
mutation: RootMutationType
}

type RootQueryType {
allAnimals: [Animal!]
}

type RootMutationType {
feedAnimal: Animal!
}

type Animal {
FieldName: String!
}
"""

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

let expected = """
public static var __selections: [ApolloAPI.Selection] { [
.field("allAnimals", [AllAnimal]?.self),
] }
"""

// when
try buildSubjectAndOperation()
let allAnimals = try XCTUnwrap(
operation[field: "query"] as? IR.EntityField
)

let actual = subject.render(field: allAnimals)

// then
expect(actual).to(equalLineByLine(expected, atLine: 7, ignoringExtraLines: true))
}

// MARK: Selections - Fields

Expand Down