From 8d18f67a6dc0e68baeb2b64aa6116dd13a4f94d7 Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Mon, 21 Oct 2024 20:35:52 -0600
Subject: [PATCH 01/12] chore: Updates to GraphQL 3.0

---
 Package.resolved | 96 ++++++++++++++++++++++++------------------------
 Package.swift    |  2 +-
 2 files changed, 48 insertions(+), 50 deletions(-)

diff --git a/Package.resolved b/Package.resolved
index 253fc02..d84a2e5 100644
--- a/Package.resolved
+++ b/Package.resolved
@@ -1,52 +1,50 @@
 {
-  "object": {
-    "pins": [
-      {
-        "package": "GraphQL",
-        "repositoryURL": "https://github.com/GraphQLSwift/GraphQL.git",
-        "state": {
-          "branch": null,
-          "revision": "ec809df8cce95d6aea820f70f04067abc08080f2",
-          "version": "2.10.3"
-        }
-      },
-      {
-        "package": "swift-atomics",
-        "repositoryURL": "https://github.com/apple/swift-atomics.git",
-        "state": {
-          "branch": null,
-          "revision": "cd142fd2f64be2100422d658e7411e39489da985",
-          "version": "1.2.0"
-        }
-      },
-      {
-        "package": "swift-collections",
-        "repositoryURL": "https://github.com/apple/swift-collections",
-        "state": {
-          "branch": null,
-          "revision": "671108c96644956dddcd89dd59c203dcdb36cec7",
-          "version": "1.1.4"
-        }
-      },
-      {
-        "package": "swift-nio",
-        "repositoryURL": "https://github.com/apple/swift-nio.git",
-        "state": {
-          "branch": null,
-          "revision": "914081701062b11e3bb9e21accc379822621995e",
-          "version": "2.76.1"
-        }
-      },
-      {
-        "package": "swift-system",
-        "repositoryURL": "https://github.com/apple/swift-system.git",
-        "state": {
-          "branch": null,
-          "revision": "c8a44d836fe7913603e246acab7c528c2e780168",
-          "version": "1.4.0"
-        }
+  "pins" : [
+    {
+      "identity" : "graphql",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/GraphQLSwift/GraphQL.git",
+      "state" : {
+        "revision" : "5e098b3b1789169dded5116c171f716d584225ea",
+        "version" : "3.0.0"
       }
-    ]
-  },
-  "version": 1
+    },
+    {
+      "identity" : "swift-atomics",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/apple/swift-atomics.git",
+      "state" : {
+        "revision" : "cd142fd2f64be2100422d658e7411e39489da985",
+        "version" : "1.2.0"
+      }
+    },
+    {
+      "identity" : "swift-collections",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/apple/swift-collections",
+      "state" : {
+        "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7",
+        "version" : "1.1.4"
+      }
+    },
+    {
+      "identity" : "swift-nio",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/apple/swift-nio.git",
+      "state" : {
+        "revision" : "f7dc3f527576c398709b017584392fb58592e7f5",
+        "version" : "2.75.0"
+      }
+    },
+    {
+      "identity" : "swift-system",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/apple/swift-system.git",
+      "state" : {
+        "revision" : "c8a44d836fe7913603e246acab7c528c2e780168",
+        "version" : "1.4.0"
+      }
+    }
+  ],
+  "version" : 2
 }
diff --git a/Package.swift b/Package.swift
index 08fb00e..26346f1 100644
--- a/Package.swift
+++ b/Package.swift
@@ -7,7 +7,7 @@ let package = Package(
         .library(name: "Graphiti", targets: ["Graphiti"]),
     ],
     dependencies: [
-        .package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "2.10.0"),
+        .package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "3.0.0"),
     ],
     targets: [
         .target(name: "Graphiti", dependencies: ["GraphQL"]),

From afd1160ee887b1347e99b335eae54d35473fdeaa Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Mon, 21 Oct 2024 19:22:30 -0600
Subject: [PATCH 02/12] feat: Converts to closure API

---
 Sources/Graphiti/Input/Input.swift            |  4 +-
 Sources/Graphiti/Interface/Interface.swift    |  4 +-
 Sources/Graphiti/Mutation/Mutation.swift      |  4 +-
 Sources/Graphiti/Query/Query.swift            | 51 ++++++++++---------
 .../Graphiti/Subscription/Subscription.swift  |  4 +-
 Sources/Graphiti/Type/Type.swift              | 31 ++++++-----
 Sources/Graphiti/Union/Union.swift            |  6 ++-
 7 files changed, 59 insertions(+), 45 deletions(-)

diff --git a/Sources/Graphiti/Input/Input.swift b/Sources/Graphiti/Input/Input.swift
index 8930210..28eefc9 100644
--- a/Sources/Graphiti/Input/Input.swift
+++ b/Sources/Graphiti/Input/Input.swift
@@ -15,7 +15,9 @@ public final class Input<
         let inputObjectType = try GraphQLInputObjectType(
             name: name,
             description: description,
-            fields: fields(typeProvider: typeProvider),
+            fields: {
+                try self.fields(typeProvider: typeProvider)
+            },
             isOneOf: isOneOf
         )
 
diff --git a/Sources/Graphiti/Interface/Interface.swift b/Sources/Graphiti/Interface/Interface.swift
index d6601d0..aad7e97 100644
--- a/Sources/Graphiti/Interface/Interface.swift
+++ b/Sources/Graphiti/Interface/Interface.swift
@@ -10,7 +10,9 @@ public final class Interface<Resolver, Context, InterfaceType>: TypeComponent<
         let interfaceType = try GraphQLInterfaceType(
             name: name,
             description: description,
-            fields: fields(typeProvider: typeProvider, coders: coders),
+            fields: {
+                try self.fields(typeProvider: typeProvider, coders: coders)
+            },
             resolveType: nil
         )
 
diff --git a/Sources/Graphiti/Mutation/Mutation.swift b/Sources/Graphiti/Mutation/Mutation.swift
index 42890e8..51f8773 100644
--- a/Sources/Graphiti/Mutation/Mutation.swift
+++ b/Sources/Graphiti/Mutation/Mutation.swift
@@ -11,7 +11,9 @@ public final class Mutation<Resolver, Context>: Component<Resolver, Context> {
         typeProvider.mutation = try GraphQLObjectType(
             name: name,
             description: description,
-            fields: fields(typeProvider: typeProvider, coders: coders),
+            fields: {
+                try self.fields(typeProvider: typeProvider, coders: coders)
+            },
             isTypeOf: isTypeOf
         )
     }
diff --git a/Sources/Graphiti/Query/Query.swift b/Sources/Graphiti/Query/Query.swift
index 727fc94..e9f3237 100644
--- a/Sources/Graphiti/Query/Query.swift
+++ b/Sources/Graphiti/Query/Query.swift
@@ -8,34 +8,35 @@ public final class Query<Resolver, Context>: Component<Resolver, Context> {
     }
 
     override func update(typeProvider: SchemaTypeProvider, coders: Coders) throws {
-        var queryFields = try fields(typeProvider: typeProvider, coders: coders)
-
-        // Add federated types and queries if they exist
-        if !typeProvider.federatedTypes.isEmpty {
-            let federatedTypes = typeProvider.federatedTypes
-            guard let sdl = typeProvider.federatedSDL else {
-                throw GraphQLError(message: "If federated types are included, SDL must be provided")
-            }
-
-            // Add subgraph types to provider (_Service, _Any, _Entity)
-            let entity = entityType(federatedTypes)
-            typeProvider.types.append(serviceType)
-            typeProvider.types.append(anyType)
-            typeProvider.types.append(entity)
-
-            // Add subgraph queries (_entities, _service)
-            queryFields["_entities"] = entitiesQuery(
-                for: typeProvider.federatedResolvers,
-                entityType: entity,
-                coders: coders
-            )
-            queryFields["_service"] = serviceQuery(for: sdl)
-        }
-
         typeProvider.query = try GraphQLObjectType(
             name: name,
             description: description,
-            fields: queryFields,
+            fields: {
+                var queryFields = try self.fields(typeProvider: typeProvider, coders: coders)
+
+                // Add federated types and queries if they exist
+                if !typeProvider.federatedTypes.isEmpty {
+                    let federatedTypes = typeProvider.federatedTypes
+                    guard let sdl = typeProvider.federatedSDL else {
+                        throw GraphQLError(message: "If federated types are included, SDL must be provided")
+                    }
+
+                    // Add subgraph types to provider (_Service, _Any, _Entity)
+                    let entity = entityType(federatedTypes)
+                    typeProvider.types.append(serviceType)
+                    typeProvider.types.append(anyType)
+                    typeProvider.types.append(entity)
+
+                    // Add subgraph queries (_entities, _service)
+                    queryFields["_entities"] = entitiesQuery(
+                        for: typeProvider.federatedResolvers,
+                        entityType: entity,
+                        coders: coders
+                    )
+                    queryFields["_service"] = serviceQuery(for: sdl)
+                }
+                return queryFields
+            },
             isTypeOf: isTypeOf
         )
     }
diff --git a/Sources/Graphiti/Subscription/Subscription.swift b/Sources/Graphiti/Subscription/Subscription.swift
index 2a9a0bf..e775205 100644
--- a/Sources/Graphiti/Subscription/Subscription.swift
+++ b/Sources/Graphiti/Subscription/Subscription.swift
@@ -11,7 +11,9 @@ public final class Subscription<Resolver, Context>: Component<Resolver, Context>
         typeProvider.subscription = try GraphQLObjectType(
             name: name,
             description: description,
-            fields: fields(typeProvider: typeProvider, coders: coders),
+            fields: {
+                try self.fields(typeProvider: typeProvider, coders: coders)
+            },
             isTypeOf: isTypeOf
         )
     }
