Monorepo for Tangled tangled.org

appview,lexicons: atprotate the mentions & references #761

merged opened by boltless.me targeting master from feat/mentions

Storing references parsed from the markdown body in atproto record and DB. There can be lots of reference types considering the from/to types so storing both as AT-URIs

Using sql.Tx more to combine multiple DB query to single recoverable operation.

Note: Pulls don't have mentinos/references yet

Signed-off-by: Seongmin Lee git@boltless.me

Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:xasnlahkri4ewmbuzly2rlc5/sh.tangled.repo.pull/3m4vklvknse22
+58 -39
Interdiff #0 #1
api/tangled/cbor_gen.go

This patch was likely rebased, as context lines do not match.

api/tangled/issuecomment.go

This file has not been changed.

api/tangled/pullcomment.go

This file has not been changed.

api/tangled/repoissue.go

This file has not been changed.

+4 -4
appview/db/db.go
··· 561 email_notifications integer not null default 0 562 ); 563 564 - create table if not exists references ( 565 id integer primary key autoincrement, 566 from_at text not null, 567 to_at text not null, 568 - unique (from, to) 569 ); 570 571 create table if not exists migrations ( ··· 578 create index if not exists idx_notifications_recipient_read on notifications(recipient_did, read); 579 create index if not exists idx_stars_created on stars(created); 580 create index if not exists idx_stars_repo_at_created on stars(repo_at, created); 581 - create index if not exists idx_references_from_at on references(from_at); 582 - create index if not exists idx_references_to_at on references(to_at); 583 `) 584 if err != nil { 585 return nil, err
··· 561 email_notifications integer not null default 0 562 ); 563 564 + create table if not exists reference_links ( 565 id integer primary key autoincrement, 566 from_at text not null, 567 to_at text not null, 568 + unique (from_at, to_at) 569 ); 570 571 create table if not exists migrations ( ··· 578 create index if not exists idx_notifications_recipient_read on notifications(recipient_did, read); 579 create index if not exists idx_stars_created on stars(created); 580 create index if not exists idx_stars_repo_at_created on stars(repo_at, created); 581 + create index if not exists idx_references_from_at on reference_links(from_at); 582 + create index if not exists idx_references_to_at on reference_links(to_at); 583 `) 584 if err != nil { 585 return nil, err
+9 -9
appview/db/issues.go
··· 76 } 77 78 if err := putReferences(tx, issue.AtUri(), issue.References); err != nil { 79 - return fmt.Errorf("put references: %w", err) 80 } 81 return nil 82 } ··· 93 } 94 95 if err := putReferences(tx, issue.AtUri(), issue.References); err != nil { 96 - return fmt.Errorf("put references: %w", err) 97 } 98 return nil 99 } ··· 253 // collect references for each issue 254 allReferencs, err := GetReferencesAll(e, FilterIn("from_at", issueAts)) 255 if err != nil { 256 - return nil, fmt.Errorf("failed to query references: %w", err) 257 } 258 for issueAt, references := range allReferencs { 259 if issue, ok := issueMap[issueAt.String()]; ok { ··· 385 return 0, err 386 } 387 388 - if err := putReferences(tx, c.AtUri(), c.References); err != nil { 389 - return 0, fmt.Errorf("put references: %w", err) 390 - } 391 - 392 id, err := result.LastInsertId() 393 if err != nil { 394 return 0, err 395 } 396 397 return id, nil 398 } 399 ··· 508 commentAts := slices.Collect(maps.Keys(commentMap)) 509 allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts)) 510 if err != nil { 511 - return nil, fmt.Errorf("failed to query references: %w", err) 512 } 513 for commentAt, references := range allReferencs { 514 if comment, ok := commentMap[commentAt.String()]; ok { ··· 542 uri := syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", did, tangled.RepoIssueNSID, rkey)) 543 err = deleteReferences(tx, uri) 544 if err != nil { 545 - return fmt.Errorf("delete references: %w", err) 546 } 547 548 return nil
··· 76 } 77 78 if err := putReferences(tx, issue.AtUri(), issue.References); err != nil { 79 + return fmt.Errorf("put reference_links: %w", err) 80 } 81 return nil 82 } ··· 93 } 94 95 if err := putReferences(tx, issue.AtUri(), issue.References); err != nil { 96 + return fmt.Errorf("put reference_links: %w", err) 97 } 98 return nil 99 } ··· 253 // collect references for each issue 254 allReferencs, err := GetReferencesAll(e, FilterIn("from_at", issueAts)) 255 if err != nil { 256 + return nil, fmt.Errorf("failed to query reference_links: %w", err) 257 } 258 for issueAt, references := range allReferencs { 259 if issue, ok := issueMap[issueAt.String()]; ok { ··· 385 return 0, err 386 } 387 388 id, err := result.LastInsertId() 389 if err != nil { 390 return 0, err 391 } 392 393 + if err := putReferences(tx, c.AtUri(), c.References); err != nil { 394 + return 0, fmt.Errorf("put reference_links: %w", err) 395 + } 396 + 397 return id, nil 398 } 399 ··· 508 commentAts := slices.Collect(maps.Keys(commentMap)) 509 allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts)) 510 if err != nil { 511 + return nil, fmt.Errorf("failed to query reference_links: %w", err) 512 } 513 for commentAt, references := range allReferencs { 514 if comment, ok := commentMap[commentAt.String()]; ok { ··· 542 uri := syntax.ATURI(fmt.Sprintf("at://%s/%s/%s", did, tangled.RepoIssueNSID, rkey)) 543 err = deleteReferences(tx, uri) 544 if err != nil { 545 + return fmt.Errorf("delete reference_links: %w", err) 546 } 547 548 return nil
+4 -4
appview/db/pulls.go
··· 432 submissionIds := slices.Collect(maps.Keys(submissionMap)) 433 comments, err := GetPullComments(e, FilterIn("submission_id", submissionIds)) 434 if err != nil { 435 - return nil, err 436 } 437 for _, comment := range comments { 438 if submission, ok := submissionMap[comment.SubmissionId]; ok { ··· 526 commentAts := slices.Collect(maps.Keys(commentMap)) 527 allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts)) 528 if err != nil { 529 - return nil, fmt.Errorf("failed to query references: %w", err) 530 } 531 for commentAt, references := range allReferencs { 532 if comment, ok := commentMap[commentAt.String()]; ok { ··· 540 } 541 542 sort.Slice(comments, func(i, j int) bool { 543 - return comments[i].Created.After(comments[j].Created) 544 }) 545 546 return comments, nil ··· 643 } 644 645 if err := putReferences(tx, comment.AtUri(), comment.References); err != nil { 646 - return 0, fmt.Errorf("put references: %w", err) 647 } 648 649 return i, nil
··· 432 submissionIds := slices.Collect(maps.Keys(submissionMap)) 433 comments, err := GetPullComments(e, FilterIn("submission_id", submissionIds)) 434 if err != nil { 435 + return nil, fmt.Errorf("failed to get pull comments: %w", err) 436 } 437 for _, comment := range comments { 438 if submission, ok := submissionMap[comment.SubmissionId]; ok { ··· 526 commentAts := slices.Collect(maps.Keys(commentMap)) 527 allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts)) 528 if err != nil { 529 + return nil, fmt.Errorf("failed to query reference_links: %w", err) 530 } 531 for commentAt, references := range allReferencs { 532 if comment, ok := commentMap[commentAt.String()]; ok { ··· 540 } 541 542 sort.Slice(comments, func(i, j int) bool { 543 + return comments[i].Created.Before(comments[j].Created) 544 }) 545 546 return comments, nil ··· 643 } 644 645 if err := putReferences(tx, comment.AtUri(), comment.References); err != nil { 646 + return 0, fmt.Errorf("put reference_links: %w", err) 647 } 648 649 return i, nil
+21 -20
appview/db/reference.go
··· 10 "tangled.org/core/appview/models" 11 ) 12 13 - // FindReferences resolves refLinks to Issue/PR/IssueComment/PullComment ATURIs. 14 // It will ignore missing refLinks. 15 - func FindReferences(e Execer, refLinks []models.ReferenceLink) ([]syntax.ATURI, error) { 16 var ( 17 issueRefs []models.ReferenceLink 18 pullRefs []models.ReferenceLink ··· 27 } 28 issueUris, err := findIssueReferences(e, issueRefs) 29 if err != nil { 30 - return nil, err 31 } 32 pullUris, err := findPullReferences(e, pullRefs) 33 if err != nil { 34 - return nil, err 35 } 36 37 return append(issueUris, pullUris...), nil ··· 124 ) 125 select 126 p.owner_did, p.rkey, 127 - c.owner_did, c.rkey 128 from input inp 129 join repos r 130 on r.did = inp.owner_did ··· 150 for rows.Next() { 151 // Scan rows 152 var pullOwner, pullRkey string 153 - var commentOwner, commentRkey sql.NullString 154 var uri syntax.ATURI 155 - if err := rows.Scan(&pullOwner, &pullRkey, &commentOwner, &commentRkey); err != nil { 156 return nil, err 157 } 158 - if commentOwner.Valid && commentRkey.Valid { 159 - uri = syntax.ATURI(fmt.Sprintf( 160 - "at://%s/%s/%s", 161 - commentOwner.String, 162 - tangled.RepoPullCommentNSID, 163 - commentRkey.String, 164 - )) 165 } else { 166 uri = syntax.ATURI(fmt.Sprintf( 167 "at://%s/%s/%s", ··· 176 } 177 178 func putReferences(tx *sql.Tx, fromAt syntax.ATURI, references []syntax.ATURI) error { 179 err := deleteReferences(tx, fromAt) 180 if err != nil { 181 - return fmt.Errorf("delete old references: %w", err) 182 } 183 184 values := make([]string, 0, len(references)) ··· 189 } 190 _, err = tx.Exec( 191 fmt.Sprintf( 192 - `insert into references (from, at) 193 values %s`, 194 strings.Join(values, ","), 195 ), 196 args..., 197 ) 198 if err != nil { 199 - return fmt.Errorf("insert new references: %w", err) 200 } 201 return nil 202 } 203 204 func deleteReferences(tx *sql.Tx, fromAt syntax.ATURI) error { 205 - _, err := tx.Exec(`delete from references where from_at = ?`, fromAt) 206 return err 207 } 208 ··· 223 224 rows, err := e.Query( 225 fmt.Sprintf( 226 - `select from_at, to_at from references %s`, 227 whereClause, 228 ), 229 ) 230 if err != nil { 231 - return nil, fmt.Errorf("query references: %w", err) 232 } 233 defer rows.Close() 234
··· 10 "tangled.org/core/appview/models" 11 ) 12 13 + // ValidateReferenceLinks resolves refLinks to Issue/PR/IssueComment/PullComment ATURIs. 14 // It will ignore missing refLinks. 15 + func ValidateReferenceLinks(e Execer, refLinks []models.ReferenceLink) ([]syntax.ATURI, error) { 16 var ( 17 issueRefs []models.ReferenceLink 18 pullRefs []models.ReferenceLink ··· 27 } 28 issueUris, err := findIssueReferences(e, issueRefs) 29 if err != nil { 30 + return nil, fmt.Errorf("find issue references: %w", err) 31 } 32 pullUris, err := findPullReferences(e, pullRefs) 33 if err != nil { 34 + return nil, fmt.Errorf("find pull references: %w", err) 35 } 36 37 return append(issueUris, pullUris...), nil ··· 124 ) 125 select 126 p.owner_did, p.rkey, 127 + c.comment_at 128 from input inp 129 join repos r 130 on r.did = inp.owner_did ··· 150 for rows.Next() { 151 // Scan rows 152 var pullOwner, pullRkey string 153 + var commentUri sql.NullString 154 var uri syntax.ATURI 155 + if err := rows.Scan(&pullOwner, &pullRkey, &commentUri); err != nil { 156 return nil, err 157 } 158 + if commentUri.Valid { 159 + // no-op 160 + uri = syntax.ATURI(commentUri.String) 161 } else { 162 uri = syntax.ATURI(fmt.Sprintf( 163 "at://%s/%s/%s", ··· 172 } 173 174 func putReferences(tx *sql.Tx, fromAt syntax.ATURI, references []syntax.ATURI) error { 175 + fmt.Println("insering references", references) 176 err := deleteReferences(tx, fromAt) 177 if err != nil { 178 + return fmt.Errorf("delete old reference_links: %w", err) 179 + } 180 + if len(references) == 0 { 181 + return nil 182 } 183 184 values := make([]string, 0, len(references)) ··· 189 } 190 _, err = tx.Exec( 191 fmt.Sprintf( 192 + `insert into reference_links (from_at, to_at) 193 values %s`, 194 strings.Join(values, ","), 195 ), 196 args..., 197 ) 198 if err != nil { 199 + return fmt.Errorf("insert new reference_links: %w", err) 200 } 201 return nil 202 } 203 204 func deleteReferences(tx *sql.Tx, fromAt syntax.ATURI) error { 205 + _, err := tx.Exec(`delete from reference_links where from_at = ?`, fromAt) 206 return err 207 } 208 ··· 223 224 rows, err := e.Query( 225 fmt.Sprintf( 226 + `select from_at, to_at from reference_links %s`, 227 whereClause, 228 ), 229 + args..., 230 ) 231 if err != nil { 232 + return nil, fmt.Errorf("query reference_links: %w", err) 233 } 234 defer rows.Close() 235
appview/ingester.go

