Monorepo for Tangled tangled.org

appview: add basic issue indexer (wip) #494

merged opened by boltless.me targeting master from boltless.me/core: feat/search
  • Heavily inspired by gitea
  • add GetAllIssues which only receives a paginator and gathers all issues ignoring repoAt field

Signed-off-by: Seongmin Lee boltlessengineer@proton.me

Labels

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:xasnlahkri4ewmbuzly2rlc5/sh.tangled.repo.pull/3lwecnvoz4z22
+504 -1
Diff #2
+1
.gitignore
··· 15 15 .env 16 16 *.rdb 17 17 .envrc 18 + *.bleve 18 19 # Created if following hacking.md 19 20 genjwks.out 20 21 /nix/vm-data
+56
appview/db/issues.go
··· 104 104 return ownerDid, err 105 105 } 106 106 107 + func GetAllIssues(e Execer, page pagination.Page) ([]Issue, error) { 108 + var issues []Issue 109 + rows, err := e.Query( 110 + ` 111 + select 112 + i.id, 113 + i.owner_did, 114 + i.repo_at, 115 + i.issue_id, 116 + i.created, 117 + i.title, 118 + i.body, 119 + i.open, 120 + count(c.id) as comment_count 121 + from 122 + issues i 123 + left join 124 + comments c on i.repo_at = c.repo_at and i.issue_id = c.issue_id 125 + group by 126 + i.id 127 + order by i.created desc 128 + limit ? offset ?`, 129 + page.Limit, 130 + page.Offset, 131 + ) 132 + if err != nil { 133 + return nil, err 134 + } 135 + defer rows.Close() 136 + 137 + for rows.Next() { 138 + var issue Issue 139 + var createdAt string 140 + var metadata IssueMetadata 141 + err := rows.Scan(&issue.ID, &issue.OwnerDid, &issue.RepoAt, &issue.IssueId, &createdAt, &issue.Title, &issue.Body, &issue.Open, &metadata.CommentCount) 142 + if err != nil { 143 + return nil, err 144 + } 145 + 146 + createdTime, err := time.Parse(time.RFC3339, createdAt) 147 + if err != nil { 148 + return nil, err 149 + } 150 + issue.Created = createdTime 151 + issue.Metadata = &metadata 152 + 153 + issues = append(issues, issue) 154 + } 155 + 156 + if err := rows.Err(); err != nil { 157 + return nil, err 158 + } 159 + 160 + return issues, nil 161 + } 162 + 107 163 func GetIssues(e Execer, repoAt syntax.ATURI, isOpen bool, page pagination.Page) ([]Issue, error) { 108 164 var issues []Issue 109 165 openValue := 0
+20
appview/indexer/base36/base36.go
··· 1 + // mostly copied from gitea/modules/indexer/internal/base32 2 + 3 + package base36 4 + 5 + import ( 6 + "fmt" 7 + "strconv" 8 + ) 9 + 10 + func Encode(i int64) string { 11 + return strconv.FormatInt(i, 36) 12 + } 13 + 14 + func Decode(s string) (int64, error) { 15 + i, err := strconv.ParseInt(s, 36, 64) 16 + if err != nil { 17 + return 0, fmt.Errorf("invalid base36 integer %q: %w", s, err) 18 + } 19 + return i, nil 20 + }
+58
appview/indexer/bleve/batch.go
··· 1 + // Copyright 2021 The Gitea Authors. All rights reserved. 2 + // SPDX-License-Identifier: MIT 3 + 4 + package bleveutil 5 + 6 + import ( 7 + "github.com/blevesearch/bleve/v2" 8 + ) 9 + 10 + // FlushingBatch is a batch of operations that automatically flushes to the 11 + // underlying index once it reaches a certain size. 12 + type FlushingBatch struct { 13 + maxBatchSize int 14 + batch *bleve.Batch 15 + index bleve.Index 16 + } 17 + 18 + // NewFlushingBatch creates a new flushing batch for the specified index. Once 19 + // the number of operations in the batch reaches the specified limit, the batch 20 + // automatically flushes its operations to the index. 21 + func NewFlushingBatch(index bleve.Index, maxBatchSize int) *FlushingBatch { 22 + return &FlushingBatch{ 23 + maxBatchSize: maxBatchSize, 24 + batch: index.NewBatch(), 25 + index: index, 26 + } 27 + } 28 + 29 + // Index add a new index to batch 30 + func (b *FlushingBatch) Index(id string, data any) error { 31 + if err := b.batch.Index(id, data); err != nil { 32 + return err 33 + } 34 + return b.flushIfFull() 35 + } 36 + 37 + // Delete add a delete index to batch 38 + func (b *FlushingBatch) Delete(id string) error { 39 + b.batch.Delete(id) 40 + return b.flushIfFull() 41 + } 42 + 43 + func (b *FlushingBatch) flushIfFull() error { 44 + if b.batch.Size() < b.maxBatchSize { 45 + return nil 46 + } 47 + return b.Flush() 48 + } 49 + 50 + // Flush submit the batch and create a new one 51 + func (b *FlushingBatch) Flush() error { 52 + err := b.index.Batch(b.batch) 53 + if err != nil { 54 + return err 55 + } 56 + b.batch = b.index.NewBatch() 57 + return nil 58 + }
+27
appview/indexer/indexer.go
··· 1 + package indexer 2 + 3 + import ( 4 + "context" 5 + 6 + "tangled.sh/tangled.sh/core/appview/db" 7 + issues_indexer "tangled.sh/tangled.sh/core/appview/indexer/issues" 8 + "tangled.sh/tangled.sh/core/appview/notify" 9 + ) 10 + 11 + type Indexer struct { 12 + Issues *issues_indexer.Indexer 13 + notify.BaseNotifier 14 + } 15 + 16 + func New() *Indexer { 17 + return &Indexer { 18 + issues_indexer.NewIndexer("indexes.bleve"), 19 + notify.BaseNotifier{}, 20 + } 21 + } 22 + 23 + // Init initializes all indexers 24 + func (ix *Indexer) Init(ctx context.Context, db *db.DB) error { 25 + ix.Issues.Init(ctx, db) 26 + return nil 27 + }
+192
appview/indexer/issues/indexer.go
··· 1 + package issues_indexer 2 + 3 + import ( 4 + "context" 5 + "errors" 6 + "log" 7 + "os" 8 + 9 + "github.com/blevesearch/bleve/v2" 10 + "github.com/blevesearch/bleve/v2/index/upsidedown" 11 + "github.com/blevesearch/bleve/v2/search/query" 12 + "tangled.sh/tangled.sh/core/appview/db" 13 + "tangled.sh/tangled.sh/core/appview/indexer/base36" 14 + "tangled.sh/tangled.sh/core/appview/indexer/bleve" 15 + "tangled.sh/tangled.sh/core/appview/models" 16 + "tangled.sh/tangled.sh/core/appview/pagination" 17 + ) 18 + 19 + type Indexer struct { 20 + indexer bleve.Index 21 + path string 22 + } 23 + 24 + func NewIndexer(indexDir string) *Indexer { 25 + return &Indexer{ 26 + path: indexDir, 27 + } 28 + } 29 + 30 + // Init initializes the indexer 31 + func (ix *Indexer) Init(ctx context.Context, e db.Execer) { 32 + existed, err := ix.intialize(ctx) 33 + if err != nil { 34 + log.Fatalf("failed to initialize issue indexer: %v", err) 35 + } 36 + if !existed { 37 + log.Println("Populating the issue indexer") 38 + err := PopulateIndexer(ctx, ix, e) 39 + if err != nil { 40 + log.Fatalf("failed to populate issue indexer: %v", err) 41 + } 42 + } 43 + log.Println("Initialized the issue indexer") 44 + } 45 + 46 + func (ix *Indexer) intialize(_ context.Context) (bool, error) { 47 + if ix.indexer != nil { 48 + return false, errors.New("indexer is already initialized") 49 + } 50 + 51 + indexer, err := openIndexer(ix.path) 52 + if err != nil { 53 + return false, nil 54 + } 55 + if indexer != nil { 56 + ix.indexer = indexer 57 + return true, nil 58 + } 59 + 60 + mapping := bleve.NewIndexMapping() 61 + indexer, err = bleve.New(ix.path, mapping) 62 + if err != nil { 63 + return false, err 64 + } 65 + 66 + ix.indexer = indexer 67 + 68 + return false, nil 69 + } 70 + 71 + func openIndexer(path string) (bleve.Index, error) { 72 + _, err := os.Stat(path) 73 + indexer, err := bleve.Open(path) 74 + if err != nil { 75 + if errors.Is(err, upsidedown.IncompatibleVersion) { 76 + log.Println("Indexer was built with a previous version of bleve, deleting and rebuilding") 77 + return nil, os.RemoveAll(path) 78 + } 79 + return nil, nil 80 + } 81 + return indexer, nil 82 + } 83 + 84 + func PopulateIndexer(ctx context.Context, ix *Indexer, e db.Execer) error { 85 + page := pagination.FirstPage() 86 + for { 87 + issues, err := db.GetAllIssues(e, page) 88 + if err != nil { 89 + return err 90 + } 91 + var dataList []*IssueData 92 + for _, issue := range issues { 93 + issue, _, err := db.GetIssueWithComments(e, issue.RepoAt, issue.IssueId) 94 + if err != nil { 95 + return err 96 + } 97 + dataList = append(dataList, &IssueData{ 98 + ID: issue.ID, 99 + IssueID: issue.IssueId, 100 + Title: issue.Title, 101 + Body: issue.Body, 102 + IsOpen: issue.Open, 103 + }) 104 + } 105 + err = ix.Index(ctx, dataList...) 106 + if err != nil { 107 + return err 108 + } 109 + if len(issues) < page.Limit { 110 + break 111 + } 112 + page = page.Next() 113 + } 114 + return nil 115 + } 116 + 117 + // IssueData data stored and will be indexed 118 + type IssueData struct { 119 + ID int64 `json:"id"` 120 + IssueID int `json:"issue_id"` 121 + Title string `json:"title"` 122 + Body string `json:"body"` 123 + 124 + IsOpen bool `json:"is_open"` 125 + Comments []IssueCommentData `json:"comments"` 126 + } 127 + 128 + type IssueCommentData struct { 129 + Body string `json:"body"` 130 + } 131 + 132 + type SearchResult struct { 133 + Hits []int64 134 + Total uint64 135 + } 136 + 137 + const maxBatchSize = 20 138 + 139 + func (ix *Indexer) Index(ctx context.Context, issues ...*IssueData) error { 140 + batch := bleveutil.NewFlushingBatch(ix.indexer, maxBatchSize) 141 + for _, issue := range issues { 142 + if err := batch.Index(base36.Encode(issue.ID), issue); err != nil { 143 + return err 144 + } 145 + } 146 + return batch.Flush() 147 + } 148 + 149 + // Search searches for issues 150 + func (ix *Indexer) Search(ctx context.Context, opts models.IssueSearchOptions) (*SearchResult, error) { 151 + var queries []query.Query 152 + 153 + if opts.Keyword != "" { 154 + queries = append(queries, bleve.NewDisjunctionQuery( 155 + matchAndQuery(opts.Keyword, "title"), 156 + matchAndQuery(opts.Keyword, "body"), 157 + )) 158 + } 159 + queries = append(queries, boolFieldQuery(opts.IsOpen, "is_open")) 160 + // TODO: append more queries 161 + 162 + var indexerQuery query.Query = bleve.NewConjunctionQuery(queries...) 163 + searchReq := bleve.NewSearchRequestOptions(indexerQuery, opts.Page.Limit, opts.Page.Offset, false) 164 + res, err := ix.indexer.SearchInContext(ctx, searchReq) 165 + if err != nil { 166 + return nil, nil 167 + } 168 + ret := &SearchResult{ 169 + Total: res.Total, 170 + Hits: make([]int64, len(res.Hits)), 171 + } 172 + for i, hit := range res.Hits { 173 + id, err := base36.Decode(hit.ID) 174 + if err != nil { 175 + return nil, err 176 + } 177 + ret.Hits[i] = id 178 + } 179 + return ret, nil 180 + } 181 + 182 + func matchAndQuery(keyword, field string) query.Query { 183 + q := bleve.NewMatchQuery(keyword) 184 + q.FieldVal = field 185 + return q 186 + } 187 + 188 + func boolFieldQuery(val bool, field string) query.Query { 189 + q := bleve.NewBoolFieldQuery(val) 190 + q.FieldVal = field 191 + return q 192 + }
+26
appview/indexer/notifier.go
··· 1 + package indexer 2 + 3 + import ( 4 + "context" 5 + 6 + "tangled.sh/tangled.sh/core/appview/db" 7 + issues_indexer "tangled.sh/tangled.sh/core/appview/indexer/issues" 8 + "tangled.sh/tangled.sh/core/appview/notify" 9 + ) 10 + 11 + var _ notify.Notifier = &Indexer{} 12 + 13 + func (ix *Indexer) NewIssue(ctx context.Context, issue *db.Issue) { 14 + ix.Issues.Index(ctx, &issues_indexer.IssueData{ 15 + ID: issue.ID, 16 + IssueID: issue.IssueId, 17 + Title: issue.Title, 18 + Body: issue.Body, 19 + IsOpen: issue.Open, 20 + Comments: []issues_indexer.IssueCommentData{}, 21 + }) 22 + } 23 + 24 + func (ix *Indexer) NewPullComment(ctx context.Context, comment *db.PullComment) { 25 + panic("unimplemented") 26 + }
+4
appview/issues/issues.go
··· 18 18 "tangled.sh/tangled.sh/core/api/tangled" 19 19 "tangled.sh/tangled.sh/core/appview/config" 20 20 "tangled.sh/tangled.sh/core/appview/db" 21 + issues_indexer "tangled.sh/tangled.sh/core/appview/indexer/issues" 21 22 "tangled.sh/tangled.sh/core/appview/notify" 22 23 "tangled.sh/tangled.sh/core/appview/oauth" 23 24 "tangled.sh/tangled.sh/core/appview/pages" ··· 35 36 db *db.DB 36 37 config *config.Config 37 38 notifier notify.Notifier 39 + indexer *issues_indexer.Indexer 38 40 } 39 41 40 42 func New( ··· 45 47 db *db.DB, 46 48 config *config.Config, 47 49 notifier notify.Notifier, 50 + indexer *issues_indexer.Indexer, 48 51 ) *Issues { 49 52 return &Issues{ 50 53 oauth: oauth, ··· 54 57 db: db, 55 58 config: config, 56 59 notifier: notifier, 60 + indexer: indexer, 57 61 } 58 62 } 59 63
+23
appview/models/search.go
··· 1 + package models 2 + 3 + import "tangled.sh/tangled.sh/core/appview/pagination" 4 + 5 + type IssueSearchOptions struct { 6 + Keyword string 7 + RepoAt string 8 + IsOpen bool 9 + 10 + Page pagination.Page 11 + } 12 + 13 + // func (so *SearchOptions) ToFilters() []filter { 14 + // var filters []filter 15 + // if so.IsOpen != nil { 16 + // openValue := 0 17 + // if *so.IsOpen { 18 + // openValue = 1 19 + // } 20 + // filters = append(filters, FilterEq("open", openValue)) 21 + // } 22 + // return filters 23 + // }
+1
appview/pages/pages.go
··· 782 782 Issues []db.Issue 783 783 Page pagination.Page 784 784 FilteringByOpen bool 785 + FilterQuery string 785 786 } 786 787 787 788 func (p *Pages) RepoIssues(w io.Writer, params RepoIssuesParams) error {
+1 -1
appview/state/router.go
··· 222 222 } 223 223 224 224 func (s *State) IssuesRouter(mw *middleware.Middleware) http.Handler { 225 - issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier) 225 + issues := issues.New(s.oauth, s.repoResolver, s.pages, s.idResolver, s.db, s.config, s.notifier, s.indexer.Issues) 226 226 return issues.Router(mw) 227 227 } 228 228
+10
appview/state/state.go
··· 20 20 "tangled.sh/tangled.sh/core/appview/cache/session" 21 21 "tangled.sh/tangled.sh/core/appview/config" 22 22 "tangled.sh/tangled.sh/core/appview/db" 23 + "tangled.sh/tangled.sh/core/appview/indexer" 23 24 "tangled.sh/tangled.sh/core/appview/notify" 24 25 "tangled.sh/tangled.sh/core/appview/oauth" 25 26 "tangled.sh/tangled.sh/core/appview/pages" ··· 37 38 type State struct { 38 39 db *db.DB 39 40 notifier notify.Notifier 41 + indexer *indexer.Indexer 40 42 oauth *oauth.OAuth 41 43 enforcer *rbac.Enforcer 42 44 pages *pages.Pages ··· 56 58 return nil, fmt.Errorf("failed to create db: %w", err) 57 59 } 58 60 61 + indexer := indexer.New() 62 + err = indexer.Init(ctx, d) 63 + if err != nil { 64 + return nil, fmt.Errorf("failed to create indexer: %w", err) 65 + } 66 + 59 67 enforcer, err := rbac.NewEnforcer(config.Core.DbPath) 60 68 if err != nil { 61 69 return nil, fmt.Errorf("failed to create enforcer: %w", err) ··· 136 144 if !config.Core.Dev { 137 145 notifiers = append(notifiers, posthogService.NewPosthogNotifier(posthog)) 138 146 } 147 + notifiers = append(notifiers, indexer) 139 148 notifier := notify.NewMergedNotifier(notifiers...) 140 149 141 150 state := &State{ 142 151 d, 143 152 notifier, 153 + indexer, 144 154 oauth, 145 155 enforcer, 146 156 pgs,
+27
go.mod
··· 53 53 dario.cat/mergo v1.0.1 // indirect 54 54 github.com/Microsoft/go-winio v0.6.2 // indirect 55 55 github.com/ProtonMail/go-crypto v1.3.0 // indirect 56 + github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect 56 57 github.com/alecthomas/repr v0.4.0 // indirect 57 58 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 58 59 github.com/aymerick/douceur v0.2.0 // indirect 59 60 github.com/beorn7/perks v1.0.1 // indirect 61 + github.com/bits-and-blooms/bitset v1.22.0 // indirect 62 + github.com/blevesearch/bleve/v2 v2.5.3 // indirect 63 + github.com/blevesearch/bleve_index_api v1.2.8 // indirect 64 + github.com/blevesearch/geo v0.2.4 // indirect 65 + github.com/blevesearch/go-faiss v1.0.25 // indirect 66 + github.com/blevesearch/go-porterstemmer v1.0.3 // indirect 67 + github.com/blevesearch/gtreap v0.1.1 // indirect 68 + github.com/blevesearch/mmap-go v1.0.4 // indirect 69 + github.com/blevesearch/scorch_segment_api/v2 v2.3.10 // indirect 70 + github.com/blevesearch/segment v0.9.1 // indirect 71 + github.com/blevesearch/snowballstem v0.9.0 // indirect 72 + github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect 73 + github.com/blevesearch/vellum v1.1.0 // indirect 74 + github.com/blevesearch/zapx/v11 v11.4.2 // indirect 75 + github.com/blevesearch/zapx/v12 v12.4.2 // indirect 76 + github.com/blevesearch/zapx/v13 v13.4.2 // indirect 77 + github.com/blevesearch/zapx/v14 v14.4.2 // indirect 78 + github.com/blevesearch/zapx/v15 v15.4.2 // indirect 79 + github.com/blevesearch/zapx/v16 v16.2.4 // indirect 60 80 github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect 61 81 github.com/casbin/govaluate v1.3.0 // indirect 62 82 github.com/cenkalti/backoff/v4 v4.3.0 // indirect ··· 88 108 github.com/golang-jwt/jwt/v5 v5.2.3 // indirect 89 109 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 90 110 github.com/golang/mock v1.6.0 // indirect 111 + github.com/golang/protobuf v1.5.4 // indirect 112 + github.com/golang/snappy v0.0.4 // indirect 91 113 github.com/google/go-querystring v1.1.0 // indirect 92 114 github.com/gorilla/css v1.0.1 // indirect 93 115 github.com/gorilla/securecookie v1.1.2 // indirect ··· 113 135 github.com/ipfs/go-log v1.0.5 // indirect 114 136 github.com/ipfs/go-log/v2 v2.6.0 // indirect 115 137 github.com/ipfs/go-metrics-interface v0.3.0 // indirect 138 + github.com/json-iterator/go v1.1.12 // indirect 116 139 github.com/kevinburke/ssh_config v1.2.0 // indirect 117 140 github.com/klauspost/compress v1.18.0 // indirect 118 141 github.com/klauspost/cpuid/v2 v2.3.0 // indirect ··· 127 150 github.com/moby/docker-image-spec v1.3.1 // indirect 128 151 github.com/moby/sys/atomicwriter v0.1.0 // indirect 129 152 github.com/moby/term v0.5.2 // indirect 153 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 154 + github.com/modern-go/reflect2 v1.0.2 // indirect 130 155 github.com/morikuni/aec v1.0.0 // indirect 131 156 github.com/mr-tron/base58 v1.2.0 // indirect 157 + github.com/mschoch/smat v0.2.0 // indirect 132 158 github.com/multiformats/go-base32 v0.1.0 // indirect 133 159 github.com/multiformats/go-base36 v0.2.0 // indirect 134 160 github.com/multiformats/go-multibase v0.2.0 // indirect ··· 156 182 github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 157 183 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect 158 184 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect 185 + go.etcd.io/bbolt v1.4.0 // indirect 159 186 go.opentelemetry.io/auto/sdk v1.1.0 // indirect 160 187 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect 161 188 go.opentelemetry.io/otel v1.37.0 // indirect
+58
go.sum
··· 9 9 github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 10 10 github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= 11 11 github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= 12 + github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg= 13 + github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0= 12 14 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= 13 15 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= 14 16 github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= ··· 23 25 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= 24 26 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 25 27 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 28 + github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 29 + github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= 30 + github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 31 + github.com/blevesearch/bleve/v2 v2.5.3 h1:9l1xtKaETv64SZc1jc4Sy0N804laSa/LeMbYddq1YEM= 32 + github.com/blevesearch/bleve/v2 v2.5.3/go.mod h1:Z/e8aWjiq8HeX+nW8qROSxiE0830yQA071dwR3yoMzw= 33 + github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y= 34 + github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0= 35 + github.com/blevesearch/geo v0.2.4 h1:ECIGQhw+QALCZaDcogRTNSJYQXRtC8/m8IKiA706cqk= 36 + github.com/blevesearch/geo v0.2.4/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8= 37 + github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U= 38 + github.com/blevesearch/go-faiss v1.0.25/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk= 39 + github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= 40 + github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= 41 + github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= 42 + github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= 43 + github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= 44 + github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= 45 + github.com/blevesearch/scorch_segment_api/v2 v2.3.10 h1:Yqk0XD1mE0fDZAJXTjawJ8If/85JxnLd8v5vG/jWE/s= 46 + github.com/blevesearch/scorch_segment_api/v2 v2.3.10/go.mod h1:Z3e6ChN3qyN35yaQpl00MfI5s8AxUJbpTR/DL8QOQ+8= 47 + github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= 48 + github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= 49 + github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= 50 + github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= 51 + github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A= 52 + github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ= 53 + github.com/blevesearch/vellum v1.1.0 h1:CinkGyIsgVlYf8Y2LUQHvdelgXr6PYuvoDIajq6yR9w= 54 + github.com/blevesearch/vellum v1.1.0/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y= 55 + github.com/blevesearch/zapx/v11 v11.4.2 h1:l46SV+b0gFN+Rw3wUI1YdMWdSAVhskYuvxlcgpQFljs= 56 + github.com/blevesearch/zapx/v11 v11.4.2/go.mod h1:4gdeyy9oGa/lLa6D34R9daXNUvfMPZqUYjPwiLmekwc= 57 + github.com/blevesearch/zapx/v12 v12.4.2 h1:fzRbhllQmEMUuAQ7zBuMvKRlcPA5ESTgWlDEoB9uQNE= 58 + github.com/blevesearch/zapx/v12 v12.4.2/go.mod h1:TdFmr7afSz1hFh/SIBCCZvcLfzYvievIH6aEISCte58= 59 + github.com/blevesearch/zapx/v13 v13.4.2 h1:46PIZCO/ZuKZYgxI8Y7lOJqX3Irkc3N8W82QTK3MVks= 60 + github.com/blevesearch/zapx/v13 v13.4.2/go.mod h1:knK8z2NdQHlb5ot/uj8wuvOq5PhDGjNYQQy0QDnopZk= 61 + github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT7fWYz0= 62 + github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8= 63 + github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k= 64 + github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw= 65 + github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww= 66 + github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs= 26 67 github.com/bluesky-social/indigo v0.0.0-20250724221105-5827c8fb61bb h1:BqMNDZMfXwiRTJ6NvQotJ0qInn37JH5U8E+TF01CFHQ= 27 68 github.com/bluesky-social/indigo v0.0.0-20250724221105-5827c8fb61bb/go.mod h1:0XUyOCRtL4/OiyeqMTmr6RlVHQMDgw3LS7CfibuZR5Q= 28 69 github.com/bluesky-social/jetstream v0.0.0-20241210005130-ea96859b93d1 h1:CFvRtYNSnWRAi/98M3O466t9dYuwtesNbu6FVPymRrA= ··· 152 193 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 153 194 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 154 195 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 196 + github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 197 + github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 198 + github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= 199 + github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 155 200 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 156 201 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 157 202 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= ··· 163 208 github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 164 209 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 165 210 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 211 + github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 166 212 github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= 167 213 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 168 214 github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= ··· 245 291 github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= 246 292 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 247 293 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 294 + github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 295 + github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 248 296 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 249 297 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 250 298 github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= ··· 296 344 github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= 297 345 github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= 298 346 github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= 347 + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 348 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 349 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 350 + github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 351 + github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 299 352 github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= 300 353 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 301 354 github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 302 355 github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 356 + github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= 357 + github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= 303 358 github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= 304 359 github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= 305 360 github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= ··· 439 494 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= 440 495 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= 441 496 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= 497 + go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= 498 + go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= 442 499 go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= 443 500 go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= 444 501 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= ··· 640 697 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 641 698 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 642 699 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 700 + gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 643 701 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 644 702 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 645 703 gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=

History

15 rounds 2 comments
sign up or login to add to the discussion
1 commit
expand
appview: add basic issue indexer
expand 0 comments
pull request successfully merged
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 1 comment

this changeset largely lgtm!

1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 1 comment
  • this is an N+1 query, because we first get all issues and then make one query for each issue. understandably this only needs to happen when populating the indices but we could improve this by just making one query
  • we can use a pagination free API for getting issues with comments while populating indexer
  • more of a note to self: search index should also handle issue deletions
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer
expand 0 comments
1 commit
expand
appview: add basic issue indexer (wip)
expand 0 comments