1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
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)
}
|