馃寠 A GraphQL implementation in Gleam
at v2.1.4 8.3 kB view raw
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}