Auto-indexing service and GraphQL API for AT Protocol Records quickslice.slices.network/
atproto gleam graphql
at main 225 lines 6.8 kB view raw
1/// Tests for nested forward join resolution in object_builder 2/// 3/// Verifies that object types containing strongRef fields get *Resolved fields 4/// when batch_fetcher and generic_record_type are provided 5import gleam/dict 6import gleam/list 7import gleam/option.{None, Some} 8import gleeunit/should 9import lexicon_graphql/internal/graphql/object_builder 10import lexicon_graphql/internal/lexicon/registry 11import lexicon_graphql/types 12import swell/schema 13 14/// Test that nested strongRef fields get *Resolved fields when batch_fetcher is provided 15pub fn nested_strongref_gets_resolved_field_test() { 16 // Create a lexicon with an object type containing strongRef fields 17 let lexicon = 18 types.Lexicon( 19 id: "app.bsky.feed.post", 20 defs: types.Defs( 21 main: Some( 22 types.RecordDef(type_: "record", key: Some("tid"), properties: [ 23 #( 24 "text", 25 types.Property( 26 type_: "string", 27 required: True, 28 format: None, 29 ref: None, 30 refs: None, 31 items: None, 32 ), 33 ), 34 ]), 35 ), 36 others: dict.from_list([ 37 #( 38 "replyRef", 39 types.Object( 40 types.ObjectDef( 41 type_: "object", 42 required_fields: ["parent", "root"], 43 properties: [ 44 #( 45 "parent", 46 types.Property( 47 type_: "ref", 48 required: True, 49 format: None, 50 ref: Some("com.atproto.repo.strongRef"), 51 refs: None, 52 items: None, 53 ), 54 ), 55 #( 56 "root", 57 types.Property( 58 type_: "ref", 59 required: True, 60 format: None, 61 ref: Some("com.atproto.repo.strongRef"), 62 refs: None, 63 items: None, 64 ), 65 ), 66 ], 67 ), 68 ), 69 ), 70 ]), 71 ), 72 ) 73 74 // Build a registry from the lexicon 75 let reg = registry.from_lexicons([lexicon]) 76 77 // Create a mock Record union type (the generic type for *Resolved fields) 78 let mock_record_type = schema.object_type("Record", "Mock record union", []) 79 80 // Create a mock batch fetcher that returns empty results 81 let mock_batch_fetcher = fn(_uris, _collection, _field) { Ok(dict.new()) } 82 83 // Build object types WITH batch_fetcher and generic_record_type 84 let object_types = 85 object_builder.build_all_object_types( 86 reg, 87 Some(mock_batch_fetcher), 88 Some(mock_record_type), 89 ) 90 91 // The replyRef object type should exist 92 let assert Ok(reply_ref_type) = 93 dict.get(object_types, "app.bsky.feed.post#replyRef") 94 95 // Get the fields from the type 96 let fields = schema.get_fields(reply_ref_type) 97 let field_names = list.map(fields, schema.field_name) 98 99 // Should have parentResolved and rootResolved fields 100 list.contains(field_names, "parentResolved") 101 |> should.be_true 102 103 list.contains(field_names, "rootResolved") 104 |> should.be_true 105} 106 107/// Test that at-uri format fields in nested objects also get *Resolved fields 108pub fn nested_at_uri_gets_resolved_field_test() { 109 let lexicon = 110 types.Lexicon( 111 id: "test.record", 112 defs: types.Defs( 113 main: Some( 114 types.RecordDef(type_: "record", key: Some("tid"), properties: []), 115 ), 116 others: dict.from_list([ 117 #( 118 "refObject", 119 types.Object( 120 types.ObjectDef( 121 type_: "object", 122 required_fields: ["target"], 123 properties: [ 124 #( 125 "target", 126 types.Property( 127 type_: "string", 128 required: True, 129 format: Some("at-uri"), 130 ref: None, 131 refs: None, 132 items: None, 133 ), 134 ), 135 ], 136 ), 137 ), 138 ), 139 ]), 140 ), 141 ) 142 143 // Build a registry from the lexicon 144 let reg = registry.from_lexicons([lexicon]) 145 146 // Create mock types 147 let mock_record_type = schema.object_type("Record", "Mock record union", []) 148 let mock_batch_fetcher = fn(_uris, _collection, _field) { Ok(dict.new()) } 149 150 // Build object types WITH batch_fetcher and generic_record_type 151 let object_types = 152 object_builder.build_all_object_types( 153 reg, 154 Some(mock_batch_fetcher), 155 Some(mock_record_type), 156 ) 157 158 // The refObject type should exist 159 let assert Ok(ref_object_type) = 160 dict.get(object_types, "test.record#refObject") 161 162 // Get the fields from the type 163 let fields = schema.get_fields(ref_object_type) 164 let field_names = list.map(fields, schema.field_name) 165 166 // Should have targetResolved field 167 list.contains(field_names, "targetResolved") 168 |> should.be_true 169} 170 171/// Test that *Resolved fields are NOT added when batch_fetcher is None 172pub fn no_resolved_fields_without_batch_fetcher_test() { 173 let lexicon = 174 types.Lexicon( 175 id: "app.bsky.feed.post", 176 defs: types.Defs( 177 main: Some( 178 types.RecordDef(type_: "record", key: Some("tid"), properties: []), 179 ), 180 others: dict.from_list([ 181 #( 182 "replyRef", 183 types.Object( 184 types.ObjectDef( 185 type_: "object", 186 required_fields: ["parent"], 187 properties: [ 188 #( 189 "parent", 190 types.Property( 191 type_: "ref", 192 required: True, 193 format: None, 194 ref: Some("com.atproto.repo.strongRef"), 195 refs: None, 196 items: None, 197 ), 198 ), 199 ], 200 ), 201 ), 202 ), 203 ]), 204 ), 205 ) 206 207 let reg = registry.from_lexicons([lexicon]) 208 209 // Build object types WITHOUT batch_fetcher (None, None) 210 let object_types = object_builder.build_all_object_types(reg, None, None) 211 212 let assert Ok(reply_ref_type) = 213 dict.get(object_types, "app.bsky.feed.post#replyRef") 214 215 let fields = schema.get_fields(reply_ref_type) 216 let field_names = list.map(fields, schema.field_name) 217 218 // Should NOT have parentResolved field (no batch_fetcher) 219 list.contains(field_names, "parentResolved") 220 |> should.be_false 221 222 // Should still have the regular parent field 223 list.contains(field_names, "parent") 224 |> should.be_true 225}