Auto-indexing service and GraphQL API for AT Protocol Records quickslice.slices.network/
atproto gleam graphql
at main 335 lines 9.0 kB view raw
1/// Tests for forward join field generation 2/// 3/// Verifies that forward join fields are added to GraphQL schemas based on lexicon metadata 4import gleam/dict 5import gleam/option.{None, Some} 6import gleam/string 7import gleeunit/should 8import lexicon_graphql/schema/database as db_schema_builder 9import lexicon_graphql/types 10import swell/introspection 11import swell/schema 12import swell/sdl 13 14// Helper to create a test schema with a mock fetcher 15fn create_test_schema_from_lexicons( 16 lexicons: List(types.Lexicon), 17) -> schema.Schema { 18 // Mock fetcher that returns empty results (we're only testing schema generation) 19 let fetcher = fn(_collection, _params) { 20 Ok(#([], option.None, False, False, option.None)) 21 } 22 23 case 24 db_schema_builder.build_schema_with_fetcher( 25 lexicons, 26 fetcher, 27 option.None, 28 option.None, 29 option.None, 30 option.None, 31 option.None, 32 option.None, 33 ) 34 { 35 Ok(s) -> s 36 Error(_) -> panic as "Failed to build test schema" 37 } 38} 39 40// Test that strongRef fields generate forward join fields 41pub fn strong_ref_generates_forward_join_field_test() { 42 let lexicon = 43 types.Lexicon( 44 id: "app.bsky.actor.profile", 45 defs: types.Defs( 46 main: Some( 47 types.RecordDef(type_: "record", key: None, properties: [ 48 #( 49 "displayName", 50 types.Property( 51 type_: "string", 52 required: True, 53 format: None, 54 ref: None, 55 refs: None, 56 items: None, 57 ), 58 ), 59 #( 60 "pinnedPost", 61 types.Property( 62 type_: "ref", 63 required: False, 64 format: None, 65 ref: Some("com.atproto.repo.strongRef"), 66 refs: None, 67 items: None, 68 ), 69 ), 70 ]), 71 ), 72 others: dict.new(), 73 ), 74 ) 75 76 let test_schema = create_test_schema_from_lexicons([lexicon]) 77 78 // Get all types and serialize to SDL 79 let all_types = introspection.get_all_schema_types(test_schema) 80 let serialized = sdl.print_types(all_types) 81 82 // Verify that pinnedPostResolved field appears in the schema 83 string.contains(serialized, "pinnedPostResolved") 84 |> should.be_true 85} 86 87// Test that at-uri fields generate forward join fields 88pub fn at_uri_generates_forward_join_field_test() { 89 let lexicon = 90 types.Lexicon( 91 id: "app.bsky.feed.like", 92 defs: types.Defs( 93 main: Some( 94 types.RecordDef(type_: "record", key: None, properties: [ 95 #( 96 "subject", 97 types.Property( 98 type_: "string", 99 required: True, 100 format: Some("at-uri"), 101 ref: None, 102 refs: None, 103 items: None, 104 ), 105 ), 106 #( 107 "createdAt", 108 types.Property( 109 type_: "string", 110 required: True, 111 format: Some("datetime"), 112 ref: None, 113 refs: None, 114 items: None, 115 ), 116 ), 117 ]), 118 ), 119 others: dict.new(), 120 ), 121 ) 122 123 let test_schema = create_test_schema_from_lexicons([lexicon]) 124 125 let all_types = introspection.get_all_schema_types(test_schema) 126 let serialized = sdl.print_types(all_types) 127 128 // Verify that subjectResolved field appears in the schema 129 string.contains(serialized, "subjectResolved") 130 |> should.be_true 131} 132 133// Test that multiple forward join fields are all generated 134pub fn multiple_forward_join_fields_test() { 135 let lexicon = 136 types.Lexicon( 137 id: "app.bsky.feed.post", 138 defs: types.Defs( 139 main: Some( 140 types.RecordDef(type_: "record", key: None, properties: [ 141 #( 142 "text", 143 types.Property( 144 type_: "string", 145 required: True, 146 format: None, 147 ref: None, 148 refs: None, 149 items: None, 150 ), 151 ), 152 #( 153 "reply", 154 types.Property( 155 type_: "ref", 156 required: False, 157 format: None, 158 ref: Some("com.atproto.repo.strongRef"), 159 refs: None, 160 items: None, 161 ), 162 ), 163 #( 164 "via", 165 types.Property( 166 type_: "string", 167 required: False, 168 format: Some("at-uri"), 169 ref: None, 170 refs: None, 171 items: None, 172 ), 173 ), 174 ]), 175 ), 176 others: dict.new(), 177 ), 178 ) 179 180 let test_schema = create_test_schema_from_lexicons([lexicon]) 181 182 let all_types = introspection.get_all_schema_types(test_schema) 183 let serialized = sdl.print_types(all_types) 184 185 // Check both forward join fields exist 186 string.contains(serialized, "replyResolved") 187 |> should.be_true 188 189 string.contains(serialized, "viaResolved") 190 |> should.be_true 191} 192 193// Test that collections without join fields don't generate extra fields 194pub fn no_join_fields_test() { 195 let lexicon = 196 types.Lexicon( 197 id: "xyz.statusphere.status", 198 defs: types.Defs( 199 main: Some( 200 types.RecordDef(type_: "record", key: None, properties: [ 201 #( 202 "status", 203 types.Property( 204 type_: "string", 205 required: True, 206 format: None, 207 ref: None, 208 refs: None, 209 items: None, 210 ), 211 ), 212 #( 213 "createdAt", 214 types.Property( 215 type_: "string", 216 required: True, 217 format: Some("datetime"), 218 ref: None, 219 refs: None, 220 items: None, 221 ), 222 ), 223 ]), 224 ), 225 others: dict.new(), 226 ), 227 ) 228 229 let test_schema = create_test_schema_from_lexicons([lexicon]) 230 231 let all_types = introspection.get_all_schema_types(test_schema) 232 let serialized = sdl.print_types(all_types) 233 234 // Should not have any "Resolved" fields for non-join fields 235 let has_status_resolved = string.contains(serialized, "statusResolved") 236 let has_created_at_resolved = string.contains(serialized, "createdAtResolved") 237 238 has_status_resolved 239 |> should.be_false 240 241 has_created_at_resolved 242 |> should.be_false 243} 244 245// Test that Record union is generated for forward joins 246pub fn record_union_type_exists_test() { 247 let lexicon = 248 types.Lexicon( 249 id: "app.bsky.feed.post", 250 defs: types.Defs( 251 main: Some( 252 types.RecordDef(type_: "record", key: None, properties: [ 253 #( 254 "text", 255 types.Property( 256 type_: "string", 257 required: True, 258 format: None, 259 ref: None, 260 refs: None, 261 items: None, 262 ), 263 ), 264 #( 265 "reply", 266 types.Property( 267 type_: "ref", 268 required: False, 269 format: None, 270 ref: Some("com.atproto.repo.strongRef"), 271 refs: None, 272 items: None, 273 ), 274 ), 275 ]), 276 ), 277 others: dict.new(), 278 ), 279 ) 280 281 let test_schema = create_test_schema_from_lexicons([lexicon]) 282 283 let all_types = introspection.get_all_schema_types(test_schema) 284 let serialized = sdl.print_types(all_types) 285 286 // Verify that Record union exists 287 string.contains(serialized, "union Record") 288 |> should.be_true 289} 290 291// Test that forward join fields have Record union type 292pub fn forward_join_field_has_union_type_test() { 293 let lexicon = 294 types.Lexicon( 295 id: "app.bsky.feed.post", 296 defs: types.Defs( 297 main: Some( 298 types.RecordDef(type_: "record", key: None, properties: [ 299 #( 300 "text", 301 types.Property( 302 type_: "string", 303 required: True, 304 format: None, 305 ref: None, 306 refs: None, 307 items: None, 308 ), 309 ), 310 #( 311 "reply", 312 types.Property( 313 type_: "ref", 314 required: False, 315 format: None, 316 ref: Some("com.atproto.repo.strongRef"), 317 refs: None, 318 items: None, 319 ), 320 ), 321 ]), 322 ), 323 others: dict.new(), 324 ), 325 ) 326 327 let test_schema = create_test_schema_from_lexicons([lexicon]) 328 329 let all_types = introspection.get_all_schema_types(test_schema) 330 let serialized = sdl.print_types(all_types) 331 332 // Verify that replyResolved field has Record type 333 string.contains(serialized, "replyResolved: Record") 334 |> should.be_true 335}