141 lines
3.0 KiB
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)
|
|
}
|