appview: create search endpoint (wip) #10

open
opened by boltless.me targeting master from feat/search
Changed files
+99 -9
appview
db
indexer
issues
issues
+78 -7
appview/db/issues.go
··· 2 2 3 3 import ( 4 4 "database/sql" 5 + "fmt" 6 + "strconv" 7 + "strings" 5 8 "time" 6 9 7 10 "github.com/bluesky-social/indigo/atproto/syntax" ··· 104 107 return ownerDid, err 105 108 } 106 109 107 - func GetIssues(e Execer, repoAt syntax.ATURI, isOpen bool, page pagination.Page) ([]Issue, error) { 110 + func GetIssues(e Execer, repoAt syntax.ATURI, page pagination.Page) ([]Issue, error) { 108 111 var issues []Issue 109 - openValue := 0 110 - if isOpen { 111 - openValue = 1 112 - } 113 112 114 113 rows, err := e.Query( 115 114 ` ··· 129 128 left join 130 129 comments c on i.repo_at = c.repo_at and i.issue_id = c.issue_id 131 130 where 132 - i.repo_at = ? and i.open = ? 131 + i.repo_at = ? 133 132 group by 134 133 i.id, i.owner_did, i.issue_id, i.created, i.title, i.body, i.open 135 134 ) ··· 146 145 numbered_issue 147 146 where 148 147 row_num between ? and ?`, 149 - repoAt, openValue, page.Offset+1, page.Offset+page.Limit) 148 + repoAt, page.Offset+1, page.Offset+page.Limit) 150 149 if err != nil { 151 150 return nil, err 152 151 } ··· 178 177 return issues, nil 179 178 } 180 179 180 + func GetIssuesByIDs(e Execer, ids []int64) ([]Issue, error) { 181 + var issues []Issue 182 + 183 + // HACK: would be better to create "?,?,?,..." or use something like sqlx 184 + idStrings := make([]string, len(ids)) 185 + for i, id := range ids { 186 + idStrings[i] = strconv.FormatInt(id, 10) 187 + } 188 + idList := strings.Join(idStrings, ",") 189 + query := fmt.Sprintf( 190 + ` 191 + select 192 + i.id, 193 + i.owner_did, 194 + i.issue_id, 195 + i.created, 196 + i.title, 197 + i.body, 198 + i.open, 199 + count(c.id) as comment_count 200 + from 201 + issues i 202 + left join 203 + comments c on i.repo_at = c.repo_at and i.issue_id = c.issue_id 204 + where 205 + i.id in (%s) 206 + group by 207 + i.id 208 + order by i.created desc`, 209 + idList, 210 + ) 211 + rows, err := e.Query(query) 212 + if err != nil { 213 + return nil, err 214 + } 215 + defer rows.Close() 216 + 217 + for rows.Next() { 218 + var issue Issue 219 + var createdAt string 220 + var metadata IssueMetadata 221 + err := rows.Scan( 222 + &issue.ID, 223 + &issue.OwnerDid, 224 + &issue.IssueId, 225 + &createdAt, 226 + &issue.Title, 227 + &issue.Body, 228 + &issue.Open, 229 + &metadata.CommentCount, 230 + ) 231 + if err != nil { 232 + return nil, err 233 + } 234 + 235 + createdTime, err := time.Parse(time.RFC3339, createdAt) 236 + if err != nil { 237 + return nil, err 238 + } 239 + issue.Created = createdTime 240 + issue.Metadata = &metadata 241 + 242 + issues = append(issues, issue) 243 + } 244 + 245 + if err := rows.Err(); err != nil { 246 + return nil, err 247 + } 248 + 249 + return issues, nil 250 + } 251 + 181 252 // timeframe here is directly passed into the sql query filter, and any 182 253 // timeframe in the past should be negative; e.g.: "-3 months" 183 254 func GetIssuesByOwnerDid(e Execer, ownerDid string, timeframe string) ([]Issue, error) {
+1 -1
appview/indexer/issues/indexer.go
··· 87 87 } 88 88 for _, repo := range repos { 89 89 page := pagination.FirstPage() 90 - issues, err := db.GetIssues(e, repo.RepoAt(), true, page) 90 + issues, err := db.GetIssues(e, repo.RepoAt(), page) 91 91 if err != nil { 92 92 return err 93 93 }
+20 -1
appview/issues/issues.go
··· 620 620 isOpen = true 621 621 } 622 622 623 + keyword := params.Get("q") 624 + 625 + res, err := rp.indexer.Search(r.Context(), issues_indexer.SearchOptions{ 626 + Keyword: keyword, 627 + IsOpen: &isOpen, 628 + Page: pagination.FirstPage(), 629 + }) 630 + if err != nil { 631 + log.Println("failed to search for issues", err) 632 + return 633 + } 634 + log.Println("searched issues:", res.Hits) 635 + 623 636 page, ok := r.Context().Value("page").(pagination.Page) 624 637 if !ok { 625 638 log.Println("failed to get page") ··· 633 646 return 634 647 } 635 648 636 - issues, err := db.GetIssues(rp.db, f.RepoAt, isOpen, page) 649 + // issues, err := db.GetIssues(rp.db, f.RepoAt, isOpen, page) 650 + // if err != nil { 651 + // log.Println("failed to get issues", err) 652 + // rp.pages.Notice(w, "issues", "Failed to load issues. Try again later.") 653 + // return 654 + // } 655 + issues, err := db.GetIssuesByIDs(rp.db, res.Hits) 637 656 if err != nil { 638 657 log.Println("failed to get issues", err) 639 658 rp.pages.Notice(w, "issues", "Failed to load issues. Try again later.")