diff --git a/Sources/Graphiti/Type/Type.swift b/Sources/Graphiti/Type/Type.swift
index 4f9157d..a8df744 100644
--- a/Sources/Graphiti/Type/Type.swift
+++ b/Sources/Graphiti/Type/Type.swift
@@ -13,30 +13,33 @@ public final class Type<Resolver, Context, ObjectType>: TypeComponent<
     }
 
     override func update(typeProvider: SchemaTypeProvider, coders: Coders) throws {
-        let fieldDefs = try fields(typeProvider: typeProvider, coders: coders)
         let objectType = try GraphQLObjectType(
             name: name,
             description: description,
-            fields: fieldDefs,
-            interfaces: interfaces.map {
-                try typeProvider.getInterfaceType(from: $0)
+            fields: {
+                let fields = try self.fields(typeProvider: typeProvider, coders: coders)
+                // Validate federation keys, if present
+                for key in self.keys {
+                    try key.validate(
+                        againstFields: Array(fields.keys),
+                        typeProvider: typeProvider,
+                        coders: coders
+                    )
+                }
+                return fields
+            },
+            interfaces: {
+                try self.interfaces.map {
+                    try typeProvider.getInterfaceType(from: $0)
+                }
             },
             isTypeOf: isTypeOf
         )
 
         try typeProvider.add(type: ObjectType.self, as: objectType)
 
-        // If federation keys are included, validate and create resolver closure
+        // If federation keys are included, create resolver closure
         if !keys.isEmpty {
-            let fieldNames = Array(fieldDefs.keys)
-            for key in keys {
-                try key.validate(
-                    againstFields: fieldNames,
-                    typeProvider: typeProvider,
-                    coders: coders
-                )
-            }
-
             let resolve: GraphQLFieldResolve = { source, args, context, eventLoopGroup, _ in
                 guard let s = source as? Resolver else {
                     throw GraphQLError(
diff --git a/Sources/Graphiti/Union/Union.swift b/Sources/Graphiti/Union/Union.swift
index 6d8d0c3..d4babf5 100644
--- a/Sources/Graphiti/Union/Union.swift
+++ b/Sources/Graphiti/Union/Union.swift
@@ -8,8 +8,10 @@ public final class Union<Resolver, Context, UnionType>: TypeComponent<Resolver,
             name: name,
             description: description,
             resolveType: nil,
-            types: members.map {
-                try typeProvider.getObjectType(from: $0)
+            types: {
+                try self.members.map {
+                    try typeProvider.getObjectType(from: $0)
+                }
             }
         )
 

From 0ba4aaa2b07dbd225a06aeb3df9c00c99d7a2047 Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Mon, 21 Oct 2024 20:23:57 -0600
Subject: [PATCH 03/12] test: Removes TypeReferences

---
 Tests/GraphitiTests/PartialSchemaTests.swift      | 4 ++--
 Tests/GraphitiTests/SchemaBuilderTests.swift      | 2 +-
 Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Tests/GraphitiTests/PartialSchemaTests.swift b/Tests/GraphitiTests/PartialSchemaTests.swift
index 8004314..737c4de 100644
--- a/Tests/GraphitiTests/PartialSchemaTests.swift
+++ b/Tests/GraphitiTests/PartialSchemaTests.swift
@@ -12,7 +12,7 @@ class PartialSchemaTests: XCTestCase {
                     .description("The id of the character.")
                 Field("name", at: \.name)
                     .description("The name of the character.")
-                Field("friends", at: \.friends, as: [TypeReference<Character>].self)
+                Field("friends", at: \.friends)
                     .description(
                         "The friends of the character, or an empty list if they have none."
                     )
@@ -218,7 +218,7 @@ class PartialSchemaTests: XCTestCase {
                         .description("The id of the character.")
                     Field("name", at: \.name)
                         .description("The name of the character.")
-                    Field("friends", at: \.friends, as: [TypeReference<Character>].self)
+                    Field("friends", at: \.friends)
                         .description(
                             "The friends of the character, or an empty list if they have none."
                         )
diff --git a/Tests/GraphitiTests/SchemaBuilderTests.swift b/Tests/GraphitiTests/SchemaBuilderTests.swift
index 3510682..043f93b 100644
--- a/Tests/GraphitiTests/SchemaBuilderTests.swift
+++ b/Tests/GraphitiTests/SchemaBuilderTests.swift
@@ -70,7 +70,7 @@ class SchemaBuilderTests: XCTestCase {
                     .description("The id of the character.")
                 Field("name", at: \.name)
                     .description("The name of the character.")
-                Field("friends", at: \.friends, as: [TypeReference<Character>].self)
+                Field("friends", at: \.friends)
                     .description(
                         "The friends of the character, or an empty list if they have none."
                     )
diff --git a/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift b/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift
index 4b11077..26e4d00 100644
--- a/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift
+++ b/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift
@@ -23,7 +23,7 @@ public struct StarWarsAPI: API {
             Field("name", at: \.name)
                 .description("The name of the character.")
 
-            Field("friends", at: \.friends, as: [TypeReference<Character>].self)
+            Field("friends", at: Character.getFriends)
                 .description("The friends of the character, or an empty list if they have none.")
 
             Field("appearsIn", at: \.appearsIn)

From 4351e1ecf512e667962bc1f3a1b93009ef80146b Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Mon, 21 Oct 2024 20:29:35 -0600
Subject: [PATCH 04/12] feat: Removes build ordering

---
 Sources/Graphiti/Component/Component.swift | 21 ---------------------
 Sources/Graphiti/Schema/Schema.swift       |  8 --------
 2 files changed, 29 deletions(-)

diff --git a/Sources/Graphiti/Component/Component.swift b/Sources/Graphiti/Component/Component.swift
index 18694b6..3aca66f 100644
--- a/Sources/Graphiti/Component/Component.swift
+++ b/Sources/Graphiti/Component/Component.swift
@@ -36,25 +36,4 @@ enum ComponentType {
     case type
     case types
     case union
-
-    /// An index used to sort components into the correct schema build order. This order goes
-    /// from "least other type references" to "most". By building in this order we are able to satisfy
-    /// hard ordering requirements (interfaces MUST be built before inheriting types), as well as
-    /// reduce unnecessary TypeReferences.
-    var buildOrder: Int {
-        switch self {
-        case .none: return 0
-        case .scalar: return 1
-        case .enum: return 2
-        case .interface: return 3
-        case .input: return 4
-        case .connection: return 5
-        case .type: return 6
-        case .types: return 7
-        case .union: return 8
-        case .query: return 9
-        case .mutation: return 10
-        case .subscription: return 11
-        }
-    }
 }
diff --git a/Sources/Graphiti/Schema/Schema.swift b/Sources/Graphiti/Schema/Schema.swift
index 75fd701..e02ce65 100644
--- a/Sources/Graphiti/Schema/Schema.swift
+++ b/Sources/Graphiti/Schema/Schema.swift
@@ -12,16 +12,8 @@ public final class Schema<Resolver, Context> {
         let typeProvider = SchemaTypeProvider()
         typeProvider.federatedSDL = federatedSDL
 
-        // Collect types mappings first
         for component in components {
             try component.setGraphQLName(typeProvider: typeProvider)
-        }
-
-        // Order component by componentType build order
-        let sortedComponents = components.sorted {
-            $0.componentType.buildOrder <= $1.componentType.buildOrder
-        }
-        for component in sortedComponents {
             try component.update(typeProvider: typeProvider, coders: coders)
         }
 

From e953b7c42496407a20fb12aab8d4f6a92ac08624 Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Mon, 21 Oct 2024 20:31:57 -0600
Subject: [PATCH 05/12] feat: Removes unnecessary setGraphQLName

---
 Sources/Graphiti/Component/Component.swift | 1 -
 Sources/Graphiti/Enum/Enum.swift           | 4 ----
 Sources/Graphiti/Input/Input.swift         | 4 ----
 Sources/Graphiti/Interface/Interface.swift | 4 ----
 Sources/Graphiti/Scalar/Scalar.swift       | 4 ----
 Sources/Graphiti/Schema/Schema.swift       | 1 -
 Sources/Graphiti/Type/Type.swift           | 4 ----
 Sources/Graphiti/Union/Union.swift         | 4 ----
 8 files changed, 26 deletions(-)

diff --git a/Sources/Graphiti/Component/Component.swift b/Sources/Graphiti/Component/Component.swift
index 3aca66f..2cb031a 100644
--- a/Sources/Graphiti/Component/Component.swift
+++ b/Sources/Graphiti/Component/Component.swift
@@ -11,7 +11,6 @@ open class Component<Resolver, Context> {
     }
 
     func update(typeProvider _: SchemaTypeProvider, coders _: Coders) throws {}
-    func setGraphQLName(typeProvider _: SchemaTypeProvider) throws {}
 }
 
 public extension Component {
diff --git a/Sources/Graphiti/Enum/Enum.swift b/Sources/Graphiti/Enum/Enum.swift
index 22b2ff4..f32fc98 100644
--- a/Sources/Graphiti/Enum/Enum.swift
+++ b/Sources/Graphiti/Enum/Enum.swift
@@ -26,10 +26,6 @@ public final class Enum<
         try typeProvider.add(type: EnumType.self, as: enumType)
     }
 
-    override func setGraphQLName(typeProvider: SchemaTypeProvider) throws {
-        try typeProvider.mapName(EnumType.self, to: name)
-    }
-
     private init(
         type _: EnumType.Type,
         name: String?,
diff --git a/Sources/Graphiti/Input/Input.swift b/Sources/Graphiti/Input/Input.swift
index 28eefc9..3b3e21c 100644
--- a/Sources/Graphiti/Input/Input.swift
+++ b/Sources/Graphiti/Input/Input.swift
@@ -24,10 +24,6 @@ public final class Input<
         try typeProvider.add(type: InputObjectType.self, as: inputObjectType)
     }
 
-    override func setGraphQLName(typeProvider: SchemaTypeProvider) throws {
-        try typeProvider.mapName(InputObjectType.self, to: name)
-    }
-
     func fields(typeProvider: TypeProvider) throws -> InputObjectFieldMap {
         var map: InputObjectFieldMap = [:]
 
diff --git a/Sources/Graphiti/Interface/Interface.swift b/Sources/Graphiti/Interface/Interface.swift
index aad7e97..a6446da 100644
--- a/Sources/Graphiti/Interface/Interface.swift
+++ b/Sources/Graphiti/Interface/Interface.swift
@@ -19,10 +19,6 @@ public final class Interface<Resolver, Context, InterfaceType>: TypeComponent<
         try typeProvider.add(type: InterfaceType.self, as: interfaceType)
     }
 
-    override func setGraphQLName(typeProvider: SchemaTypeProvider) throws {
-        try typeProvider.mapName(InterfaceType.self, to: name)
-    }
-
     func fields(typeProvider: TypeProvider, coders: Coders) throws -> GraphQLFieldMap {
         var map: GraphQLFieldMap = [:]
 
diff --git a/Sources/Graphiti/Scalar/Scalar.swift b/Sources/Graphiti/Scalar/Scalar.swift
index d62720b..3de7bed 100644
--- a/Sources/Graphiti/Scalar/Scalar.swift
+++ b/Sources/Graphiti/Scalar/Scalar.swift
@@ -51,10 +51,6 @@ open class Scalar<Resolver, Context, ScalarType: Codable>: TypeComponent<Resolve
         try typeProvider.add(type: ScalarType.self, as: scalarType)
     }
 
-    override func setGraphQLName(typeProvider: SchemaTypeProvider) throws {
-        try typeProvider.mapName(ScalarType.self, to: name)
-    }
-
     // TODO: Remove open func, instead relying on a passed closure
     open func serialize(scalar: ScalarType, encoder: MapEncoder) throws -> Map {
         try encoder.encode(scalar)
diff --git a/Sources/Graphiti/Schema/Schema.swift b/Sources/Graphiti/Schema/Schema.swift
index e02ce65..959b297 100644
--- a/Sources/Graphiti/Schema/Schema.swift
+++ b/Sources/Graphiti/Schema/Schema.swift
@@ -13,7 +13,6 @@ public final class Schema<Resolver, Context> {
         typeProvider.federatedSDL = federatedSDL
 
         for component in components {
-            try component.setGraphQLName(typeProvider: typeProvider)
             try component.update(typeProvider: typeProvider, coders: coders)
         }
 
diff --git a/Sources/Graphiti/Type/Type.swift b/Sources/Graphiti/Type/Type.swift
index a8df744..d305dc8 100644
--- a/Sources/Graphiti/Type/Type.swift
+++ b/Sources/Graphiti/Type/Type.swift
@@ -76,10 +76,6 @@ public final class Type<Resolver, Context, ObjectType>: TypeComponent<
         }
     }
 
-    override func setGraphQLName(typeProvider: SchemaTypeProvider) throws {
-        try typeProvider.mapName(ObjectType.self, to: name)
-    }
-
     func fields(typeProvider: TypeProvider, coders: Coders) throws -> GraphQLFieldMap {
         var map: GraphQLFieldMap = [:]
 
diff --git a/Sources/Graphiti/Union/Union.swift b/Sources/Graphiti/Union/Union.swift
index d4babf5..791d495 100644
--- a/Sources/Graphiti/Union/Union.swift
+++ b/Sources/Graphiti/Union/Union.swift
@@ -18,10 +18,6 @@ public final class Union<Resolver, Context, UnionType>: TypeComponent<Resolver,
         try typeProvider.add(type: UnionType.self, as: unionType)
     }
 
-    override func setGraphQLName(typeProvider: SchemaTypeProvider) throws {
-        try typeProvider.mapName(UnionType.self, to: name)
-    }
-
     init(
         type _: UnionType.Type,
         name: String? = nil,

From 27a4b723d0dc27b49e68fa9ee9eeb866189fd319 Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Thu, 31 Oct 2024 22:58:47 -0600
Subject: [PATCH 06/12] feat!: Remove Graphiti TypeReference

---
 Sources/Graphiti/Definition/TypeProvider.swift  | 16 +++-------------
 Sources/Graphiti/Definition/TypeReference.swift | 11 -----------
 Sources/Graphiti/Definition/Wrappers.swift      |  1 -
 3 files changed, 3 insertions(+), 25 deletions(-)
 delete mode 100644 Sources/Graphiti/Definition/TypeReference.swift

diff --git a/Sources/Graphiti/Definition/TypeProvider.swift b/Sources/Graphiti/Definition/TypeProvider.swift
index 164b188..6be0f8c 100644
--- a/Sources/Graphiti/Definition/TypeProvider.swift
+++ b/Sources/Graphiti/Definition/TypeProvider.swift
@@ -66,22 +66,12 @@ extension TypeProvider {
                     from: GraphQLList(graphQLType),
                     isOptional: isOptional
                 )
-            case .reference:
-                let name = getGraphQLName(of: type.wrappedType)
-                let referenceType = GraphQLTypeReference(name)
-
-                return try getGraphQLOptionalType(from: referenceType, isOptional: isOptional)
             }
         } else {
-            if let graphQLType = graphQLTypeMap[AnyType(type)] {
-                return try getGraphQLOptionalType(from: graphQLType, isOptional: isOptional)
-            } else {
-                // If we haven't seen this type yet, just store it as a type reference and resolve later.
-                let name = getGraphQLName(of: type)
-                let referenceType = GraphQLTypeReference(name)
-
-                return try getGraphQLOptionalType(from: referenceType, isOptional: isOptional)
+            guard let graphQLType = graphQLTypeMap[AnyType(type)] else {
+                throw GraphQLError(message: "Type not found \(type).")
             }
+            return try getGraphQLOptionalType(from: graphQLType, isOptional: isOptional)
         }
     }
 
diff --git a/Sources/Graphiti/Definition/TypeReference.swift b/Sources/Graphiti/Definition/TypeReference.swift
deleted file mode 100644
index f2f4cba..0000000
--- a/Sources/Graphiti/Definition/TypeReference.swift
+++ /dev/null
@@ -1,11 +0,0 @@
-public enum TypeReference<Referent> {}
-
-extension TypeReference: Wrapper {
-    static var wrappedType: Any.Type {
-        return Referent.self
-    }
-
-    static var modifier: WrapperModifier {
-        return .reference
-    }
-}
diff --git a/Sources/Graphiti/Definition/Wrappers.swift b/Sources/Graphiti/Definition/Wrappers.swift
index c5c7a59..3eae529 100644
--- a/Sources/Graphiti/Definition/Wrappers.swift
+++ b/Sources/Graphiti/Definition/Wrappers.swift
@@ -1,7 +1,6 @@
 enum WrapperModifier {
     case optional
     case list
-    case reference
 }
 
 protocol Wrapper {

From 520659669471162f98927efc2178abff36dbfd57 Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Thu, 31 Oct 2024 22:58:53 -0600
Subject: [PATCH 07/12] fix: Avoid SDL key build ordering issue

---
 Sources/Graphiti/Argument/Argument.swift           | 4 ++++
 Sources/Graphiti/Argument/ArgumentComponent.swift  | 4 ++++
 Sources/Graphiti/Federation/Key/Key.swift          | 6 ++----
 Sources/Graphiti/Federation/Key/KeyComponent.swift | 4 +---
 Sources/Graphiti/Type/Type.swift                   | 6 +-----
 5 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/Sources/Graphiti/Argument/Argument.swift b/Sources/Graphiti/Argument/Argument.swift
index 31b8ac8..737e1f9 100644
--- a/Sources/Graphiti/Argument/Argument.swift
+++ b/Sources/Graphiti/Argument/Argument.swift
@@ -17,6 +17,10 @@ public class Argument<ArgumentsType: Decodable, ArgumentType>: ArgumentComponent
         return (name, argument)
     }
 
+    override func getName() -> String {
+        return name
+    }
+
     init(name: String) {
         self.name = name
     }
diff --git a/Sources/Graphiti/Argument/ArgumentComponent.swift b/Sources/Graphiti/Argument/ArgumentComponent.swift
index c0378b4..0d8163a 100644
--- a/Sources/Graphiti/Argument/ArgumentComponent.swift
+++ b/Sources/Graphiti/Argument/ArgumentComponent.swift
@@ -9,6 +9,10 @@ public class ArgumentComponent<ArgumentsType: Decodable> {
     ) throws -> (String, GraphQLArgument) {
         fatalError()
     }
+
+    func getName() -> String {
+        fatalError()
+    }
 }
 
 public extension ArgumentComponent {
diff --git a/Sources/Graphiti/Federation/Key/Key.swift b/Sources/Graphiti/Federation/Key/Key.swift
index 0fe8799..e05c8e6 100644
--- a/Sources/Graphiti/Federation/Key/Key.swift
+++ b/Sources/Graphiti/Federation/Key/Key.swift
@@ -26,12 +26,10 @@ public class Key<ObjectType, Resolver, Context, Arguments: Codable>: KeyComponen
     }
 
     override func validate(
-        againstFields fieldNames: [String],
-        typeProvider: TypeProvider,
-        coders: Coders
+        againstFields fieldNames: [String]
     ) throws {
         // Ensure that every argument is included in the provided field list
-        for (name, _) in try arguments(typeProvider: typeProvider, coders: coders) {
+        for name in arguments.map({ $0.getName() }) {
             if !fieldNames.contains(name) {
                 throw GraphQLError(message: "Argument name not found in type fields: \(name)")
             }
diff --git a/Sources/Graphiti/Federation/Key/KeyComponent.swift b/Sources/Graphiti/Federation/Key/KeyComponent.swift
index c897d1d..0bb51bc 100644
--- a/Sources/Graphiti/Federation/Key/KeyComponent.swift
+++ b/Sources/Graphiti/Federation/Key/KeyComponent.swift
@@ -17,9 +17,7 @@ public class KeyComponent<ObjectType, Resolver, Context> {
     }
 
     func validate(
-        againstFields _: [String],
-        typeProvider _: TypeProvider,
-        coders _: Coders
+        againstFields _: [String]
     ) throws {
         fatalError()
     }
diff --git a/Sources/Graphiti/Type/Type.swift b/Sources/Graphiti/Type/Type.swift
index d305dc8..96c74bd 100644
--- a/Sources/Graphiti/Type/Type.swift
+++ b/Sources/Graphiti/Type/Type.swift
@@ -20,11 +20,7 @@ public final class Type<Resolver, Context, ObjectType>: TypeComponent<
                 let fields = try self.fields(typeProvider: typeProvider, coders: coders)
                 // Validate federation keys, if present
                 for key in self.keys {
-                    try key.validate(
-                        againstFields: Array(fields.keys),
-                        typeProvider: typeProvider,
-                        coders: coders
-                    )
+                    try key.validate(againstFields: Array(fields.keys))
                 }
                 return fields
             },

From e9853e2837ba9dcfabbb86312d77a7b6809364e3 Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Thu, 31 Oct 2024 23:33:13 -0600
Subject: [PATCH 08/12] chore: Formatting

---
 Sources/Graphiti/Query/Query.swift | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Sources/Graphiti/Query/Query.swift b/Sources/Graphiti/Query/Query.swift
index e9f3237..7c257e1 100644
--- a/Sources/Graphiti/Query/Query.swift
+++ b/Sources/Graphiti/Query/Query.swift
@@ -18,7 +18,9 @@ public final class Query<Resolver, Context>: Component<Resolver, Context> {
                 if !typeProvider.federatedTypes.isEmpty {
                     let federatedTypes = typeProvider.federatedTypes
                     guard let sdl = typeProvider.federatedSDL else {
-                        throw GraphQLError(message: "If federated types are included, SDL must be provided")
+                        throw GraphQLError(
+                            message: "If federated types are included, SDL must be provided"
+                        )
                     }
 
                     // Add subgraph types to provider (_Service, _Any, _Entity)

From 8811ad619ac16c5526ec8ac199bd862ff93118e0 Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Tue, 5 Nov 2024 23:46:27 -0700
Subject: [PATCH 09/12] feat!: Removes Field/InputField `as` instantiate arg

This was typically used to override a resolver type into a TypeReference. With TypeReference no longer necessary, allowing this simply reduces type safety.
---
 Sources/Graphiti/Field/Field/Field.swift      | 104 ------------------
 Sources/Graphiti/InputField/InputField.swift  |  19 ----
 Tests/GraphitiTests/ConnectionTests.swift     |   2 +-
 .../DirectiveTests/DirectiveTests.swift       |   2 +-
 .../HelloWorldTests/HelloWorldTests.swift     |   2 +-
 Tests/GraphitiTests/PartialSchemaTests.swift  |  16 +--
 Tests/GraphitiTests/SchemaBuilderTests.swift  |   8 +-
 .../StarWarsAPI/StarWarsAPI.swift             |   8 +-
 Tests/GraphitiTests/UnionTests.swift          |   4 +-
 9 files changed, 21 insertions(+), 144 deletions(-)

diff --git a/Sources/Graphiti/Field/Field/Field.swift b/Sources/Graphiti/Field/Field/Field.swift
index 22152bb..5ba7ea1 100644
--- a/Sources/Graphiti/Field/Field/Field.swift
+++ b/Sources/Graphiti/Field/Field/Field.swift
@@ -131,27 +131,6 @@ public extension Field {
     }
 }
 
-public extension Field {
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping AsyncResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ argument: () -> ArgumentComponent<Arguments>
-    ) {
-        self.init(name: name, arguments: [argument()], asyncResolve: function)
-    }
-
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping AsyncResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ arguments: ()
-            -> [ArgumentComponent<Arguments>] = { [] }
-    ) {
-        self.init(name: name, arguments: arguments(), asyncResolve: function)
-    }
-}
-
 // MARK: SimpleAsyncResolve Initializers
 
 public extension Field {
@@ -173,27 +152,6 @@ public extension Field {
     }
 }
 
-public extension Field {
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping SimpleAsyncResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ argument: () -> ArgumentComponent<Arguments>
-    ) {
-        self.init(name: name, arguments: [argument()], simpleAsyncResolve: function)
-    }
-
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping SimpleAsyncResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ arguments: ()
-            -> [ArgumentComponent<Arguments>] = { [] }
-    ) {
-        self.init(name: name, arguments: arguments(), simpleAsyncResolve: function)
-    }
-}
-
 // MARK: SyncResolve Initializers
 
 // '@_disfavoredOverload' is included below because otherwise `SimpleAsyncResolve` initializers also match this signature, causing the
@@ -220,29 +178,6 @@ public extension Field {
     }
 }
 
-public extension Field {
-    @_disfavoredOverload
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping SyncResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ argument: () -> ArgumentComponent<Arguments>
-    ) {
-        self.init(name: name, arguments: [argument()], syncResolve: function)
-    }
-
-    @_disfavoredOverload
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping SyncResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ arguments: ()
-            -> [ArgumentComponent<Arguments>] = { [] }
-    ) {
-        self.init(name: name, arguments: arguments(), syncResolve: function)
-    }
-}
-
 // MARK: Keypath Initializers
 
 public extension Field where Arguments == NoArguments {
@@ -260,22 +195,6 @@ public extension Field where Arguments == NoArguments {
     }
 }
 
-public extension Field where Arguments == NoArguments {
-    convenience init<ResolveType>(
-        _ name: String,
-        at keyPath: KeyPath<ObjectType, ResolveType>,
-        as _: FieldType.Type
-    ) {
-        let syncResolve: SyncResolve<ObjectType, Context, NoArguments, ResolveType> = { type in
-            { _, _ in
-                type[keyPath: keyPath]
-            }
-        }
-
-        self.init(name: name, arguments: [], syncResolve: syncResolve)
-    }
-}
-
 public extension Field {
     @available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
     convenience init<ResolveType>(
@@ -323,26 +242,3 @@ public extension Field {
         self.init(name: name, arguments: arguments(), concurrentResolve: function)
     }
 }
-
-public extension Field {
-    @available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping ConcurrentResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ argument: () -> ArgumentComponent<Arguments>
-    ) {
-        self.init(name: name, arguments: [argument()], concurrentResolve: function)
-    }
-
-    @available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
-    convenience init<ResolveType>(
-        _ name: String,
-        at function: @escaping ConcurrentResolve<ObjectType, Context, Arguments, ResolveType>,
-        as: FieldType.Type,
-        @ArgumentComponentBuilder<Arguments> _ arguments: ()
-            -> [ArgumentComponent<Arguments>] = { [] }
-    ) {
-        self.init(name: name, arguments: arguments(), concurrentResolve: function)
-    }
-}
diff --git a/Sources/Graphiti/InputField/InputField.swift b/Sources/Graphiti/InputField/InputField.swift
index 46d4133..fb95ea8 100644
--- a/Sources/Graphiti/InputField/InputField.swift
+++ b/Sources/Graphiti/InputField/InputField.swift
@@ -39,25 +39,6 @@ public extension InputField {
     }
 }
 
-public extension InputField {
-    convenience init<KeyPathType>(
-        _ name: String,
-        at _: KeyPath<InputObjectType, KeyPathType>,
-        as _: FieldType.Type
-    ) {
-        self.init(name: name)
-    }
-}
-
-public extension InputField {
-    convenience init(
-        _ name: String,
-        as _: FieldType.Type
-    ) {
-        self.init(name: name)
-    }
-}
-
 public extension InputField where FieldType: Encodable {
     func defaultValue(_ defaultValue: FieldType) -> Self {
         self.defaultValue = AnyEncodable(defaultValue)
diff --git a/Tests/GraphitiTests/ConnectionTests.swift b/Tests/GraphitiTests/ConnectionTests.swift
index 0b92114..96e3f43 100644
--- a/Tests/GraphitiTests/ConnectionTests.swift
+++ b/Tests/GraphitiTests/ConnectionTests.swift
@@ -489,7 +489,7 @@ class ConnectionTests: XCTestCase {
 
         let schema = try Schema<Resolver, NoContext> {
             Type(ChatObject.self, as: "Chat") {
-                Field("messages", at: ChatObject.messages, as: Connection<MessageObject>.self) {
+                Field("messages", at: ChatObject.messages) {
                     Argument("first", at: \.first)
                     Argument("after", at: \.after)
                     Argument("last", at: \.last)
diff --git a/Tests/GraphitiTests/DirectiveTests/DirectiveTests.swift b/Tests/GraphitiTests/DirectiveTests/DirectiveTests.swift
index 2beb636..34db5c8 100644
--- a/Tests/GraphitiTests/DirectiveTests/DirectiveTests.swift
+++ b/Tests/GraphitiTests/DirectiveTests/DirectiveTests.swift
@@ -153,7 +153,7 @@ class DirectiveTests: XCTestCase {
             }
 
             Query {
-                Field("test", at: OneOfResolver.test, as: TestObject.self) {
+                Field("test", at: OneOfResolver.test) {
                     Argument("input", at: \.input)
                 }
             }
diff --git a/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift b/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift
index d80c051..eb316bc 100644
--- a/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift
+++ b/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift
@@ -126,7 +126,7 @@ struct HelloAPI: API {
 
         Input(UserInput.self) {
             InputField("id", at: \.id)
-            InputField("name", as: String?.self)
+            InputField("name", at: \.name)
             InputField("friends", at: \.friends)
         }
 
diff --git a/Tests/GraphitiTests/PartialSchemaTests.swift b/Tests/GraphitiTests/PartialSchemaTests.swift
index 737c4de..0a38c66 100644
--- a/Tests/GraphitiTests/PartialSchemaTests.swift
+++ b/Tests/GraphitiTests/PartialSchemaTests.swift
@@ -34,7 +34,7 @@ class PartialSchemaTests: XCTestCase {
 
         @FieldDefinitions
         override var query: Fields {
-            Field("hero", at: StarWarsResolver.hero, as: Character.self) {
+            Field("hero", at: StarWarsResolver.hero) {
                 Argument("episode", at: \.episode)
                     .description(
                         "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode."
@@ -61,7 +61,7 @@ class PartialSchemaTests: XCTestCase {
                 Field("name", at: \.name)
                 Field("appearsIn", at: \.appearsIn)
                 Field("homePlanet", at: \.homePlanet)
-                Field("friends", at: Human.getFriends, as: [Character].self)
+                Field("friends", at: Human.getFriends)
                     .description("The friends of the human, or an empty list if they have none.")
                 Field("secretBackstory", at: Human.getSecretBackstory)
                     .description("Where are they from and how they came to be who they are.")
@@ -71,7 +71,7 @@ class PartialSchemaTests: XCTestCase {
                 Field("name", at: \.name)
                 Field("appearsIn", at: \.appearsIn)
                 Field("primaryFunction", at: \.primaryFunction)
-                Field("friends", at: Droid.getFriends, as: [Character].self)
+                Field("friends", at: Droid.getFriends)
                     .description("The friends of the droid, or an empty list if they have none.")
                 Field("secretBackstory", at: Droid.getSecretBackstory)
                     .description("Where are they from and how they came to be who they are.")
@@ -89,7 +89,7 @@ class PartialSchemaTests: XCTestCase {
                 Argument("id", at: \.id)
                     .description("Id of the droid.")
             }
-            Field("search", at: StarWarsResolver.search, as: [SearchResult].self) {
+            Field("search", at: StarWarsResolver.search) {
                 Argument("query", at: \.query)
                     .defaultValue("R2-D2")
             }
@@ -238,7 +238,7 @@ class PartialSchemaTests: XCTestCase {
                 }.description("One of the films in the Star Wars Trilogy.")
             },
             query: {
-                Field("hero", at: StarWarsResolver.hero, as: Character.self) {
+                Field("hero", at: StarWarsResolver.hero) {
                     Argument("episode", at: \.episode)
                         .description(
                             "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode."
@@ -264,7 +264,7 @@ class PartialSchemaTests: XCTestCase {
                     Field("name", at: \.name)
                     Field("appearsIn", at: \.appearsIn)
                     Field("homePlanet", at: \.homePlanet)
-                    Field("friends", at: Human.getFriends, as: [Character].self)
+                    Field("friends", at: Human.getFriends)
                         .description(
                             "The friends of the human, or an empty list if they have none."
                         )
@@ -276,7 +276,7 @@ class PartialSchemaTests: XCTestCase {
                     Field("name", at: \.name)
                     Field("appearsIn", at: \.appearsIn)
                     Field("primaryFunction", at: \.primaryFunction)
-                    Field("friends", at: Droid.getFriends, as: [Character].self)
+                    Field("friends", at: Droid.getFriends)
                         .description(
                             "The friends of the droid, or an empty list if they have none."
                         )
@@ -294,7 +294,7 @@ class PartialSchemaTests: XCTestCase {
                     Argument("id", at: \.id)
                         .description("Id of the droid.")
                 }
-                Field("search", at: StarWarsResolver.search, as: [SearchResult].self) {
+                Field("search", at: StarWarsResolver.search) {
                     Argument("query", at: \.query)
                         .defaultValue("R2-D2")
                 }
diff --git a/Tests/GraphitiTests/SchemaBuilderTests.swift b/Tests/GraphitiTests/SchemaBuilderTests.swift
index 043f93b..e531e57 100644
--- a/Tests/GraphitiTests/SchemaBuilderTests.swift
+++ b/Tests/GraphitiTests/SchemaBuilderTests.swift
@@ -11,7 +11,7 @@ class SchemaBuilderTests: XCTestCase {
 
         // Add assets slightly out of order
         builder.addQuery {
-            Field("hero", at: StarWarsResolver.hero, as: Character.self) {
+            Field("hero", at: StarWarsResolver.hero) {
                 Argument("episode", at: \.episode)
                     .description(
                         "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode."
@@ -49,7 +49,7 @@ class SchemaBuilderTests: XCTestCase {
                 Field("name", at: \.name)
                 Field("appearsIn", at: \.appearsIn)
                 Field("homePlanet", at: \.homePlanet)
-                Field("friends", at: Human.getFriends, as: [Character].self)
+                Field("friends", at: Human.getFriends)
                     .description("The friends of the human, or an empty list if they have none.")
                 Field("secretBackstory", at: Human.getSecretBackstory)
                     .description("Where are they from and how they came to be who they are.")
@@ -59,7 +59,7 @@ class SchemaBuilderTests: XCTestCase {
                 Field("name", at: \.name)
                 Field("appearsIn", at: \.appearsIn)
                 Field("primaryFunction", at: \.primaryFunction)
-                Field("friends", at: Droid.getFriends, as: [Character].self)
+                Field("friends", at: Droid.getFriends)
                     .description("The friends of the droid, or an empty list if they have none.")
                 Field("secretBackstory", at: Droid.getSecretBackstory)
                     .description("Where are they from and how they came to be who they are.")
@@ -89,7 +89,7 @@ class SchemaBuilderTests: XCTestCase {
                 Argument("id", at: \.id)
                     .description("Id of the droid.")
             }
-            Field("search", at: StarWarsResolver.search, as: [SearchResult].self) {
+            Field("search", at: StarWarsResolver.search) {
                 Argument("query", at: \.query)
                     .defaultValue("R2-D2")
             }
diff --git a/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift b/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift
index 26e4d00..fa751ba 100644
--- a/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift
+++ b/Tests/GraphitiTests/StarWarsAPI/StarWarsAPI.swift
@@ -52,7 +52,7 @@ public struct StarWarsAPI: API {
             Field("appearsIn", at: \.appearsIn)
             Field("homePlanet", at: \.homePlanet)
 
-            Field("friends", at: Human.getFriends, as: [Character].self)
+            Field("friends", at: Human.getFriends)
                 .description("The friends of the human, or an empty list if they have none.")
 
             Field("secretBackstory", at: Human.getSecretBackstory)
@@ -66,7 +66,7 @@ public struct StarWarsAPI: API {
             Field("appearsIn", at: \.appearsIn)
             Field("primaryFunction", at: \.primaryFunction)
 
-            Field("friends", at: Droid.getFriends, as: [Character].self)
+            Field("friends", at: Droid.getFriends)
                 .description("The friends of the droid, or an empty list if they have none.")
 
             Field("secretBackstory", at: Droid.getSecretBackstory)
@@ -77,7 +77,7 @@ public struct StarWarsAPI: API {
         Union(SearchResult.self, members: Planet.self, Human.self, Droid.self)
 
         Query {
-            Field("hero", at: StarWarsResolver.hero, as: Character.self) {
+            Field("hero", at: StarWarsResolver.hero) {
                 Argument("episode", at: \.episode)
                     .description(
                         "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode."
@@ -95,7 +95,7 @@ public struct StarWarsAPI: API {
                     .description("Id of the droid.")
             }
 
-            Field("search", at: StarWarsResolver.search, as: [SearchResult].self) {
+            Field("search", at: StarWarsResolver.search) {
                 Argument("query", at: \.query)
                     .defaultValue("R2-D2")
             }
diff --git a/Tests/GraphitiTests/UnionTests.swift b/Tests/GraphitiTests/UnionTests.swift
index 6e93d8c..33209c2 100644
--- a/Tests/GraphitiTests/UnionTests.swift
+++ b/Tests/GraphitiTests/UnionTests.swift
@@ -22,7 +22,7 @@ class UnionTests: XCTestCase {
             Union(SearchResult.self, members: Planet.self, Human.self, Droid.self)
 
             Query {
-                Field("search", at: StarWarsResolver.search, as: [SearchResult].self) {
+                Field("search", at: StarWarsResolver.search) {
                     Argument("query", at: \.query)
                 }
             }
@@ -48,7 +48,7 @@ class UnionTests: XCTestCase {
             ])
 
             Query {
-                Field("search", at: StarWarsResolver.search, as: [SearchResult].self) {
+                Field("search", at: StarWarsResolver.search) {
                     Argument("query", at: \.query)
                 }
             }

From c18bbc384112a3e8c07badda047d7891e0709a7d Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Wed, 6 Nov 2024 00:52:33 -0700
Subject: [PATCH 10/12] chore!: Deletes Reflection.isEncodable

---
 Sources/Graphiti/Definition/Reflection.swift | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/Sources/Graphiti/Definition/Reflection.swift b/Sources/Graphiti/Definition/Reflection.swift
index 618577c..46a016c 100644
--- a/Sources/Graphiti/Definition/Reflection.swift
+++ b/Sources/Graphiti/Definition/Reflection.swift
@@ -4,19 +4,6 @@ public enum Reflection {
         return description.hasSuffix("Protocol")
     }
 
-    @available(*, deprecated, message: "No longer used")
-    public static func isEncodable(type: Any.Type) -> Bool {
-        if isProtocol(type: type) {
-            return true
-        }
-
-        if let type = type as? Wrapper.Type {
-            return isEncodable(type: type.wrappedType)
-        }
-
-        return type is Encodable.Type
-    }
-
     public static func name<Subject>(for instance: Subject) -> String {
         var typeName: [Character] = []
         var genericArgument: [Character] = []

From 8ef2aae31610a249827096d112eb1f8f02221dac Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Wed, 6 Nov 2024 00:52:45 -0700
Subject: [PATCH 11/12] chore!: Deletes Types

---
 Sources/Graphiti/Types/Types.swift | 24 ------------------------
 1 file changed, 24 deletions(-)
 delete mode 100644 Sources/Graphiti/Types/Types.swift

diff --git a/Sources/Graphiti/Types/Types.swift b/Sources/Graphiti/Types/Types.swift
deleted file mode 100644
index d52dcd0..0000000
--- a/Sources/Graphiti/Types/Types.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-import GraphQL
-
-@available(*, deprecated, message: "No longer use this. Instead define types using `Type`.")
-public final class Types<Resolver, Context>: Component<Resolver, Context> {
-    let types: [Any.Type]
-
-    override func update(typeProvider: SchemaTypeProvider, coders _: Coders) throws {
-        typeProvider.types = try types.map {
-            try typeProvider.getNamedType(from: $0)
-        }
-    }
-
-    init(types: [Any.Type]) {
-        self.types = types
-        super.init(
-            name: "",
-            type: .types
-        )
-    }
-
-    public convenience init(_ types: Any.Type...) {
-        self.init(types: types)
-    }
-}

From 1f356743ccc9ebcf7cada4e1aeb390dd2db8abad Mon Sep 17 00:00:00 2001
From: Jay Herron <NeedleInAJayStack@protonmail.com>
Date: Wed, 6 Nov 2024 00:52:55 -0700
Subject: [PATCH 12/12] doc: Adds migration guide

---
 MIGRATION.md | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 MIGRATION.md

diff --git a/MIGRATION.md b/MIGRATION.md
new file mode 100644
index 0000000..584860b
--- /dev/null
+++ b/MIGRATION.md
@@ -0,0 +1,39 @@
+# Migration
+
+## 1.0 to 2.0
+
+### TypeReference removal
+
+The `TypeReference` type was removed in v2.0.0, since it was made unnecessary when using the [GraphQL](https://github.com/GraphQLSwift/GraphQL)  closure-based `field` API. Simply replace any `TypeReference` usage with the actual type:
+
+```swift
+// Before
+let schema = try! Schema<HelloResolver, HelloContext> {
+    Type(Object1.self) { }
+    Type(Object2.self) {
+        Field("object1", at: \.object1, as: TypeReference<Object1>.self)
+    }
+}
+
+// After
+let schema = try! Schema<HelloResolver, HelloContext> {
+    Type(Object1.self) { }
+    Type(Object2.self) {
+        Field("object1", at: \.object1)
+    }
+}
+```
+
+### Field/InputField `as` argument removal
+
+Since TypeReference was removed, there is no longer a functional need for the `as` argument on `Field` and `InputField`
+types. To remove it, simply omit it and let the compiler determine the type from the signature of the `at` argument.
+
+### `Types` removal
+
+The deprecated `Types` type has been removed. Instead define types individually using the `Type` initializers.
+
+### Reflection `isEncodable`
+
+The deprecated `Reflection.isEncodable(type: Any.Type) -> Bool` function has been removed. Please re-implement in your
+package if this functionality is needed.
\ No newline at end of file
