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

Set Swift 5.7 as the minimum supported version #146

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
14 changes: 0 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,3 @@ jobs:
- name: Test
run: swift test --parallel

# Swift versions older than 5.7 don't have builds for 22.04. https://www.swift.org/download/
backcompat-ubuntu-20_04:
name: Test Swift ${{ matrix.swift }} on Ubuntu 20.04
runs-on: ubuntu-20.04
strategy:
matrix:
swift: ["5.4", "5.5", "5.6"]
steps:
- uses: swift-actions/setup-swift@v2
with:
swift-version: ${{ matrix.swift }}
- uses: actions/checkout@v3
- name: Test
run: swift test --parallel
60 changes: 38 additions & 22 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
{
"object": {
"pins": [
{
"package": "swift-collections",
"repositoryURL": "https://github.com/apple/swift-collections",
"state": {
"branch": null,
"revision": "48254824bb4248676bf7ce56014ff57b142b77eb",
"version": "1.0.2"
}
},
{
"package": "swift-nio",
"repositoryURL": "https://github.com/apple/swift-nio.git",
"state": {
"branch": null,
"revision": "124119f0bb12384cef35aa041d7c3a686108722d",
"version": "2.40.0"
}
"pins" : [
{
"identity" : "swift-atomics",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-atomics.git",
"state" : {
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
"version" : "1.2.0"
}
]
},
"version": 1
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections",
"state" : {
"revision" : "9bf03ff58ce34478e66aaee630e491823326fd06",
"version" : "1.1.3"
}
},
{
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "4c4453b489cf76e6b3b0f300aba663eb78182fad",
"version" : "2.70.0"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "d2ba781702a1d8285419c15ee62fd734a9437ff5",
"version" : "1.3.2"
}
}
],
"version" : 2
}
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.4
// swift-tools-version:5.7
import PackageDescription

