1package repositories 2 3import ( 4 "database/sql" 5 6 "github.com/pkg/errors" 7 "github.com/satori/go.uuid" 8 9 "repodiff/constants" 10 e "repodiff/entities" 11 "repodiff/mappers" 12 repoSQL "repodiff/persistence/sql" 13 "repodiff/utils" 14) 15 16type project struct { 17 db *sql.DB 18 target e.MappedDiffTarget 19 timestampGenerator func() e.RepoTimestamp 20} 21 22func (p project) InsertDiffRows(diffRows []e.AnalyzedDiffRow) error { 23 return errors.Wrap( 24 repoSQL.SingleTransactionInsert( 25 p.db, 26 `INSERT INTO project_differential ( 27 upstream_target_id, 28 downstream_target_id, 29 timestamp, 30 uuid, 31 row_index, 32 downstream_project, 33 upstream_project, 34 status, 35 files_changed, 36 line_insertions, 37 line_deletions, 38 line_changes, 39 commits_not_upstreamed, 40 project_type 41 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, 42 mappers.PrependMappedDiffTarget( 43 p.target, 44 mappers.DiffRowsToPersistCols(diffRows, p.timestampGenerator()), 45 ), 46 ), 47 "Error inserting rows into project_differential", 48 ) 49} 50 51func (p project) GetMostRecentOuterKey() (int64, uuid.UUID, error) { 52 var timestamp int64 53 var uuidBytes []byte 54 err := p.db.QueryRow( 55 `SELECT timestamp, uuid FROM project_differential WHERE upstream_target_id = ? AND downstream_target_id = ? AND timestamp=( 56 SELECT MAX(timestamp) FROM project_differential WHERE upstream_target_id = ? AND downstream_target_id = ? 57 ) LIMIT 1`, 58 p.target.UpstreamTarget, 59 p.target.DownstreamTarget, 60 p.target.UpstreamTarget, 61 p.target.DownstreamTarget, 62 ).Scan( 63 ×tamp, 64 &uuidBytes, 65 ) 66 if err != nil { 67 return 0, constants.NullUUID(), err 68 } 69 u, err := uuid.FromBytes(uuidBytes) 70 if err != nil { 71 return 0, constants.NullUUID(), errors.Wrap(err, "Error casting string to UUID") 72 } 73 return timestamp, u, nil 74} 75 76func (p project) GetMostRecentDifferentials() ([]e.AnalyzedDiffRow, error) { 77 timestamp, uid, err := p.GetMostRecentOuterKey() 78 if err == sql.ErrNoRows { 79 return nil, nil 80 } 81 if err != nil { 82 // TODO this doesn't handle empty case properly 83 return nil, err 84 } 85 var errMapping error 86 87 var diffRows []e.AnalyzedDiffRow 88 errSelect := repoSQL.Select( 89 p.db, 90 func(row *sql.Rows) { 91 if errMapping != nil { 92 return 93 } 94 d, err := mappers.SQLRowToDiffRow(row) 95 errMapping = err 96 diffRows = append( 97 diffRows, 98 d, 99 ) 100 }, 101 `SELECT 102 timestamp, 103 uuid, 104 row_index, 105 downstream_project, 106 upstream_project, 107 status, 108 files_changed, 109 line_insertions, 110 line_deletions, 111 line_changes, 112 commits_not_upstreamed, 113 project_type 114 FROM project_differential 115 WHERE 116 upstream_target_id = ? 117 AND downstream_target_id = ? 118 AND timestamp = ? 119 AND uuid = ?`, 120 p.target.UpstreamTarget, 121 p.target.DownstreamTarget, 122 timestamp, 123 string(uid.Bytes()), 124 ) 125 if errSelect != nil { 126 return nil, errSelect 127 } 128 if errMapping != nil { 129 return nil, errMapping 130 } 131 return diffRows, nil 132} 133 134func NewProjectRepository(target e.MappedDiffTarget) (project, error) { 135 db, err := repoSQL.GetDBConnectionPool() 136 return project{ 137 db: db, 138 target: target, 139 timestampGenerator: utils.TimestampSeconds, 140 }, errors.Wrap(err, "Could not establish a database connection") 141} 142