Skip to content

Commit 9da26da

Browse files
author
Jay Herron
committed
All subscription tests passing
1 parent 33130f3 commit 9da26da

File tree

2 files changed

+221
-203
lines changed

2 files changed

+221
-203
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import GraphQL
2+
import NIO
3+
import RxSwift
4+
5+
// MARK: Types
6+
struct Email : Encodable {
7+
let from:String
8+
let subject:String
9+
let message:String
10+
let unread:Bool
11+
let priority:Int
12+
13+
init(from:String, subject:String, message:String, unread:Bool, priority:Int = 0) {
14+
self.from = from
15+
self.subject = subject
16+
self.message = message
17+
self.unread = unread
18+
self.priority = priority
19+
}
20+
}
21+
22+
struct Inbox : Encodable {
23+
let emails:[Email]
24+
}
25+
26+
struct EmailEvent : Encodable {
27+
let email:Email
28+
let inbox:Inbox
29+
}
30+
31+
// MARK: Schema
32+
let EmailType = try! GraphQLObjectType(
33+
name: "Email",
34+
fields: [
35+
"from": GraphQLField(
36+
type: GraphQLString
37+
),
38+
"subject": GraphQLField(
39+
type: GraphQLString
40+
),
41+
"message": GraphQLField(
42+
type: GraphQLString
43+
),
44+
"unread": GraphQLField(
45+
type: GraphQLBoolean
46+
),
47+
]
48+
)
49+
let InboxType = try! GraphQLObjectType(
50+
name: "Inbox",
51+
fields: [
52+
"emails": GraphQLField(
53+
type: GraphQLList(EmailType)
54+
),
55+
"total": GraphQLField(
56+
type: GraphQLInt,
57+
resolve: { inbox, _, _, _ in
58+
(inbox as! Inbox).emails.count
59+
}
60+
),
61+
"unread": GraphQLField(
62+
type: GraphQLInt,
63+
resolve: { inbox, _, _, _ in
64+
(inbox as! Inbox).emails.filter({$0.unread}).count
65+
}
66+
),
67+
]
68+
)
69+
let EmailEventType = try! GraphQLObjectType(
70+
name: "EmailEvent",
71+
fields: [
72+
"email": GraphQLField(
73+
type: EmailType
74+
),
75+
"inbox": GraphQLField(
76+
type: InboxType
77+
)
78+
]
79+
)
80+
let EmailQueryType = try! GraphQLObjectType(
81+
name: "Query",
82+
fields: [
83+
"inbox": GraphQLField(
84+
type: InboxType
85+
)
86+
]
87+
)
88+
89+
// MARK: Test Helpers
90+
91+
let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
92+
93+
class EmailDb {
94+
var emails: [Email]
95+
let publisher: PublishSubject<Any>
96+
let disposeBag: DisposeBag
97+
98+
init() {
99+
emails = [
100+
Email(
101+
102+
subject: "Hello",
103+
message: "Hello World",
104+
unread: false
105+
)
106+
]
107+
publisher = PublishSubject<Any>()
108+
disposeBag = DisposeBag()
109+
}
110+
111+
/// Adds a new email to the database and triggers all observers
112+
func trigger(email:Email) {
113+
emails.append(email)
114+
publisher.onNext(email)
115+
}
116+
117+
/// Returns the default email schema, with standard resolvers.
118+
func defaultSchema() -> GraphQLSchema {
119+
return emailSchemaWithResolvers(
120+
resolve: {emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
121+
if let email = emailAny as? Email {
122+
return eventLoopGroup.next().makeSucceededFuture(EmailEvent(
123+
email: email,
124+
inbox: Inbox(emails: self.emails)
125+
))
126+
} else {
127+
throw GraphQLError(message: "\(type(of:emailAny)) is not Email")
128+
}
129+
},
130+
subscribe: {_, args, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
131+
let priority = args["priority"].int ?? 0
132+
let filtered = self.publisher.filter { emailAny throws in
133+
if let email = emailAny as? Email {
134+
return email.priority >= priority
135+
} else {
136+
return true
137+
}
138+
}
139+
return eventLoopGroup.next().makeSucceededFuture(filtered.toEventStream())
140+
}
141+
)
142+
}
143+
144+
/// Generates a subscription to the database using the default schema and resolvers
145+
func subscription (
146+
query:String,
147+
variableValues: [String: Map] = [:]
148+
) throws -> SubscriptionEventStream {
149+
return try createSubscription(schema: defaultSchema(), query: query, variableValues: variableValues)
150+
}
151+
}
152+
153+
/// Generates an email schema with the specified resolve and subscribe methods
154+
func emailSchemaWithResolvers(resolve: GraphQLFieldResolve? = nil, subscribe: GraphQLFieldResolve? = nil) -> GraphQLSchema {
155+
return try! GraphQLSchema(
156+
query: EmailQueryType,
157+
subscription: try! GraphQLObjectType(
158+
name: "Subscription",
159+
fields: [
160+
"importantEmail": GraphQLField(
161+
type: EmailEventType,
162+
args: [
163+
"priority": GraphQLArgument(
164+
type: GraphQLInt
165+
)
166+
],
167+
resolve: resolve,
168+
subscribe: subscribe
169+
)
170+
]
171+
)
172+
)
173+
}
174+
175+
/// Generates a subscription from the given schema and query. It's expected that the resolver/database interactions are configured by the caller.
176+
func createSubscription(
177+
schema: GraphQLSchema,
178+
query: String,
179+
variableValues: [String: Map] = [:]
180+
) throws -> SubscriptionEventStream {
181+
let result = try graphqlSubscribe(
182+
queryStrategy: SerialFieldExecutionStrategy(),
183+
mutationStrategy: SerialFieldExecutionStrategy(),
184+
subscriptionStrategy: SerialFieldExecutionStrategy(),
185+
instrumentation: NoOpInstrumentation,
186+
schema: schema,
187+
request: query,
188+
rootValue: Void(),
189+
context: Void(),
190+
eventLoopGroup: eventLoopGroup,
191+
variableValues: variableValues,
192+
operationName: nil
193+
).wait()
194+
195+
if let stream = result.stream {
196+
return stream
197+
} else {
198+
throw result.errors.first! // We may have more than one...
199+
}
200+
}

0 commit comments

Comments
 (0)