Home | History | Annotate | Download | only in repositories
      1 package repositories
      2 
      3 import (
      4 	"database/sql"
      5 	"fmt"
      6 
      7 	lru "github.com/hashicorp/golang-lru"
      8 	"github.com/pkg/errors"
      9 
     10 	e "repodiff/entities"
     11 	repoSQL "repodiff/persistence/sql"
     12 )
     13 
     14 var cacheSingleton *lru.Cache
     15 
     16 const cacheSize = 1024
     17 
     18 type source struct {
     19 	db *sql.DB
     20 }
     21 
     22 func (s source) getOrCreateURLBranchID(url, branch string) (int16, error) {
     23 	url = protocolStrippedURL(url)
     24 	id, ok := cacheSingleton.Get(cacheKey(url, branch))
     25 	if ok {
     26 		return id.(int16), nil
     27 	}
     28 	val, err := s.getOrCreateURLBranchIDPersistence(url, branch)
     29 	if err != nil {
     30 		return 0, err
     31 	}
     32 	cacheSingleton.Add(cacheKey(url, branch), val)
     33 	return val, nil
     34 }
     35 
     36 func (s source) getOrCreateURLBranchIDPersistence(url, branch string) (int16, error) {
     37 	id, err := s.getIDByURLBranch(url, branch)
     38 	if err == nil {
     39 		return id, nil
     40 	}
     41 	s.insertIgnoreError(url, branch)
     42 	return s.getIDByURLBranch(url, branch)
     43 }
     44 
     45 func (s source) insertIgnoreError(url, branch string) {
     46 	repoSQL.SingleTransactionInsert(
     47 		s.db,
     48 		`INSERT INTO id_to_url_branch (
     49 			url,
     50 			branch
     51 		) VALUES (?, ?)`,
     52 		[][]interface{}{
     53 			[]interface{}{
     54 				url,
     55 				branch,
     56 			},
     57 		},
     58 	)
     59 }
     60 
     61 func (s source) getIDByURLBranch(url, branch string) (int16, error) {
     62 	var id *int16
     63 	repoSQL.Select(
     64 		s.db,
     65 		func(row *sql.Rows) {
     66 			id = new(int16)
     67 			row.Scan(id)
     68 		},
     69 		"SELECT id FROM id_to_url_branch WHERE url = ? AND branch = ?",
     70 		url,
     71 		branch,
     72 	)
     73 	if id == nil {
     74 		return 0, errors.New(fmt.Sprintf("No ID found for %s %s", url, branch))
     75 	}
     76 	return *id, nil
     77 }
     78 
     79 func (s source) GetURLBranchByID(id int16) (string, string, error) {
     80 	urlBranchPair, ok := cacheSingleton.Get(id)
     81 	if ok {
     82 		asSlice := urlBranchPair.([]string)
     83 		return asSlice[0], asSlice[1], nil
     84 	}
     85 	url, branch, err := s.getURLBranchByIDPersistence(id)
     86 	if err == nil {
     87 		cacheSingleton.Add(id, []string{url, branch})
     88 	}
     89 	return url, branch, err
     90 }
     91 
     92 func (s source) getURLBranchByIDPersistence(id int16) (string, string, error) {
     93 	url := ""
     94 	branch := ""
     95 	repoSQL.Select(
     96 		s.db,
     97 		func(row *sql.Rows) {
     98 			row.Scan(&url, &branch)
     99 		},
    100 		"SELECT url, branch FROM id_to_url_branch WHERE id = ?",
    101 		id,
    102 	)
    103 	if url == "" {
    104 		return "", "", errors.New(fmt.Sprintf("No matching records for ID %d", id))
    105 	}
    106 	return url, branch, nil
    107 }
    108 
    109 func (s source) DiffTargetToMapped(target e.DiffTarget) (e.MappedDiffTarget, error) {
    110 	upstream, errU := s.getOrCreateURLBranchID(
    111 		target.Upstream.URL,
    112 		target.Upstream.Branch,
    113 	)
    114 	downstream, errD := s.getOrCreateURLBranchID(
    115 		target.Downstream.URL,
    116 		target.Downstream.Branch,
    117 	)
    118 	if errU != nil || errD != nil {
    119 		return e.MappedDiffTarget{}, errors.New("Failed interacting with the database")
    120 	}
    121 	return e.MappedDiffTarget{
    122 		UpstreamTarget:   upstream,
    123 		DownstreamTarget: downstream,
    124 	}, nil
    125 }
    126 
    127 func NewSourceRepository() (source, error) {
    128 	db, err := repoSQL.GetDBConnectionPool()
    129 	return source{
    130 		db: db,
    131 	}, errors.Wrap(err, "Could not establish a database connection")
    132 }
    133 
    134 func cacheKey(url, branch string) string {
    135 	return fmt.Sprintf("%s:%s", url, branch)
    136 }
    137 
    138 func init() {
    139 	cacheSingleton, _ = lru.New(cacheSize)
    140 }
    141