Monorepo for Tangled tangled.org
5

Configure Feed

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

1package db 2 3import ( 4 "database/sql" 5 "errors" 6 "testing" 7) 8 9func seedProfile(t *testing.T, d *DB, did string) { 10 t.Helper() 11 if _, err := d.Exec( 12 `insert into profile (did, description, include_bluesky, location, preferred_handle) 13 values (?, ?, ?, ?, ?)`, 14 did, "hi", 0, "", "boltless.bsky.social", 15 ); err != nil { 16 t.Fatalf("seed profile: %v", err) 17 } 18 if _, err := d.Exec( 19 `insert into profile_links (did, link) values (?, ?)`, 20 did, "https://boltless.example/blog", 21 ); err != nil { 22 t.Fatalf("seed profile_links: %v", err) 23 } 24 if _, err := d.Exec( 25 `insert into profile_stats (did, kind) values (?, ?)`, 26 did, "open-pull-request-count", 27 ); err != nil { 28 t.Fatalf("seed profile_stats: %v", err) 29 } 30 if _, err := d.Exec( 31 `insert into profile_pinned_repositories (did, pin) values (?, ?)`, 32 did, "did:plc:limpet", 33 ); err != nil { 34 t.Fatalf("seed profile_pinned_repositories: %v", err) 35 } 36} 37 38func countRows(t *testing.T, d *DB, query string, args ...any) int { 39 t.Helper() 40 var n int 41 if err := d.QueryRow(query, args...).Scan(&n); err != nil { 42 t.Fatalf("count: %v", err) 43 } 44 return n 45} 46 47func TestDeleteProfile_CascadesAllChildTables(t *testing.T) { 48 d := newTestDB(t) 49 const did = "did:plc:boltless" 50 seedProfile(t, d, did) 51 52 if got := countRows(t, d, `select count(*) from profile where did = ?`, did); got != 1 { 53 t.Fatalf("pre: profile rows = %d, want 1", got) 54 } 55 if got := countRows(t, d, `select count(*) from profile_links where did = ?`, did); got != 1 { 56 t.Fatalf("pre: profile_links rows = %d, want 1", got) 57 } 58 if got := countRows(t, d, `select count(*) from profile_stats where did = ?`, did); got != 1 { 59 t.Fatalf("pre: profile_stats rows = %d, want 1", got) 60 } 61 if got := countRows(t, d, `select count(*) from profile_pinned_repositories where did = ?`, did); got != 1 { 62 t.Fatalf("pre: profile_pinned_repositories rows = %d, want 1", got) 63 } 64 65 tx, err := d.Begin() 66 if err != nil { 67 t.Fatalf("Begin: %v", err) 68 } 69 if err := DeleteProfile(tx, did); err != nil { 70 t.Fatalf("DeleteProfile: %v", err) 71 } 72 73 if got := countRows(t, d, `select count(*) from profile where did = ?`, did); got != 0 { 74 t.Errorf("post: profile rows = %d, want 0", got) 75 } 76 if got := countRows(t, d, `select count(*) from profile_links where did = ?`, did); got != 0 { 77 t.Errorf("post: profile_links rows = %d, want 0 (cascade)", got) 78 } 79 if got := countRows(t, d, `select count(*) from profile_stats where did = ?`, did); got != 0 { 80 t.Errorf("post: profile_stats rows = %d, want 0 (cascade)", got) 81 } 82 if got := countRows(t, d, `select count(*) from profile_pinned_repositories where did = ?`, did); got != 0 { 83 t.Errorf("post: profile_pinned_repositories rows = %d, want 0 (cascade)", got) 84 } 85} 86 87func TestDeleteProfile_NoRowsIsNoop(t *testing.T) { 88 d := newTestDB(t) 89 90 tx, err := d.Begin() 91 if err != nil { 92 t.Fatalf("Begin: %v", err) 93 } 94 if err := DeleteProfile(tx, "did:plc:akshay"); err != nil { 95 t.Errorf("DeleteProfile on missing did: %v, want nil", err) 96 } 97} 98 99func TestDeleteProfile_LeavesOtherDidsAlone(t *testing.T) { 100 d := newTestDB(t) 101 seedProfile(t, d, "did:plc:boltless") 102 seedProfile(t, d, "did:plc:akshay") 103 104 tx, err := d.Begin() 105 if err != nil { 106 t.Fatalf("Begin: %v", err) 107 } 108 if err := DeleteProfile(tx, "did:plc:boltless"); err != nil { 109 t.Fatalf("DeleteProfile: %v", err) 110 } 111 112 if got := countRows(t, d, `select count(*) from profile where did = ?`, "did:plc:akshay"); got != 1 { 113 t.Errorf("other profile should survive: rows = %d, want 1", got) 114 } 115 if got := countRows(t, d, `select count(*) from profile_links where did = ?`, "did:plc:akshay"); got != 1 { 116 t.Errorf("other profile_links should survive: rows = %d, want 1", got) 117 } 118 if got := countRows(t, d, `select count(*) from profile_stats where did = ?`, "did:plc:akshay"); got != 1 { 119 t.Errorf("other profile_stats should survive: rows = %d, want 1", got) 120 } 121 if got := countRows(t, d, `select count(*) from profile_pinned_repositories where did = ?`, "did:plc:akshay"); got != 1 { 122 t.Errorf("other profile_pinned_repositories should survive: rows = %d, want 1", got) 123 } 124} 125 126func TestGetPreferredHandle_AfterDeleteReturnsNoRows(t *testing.T) { 127 d := newTestDB(t) 128 const did = "did:plc:boltless" 129 seedProfile(t, d, did) 130 131 h, err := GetPreferredHandle(d, did) 132 if err != nil { 133 t.Fatalf("GetPreferredHandle pre-delete: %v", err) 134 } 135 if string(h) != "boltless.bsky.social" { 136 t.Fatalf("handle = %q, want %q", h, "boltless.bsky.social") 137 } 138 139 tx, err := d.Begin() 140 if err != nil { 141 t.Fatalf("Begin: %v", err) 142 } 143 if err := DeleteProfile(tx, did); err != nil { 144 t.Fatalf("DeleteProfile: %v", err) 145 } 146 147 _, err = GetPreferredHandle(d, did) 148 if !errors.Is(err, sql.ErrNoRows) { 149 t.Errorf("GetPreferredHandle post-delete: err = %v, want sql.ErrNoRows", err) 150 } 151}