diff --git a/Package.resolved b/Package.resolved index 4b4f5302..405f179f 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/apple/swift-collections", "state": { "branch": null, - "revision": "2d33a0ea89c961dcb2b3da2157963d9c0370347e", - "version": "1.0.1" + "revision": "48254824bb4248676bf7ce56014ff57b142b77eb", + "version": "1.0.2" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/apple/swift-nio.git", "state": { "branch": null, - "revision": "120acb15c39aa3217e9888e515de160378fbcc1e", - "version": "2.18.0" + "revision": "51c3fc2e4a0fcdf4a25089b288dd65b73df1b0ef", + "version": "2.37.0" } } ] diff --git a/Sources/GraphQL/GraphQLRequest.swift b/Sources/GraphQL/GraphQLRequest.swift new file mode 100644 index 00000000..0e4eced3 --- /dev/null +++ b/Sources/GraphQL/GraphQLRequest.swift @@ -0,0 +1,40 @@ +import Foundation + +/// A GraphQL request object, containing `query`, `operationName`, and `variables` fields +public struct GraphQLRequest: Equatable, Codable { + public var query: String + public var operationName: String? + public var variables: [String: Map] + + public init(query: String, operationName: String? = nil, variables: [String: Map] = [:]) { + self.query = query + self.operationName = operationName + self.variables = variables + } + + // To handle decoding with a default of variables = [] + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.query = try container.decode(String.self, forKey: .query) + self.operationName = try container.decodeIfPresent(String.self, forKey: .operationName) + self.variables = try container.decodeIfPresent([String: Map].self, forKey: .variables) ?? [:] + } + + /// Boolean indicating if the GraphQL request is a subscription operation. + /// This operation performs an entire AST parse on the GraphQL request, so consider + /// performance when calling multiple times. + /// + /// - Returns: True if request is a subscription, false if it is an atomic operation (like `query` or `mutation`) + public func isSubscription() throws -> Bool { + let documentAST = try GraphQL.parse( + instrumentation: NoOpInstrumentation, + source: Source(body: self.query, name: "GraphQL request") + ) + let firstOperation = documentAST.definitions.compactMap { $0 as? OperationDefinition }.first + guard let operationType = firstOperation?.operation else { + throw GraphQLError(message: "GraphQL operation type could not be determined") + } + return operationType == .subscription + } +} +