android13/development/tools/repo_diff/service/repodiff/repositories/source.go

141 lines
3.0 KiB
Go

package repositories
import (
"database/sql"
"fmt"
lru "github.com/hashicorp/golang-lru"
"github.com/pkg/errors"
e "repodiff/entities"
repoSQL "repodiff/persistence/sql"
)
var cacheSingleton *lru.Cache
const cacheSize = 1024
type source struct {
db *sql.DB
}
func (s source) getOrCreateURLBranchID(url, branch string) (int16, error) {
url = protocolStrippedURL(url)
id, ok := cacheSingleton.Get(cacheKey(url, branch))
if ok {
return id.(int16), nil
}
val, err := s.getOrCreateURLBranchIDPersistence(url, branch)
if err != nil {
return 0, err
}
cacheSingleton.Add(cacheKey(url, branch), val)
return val, nil
}
func (s source) getOrCreateURLBranchIDPersistence(url, branch string) (int16, error) {
id, err := s.getIDByURLBranch(url, branch)
if err == nil {
return id, nil
}
s.insertIgnoreError(url, branch)
return s.getIDByURLBranch(url, branch)
}
func (s source) insertIgnoreError(url, branch string) {
repoSQL.SingleTransactionInsert(
s.db,
`INSERT INTO id_to_url_branch (
url,
branch
) VALUES (?, ?)`,
[][]interface{}{
[]interface{}{
url,
branch,
},
},
)
}
func (s source) getIDByURLBranch(url, branch string) (int16, error) {
var id *int16
repoSQL.Select(
s.db,
func(row *sql.Rows) {
id = new(int16)
row.Scan(id)
},
"SELECT id FROM id_to_url_branch WHERE url = ? AND branch = ?",
url,
branch,
)
if id == nil {
return 0, errors.New(fmt.Sprintf("No ID found for %s %s", url, branch))
}
return *id, nil
}
func (s source) GetURLBranchByID(id int16) (string, string, error) {
urlBranchPair, ok := cacheSingleton.Get(id)
if ok {
asSlice := urlBranchPair.([]string)
return asSlice[0], asSlice[1], nil
}
url, branch, err := s.getURLBranchByIDPersistence(id)
if err == nil {
cacheSingleton.Add(id, []string{url, branch})
}
return url, branch, err
}
func (s source) getURLBranchByIDPersistence(id int16) (string, string, error) {
url := ""
branch := ""
repoSQL.Select(
s.db,
func(row *sql.Rows) {
row.Scan(&url, &branch)
},
"SELECT url, branch FROM id_to_url_branch WHERE id = ?",
id,
)
if url == "" {
return "", "", errors.New(fmt.Sprintf("No matching records for ID %d", id))
}
return url, branch, nil
}
func (s source) DiffTargetToMapped(target e.DiffTarget) (e.MappedDiffTarget, error) {
upstream, errU := s.getOrCreateURLBranchID(
target.Upstream.URL,
target.Upstream.Branch,
)
downstream, errD := s.getOrCreateURLBranchID(
target.Downstream.URL,
target.Downstream.Branch,
)
if errU != nil || errD != nil {
return e.MappedDiffTarget{}, errors.New("Failed interacting with the database")
}
return e.MappedDiffTarget{
UpstreamTarget: upstream,
DownstreamTarget: downstream,
}, nil
}
func NewSourceRepository() (source, error) {
db, err := repoSQL.GetDBConnectionPool()
return source{
db: db,
}, errors.Wrap(err, "Could not establish a database connection")
}
func cacheKey(url, branch string) string {
return fmt.Sprintf("%s:%s", url, branch)
}
func init() {
cacheSingleton, _ = lru.New(cacheSize)
}