diff --git a/Sources/Graphiti/Connection/Connection.swift b/Sources/Graphiti/Connection/Connection.swift index 67bc5541..7a94b490 100644 --- a/Sources/Graphiti/Connection/Connection.swift +++ b/Sources/Graphiti/Connection/Connection.swift @@ -2,7 +2,7 @@ import Foundation import GraphQL import NIO -public struct Connection: Encodable { +public struct Connection { public let edges: [Edge] public let pageInfo: PageInfo } @@ -19,7 +19,7 @@ public extension Connection where Node: Identifiable, Node.ID: LosslessStringCon } @available(macOS 10.15, macCatalyst 13.0, iOS 13.0, tvOS 13, watchOS 6.0, *) // For Identifiable -public extension EventLoopFuture where Value: Sequence, Value.Element: Encodable & Identifiable, +public extension EventLoopFuture where Value: Sequence, Value.Element: Identifiable, Value.Element.ID: LosslessStringConvertible { func connection(from arguments: Paginatable) -> EventLoopFuture> { connection(from: arguments, makeCursor: Connection.cursor) @@ -36,7 +36,7 @@ Value.Element.ID: LosslessStringConvertible { } } -public extension EventLoopFuture where Value: Sequence, Value.Element: Encodable { +public extension EventLoopFuture where Value: Sequence { func connection( from arguments: Paginatable, makeCursor: @escaping (Value.Element) throws -> String @@ -66,7 +66,7 @@ public extension EventLoopFuture where Value: Sequence, Value.Element: Encodable } @available(macOS 10.15, macCatalyst 13.0, iOS 13.0, tvOS 13, watchOS 6.0, *) // For Identifiable -public extension Sequence where Element: Encodable & Identifiable, +public extension Sequence where Element: Identifiable, Element.ID: LosslessStringConvertible { func connection(from arguments: Paginatable) throws -> Connection { try connection(from: arguments, makeCursor: Connection.cursor) @@ -81,7 +81,7 @@ Element.ID: LosslessStringConvertible { } } -public extension Sequence where Element: Encodable { +public extension Sequence { func connection( from arguments: Paginatable, makeCursor: @escaping (Element) throws -> String @@ -120,7 +120,7 @@ func connect( to elements: [Node], arguments: PaginationArguments, makeCursor: @escaping (Node) throws -> String -) throws -> Connection where Node: Encodable { +) throws -> Connection { let edges = try elements.map { element in // swiftformat:disable:next hoistTry Edge(node: element, cursor: try makeCursor(element)) @@ -140,7 +140,7 @@ func connect( ) } -func slicingCursor( +func slicingCursor( edges: [Edge], arguments: PaginationArguments ) -> ArraySlice> { @@ -166,7 +166,7 @@ func slicingCursor( return edges } -func slicingCount( +func slicingCount( edges: ArraySlice>, arguments: PaginationArguments ) throws -> [Edge] { @@ -195,7 +195,7 @@ func slicingCount( return Array(edges) } -func hasPreviousPage( +func hasPreviousPage( edges: ArraySlice>, arguments: PaginationArguments ) -> Bool { @@ -206,7 +206,7 @@ func hasPreviousPage( return false } -func hasNextPage( +func hasNextPage( edges: ArraySlice>, arguments: PaginationArguments ) -> Bool { diff --git a/Sources/Graphiti/Connection/ConnectionType.swift b/Sources/Graphiti/Connection/ConnectionType.swift index 83d10aac..5f8faa9e 100644 --- a/Sources/Graphiti/Connection/ConnectionType.swift +++ b/Sources/Graphiti/Connection/ConnectionType.swift @@ -3,7 +3,7 @@ import GraphQL public final class ConnectionType< Resolver, Context, - ObjectType: Encodable + ObjectType >: TypeComponent< Resolver, Context diff --git a/Sources/Graphiti/Connection/Edge.swift b/Sources/Graphiti/Connection/Edge.swift index 51db0a0f..0ab61c26 100644 --- a/Sources/Graphiti/Connection/Edge.swift +++ b/Sources/Graphiti/Connection/Edge.swift @@ -1,10 +1,10 @@ protocol Edgeable { - associatedtype Node: Encodable + associatedtype Node var node: Node { get } var cursor: String { get } } -public struct Edge: Edgeable, Encodable { +public struct Edge: Edgeable { public let node: Node public let cursor: String } diff --git a/Sources/Graphiti/Definition/Reflection.swift b/Sources/Graphiti/Definition/Reflection.swift index d1b149ae..618577c6 100644 --- a/Sources/Graphiti/Definition/Reflection.swift +++ b/Sources/Graphiti/Definition/Reflection.swift @@ -4,6 +4,7 @@ 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 diff --git a/Sources/Graphiti/Definition/TypeProvider.swift b/Sources/Graphiti/Definition/TypeProvider.swift index 9b47e08f..164b1881 100644 --- a/Sources/Graphiti/Definition/TypeProvider.swift +++ b/Sources/Graphiti/Definition/TypeProvider.swift @@ -86,16 +86,6 @@ extension TypeProvider { } func getOutputType(from type: Any.Type, field: String) throws -> GraphQLOutputType { - // TODO: Remove this when Reflection error is fixed - guard Reflection.isEncodable(type: type) else { - throw GraphQLError( - message: - // TODO: Add field type and use "type.field" format. - "Cannot use type \"\(type)\" for field \"\(field)\". " + - "Type does not conform to \"Encodable\"." - ) - } - let graphQLType: GraphQLType do { diff --git a/Sources/Graphiti/Field/Field/Field.swift b/Sources/Graphiti/Field/Field/Field.swift index 2cb55859..adfbb2a4 100644 --- a/Sources/Graphiti/Field/Field/Field.swift +++ b/Sources/Graphiti/Field/Field/Field.swift @@ -112,7 +112,7 @@ public class Field: FieldC // MARK: AsyncResolve Initializers -public extension Field where FieldType: Encodable { +public extension Field { convenience init( _ name: String, at function: @escaping AsyncResolve, @@ -154,7 +154,7 @@ public extension Field { // MARK: SimpleAsyncResolve Initializers -public extension Field where FieldType: Encodable { +public extension Field { convenience init( _ name: String, at function: @escaping SimpleAsyncResolve, @@ -196,7 +196,11 @@ public extension Field { // MARK: SyncResolve Initializers -public extension Field where FieldType: Encodable { +// '@_disfavoredOverload' is included below because otherwise `SimpleAsyncResolve` initializers also match this signature, causing the +// calls to be ambiguous. We prefer that if an EventLoopFuture is returned from the resolve, that `SimpleAsyncResolve` is matched. + +public extension Field { + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -205,6 +209,7 @@ public extension Field where FieldType: Encodable { self.init(name: name, arguments: [argument()], syncResolve: function) } + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -216,6 +221,7 @@ public extension Field where FieldType: Encodable { } public extension Field { + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -225,6 +231,7 @@ public extension Field { self.init(name: name, arguments: [argument()], syncResolve: function) } + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -298,7 +305,7 @@ public extension Field where Arguments == NoArguments { // MARK: ConcurrentResolve Initializers - public extension Field where FieldType: Encodable { + public extension Field { @available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *) convenience init( _ name: String, diff --git a/Sources/Graphiti/Input/Input.swift b/Sources/Graphiti/Input/Input.swift index 48ed8240..c3296522 100644 --- a/Sources/Graphiti/Input/Input.swift +++ b/Sources/Graphiti/Input/Input.swift @@ -3,7 +3,7 @@ import GraphQL public final class Input< Resolver, Context, - InputObjectType: Decodable + InputObjectType >: TypeComponent< Resolver, Context diff --git a/Sources/Graphiti/Subscription/SubscribeField.swift b/Sources/Graphiti/Subscription/SubscribeField.swift index 4b453a33..c3dbe993 100644 --- a/Sources/Graphiti/Subscription/SubscribeField.swift +++ b/Sources/Graphiti/Subscription/SubscribeField.swift @@ -263,7 +263,7 @@ public class SubscriptionField< // MARK: AsyncResolve Initializers -public extension SubscriptionField where FieldType: Encodable { +public extension SubscriptionField { convenience init( _ name: String, at function: @escaping AsyncResolve, @@ -376,7 +376,7 @@ public extension SubscriptionField { // MARK: SimpleAsyncResolve Initializers -public extension SubscriptionField where FieldType: Encodable { +public extension SubscriptionField { convenience init( _ name: String, at function: @escaping SimpleAsyncResolve, @@ -491,7 +491,11 @@ public extension SubscriptionField { // MARK: SyncResolve Initializers -public extension SubscriptionField where FieldType: Encodable { +// '@_disfavoredOverload' is included below because otherwise `SimpleAsyncResolve` initializers also match this signature, causing the +// calls to be ambiguous. We prefer that if an EventLoopFuture is returned from the resolve, that `SimpleAsyncResolve` is matched. + +public extension SubscriptionField { + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -511,6 +515,7 @@ public extension SubscriptionField where FieldType: Encodable { ) } + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -528,6 +533,7 @@ public extension SubscriptionField where FieldType: Encodable { } public extension SubscriptionField { + @_disfavoredOverload convenience init( _ name: String, as: FieldType.Type, @@ -542,6 +548,7 @@ public extension SubscriptionField { self.init(name: name, arguments: [argument()], as: `as`, syncSubscribe: subFunc) } + @_disfavoredOverload convenience init( _ name: String, as: FieldType.Type, @@ -557,6 +564,7 @@ public extension SubscriptionField { self.init(name: name, arguments: arguments(), as: `as`, syncSubscribe: subFunc) } + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -577,6 +585,7 @@ public extension SubscriptionField { ) } + @_disfavoredOverload convenience init( _ name: String, at function: @escaping SyncResolve, @@ -680,7 +689,7 @@ public extension SubscriptionField { // MARK: ConcurrentResolve Initializers - public extension SubscriptionField where FieldType: Encodable { + public extension SubscriptionField { @available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *) convenience init( _ name: String, diff --git a/Sources/Graphiti/Type/Type.swift b/Sources/Graphiti/Type/Type.swift index f2f25407..4f9157d6 100644 --- a/Sources/Graphiti/Type/Type.swift +++ b/Sources/Graphiti/Type/Type.swift @@ -1,6 +1,6 @@ import GraphQL -public final class Type: TypeComponent< +public final class Type: TypeComponent< Resolver, Context > { diff --git a/Tests/GraphitiTests/ConnectionTests.swift b/Tests/GraphitiTests/ConnectionTests.swift index 51ee4ca5..0b921143 100644 --- a/Tests/GraphitiTests/ConnectionTests.swift +++ b/Tests/GraphitiTests/ConnectionTests.swift @@ -4,7 +4,7 @@ import NIO import XCTest class ConnectionTests: XCTestCase { - struct Comment: Codable, Identifiable { + struct Comment: Identifiable { let id: Int let message: String } diff --git a/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift b/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift index 576b5ddb..381c8ac0 100644 --- a/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift +++ b/Tests/GraphitiTests/HelloWorldTests/HelloWorldTests.swift @@ -21,7 +21,7 @@ struct ID: Codable { } } -struct User: Codable { +struct User { let id: String let name: String? let friends: [User]? @@ -53,7 +53,7 @@ struct UserInput: Codable { let friends: [UserInput]? } -struct UserEvent: Codable { +struct UserEvent { let user: User } diff --git a/Tests/GraphitiTests/ProductAPI/ProductContext.swift b/Tests/GraphitiTests/ProductAPI/ProductContext.swift index a87f10c6..ea37ac87 100644 --- a/Tests/GraphitiTests/ProductAPI/ProductContext.swift +++ b/Tests/GraphitiTests/ProductAPI/ProductContext.swift @@ -1,5 +1,6 @@ import Foundation +// swiftformat:disable:next enumNamespaces struct ProductContext { static let dimensions = [ ProductDimension( diff --git a/Tests/GraphitiTests/ProductAPI/ProductEntities.swift b/Tests/GraphitiTests/ProductAPI/ProductEntities.swift index efe207c3..a1abec0b 100644 --- a/Tests/GraphitiTests/ProductAPI/ProductEntities.swift +++ b/Tests/GraphitiTests/ProductAPI/ProductEntities.swift @@ -1,7 +1,7 @@ import Foundation import Graphiti -struct Product: Codable { +struct Product { let id: String let sku: String? let package: String? @@ -30,7 +30,7 @@ struct Product: Codable { } } -struct DeprecatedProduct: Codable { +struct DeprecatedProduct { let sku: String let package: String let reason: String? @@ -42,11 +42,11 @@ struct DeprecatedProduct: Codable { } } -struct ProductVariation: Codable { +struct ProductVariation { let id: String } -struct ProductResearch: Codable { +struct ProductResearch { let study: CaseStudy let outcome: String? @@ -59,18 +59,18 @@ struct ProductResearch: Codable { } } -struct CaseStudy: Codable { +struct CaseStudy { let caseNumber: String let description: String? } -struct ProductDimension: Codable { +struct ProductDimension { let size: String? let weight: Float? let unit: String? } -struct ProductUser: Codable { +struct ProductUser { let email: String let name: String? let totalProductsCreated: Int? diff --git a/Tests/GraphitiTests/ScalarTests.swift b/Tests/GraphitiTests/ScalarTests.swift index 2bf068c1..3f0bb235 100644 --- a/Tests/GraphitiTests/ScalarTests.swift +++ b/Tests/GraphitiTests/ScalarTests.swift @@ -8,7 +8,7 @@ class ScalarTests: XCTestCase { // MARK: Test UUID converts to String as expected func testUUIDOutput() throws { - struct UUIDOutput: Codable { + struct UUIDOutput { let value: UUID } @@ -56,7 +56,7 @@ class ScalarTests: XCTestCase { } func testUUIDArg() throws { - struct UUIDOutput: Codable { + struct UUIDOutput { let value: UUID } @@ -110,7 +110,7 @@ class ScalarTests: XCTestCase { } func testUUIDInput() throws { - struct UUIDOutput: Codable { + struct UUIDOutput { let value: UUID } @@ -173,7 +173,7 @@ class ScalarTests: XCTestCase { // MARK: Test Date scalars convert to String using ISO8601 encoders func testDateOutput() throws { - struct DateOutput: Codable { + struct DateOutput { let value: Date } @@ -226,7 +226,7 @@ class ScalarTests: XCTestCase { } func testDateArg() throws { - struct DateOutput: Codable { + struct DateOutput { let value: Date } @@ -285,7 +285,7 @@ class ScalarTests: XCTestCase { } func testDateInput() throws { - struct DateOutput: Codable { + struct DateOutput { let value: Date } @@ -353,7 +353,7 @@ class ScalarTests: XCTestCase { // MARK: Test a scalar that converts to a single-value Map (StringCodedCoordinate -> String) func testStringCoordOutput() throws { - struct CoordinateOutput: Codable { + struct CoordinateOutput { let value: StringCodedCoordinate } @@ -401,7 +401,7 @@ class ScalarTests: XCTestCase { } func testStringCoordArg() throws { - struct CoordinateOutput: Codable { + struct CoordinateOutput { let value: StringCodedCoordinate } @@ -455,7 +455,7 @@ class ScalarTests: XCTestCase { } func testStringCoordInput() throws { - struct CoordinateOutput: Codable { + struct CoordinateOutput { let value: StringCodedCoordinate } @@ -518,7 +518,7 @@ class ScalarTests: XCTestCase { // MARK: Test a scalar that converts to a multi-value Map (Coordinate -> Dict) func testDictCoordOutput() throws { - struct CoordinateOutput: Codable { + struct CoordinateOutput { let value: DictCodedCoordinate } @@ -570,7 +570,7 @@ class ScalarTests: XCTestCase { } func testDictCoordArg() throws { - struct CoordinateOutput: Codable { + struct CoordinateOutput { let value: DictCodedCoordinate } @@ -628,7 +628,7 @@ class ScalarTests: XCTestCase { } func testDictCoordInput() throws { - struct CoordinateOutput: Codable { + struct CoordinateOutput { let value: DictCodedCoordinate } diff --git a/Tests/GraphitiTests/StarWarsAPI/StarWarsEntities.swift b/Tests/GraphitiTests/StarWarsAPI/StarWarsEntities.swift index 64687697..556caf17 100644 --- a/Tests/GraphitiTests/StarWarsAPI/StarWarsEntities.swift +++ b/Tests/GraphitiTests/StarWarsAPI/StarWarsEntities.swift @@ -1,19 +1,19 @@ -public enum Episode: String, Codable, CaseIterable { +public enum Episode: String, CaseIterable, Codable { case newHope = "NEWHOPE" case empire = "EMPIRE" case jedi = "JEDI" } -public protocol Character: Codable { +public protocol Character { var id: String { get } var name: String { get } var friends: [String] { get } var appearsIn: [Episode] { get } } -public protocol SearchResult: Codable {} +public protocol SearchResult {} -public struct Planet: SearchResult, Codable { +public struct Planet: SearchResult { public let id: String public let name: String public let diameter: Int @@ -22,7 +22,7 @@ public struct Planet: SearchResult, Codable { public var residents: [Human] } -public struct Human: Character, SearchResult, Codable { +public struct Human: Character, SearchResult { public let id: String public let name: String public let friends: [String] @@ -30,7 +30,7 @@ public struct Human: Character, SearchResult, Codable { public let homePlanet: Planet } -public struct Droid: Character, SearchResult, Codable { +public struct Droid: Character, SearchResult { public let id: String public let name: String public let friends: [String] diff --git a/Tests/GraphitiTests/StarWarsTests/StarWarsQueryTests.swift b/Tests/GraphitiTests/StarWarsTests/StarWarsQueryTests.swift index ffa91dfe..f3ea83b6 100644 --- a/Tests/GraphitiTests/StarWarsTests/StarWarsQueryTests.swift +++ b/Tests/GraphitiTests/StarWarsTests/StarWarsQueryTests.swift @@ -625,7 +625,7 @@ class StarWarsQueryTests: XCTestCase { } func testNonNullableFieldsQuery() throws { - struct A: Codable { + struct A { func nullableA(context _: NoContext, arguments _: NoArguments) -> A? { return A() }