let package = Package(
Expand All @@ -7,8 +7,8 @@ let package = Package(
.library(name: "GraphQL", targets: ["GraphQL"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.10.1")),
.package(url: "https://github.com/apple/swift-collections", .upToNextMajor(from: "1.0.0")),
.package(url: "https://github.com/apple/swift-nio.git", .upToNextMajor(from: "2.70.0")),
.package(url: "https://github.com/apple/swift-collections", .upToNextMajor(from: "1.0.3")),
Comment on lines -10 to +11
Copy link
Member

Choose a reason for hiding this comment

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

Why narrow these ranges? Wouldn't updating them in the Package.resolved be enough if we aren't using any new features introduced? Or does Swift package manager require that we pin to a compatible swift-tools-version?

Copy link
Author

Choose a reason for hiding this comment

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

The main reason is: Why not support the latest and greatest? :) As I understand it, it's not a breaking change in terms of API and contains important fixes and optimizations.

Copy link
Member

Choose a reason for hiding this comment

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

Why not support the latest and greatest?

Okay, but the last one already supported the latest and greatest. For example, both the old and new Package.swift would allow swift-nio v2.72.0. What you've done here only says that we are no longer compatible with, say, v2.68.0, which will require every downstream package to bump its NIO dependency to v2.70.0 or above. It's fine to bump this minimum version if we are relying on new functionality introduced, but if our library is functionally compatible with old versions we should allow them.

it's not a breaking change in terms of API and contains important fixes and optimizations.

While it's true that it contains important fixes and optimizations, the downstream package is in a better position to decide if and when they need them.

My request is that we remove these changes to Package.swift. We can keep the changes to Package.resolved so that we are testing the latest versions.

Copy link
Member

Choose a reason for hiding this comment

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

I agree with @NeedleInAJayStack!

],
targets: [
.target(
Expand Down
260 changes: 129 additions & 131 deletions Sources/GraphQL/GraphQL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -279,137 +279,135 @@ public func graphqlSubscribe(

// MARK: Async/Await

#if compiler(>=5.5) && canImport(_Concurrency)

@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
/// This is the primary entry point function for fulfilling GraphQL operations
/// by parsing, validating, and executing a GraphQL document along side a
/// GraphQL schema.
///
/// More sophisticated GraphQL servers, such as those which persist queries,
/// may wish to separate the validation and execution phases to a static time
/// tooling step, and a server runtime step.
///
/// - parameter queryStrategy: The field execution strategy to use for query requests
/// - parameter mutationStrategy: The field execution strategy to use for mutation requests
/// - parameter subscriptionStrategy: The field execution strategy to use for subscription
/// requests
/// - parameter instrumentation: The instrumentation implementation to call during the
/// parsing, validating, execution, and field resolution stages.
/// - parameter schema: The GraphQL type system to use when validating and
/// executing a query.
/// - parameter request: A GraphQL language formatted string representing the
/// requested operation.
/// - parameter rootValue: The value provided as the first argument to resolver
/// functions on the top level type (e.g. the query object type).
/// - parameter contextValue: A context value provided to all resolver functions
/// functions
/// - parameter variableValues: A mapping of variable name to runtime value to use for all
/// variables defined in the `request`.
/// - parameter operationName: The name of the operation to use if `request` contains
/// multiple possible operations. Can be omitted if `request` contains only one operation.
///
/// - throws: throws GraphQLError if an error occurs while parsing the `request`.
///
/// - returns: returns a `Map` dictionary containing the result of the query inside the key
/// `data` and any validation or execution errors inside the key `errors`. The value of `data`
/// might be `null` if, for example, the query is invalid. It's possible to have both `data` and
/// `errors` if an error occurs only in a specific field. If that happens the value of that
/// field will be `null` and there will be an error inside `errors` specifying the reason for
/// the failure and the path of the failed field.
public func graphql(
queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(),
mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(),
subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(),
instrumentation: Instrumentation = NoOpInstrumentation,
schema: GraphQLSchema,
request: String,
rootValue: Any = (),
context: Any = (),
eventLoopGroup: EventLoopGroup,
variableValues: [String: Map] = [:],
operationName: String? = nil
) async throws -> GraphQLResult {
return try await graphql(
queryStrategy: queryStrategy,
mutationStrategy: mutationStrategy,
subscriptionStrategy: subscriptionStrategy,
instrumentation: instrumentation,
schema: schema,
request: request,
rootValue: rootValue,
context: context,
eventLoopGroup: eventLoopGroup,
variableValues: variableValues,
operationName: operationName
).get()
}
@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
/// This is the primary entry point function for fulfilling GraphQL operations
/// by parsing, validating, and executing a GraphQL document along side a
/// GraphQL schema.
///
/// More sophisticated GraphQL servers, such as those which persist queries,
/// may wish to separate the validation and execution phases to a static time
/// tooling step, and a server runtime step.
///
/// - parameter queryStrategy: The field execution strategy to use for query requests
/// - parameter mutationStrategy: The field execution strategy to use for mutation requests
/// - parameter subscriptionStrategy: The field execution strategy to use for subscription
/// requests
/// - parameter instrumentation: The instrumentation implementation to call during the
/// parsing, validating, execution, and field resolution stages.
/// - parameter schema: The GraphQL type system to use when validating and
/// executing a query.
/// - parameter request: A GraphQL language formatted string representing the
/// requested operation.
/// - parameter rootValue: The value provided as the first argument to resolver
/// functions on the top level type (e.g. the query object type).
/// - parameter contextValue: A context value provided to all resolver functions
/// functions
/// - parameter variableValues: A mapping of variable name to runtime value to use for all
/// variables defined in the `request`.
/// - parameter operationName: The name of the operation to use if `request` contains
/// multiple possible operations. Can be omitted if `request` contains only one operation.
///
/// - throws: throws GraphQLError if an error occurs while parsing the `request`.
///
/// - returns: returns a `Map` dictionary containing the result of the query inside the key
/// `data` and any validation or execution errors inside the key `errors`. The value of `data`
/// might be `null` if, for example, the query is invalid. It's possible to have both `data` and
/// `errors` if an error occurs only in a specific field. If that happens the value of that
/// field will be `null` and there will be an error inside `errors` specifying the reason for
/// the failure and the path of the failed field.
public func graphql(
queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(),
mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(),
subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(),
instrumentation: Instrumentation = NoOpInstrumentation,
schema: GraphQLSchema,
request: String,
rootValue: Any = (),
context: Any = (),
eventLoopGroup: EventLoopGroup,
variableValues: [String: Map] = [:],
operationName: String? = nil
) async throws -> GraphQLResult {
return try await graphql(
queryStrategy: queryStrategy,
mutationStrategy: mutationStrategy,
subscriptionStrategy: subscriptionStrategy,
instrumentation: instrumentation,
schema: schema,
request: request,
rootValue: rootValue,
context: context,
eventLoopGroup: eventLoopGroup,
variableValues: variableValues,
operationName: operationName
).get()
}

@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
/// This is the primary entry point function for fulfilling GraphQL subscription
/// operations by parsing, validating, and executing a GraphQL subscription
/// document along side a GraphQL schema.
///
/// More sophisticated GraphQL servers, such as those which persist queries,
/// may wish to separate the validation and execution phases to a static time
/// tooling step, and a server runtime step.
///
/// - parameter queryStrategy: The field execution strategy to use for query requests
/// - parameter mutationStrategy: The field execution strategy to use for mutation requests
/// - parameter subscriptionStrategy: The field execution strategy to use for subscription
/// requests
/// - parameter instrumentation: The instrumentation implementation to call during the
/// parsing, validating, execution, and field resolution stages.
/// - parameter schema: The GraphQL type system to use when validating and
/// executing a query.
/// - parameter request: A GraphQL language formatted string representing the
/// requested operation.
/// - parameter rootValue: The value provided as the first argument to resolver
/// functions on the top level type (e.g. the query object type).
/// - parameter contextValue: A context value provided to all resolver functions
/// - parameter variableValues: A mapping of variable name to runtime value to use for all
/// variables defined in the `request`.
/// - parameter operationName: The name of the operation to use if `request` contains
/// multiple possible operations. Can be omitted if `request` contains only one operation.
///
/// - throws: throws GraphQLError if an error occurs while parsing the `request`.
///
/// - returns: returns a SubscriptionResult containing the subscription observable inside the
/// key `observable` and any validation or execution errors inside the key `errors`. The
/// value of `observable` might be `null` if, for example, the query is invalid. It's not
/// possible to have both `observable` and `errors`. The observable payloads are
/// GraphQLResults which contain the result of the query inside the key `data` and any
/// validation or execution errors inside the key `errors`. The value of `data` might be `null`.
/// It's possible to have both `data` and `errors` if an error occurs only in a specific field.
/// If that happens the value of that field will be `null` and there
/// will be an error inside `errors` specifying the reason for the failure and the path of the
/// failed field.
public func graphqlSubscribe(
queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(),
mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(),
subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(),
instrumentation: Instrumentation = NoOpInstrumentation,
schema: GraphQLSchema,
request: String,
rootValue: Any = (),
context: Any = (),
eventLoopGroup: EventLoopGroup,
variableValues: [String: Map] = [:],
operationName: String? = nil
) async throws -> SubscriptionResult {
return try await graphqlSubscribe(
queryStrategy: queryStrategy,
mutationStrategy: mutationStrategy,
subscriptionStrategy: subscriptionStrategy,
instrumentation: instrumentation,
schema: schema,
request: request,
rootValue: rootValue,
context: context,
eventLoopGroup: eventLoopGroup,
variableValues: variableValues,
operationName: operationName
).get()
}
@available(macOS 10.15, iOS 15, watchOS 8, tvOS 15, *)
/// This is the primary entry point function for fulfilling GraphQL subscription
/// operations by parsing, validating, and executing a GraphQL subscription
/// document along side a GraphQL schema.
///
/// More sophisticated GraphQL servers, such as those which persist queries,
/// may wish to separate the validation and execution phases to a static time
/// tooling step, and a server runtime step.
///
/// - parameter queryStrategy: The field execution strategy to use for query requests
/// - parameter mutationStrategy: The field execution strategy to use for mutation requests
/// - parameter subscriptionStrategy: The field execution strategy to use for subscription
/// requests
/// - parameter instrumentation: The instrumentation implementation to call during the
/// parsing, validating, execution, and field resolution stages.
/// - parameter schema: The GraphQL type system to use when validating and
/// executing a query.
/// - parameter request: A GraphQL language formatted string representing the
/// requested operation.
/// - parameter rootValue: The value provided as the first argument to resolver
/// functions on the top level type (e.g. the query object type).
/// - parameter contextValue: A context value provided to all resolver functions
/// - parameter variableValues: A mapping of variable name to runtime value to use for all
/// variables defined in the `request`.
/// - parameter operationName: The name of the operation to use if `request` contains
/// multiple possible operations. Can be omitted if `request` contains only one operation.
///
/// - throws: throws GraphQLError if an error occurs while parsing the `request`.
///
/// - returns: returns a SubscriptionResult containing the subscription observable inside the
/// key `observable` and any validation or execution errors inside the key `errors`. The
/// value of `observable` might be `null` if, for example, the query is invalid. It's not
/// possible to have both `observable` and `errors`. The observable payloads are
/// GraphQLResults which contain the result of the query inside the key `data` and any
/// validation or execution errors inside the key `errors`. The value of `data` might be `null`.
/// It's possible to have both `data` and `errors` if an error occurs only in a specific field.
/// If that happens the value of that field will be `null` and there
/// will be an error inside `errors` specifying the reason for the failure and the path of the
/// failed field.
public func graphqlSubscribe(
queryStrategy: QueryFieldExecutionStrategy = SerialFieldExecutionStrategy(),
mutationStrategy: MutationFieldExecutionStrategy = SerialFieldExecutionStrategy(),
subscriptionStrategy: SubscriptionFieldExecutionStrategy = SerialFieldExecutionStrategy(),
instrumentation: Instrumentation = NoOpInstrumentation,
schema: GraphQLSchema,
request: String,
rootValue: Any = (),
context: Any = (),
eventLoopGroup: EventLoopGroup,
variableValues: [String: Map] = [:],
operationName: String? = nil
) async throws -> SubscriptionResult {
return try await graphqlSubscribe(
queryStrategy: queryStrategy,
mutationStrategy: mutationStrategy,
subscriptionStrategy: subscriptionStrategy,
instrumentation: instrumentation,
schema: schema,
request: request,
rootValue: rootValue,
context: context,
eventLoopGroup: eventLoopGroup,
variableValues: variableValues,
operationName: operationName
).get()
}

#endif
Loading
Loading