馃寠 A GraphQL implementation in Gleam
1import gleam/list
2import gleam/option.{None, Some}
3import gleeunit
4import gleeunit/should
5import swell/executor
6import swell/schema
7import swell/value
8
9pub fn main() {
10 gleeunit.main()
11}
12
13// Test: Create a subscription type
14pub fn create_subscription_type_test() {
15 let subscription_field =
16 schema.field(
17 "testSubscription",
18 schema.string_type(),
19 "A test subscription",
20 fn(_ctx) { Ok(value.String("test")) },
21 )
22
23 let subscription_type =
24 schema.object_type("Subscription", "Root subscription type", [
25 subscription_field,
26 ])
27
28 schema.type_name(subscription_type)
29 |> should.equal("Subscription")
30}
31
32// Test: Schema with subscription type
33pub fn schema_with_subscription_test() {
34 let query_field =
35 schema.field("hello", schema.string_type(), "Hello query", fn(_ctx) {
36 Ok(value.String("world"))
37 })
38
39 let query_type = schema.object_type("Query", "Root query type", [query_field])
40
41 let subscription_field =
42 schema.field(
43 "messageAdded",
44 schema.string_type(),
45 "Subscribe to new messages",
46 fn(_ctx) { Ok(value.String("test message")) },
47 )
48
49 let subscription_type =
50 schema.object_type("Subscription", "Root subscription type", [
51 subscription_field,
52 ])
53
54 let test_schema =
55 schema.schema_with_subscriptions(query_type, None, Some(subscription_type))
56
57 // Schema should be created successfully
58 // We can't easily test inequality on opaque types, so just verify it doesn't crash
59 let _ = test_schema
60 should.be_true(True)
61}
62
63// Test: Get subscription fields
64pub fn get_subscription_fields_test() {
65 let subscription_field1 =
66 schema.field(
67 "postCreated",
68 schema.string_type(),
69 "New post created",
70 fn(_ctx) { Ok(value.String("post1")) },
71 )
72
73 let subscription_field2 =
74 schema.field("postUpdated", schema.string_type(), "Post updated", fn(_ctx) {
75 Ok(value.String("post1"))
76 })
77
78 let subscription_type =
79 schema.object_type("Subscription", "Root subscription type", [
80 subscription_field1,
81 subscription_field2,
82 ])
83
84 let fields = schema.get_fields(subscription_type)
85
86 list.length(fields)
87 |> should.equal(2)
88}
89
90// Test: Execute anonymous subscription
91pub fn execute_anonymous_subscription_test() {
92 let query_type =
93 schema.object_type("Query", "Root query", [
94 schema.field("dummy", schema.string_type(), "Dummy", fn(_) {
95 Ok(value.String("dummy"))
96 }),
97 ])
98
99 let message_type =
100 schema.object_type("Message", "A message", [
101 schema.field("content", schema.string_type(), "Message content", fn(ctx) {
102 case ctx.data {
103 Some(value.Object(fields)) -> {
104 case list.key_find(fields, "content") {
105 Ok(content) -> Ok(content)
106 Error(_) -> Ok(value.String(""))
107 }
108 }
109 _ -> Ok(value.String(""))
110 }
111 }),
112 ])
113
114 let subscription_type =
115 schema.object_type("Subscription", "Root subscription", [
116 schema.field("messageAdded", message_type, "New message", fn(ctx) {
117 // In real usage, this would be called with event data in ctx.data
118 case ctx.data {
119 Some(data) -> Ok(data)
120 None -> Ok(value.Object([#("content", value.String("test"))]))
121 }
122 }),
123 ])
124
125 let test_schema =
126 schema.schema_with_subscriptions(query_type, None, Some(subscription_type))
127
128 // Create context with event data
129 let event_data =
130 value.Object([#("content", value.String("Hello from subscription!"))])
131 let ctx = schema.context(Some(event_data))
132
133 let query = "subscription { messageAdded { content } }"
134
135 case executor.execute(query, test_schema, ctx) {
136 Ok(response) -> {
137 case response.data {
138 value.Object(fields) -> {
139 case list.key_find(fields, "messageAdded") {
140 Ok(value.Object(message_fields)) -> {
141 case list.key_find(message_fields, "content") {
142 Ok(value.String(content)) ->
143 should.equal(content, "Hello from subscription!")
144 _ -> should.fail()
145 }
146 }
147 _ -> should.fail()
148 }
149 }
150 _ -> should.fail()
151 }
152 }
153 Error(_) -> should.fail()
154 }
155}
156
157// Test: Execute subscription with field selection
158pub fn execute_subscription_with_field_selection_test() {
159 let query_type =
160 schema.object_type("Query", "Root query", [
161 schema.field("dummy", schema.string_type(), "Dummy", fn(_) {
162 Ok(value.String("dummy"))
163 }),
164 ])
165
166 let post_type =
167 schema.object_type("Post", "A post", [
168 schema.field("id", schema.id_type(), "Post ID", fn(ctx) {
169 case ctx.data {
170 Some(value.Object(fields)) -> {
171 case list.key_find(fields, "id") {
172 Ok(id) -> Ok(id)
173 Error(_) -> Ok(value.String(""))
174 }
175 }
176 _ -> Ok(value.String(""))
177 }
178 }),
179 schema.field("title", schema.string_type(), "Post title", fn(ctx) {
180 case ctx.data {
181 Some(value.Object(fields)) -> {
182 case list.key_find(fields, "title") {
183 Ok(title) -> Ok(title)
184 Error(_) -> Ok(value.String(""))
185 }
186 }
187 _ -> Ok(value.String(""))
188 }
189 }),
190 schema.field("content", schema.string_type(), "Post content", fn(ctx) {
191 case ctx.data {
192 Some(value.Object(fields)) -> {
193 case list.key_find(fields, "content") {
194 Ok(content) -> Ok(content)
195 Error(_) -> Ok(value.String(""))
196 }
197 }
198 _ -> Ok(value.String(""))
199 }
200 }),
201 ])
202
203 let subscription_type =
204 schema.object_type("Subscription", "Root subscription", [
205 schema.field("postCreated", post_type, "New post", fn(ctx) {
206 case ctx.data {
207 Some(data) -> Ok(data)
208 None ->
209 Ok(
210 value.Object([
211 #("id", value.String("1")),
212 #("title", value.String("Test")),
213 #("content", value.String("Test content")),
214 ]),
215 )
216 }
217 }),
218 ])
219
220 let test_schema =
221 schema.schema_with_subscriptions(query_type, None, Some(subscription_type))
222
223 // Create context with event data
224 let event_data =
225 value.Object([
226 #("id", value.String("123")),
227 #("title", value.String("New Post")),
228 #("content", value.String("This is a new post")),
229 ])
230 let ctx = schema.context(Some(event_data))
231
232 // Query only for id and title, not content
233 let query = "subscription { postCreated { id title } }"
234
235 case executor.execute(query, test_schema, ctx) {
236 Ok(response) -> {
237 case response.data {
238 value.Object(fields) -> {
239 case list.key_find(fields, "postCreated") {
240 Ok(value.Object(post_fields)) -> {
241 // Should have id and title
242 case list.key_find(post_fields, "id") {
243 Ok(value.String(id)) -> should.equal(id, "123")
244 _ -> should.fail()
245 }
246 case list.key_find(post_fields, "title") {
247 Ok(value.String(title)) -> should.equal(title, "New Post")
248 _ -> should.fail()
249 }
250 // Should NOT have content (field selection working)
251 case list.key_find(post_fields, "content") {
252 Error(_) -> should.be_true(True)
253 Ok(_) -> should.fail()
254 }
255 }
256 _ -> should.fail()
257 }
258 }
259 _ -> should.fail()
260 }
261 }
262 Error(_) -> should.fail()
263 }
264}
265
266// Test: Subscription without schema type
267pub fn subscription_without_schema_type_test() {
268 let query_type =
269 schema.object_type("Query", "Root query", [
270 schema.field("dummy", schema.string_type(), "Dummy", fn(_) {
271 Ok(value.String("dummy"))
272 }),
273 ])
274
275 // Schema WITHOUT subscription type
276 let test_schema = schema.schema(query_type, None)
277
278 let ctx = schema.context(None)
279 let query = "subscription { messageAdded }"
280
281 case executor.execute(query, test_schema, ctx) {
282 Error(msg) ->
283 should.equal(msg, "Schema does not define a subscription type")
284 Ok(_) -> should.fail()
285 }
286}