Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1/// Integration tests for joins and DataLoader with actual database
2///
3/// Tests verify that:
4/// - Forward joins (at-uri and strongRef) resolve correctly
5/// - Reverse joins discover and resolve relationships
6/// - DataLoader batches queries efficiently
7/// - All join types work with actual SQLite database queries
8import database/repositories/lexicons
9import database/repositories/records
10import gleam/json
11import gleam/option
12import gleam/string
13import gleeunit/should
14import graphql/lexicon/schema as lexicon_schema
15import lib/oauth/did_cache
16import test_helpers
17
18// Helper to create a post lexicon JSON
19fn create_post_lexicon() -> String {
20 json.object([
21 #("lexicon", json.int(1)),
22 #("id", json.string("app.bsky.feed.post")),
23 #(
24 "defs",
25 json.object([
26 #(
27 "main",
28 json.object([
29 #("type", json.string("record")),
30 #("key", json.string("tid")),
31 #(
32 "record",
33 json.object([
34 #("type", json.string("object")),
35 #(
36 "required",
37 json.array([json.string("text")], of: fn(x) { x }),
38 ),
39 #(
40 "properties",
41 json.object([
42 #(
43 "text",
44 json.object([
45 #("type", json.string("string")),
46 #("maxLength", json.int(300)),
47 ]),
48 ),
49 #(
50 "replyTo",
51 json.object([
52 #("type", json.string("string")),
53 #("format", json.string("at-uri")),
54 ]),
55 ),
56 ]),
57 ),
58 ]),
59 ),
60 ]),
61 ),
62 ]),
63 ),
64 ])
65 |> json.to_string
66}
67
68// Helper to create a like lexicon JSON with subject field (at-uri)
69fn create_like_lexicon() -> String {
70 json.object([
71 #("lexicon", json.int(1)),
72 #("id", json.string("app.bsky.feed.like")),
73 #(
74 "defs",
75 json.object([
76 #(
77 "main",
78 json.object([
79 #("type", json.string("record")),
80 #("key", json.string("tid")),
81 #(
82 "record",
83 json.object([
84 #("type", json.string("object")),
85 #(
86 "required",
87 json.array([json.string("subject")], of: fn(x) { x }),
88 ),
89 #(
90 "properties",
91 json.object([
92 #(
93 "subject",
94 json.object([
95 #("type", json.string("string")),
96 #("format", json.string("at-uri")),
97 ]),
98 ),
99 #(
100 "createdAt",
101 json.object([
102 #("type", json.string("string")),
103 #("format", json.string("datetime")),
104 ]),
105 ),
106 ]),
107 ),
108 ]),
109 ),
110 ]),
111 ),
112 ]),
113 ),
114 ])
115 |> json.to_string
116}
117
118// Helper to create a profile lexicon with strongRef
119fn create_profile_lexicon() -> String {
120 json.object([
121 #("lexicon", json.int(1)),
122 #("id", json.string("app.bsky.actor.profile")),
123 #(
124 "defs",
125 json.object([
126 #(
127 "main",
128 json.object([
129 #("type", json.string("record")),
130 #("key", json.string("self")),
131 #(
132 "record",
133 json.object([
134 #("type", json.string("object")),
135 #(
136 "properties",
137 json.object([
138 #(
139 "displayName",
140 json.object([#("type", json.string("string"))]),
141 ),
142 #(
143 "pinnedPost",
144 json.object([
145 #("type", json.string("ref")),
146 #("ref", json.string("com.atproto.repo.strongRef")),
147 ]),
148 ),
149 ]),
150 ),
151 ]),
152 ),
153 ]),
154 ),
155 ]),
156 ),
157 ])
158 |> json.to_string
159}
160
161// Test: Forward join with at-uri field resolves correctly
162pub fn forward_join_at_uri_resolves_test() {
163 // Setup database
164 let assert Ok(exec) = test_helpers.create_test_db()
165 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
166 let assert Ok(_) = test_helpers.create_record_table(exec)
167 let assert Ok(_) = test_helpers.create_actor_table(exec)
168
169 // Insert lexicons
170 let post_lexicon = create_post_lexicon()
171 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
172
173 // Insert test records
174 // Parent post
175 let parent_uri = "at://did:plc:parent123/app.bsky.feed.post/parent1"
176 let parent_json =
177 json.object([#("text", json.string("This is the parent post"))])
178 |> json.to_string
179
180 let assert Ok(_) =
181 records.insert(
182 exec,
183 parent_uri,
184 "cid_parent",
185 "did:plc:parent123",
186 "app.bsky.feed.post",
187 parent_json,
188 )
189
190 // Reply post that references parent
191 let reply_uri = "at://did:plc:user456/app.bsky.feed.post/reply1"
192 let reply_json =
193 json.object([
194 #("text", json.string("This is a reply")),
195 #("replyTo", json.string(parent_uri)),
196 ])
197 |> json.to_string
198
199 let assert Ok(_) =
200 records.insert(
201 exec,
202 reply_uri,
203 "cid_reply",
204 "did:plc:user456",
205 "app.bsky.feed.post",
206 reply_json,
207 )
208
209 // Execute GraphQL query with forward join
210 let query =
211 "
212 {
213 appBskyFeedPost {
214 edges {
215 node {
216 uri
217 replyToResolved {
218 uri
219 }
220 }
221 }
222 }
223 }
224 "
225
226 let assert Ok(cache) = did_cache.start()
227 let assert Ok(response_json) =
228 lexicon_schema.execute_query_with_db(
229 exec,
230 query,
231 "{}",
232 Error(Nil),
233 cache,
234 option.None,
235 "",
236 "https://plc.directory",
237 )
238
239 // Verify the response contains resolved join with parent URI
240 string.contains(response_json, reply_uri)
241 |> should.be_true
242
243 string.contains(response_json, parent_uri)
244 |> should.be_true
245
246 string.contains(response_json, "replyToResolved")
247 |> should.be_true
248}
249
250// Test: Forward join with strongRef resolves correctly
251pub fn forward_join_strong_ref_resolves_test() {
252 // Setup database
253 let assert Ok(exec) = test_helpers.create_test_db()
254 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
255 let assert Ok(_) = test_helpers.create_record_table(exec)
256 let assert Ok(_) = test_helpers.create_actor_table(exec)
257
258 // Insert lexicons
259 let post_lexicon = create_post_lexicon()
260 let profile_lexicon = create_profile_lexicon()
261 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
262 let assert Ok(_) =
263 lexicons.insert(exec, "app.bsky.actor.profile", profile_lexicon)
264
265 // Insert test records
266 // A post
267 let post_uri = "at://did:plc:user123/app.bsky.feed.post/post1"
268 let post_json =
269 json.object([#("text", json.string("My favorite post"))])
270 |> json.to_string
271
272 let assert Ok(_) =
273 records.insert(
274 exec,
275 post_uri,
276 "cid_post1",
277 "did:plc:user123",
278 "app.bsky.feed.post",
279 post_json,
280 )
281
282 // A profile that pins the post (using strongRef)
283 let profile_uri = "at://did:plc:user123/app.bsky.actor.profile/self"
284 let profile_json =
285 json.object([
286 #("displayName", json.string("Alice")),
287 #(
288 "pinnedPost",
289 json.object([
290 #("uri", json.string(post_uri)),
291 #("cid", json.string("cid_post1")),
292 ]),
293 ),
294 ])
295 |> json.to_string
296
297 let assert Ok(_) =
298 records.insert(
299 exec,
300 profile_uri,
301 "cid_profile",
302 "did:plc:user123",
303 "app.bsky.actor.profile",
304 profile_json,
305 )
306
307 // Execute GraphQL query with forward join on strongRef
308 let query =
309 "
310 {
311 appBskyActorProfile {
312 edges {
313 node {
314 uri
315 pinnedPostResolved {
316 uri
317 }
318 }
319 }
320 }
321 }
322 "
323
324 let assert Ok(cache) = did_cache.start()
325 let assert Ok(response_json) =
326 lexicon_schema.execute_query_with_db(
327 exec,
328 query,
329 "{}",
330 Error(Nil),
331 cache,
332 option.None,
333 "",
334 "https://plc.directory",
335 )
336
337 // Verify the response contains resolved strongRef join with post URI
338 string.contains(response_json, profile_uri)
339 |> should.be_true
340
341 string.contains(response_json, post_uri)
342 |> should.be_true
343
344 string.contains(response_json, "pinnedPostResolved")
345 |> should.be_true
346}
347
348// Test: Reverse join discovers and resolves relationships
349pub fn reverse_join_resolves_test() {
350 // Setup database
351 let assert Ok(exec) = test_helpers.create_test_db()
352 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
353 let assert Ok(_) = test_helpers.create_record_table(exec)
354 let assert Ok(_) = test_helpers.create_actor_table(exec)
355
356 // Insert lexicons
357 let post_lexicon = create_post_lexicon()
358 let like_lexicon = create_like_lexicon()
359
360 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
361
362 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.like", like_lexicon)
363
364 // Insert test records
365 // A post
366 let post_uri = "at://did:plc:author789/app.bsky.feed.post/post1"
367 let post_json =
368 json.object([#("text", json.string("Great content!"))])
369 |> json.to_string
370
371 let assert Ok(_) =
372 records.insert(
373 exec,
374 post_uri,
375 "cid_post",
376 "did:plc:author789",
377 "app.bsky.feed.post",
378 post_json,
379 )
380
381 // Multiple likes that reference the post (to test batching)
382 let like1_uri = "at://did:plc:liker1/app.bsky.feed.like/like1"
383 let like1_json =
384 json.object([
385 #("subject", json.string(post_uri)),
386 #("createdAt", json.string("2024-01-01T12:00:00Z")),
387 ])
388 |> json.to_string
389
390 let assert Ok(_) =
391 records.insert(
392 exec,
393 like1_uri,
394 "cid_like1",
395 "did:plc:liker1",
396 "app.bsky.feed.like",
397 like1_json,
398 )
399
400 let like2_uri = "at://did:plc:liker2/app.bsky.feed.like/like2"
401 let like2_json =
402 json.object([
403 #("subject", json.string(post_uri)),
404 #("createdAt", json.string("2024-01-01T12:05:00Z")),
405 ])
406 |> json.to_string
407
408 let assert Ok(_) =
409 records.insert(
410 exec,
411 like2_uri,
412 "cid_like2",
413 "did:plc:liker2",
414 "app.bsky.feed.like",
415 like2_json,
416 )
417
418 // Execute GraphQL query with reverse join (now returns connection)
419 let query =
420 "
421 {
422 appBskyFeedPost {
423 edges {
424 node {
425 uri
426 appBskyFeedLikeViaSubject {
427 edges {
428 node {
429 uri
430 }
431 }
432 }
433 }
434 }
435 }
436 }
437 "
438
439 let assert Ok(cache) = did_cache.start()
440 let assert Ok(response_json) =
441 lexicon_schema.execute_query_with_db(
442 exec,
443 query,
444 "{}",
445 Error(Nil),
446 cache,
447 option.None,
448 "",
449 "https://plc.directory",
450 )
451
452 // Verify the response contains reverse join results
453 string.contains(response_json, post_uri)
454 |> should.be_true
455
456 string.contains(response_json, "appBskyFeedLikeViaSubject")
457 |> should.be_true
458
459 // Both likes should be in the response
460 string.contains(response_json, like1_uri)
461 |> should.be_true
462
463 string.contains(response_json, like2_uri)
464 |> should.be_true
465}
466
467// Test: DataLoader batches multiple forward joins efficiently
468pub fn dataloader_batches_forward_joins_test() {
469 // Setup database
470 let assert Ok(exec) = test_helpers.create_test_db()
471 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
472 let assert Ok(_) = test_helpers.create_record_table(exec)
473 let assert Ok(_) = test_helpers.create_actor_table(exec)
474
475 // Insert lexicons
476 let post_lexicon = create_post_lexicon()
477 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
478
479 // Insert multiple parent posts
480 let parent1_uri = "at://did:plc:user1/app.bsky.feed.post/parent1"
481 let parent1_json =
482 json.object([#("text", json.string("Parent post 1"))])
483 |> json.to_string
484
485 let assert Ok(_) =
486 records.insert(
487 exec,
488 parent1_uri,
489 "cid_p1",
490 "did:plc:user1",
491 "app.bsky.feed.post",
492 parent1_json,
493 )
494
495 let parent2_uri = "at://did:plc:user2/app.bsky.feed.post/parent2"
496 let parent2_json =
497 json.object([#("text", json.string("Parent post 2"))])
498 |> json.to_string
499
500 let assert Ok(_) =
501 records.insert(
502 exec,
503 parent2_uri,
504 "cid_p2",
505 "did:plc:user2",
506 "app.bsky.feed.post",
507 parent2_json,
508 )
509
510 // Insert multiple reply posts
511 let reply1_uri = "at://did:plc:user3/app.bsky.feed.post/reply1"
512 let reply1_json =
513 json.object([
514 #("text", json.string("Reply to post 1")),
515 #("replyTo", json.string(parent1_uri)),
516 ])
517 |> json.to_string
518
519 let assert Ok(_) =
520 records.insert(
521 exec,
522 reply1_uri,
523 "cid_r1",
524 "did:plc:user3",
525 "app.bsky.feed.post",
526 reply1_json,
527 )
528
529 let reply2_uri = "at://did:plc:user4/app.bsky.feed.post/reply2"
530 let reply2_json =
531 json.object([
532 #("text", json.string("Reply to post 2")),
533 #("replyTo", json.string(parent2_uri)),
534 ])
535 |> json.to_string
536
537 let assert Ok(_) =
538 records.insert(
539 exec,
540 reply2_uri,
541 "cid_r2",
542 "did:plc:user4",
543 "app.bsky.feed.post",
544 reply2_json,
545 )
546
547 // Execute GraphQL query that fetches multiple posts with joins
548 // DataLoader should batch the replyToResolved lookups
549 let query =
550 "
551 {
552 appBskyFeedPost {
553 edges {
554 node {
555 uri
556 replyToResolved {
557 uri
558 }
559 }
560 }
561 }
562 }
563 "
564
565 let assert Ok(cache) = did_cache.start()
566 let assert Ok(response_json) =
567 lexicon_schema.execute_query_with_db(
568 exec,
569 query,
570 "{}",
571 Error(Nil),
572 cache,
573 option.None,
574 "",
575 "https://plc.directory",
576 )
577
578 // Verify all posts appear
579 string.contains(response_json, reply1_uri)
580 |> should.be_true
581
582 string.contains(response_json, reply2_uri)
583 |> should.be_true
584
585 string.contains(response_json, parent1_uri)
586 |> should.be_true
587
588 string.contains(response_json, parent2_uri)
589 |> should.be_true
590 // Note: To truly verify batching, we'd need to instrument the database
591 // layer to count queries. For now, this test ensures correctness.
592}
593
594// Test: Reverse joins work with strongRef fields
595pub fn reverse_join_with_strong_ref_test() {
596 // Setup database
597 let assert Ok(exec) = test_helpers.create_test_db()
598 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
599 let assert Ok(_) = test_helpers.create_record_table(exec)
600 let assert Ok(_) = test_helpers.create_actor_table(exec)
601
602 // Insert lexicons
603 let post_lexicon = create_post_lexicon()
604 let profile_lexicon = create_profile_lexicon()
605 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
606 let assert Ok(_) =
607 lexicons.insert(exec, "app.bsky.actor.profile", profile_lexicon)
608
609 // Insert a post
610 let post_uri = "at://did:plc:creator/app.bsky.feed.post/amazing"
611 let post_json =
612 json.object([#("text", json.string("Amazing post"))])
613 |> json.to_string
614
615 let assert Ok(_) =
616 records.insert(
617 exec,
618 post_uri,
619 "cid_amazing",
620 "did:plc:creator",
621 "app.bsky.feed.post",
622 post_json,
623 )
624
625 // Multiple profiles pin this post (using strongRef)
626 let profile1_uri = "at://did:plc:user1/app.bsky.actor.profile/self"
627 let profile1_json =
628 json.object([
629 #("displayName", json.string("User One")),
630 #(
631 "pinnedPost",
632 json.object([
633 #("uri", json.string(post_uri)),
634 #("cid", json.string("cid_amazing")),
635 ]),
636 ),
637 ])
638 |> json.to_string
639
640 let assert Ok(_) =
641 records.insert(
642 exec,
643 profile1_uri,
644 "cid_prof1",
645 "did:plc:user1",
646 "app.bsky.actor.profile",
647 profile1_json,
648 )
649
650 let profile2_uri = "at://did:plc:user2/app.bsky.actor.profile/self"
651 let profile2_json =
652 json.object([
653 #("displayName", json.string("User Two")),
654 #(
655 "pinnedPost",
656 json.object([
657 #("uri", json.string(post_uri)),
658 #("cid", json.string("cid_amazing")),
659 ]),
660 ),
661 ])
662 |> json.to_string
663
664 let assert Ok(_) =
665 records.insert(
666 exec,
667 profile2_uri,
668 "cid_prof2",
669 "did:plc:user2",
670 "app.bsky.actor.profile",
671 profile2_json,
672 )
673
674 // Query post with reverse join to find all profiles that pinned it (now returns connection)
675 let query =
676 "
677 {
678 appBskyFeedPost {
679 edges {
680 node {
681 uri
682 appBskyActorProfileViaPinnedPost {
683 edges {
684 node {
685 uri
686 }
687 }
688 }
689 }
690 }
691 }
692 }
693 "
694
695 let assert Ok(cache) = did_cache.start()
696 let assert Ok(response_json) =
697 lexicon_schema.execute_query_with_db(
698 exec,
699 query,
700 "{}",
701 Error(Nil),
702 cache,
703 option.None,
704 "",
705 "https://plc.directory",
706 )
707
708 // Verify the reverse join through strongRef works
709 string.contains(response_json, post_uri)
710 |> should.be_true
711
712 string.contains(response_json, "appBskyActorProfileViaPinnedPost")
713 |> should.be_true
714
715 string.contains(response_json, profile1_uri)
716 |> should.be_true
717
718 string.contains(response_json, profile2_uri)
719 |> should.be_true
720}
721
722// Test: Forward join with union type and inline fragments
723pub fn forward_join_union_inline_fragments_test() {
724 // Setup database
725 let assert Ok(exec) = test_helpers.create_test_db()
726 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
727 let assert Ok(_) = test_helpers.create_record_table(exec)
728 let assert Ok(_) = test_helpers.create_actor_table(exec)
729
730 // Insert lexicons
731 let post_lexicon = create_post_lexicon()
732 let like_lexicon = create_like_lexicon()
733 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
734 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.like", like_lexicon)
735
736 // Insert a parent post
737 let parent_post_uri = "at://did:plc:parent/app.bsky.feed.post/parent1"
738 let parent_post_json =
739 json.object([#("text", json.string("This is the parent post"))])
740 |> json.to_string
741
742 let assert Ok(_) =
743 records.insert(
744 exec,
745 parent_post_uri,
746 "cid_parent_post",
747 "did:plc:parent",
748 "app.bsky.feed.post",
749 parent_post_json,
750 )
751
752 // Insert a like that will be referenced
753 let target_like_uri = "at://did:plc:liker/app.bsky.feed.like/like1"
754 let target_like_json =
755 json.object([
756 #("subject", json.string(parent_post_uri)),
757 #("createdAt", json.string("2024-01-01T12:00:00Z")),
758 ])
759 |> json.to_string
760
761 let assert Ok(_) =
762 records.insert(
763 exec,
764 target_like_uri,
765 "cid_like",
766 "did:plc:liker",
767 "app.bsky.feed.like",
768 target_like_json,
769 )
770
771 // Insert a reply post that references the parent (post)
772 let reply_to_post_uri = "at://did:plc:user1/app.bsky.feed.post/reply1"
773 let reply_to_post_json =
774 json.object([
775 #("text", json.string("Reply to a post")),
776 #("replyTo", json.string(parent_post_uri)),
777 ])
778 |> json.to_string
779
780 let assert Ok(_) =
781 records.insert(
782 exec,
783 reply_to_post_uri,
784 "cid_reply1",
785 "did:plc:user1",
786 "app.bsky.feed.post",
787 reply_to_post_json,
788 )
789
790 // Insert a reply post that references the like
791 let reply_to_like_uri = "at://did:plc:user2/app.bsky.feed.post/reply2"
792 let reply_to_like_json =
793 json.object([
794 #("text", json.string("Reply to a like")),
795 #("replyTo", json.string(target_like_uri)),
796 ])
797 |> json.to_string
798
799 let assert Ok(_) =
800 records.insert(
801 exec,
802 reply_to_like_uri,
803 "cid_reply2",
804 "did:plc:user2",
805 "app.bsky.feed.post",
806 reply_to_like_json,
807 )
808
809 // Execute GraphQL query with inline fragments to access type-specific fields
810 let query =
811 "
812 {
813 appBskyFeedPost {
814 edges {
815 node {
816 uri
817 text
818 replyToResolved {
819 ... on AppBskyFeedPost {
820 uri
821 text
822 }
823 ... on AppBskyFeedLike {
824 uri
825 subject
826 createdAt
827 }
828 }
829 }
830 }
831 }
832 }
833 "
834
835 let assert Ok(cache) = did_cache.start()
836 let assert Ok(response_json) =
837 lexicon_schema.execute_query_with_db(
838 exec,
839 query,
840 "{}",
841 Error(Nil),
842 cache,
843 option.None,
844 "",
845 "https://plc.directory",
846 )
847
848 // Verify we can access type-specific fields through inline fragments
849
850 // For the post reply, we should see the parent post's text
851 string.contains(response_json, reply_to_post_uri)
852 |> should.be_true
853
854 string.contains(response_json, "Reply to a post")
855 |> should.be_true
856
857 string.contains(response_json, "This is the parent post")
858 |> should.be_true
859
860 // For the like reply, we should see the like's subject and createdAt
861 string.contains(response_json, reply_to_like_uri)
862 |> should.be_true
863
864 string.contains(response_json, "Reply to a like")
865 |> should.be_true
866
867 string.contains(response_json, "2024-01-01T12:00:00Z")
868 |> should.be_true
869
870 // Verify the resolved records have the correct URIs
871 string.contains(response_json, parent_post_uri)
872 |> should.be_true
873
874 string.contains(response_json, target_like_uri)
875 |> should.be_true
876}
877
878// Helper to create a profile lexicon with literal:self key
879fn create_profile_lexicon_with_literal_self() -> String {
880 json.object([
881 #("lexicon", json.int(1)),
882 #("id", json.string("app.bsky.actor.profile")),
883 #(
884 "defs",
885 json.object([
886 #(
887 "main",
888 json.object([
889 #("type", json.string("record")),
890 #("key", json.string("literal:self")),
891 #(
892 "record",
893 json.object([
894 #("type", json.string("object")),
895 #(
896 "properties",
897 json.object([
898 #(
899 "displayName",
900 json.object([#("type", json.string("string"))]),
901 ),
902 #("bio", json.object([#("type", json.string("string"))])),
903 ]),
904 ),
905 ]),
906 ),
907 ]),
908 ),
909 ]),
910 ),
911 ])
912 |> json.to_string
913}
914
915// Test: DID join to literal:self collection returns single nullable object
916pub fn did_join_to_literal_self_returns_single_test() {
917 // Setup database
918 let assert Ok(exec) = test_helpers.create_test_db()
919 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
920 let assert Ok(_) = test_helpers.create_record_table(exec)
921 let assert Ok(_) = test_helpers.create_actor_table(exec)
922
923 // Insert lexicons
924 let post_lexicon = create_post_lexicon()
925 let profile_lexicon = create_profile_lexicon_with_literal_self()
926 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
927 let assert Ok(_) =
928 lexicons.insert(exec, "app.bsky.actor.profile", profile_lexicon)
929
930 // Insert a profile with literal:self key
931 let profile_uri = "at://did:plc:user123/app.bsky.actor.profile/self"
932 let profile_json =
933 json.object([
934 #("displayName", json.string("Alice")),
935 #("bio", json.string("Software engineer")),
936 ])
937 |> json.to_string
938
939 let assert Ok(_) =
940 records.insert(
941 exec,
942 profile_uri,
943 "cid_profile",
944 "did:plc:user123",
945 "app.bsky.actor.profile",
946 profile_json,
947 )
948
949 // Insert a post by the same DID
950 let post_uri = "at://did:plc:user123/app.bsky.feed.post/post1"
951 let post_json =
952 json.object([#("text", json.string("My first post"))])
953 |> json.to_string
954
955 let assert Ok(_) =
956 records.insert(
957 exec,
958 post_uri,
959 "cid_post1",
960 "did:plc:user123",
961 "app.bsky.feed.post",
962 post_json,
963 )
964
965 // Execute GraphQL query with DID join from post to profile
966 let query =
967 "
968 {
969 appBskyFeedPost {
970 edges {
971 node {
972 uri
973 text
974 appBskyActorProfileByDid {
975 uri
976 displayName
977 bio
978 }
979 }
980 }
981 }
982 }
983 "
984
985 let assert Ok(cache) = did_cache.start()
986 let assert Ok(response_json) =
987 lexicon_schema.execute_query_with_db(
988 exec,
989 query,
990 "{}",
991 Error(Nil),
992 cache,
993 option.None,
994 "",
995 "https://plc.directory",
996 )
997
998 // Verify the response contains the DID-joined profile as a single object (not array)
999 string.contains(response_json, post_uri)
1000 |> should.be_true
1001
1002 string.contains(response_json, "appBskyActorProfileByDid")
1003 |> should.be_true
1004
1005 string.contains(response_json, profile_uri)
1006 |> should.be_true
1007
1008 string.contains(response_json, "Alice")
1009 |> should.be_true
1010
1011 string.contains(response_json, "Software engineer")
1012 |> should.be_true
1013}
1014
1015// Test: DID join to non-literal:self collection returns list
1016pub fn did_join_to_non_literal_self_returns_list_test() {
1017 // Setup database
1018 let assert Ok(exec) = test_helpers.create_test_db()
1019 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
1020 let assert Ok(_) = test_helpers.create_record_table(exec)
1021 let assert Ok(_) = test_helpers.create_actor_table(exec)
1022
1023 // Insert lexicons
1024 let post_lexicon = create_post_lexicon()
1025 let profile_lexicon = create_profile_lexicon_with_literal_self()
1026 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
1027 let assert Ok(_) =
1028 lexicons.insert(exec, "app.bsky.actor.profile", profile_lexicon)
1029
1030 // Insert a profile
1031 let profile_uri = "at://did:plc:author/app.bsky.actor.profile/self"
1032 let profile_json =
1033 json.object([
1034 #("displayName", json.string("Bob")),
1035 #("bio", json.string("Writes a lot")),
1036 ])
1037 |> json.to_string
1038
1039 let assert Ok(_) =
1040 records.insert(
1041 exec,
1042 profile_uri,
1043 "cid_profile",
1044 "did:plc:author",
1045 "app.bsky.actor.profile",
1046 profile_json,
1047 )
1048
1049 // Insert multiple posts by the same DID
1050 let post1_uri = "at://did:plc:author/app.bsky.feed.post/post1"
1051 let post1_json =
1052 json.object([#("text", json.string("First post"))])
1053 |> json.to_string
1054
1055 let assert Ok(_) =
1056 records.insert(
1057 exec,
1058 post1_uri,
1059 "cid_post1",
1060 "did:plc:author",
1061 "app.bsky.feed.post",
1062 post1_json,
1063 )
1064
1065 let post2_uri = "at://did:plc:author/app.bsky.feed.post/post2"
1066 let post2_json =
1067 json.object([#("text", json.string("Second post"))])
1068 |> json.to_string
1069
1070 let assert Ok(_) =
1071 records.insert(
1072 exec,
1073 post2_uri,
1074 "cid_post2",
1075 "did:plc:author",
1076 "app.bsky.feed.post",
1077 post2_json,
1078 )
1079
1080 // Execute GraphQL query with DID join from profile to posts (now returns connection)
1081 let query =
1082 "
1083 {
1084 appBskyActorProfile {
1085 edges {
1086 node {
1087 uri
1088 displayName
1089 appBskyFeedPostByDid {
1090 edges {
1091 node {
1092 uri
1093 text
1094 }
1095 }
1096 }
1097 }
1098 }
1099 }
1100 }
1101 "
1102
1103 let assert Ok(cache) = did_cache.start()
1104 let assert Ok(response_json) =
1105 lexicon_schema.execute_query_with_db(
1106 exec,
1107 query,
1108 "{}",
1109 Error(Nil),
1110 cache,
1111 option.None,
1112 "",
1113 "https://plc.directory",
1114 )
1115
1116 // Verify the response contains the DID-joined posts as a list
1117 string.contains(response_json, profile_uri)
1118 |> should.be_true
1119
1120 string.contains(response_json, "appBskyFeedPostByDid")
1121 |> should.be_true
1122
1123 string.contains(response_json, post1_uri)
1124 |> should.be_true
1125
1126 string.contains(response_json, "First post")
1127 |> should.be_true
1128
1129 string.contains(response_json, post2_uri)
1130 |> should.be_true
1131
1132 string.contains(response_json, "Second post")
1133 |> should.be_true
1134}
1135
1136// Test: DID join batches queries efficiently for multiple records
1137pub fn did_join_batches_queries_test() {
1138 // Setup database
1139 let assert Ok(exec) = test_helpers.create_test_db()
1140 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
1141 let assert Ok(_) = test_helpers.create_record_table(exec)
1142 let assert Ok(_) = test_helpers.create_actor_table(exec)
1143
1144 // Insert lexicons
1145 let post_lexicon = create_post_lexicon()
1146 let profile_lexicon = create_profile_lexicon_with_literal_self()
1147 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
1148 let assert Ok(_) =
1149 lexicons.insert(exec, "app.bsky.actor.profile", profile_lexicon)
1150
1151 // Insert multiple profiles
1152 let profile1_uri = "at://did:plc:user1/app.bsky.actor.profile/self"
1153 let profile1_json =
1154 json.object([
1155 #("displayName", json.string("User One")),
1156 #("bio", json.string("First user")),
1157 ])
1158 |> json.to_string
1159
1160 let assert Ok(_) =
1161 records.insert(
1162 exec,
1163 profile1_uri,
1164 "cid_profile1",
1165 "did:plc:user1",
1166 "app.bsky.actor.profile",
1167 profile1_json,
1168 )
1169
1170 let profile2_uri = "at://did:plc:user2/app.bsky.actor.profile/self"
1171 let profile2_json =
1172 json.object([
1173 #("displayName", json.string("User Two")),
1174 #("bio", json.string("Second user")),
1175 ])
1176 |> json.to_string
1177
1178 let assert Ok(_) =
1179 records.insert(
1180 exec,
1181 profile2_uri,
1182 "cid_profile2",
1183 "did:plc:user2",
1184 "app.bsky.actor.profile",
1185 profile2_json,
1186 )
1187
1188 // Insert posts by different DIDs
1189 let post1_uri = "at://did:plc:user1/app.bsky.feed.post/post1"
1190 let post1_json =
1191 json.object([#("text", json.string("Post by user 1"))])
1192 |> json.to_string
1193
1194 let assert Ok(_) =
1195 records.insert(
1196 exec,
1197 post1_uri,
1198 "cid_post1",
1199 "did:plc:user1",
1200 "app.bsky.feed.post",
1201 post1_json,
1202 )
1203
1204 let post2_uri = "at://did:plc:user2/app.bsky.feed.post/post2"
1205 let post2_json =
1206 json.object([#("text", json.string("Post by user 2"))])
1207 |> json.to_string
1208
1209 let assert Ok(_) =
1210 records.insert(
1211 exec,
1212 post2_uri,
1213 "cid_post2",
1214 "did:plc:user2",
1215 "app.bsky.feed.post",
1216 post2_json,
1217 )
1218
1219 // Execute GraphQL query that fetches multiple posts with DID joins to profiles
1220 // DataLoader should batch the profile lookups by DID
1221 let query =
1222 "
1223 {
1224 appBskyFeedPost {
1225 edges {
1226 node {
1227 uri
1228 text
1229 appBskyActorProfileByDid {
1230 uri
1231 displayName
1232 }
1233 }
1234 }
1235 }
1236 }
1237 "
1238
1239 let assert Ok(cache) = did_cache.start()
1240 let assert Ok(response_json) =
1241 lexicon_schema.execute_query_with_db(
1242 exec,
1243 query,
1244 "{}",
1245 Error(Nil),
1246 cache,
1247 option.None,
1248 "",
1249 "https://plc.directory",
1250 )
1251
1252 // Verify all posts and their associated profiles appear
1253 string.contains(response_json, post1_uri)
1254 |> should.be_true
1255
1256 string.contains(response_json, "Post by user 1")
1257 |> should.be_true
1258
1259 string.contains(response_json, profile1_uri)
1260 |> should.be_true
1261
1262 string.contains(response_json, "User One")
1263 |> should.be_true
1264
1265 string.contains(response_json, post2_uri)
1266 |> should.be_true
1267
1268 string.contains(response_json, "Post by user 2")
1269 |> should.be_true
1270
1271 string.contains(response_json, profile2_uri)
1272 |> should.be_true
1273
1274 string.contains(response_json, "User Two")
1275 |> should.be_true
1276 // Note: To truly verify batching, we'd need to instrument the database
1277 // layer to count queries. For now, this test ensures correctness.
1278}
1279
1280// Helper to create a post lexicon with nested reply object containing strongRef fields
1281fn create_post_lexicon_with_nested_reply() -> String {
1282 json.object([
1283 #("lexicon", json.int(1)),
1284 #("id", json.string("app.bsky.feed.post")),
1285 #(
1286 "defs",
1287 json.object([
1288 #(
1289 "main",
1290 json.object([
1291 #("type", json.string("record")),
1292 #("key", json.string("tid")),
1293 #(
1294 "record",
1295 json.object([
1296 #("type", json.string("object")),
1297 #(
1298 "required",
1299 json.array([json.string("text")], of: fn(x) { x }),
1300 ),
1301 #(
1302 "properties",
1303 json.object([
1304 #(
1305 "text",
1306 json.object([
1307 #("type", json.string("string")),
1308 #("maxLength", json.int(300)),
1309 ]),
1310 ),
1311 #(
1312 "reply",
1313 json.object([
1314 #("type", json.string("ref")),
1315 #("ref", json.string("#replyRef")),
1316 ]),
1317 ),
1318 ]),
1319 ),
1320 ]),
1321 ),
1322 ]),
1323 ),
1324 #(
1325 "replyRef",
1326 json.object([
1327 #("type", json.string("object")),
1328 #(
1329 "required",
1330 json.array(
1331 [json.string("parent"), json.string("root")],
1332 of: fn(x) { x },
1333 ),
1334 ),
1335 #(
1336 "properties",
1337 json.object([
1338 #(
1339 "parent",
1340 json.object([
1341 #("type", json.string("ref")),
1342 #("ref", json.string("com.atproto.repo.strongRef")),
1343 ]),
1344 ),
1345 #(
1346 "root",
1347 json.object([
1348 #("type", json.string("ref")),
1349 #("ref", json.string("com.atproto.repo.strongRef")),
1350 ]),
1351 ),
1352 ]),
1353 ),
1354 ]),
1355 ),
1356 ]),
1357 ),
1358 ])
1359 |> json.to_string
1360}
1361
1362// Test: Nested forward join resolution through reply.parentResolved
1363pub fn nested_forward_join_resolves_reply_parent_test() {
1364 // Setup database
1365 let assert Ok(exec) = test_helpers.create_test_db()
1366 let assert Ok(_) = test_helpers.create_lexicon_table(exec)
1367 let assert Ok(_) = test_helpers.create_record_table(exec)
1368 let assert Ok(_) = test_helpers.create_actor_table(exec)
1369
1370 // Insert lexicon with nested reply object
1371 let post_lexicon = create_post_lexicon_with_nested_reply()
1372 let assert Ok(_) = lexicons.insert(exec, "app.bsky.feed.post", post_lexicon)
1373
1374 // Insert root post
1375 let root_uri = "at://did:plc:root123/app.bsky.feed.post/root1"
1376 let root_json =
1377 json.object([#("text", json.string("This is the root post"))])
1378 |> json.to_string
1379
1380 let assert Ok(_) =
1381 records.insert(
1382 exec,
1383 root_uri,
1384 "cid_root",
1385 "did:plc:root123",
1386 "app.bsky.feed.post",
1387 root_json,
1388 )
1389
1390 // Insert parent post (reply to root)
1391 let parent_uri = "at://did:plc:parent456/app.bsky.feed.post/parent1"
1392 let parent_json =
1393 json.object([
1394 #("text", json.string("This is a reply to the root")),
1395 #(
1396 "reply",
1397 json.object([
1398 #(
1399 "parent",
1400 json.object([
1401 #("uri", json.string(root_uri)),
1402 #("cid", json.string("cid_root")),
1403 ]),
1404 ),
1405 #(
1406 "root",
1407 json.object([
1408 #("uri", json.string(root_uri)),
1409 #("cid", json.string("cid_root")),
1410 ]),
1411 ),
1412 ]),
1413 ),
1414 ])
1415 |> json.to_string
1416
1417 let assert Ok(_) =
1418 records.insert(
1419 exec,
1420 parent_uri,
1421 "cid_parent",
1422 "did:plc:parent456",
1423 "app.bsky.feed.post",
1424 parent_json,
1425 )
1426
1427 // Insert reply post (reply to parent)
1428 let reply_uri = "at://did:plc:user789/app.bsky.feed.post/reply1"
1429 let reply_json =
1430 json.object([
1431 #("text", json.string("This is a reply to the parent")),
1432 #(
1433 "reply",
1434 json.object([
1435 #(
1436 "parent",
1437 json.object([
1438 #("uri", json.string(parent_uri)),
1439 #("cid", json.string("cid_parent")),
1440 ]),
1441 ),
1442 #(
1443 "root",
1444 json.object([
1445 #("uri", json.string(root_uri)),
1446 #("cid", json.string("cid_root")),
1447 ]),
1448 ),
1449 ]),
1450 ),
1451 ])
1452 |> json.to_string
1453
1454 let assert Ok(_) =
1455 records.insert(
1456 exec,
1457 reply_uri,
1458 "cid_reply",
1459 "did:plc:user789",
1460 "app.bsky.feed.post",
1461 reply_json,
1462 )
1463
1464 // Execute GraphQL query that uses nested forward join: reply.parentResolved
1465 let query =
1466 "
1467 {
1468 appBskyFeedPost {
1469 edges {
1470 node {
1471 uri
1472 text
1473 reply {
1474 parent {
1475 uri
1476 cid
1477 }
1478 parentResolved {
1479 ... on AppBskyFeedPost {
1480 uri
1481 text
1482 }
1483 }
1484 root {
1485 uri
1486 cid
1487 }
1488 rootResolved {
1489 ... on AppBskyFeedPost {
1490 uri
1491 text
1492 }
1493 }
1494 }
1495 }
1496 }
1497 }
1498 }
1499 "
1500
1501 let assert Ok(cache) = did_cache.start()
1502 let assert Ok(response_json) =
1503 lexicon_schema.execute_query_with_db(
1504 exec,
1505 query,
1506 "{}",
1507 Error(Nil),
1508 cache,
1509 option.None,
1510 "",
1511 "https://plc.directory",
1512 )
1513
1514 // Verify the nested forward joins work correctly
1515 // The reply post should have its parent resolved
1516 string.contains(response_json, reply_uri)
1517 |> should.be_true
1518
1519 string.contains(response_json, "This is a reply to the parent")
1520 |> should.be_true
1521
1522 // The parentResolved field should contain the parent post
1523 string.contains(response_json, "parentResolved")
1524 |> should.be_true
1525
1526 string.contains(response_json, parent_uri)
1527 |> should.be_true
1528
1529 string.contains(response_json, "This is a reply to the root")
1530 |> should.be_true
1531
1532 // The rootResolved field should contain the root post
1533 string.contains(response_json, "rootResolved")
1534 |> should.be_true
1535
1536 string.contains(response_json, root_uri)
1537 |> should.be_true
1538
1539 string.contains(response_json, "This is the root post")
1540 |> should.be_true
1541}