Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
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
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 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
17pub 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}