This file has not been changed.

+6
appview/issues/issues.go
··· 472 rp.pages.Notice(w, "issue-comment", "Failed to create comment.") 473 return 474 } 475 476 // reset atUri to make rollback a no-op 477 atUri = ""
··· 472 rp.pages.Notice(w, "issue-comment", "Failed to create comment.") 473 return 474 } 475 + err = tx.Commit() 476 + if err != nil { 477 + l.Error("failed to commit transaction", "err", err) 478 + rp.pages.Notice(w, "issue-comment", "Failed to create comment, try again later.") 479 + return 480 + } 481 482 // reset atUri to make rollback a no-op 483 atUri = ""
+12
appview/models/issue.go
··· 229 return nil, err 230 } 231 232 comment := IssueComment{ 233 Did: ownerDid, 234 Rkey: rkey, ··· 236 IssueAt: record.Issue, 237 ReplyTo: record.ReplyTo, 238 Created: created, 239 } 240 241 return &comment, nil
··· 229 return nil, err 230 } 231 232 + i := record 233 + mentions := make([]syntax.DID, len(record.Mentions)) 234 + for i, did := range record.Mentions { 235 + mentions[i] = syntax.DID(did) 236 + } 237 + references := make([]syntax.ATURI, len(record.References)) 238 + for i, uri := range i.References { 239 + references[i] = syntax.ATURI(uri) 240 + } 241 + 242 comment := IssueComment{ 243 Did: ownerDid, 244 Rkey: rkey, ··· 246 IssueAt: record.Issue, 247 ReplyTo: record.ReplyTo, 248 Created: created, 249 + Mentions: mentions, 250 + References: references, 251 } 252 253 return &comment, nil
appview/models/pull.go

