Auto-indexing service and GraphQL API for AT Protocol Records
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

test: add failing test for strongRef resolution in nested objects

+170
+170
lexicon_graphql/test/strongref_nested_resolution_test.gleam
··· 1 + /// Tests for strongRef resolution in nested object types 2 + /// 3 + /// Verifies that com.atproto.repo.strongRef refs in "others" object definitions 4 + /// (like #replyRef) resolve to ComAtprotoRepoStrongRef, not String 5 + import gleam/dict 6 + import gleam/list 7 + import gleam/option.{None, Some} 8 + import gleeunit/should 9 + import lexicon_graphql/internal/graphql/object_builder 10 + import lexicon_graphql/internal/lexicon/registry 11 + import lexicon_graphql/types 12 + import swell/schema 13 + 14 + /// Test that strongRef fields in nested objects resolve to object type, not String 15 + /// This reproduces the bug: app.bsky.feed.post#replyRef.parent should be 16 + /// ComAtprotoRepoStrongRef, not String 17 + pub fn strongref_in_nested_object_resolves_to_object_type_test() { 18 + // Create com.atproto.repo.strongRef lexicon (main-level object type) 19 + let strongref_lexicon = 20 + types.Lexicon( 21 + id: "com.atproto.repo.strongRef", 22 + defs: types.Defs( 23 + main: Some( 24 + types.RecordDef(type_: "object", key: None, properties: [ 25 + #( 26 + "uri", 27 + types.Property( 28 + type_: "string", 29 + required: True, 30 + format: Some("at-uri"), 31 + ref: None, 32 + refs: None, 33 + items: None, 34 + ), 35 + ), 36 + #( 37 + "cid", 38 + types.Property( 39 + type_: "string", 40 + required: True, 41 + format: Some("cid"), 42 + ref: None, 43 + refs: None, 44 + items: None, 45 + ), 46 + ), 47 + ]), 48 + ), 49 + others: dict.new(), 50 + ), 51 + ) 52 + 53 + // Create a post lexicon with #replyRef that references strongRef 54 + let post_lexicon = 55 + types.Lexicon( 56 + id: "app.bsky.feed.post", 57 + defs: types.Defs( 58 + main: Some( 59 + types.RecordDef(type_: "record", key: Some("tid"), properties: [ 60 + #( 61 + "text", 62 + types.Property( 63 + type_: "string", 64 + required: True, 65 + format: None, 66 + ref: None, 67 + refs: None, 68 + items: None, 69 + ), 70 + ), 71 + #( 72 + "reply", 73 + types.Property( 74 + type_: "ref", 75 + required: False, 76 + format: None, 77 + ref: Some("#replyRef"), 78 + refs: None, 79 + items: None, 80 + ), 81 + ), 82 + ]), 83 + ), 84 + others: dict.from_list([ 85 + #( 86 + "replyRef", 87 + types.Object( 88 + types.ObjectDef( 89 + type_: "object", 90 + required_fields: ["parent", "root"], 91 + properties: [ 92 + #( 93 + "parent", 94 + types.Property( 95 + type_: "ref", 96 + required: True, 97 + format: None, 98 + ref: Some("com.atproto.repo.strongRef"), 99 + refs: None, 100 + items: None, 101 + ), 102 + ), 103 + #( 104 + "root", 105 + types.Property( 106 + type_: "ref", 107 + required: True, 108 + format: None, 109 + ref: Some("com.atproto.repo.strongRef"), 110 + refs: None, 111 + items: None, 112 + ), 113 + ), 114 + ], 115 + ), 116 + ), 117 + ), 118 + ]), 119 + ), 120 + ) 121 + 122 + // Build registry and object types 123 + let reg = registry.from_lexicons([strongref_lexicon, post_lexicon]) 124 + let object_types = object_builder.build_all_object_types(reg, None, None) 125 + 126 + // The strongRef type should exist 127 + let strongref_type_result = 128 + dict.get(object_types, "com.atproto.repo.strongRef") 129 + should.be_ok(strongref_type_result) 130 + 131 + // The replyRef type should exist 132 + let reply_ref_result = dict.get(object_types, "app.bsky.feed.post#replyRef") 133 + should.be_ok(reply_ref_result) 134 + 135 + // Check the replyRef type's parent field is ComAtprotoRepoStrongRef, not String 136 + case reply_ref_result { 137 + Ok(reply_ref_type) -> { 138 + let type_name = schema.type_name(reply_ref_type) 139 + should.equal(type_name, "AppBskyFeedPostReplyRef") 140 + 141 + // Get the fields and find "parent" 142 + let fields = schema.get_fields(reply_ref_type) 143 + let parent_field = 144 + list.find(fields, fn(f) { schema.field_name(f) == "parent" }) 145 + 146 + case parent_field { 147 + Ok(field) -> { 148 + // The field type should be ComAtprotoRepoStrongRef, not String 149 + let field_type = schema.field_type(field) 150 + 151 + // Unwrap NonNull wrapper to get inner type 152 + let inner_type = case schema.inner_type(field_type) { 153 + Some(t) -> t 154 + None -> field_type 155 + } 156 + 157 + let inner_type_name = schema.type_name(inner_type) 158 + 159 + // Should NOT be "String" 160 + should.not_equal(inner_type_name, "String") 161 + 162 + // Should be "ComAtprotoRepoStrongRef" 163 + should.equal(inner_type_name, "ComAtprotoRepoStrongRef") 164 + } 165 + Error(_) -> should.fail() 166 + } 167 + } 168 + Error(_) -> should.fail() 169 + } 170 + }