This file has not been changed.

appview/pulls/pulls.go

This file has not been changed.

lexicons/issue/comment.json

This file has not been changed.

lexicons/issue/issue.json

This file has not been changed.

lexicons/pulls/comment.json

This file has not been changed.

+2 -2
appview/refresolver/resolver.go
··· 34 } 35 36 func (r *Resolver) Resolve(ctx context.Context, source string) ([]syntax.DID, []syntax.ATURI) { 37 - l := r.logger.With("method", "find_references") 38 rawMentions, rawRefs := markup.FindReferences(r.config.Core.AppviewHost, source) 39 l.Debug("found possible references", "mentions", rawMentions, "refs", rawRefs) 40 idents := r.idResolver.ResolveIdents(ctx, rawMentions) ··· 55 rawRef.Handle = string(ident.DID) 56 resolvedRefs = append(resolvedRefs, rawRef) 57 } 58 - aturiRefs, err := db.FindReferences(r.execer, resolvedRefs) 59 if err != nil { 60 l.Error("failed running query", "err", err) 61 }
··· 34 } 35 36 func (r *Resolver) Resolve(ctx context.Context, source string) ([]syntax.DID, []syntax.ATURI) { 37 + l := r.logger.With("method", "Resolve") 38 rawMentions, rawRefs := markup.FindReferences(r.config.Core.AppviewHost, source) 39 l.Debug("found possible references", "mentions", rawMentions, "refs", rawRefs) 40 idents := r.idResolver.ResolveIdents(ctx, rawMentions) ··· 55 rawRef.Handle = string(ident.DID) 56 resolvedRefs = append(resolvedRefs, rawRef) 57 } 58 + aturiRefs, err := db.ValidateReferenceLinks(r.execer, resolvedRefs) 59 if err != nil { 60 l.Error("failed running query", "err", err) 61 }

History

13 rounds 0 comments
sign up or login to add to the discussion
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 failed
expand
expand 0 comments
pull request successfully merged
1 commit
expand
appview,lexicons: atprotate the mentions & references
1/3 failed, 2/3 running
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 failed
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
1/3 failed, 2/3 timeout
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
1/3 failed, 2/3 timeout
expand
expand 0 comments
1 commit
expand
appview,lexicons: atprotate the mentions & references
3/3 success
expand
expand 0 comments