internal/store/releases.go

8e64f8208b18dc40fb5c27c873802282e722255e
gitbay/internal/store/releases.go history · blame · raw

147 lines · 3695 bytes

  1package store
  2
  3import (
  4	"database/sql"
  5	"errors"
  6	"fmt"
  7)
  8
  9type Release struct {
 10	ID        int64
 11	RepoID    int64
 12	Tag       string
 13	Title     string
 14	Notes     string
 15	Author    string
 16	CreatedAt string
 17	Assets    []ReleaseAsset
 18}
 19
 20type ReleaseAsset struct {
 21	ID         int64
 22	Name       string
 23	Size       int64
 24	SHA256     string
 25	UploadedAt string
 26}
 27
 28func (s *Store) CreateRelease(repoID int64, tag, title, notes string, authorID int64) (int64, error) {
 29	res, err := s.DB.Exec(
 30		"INSERT INTO releases (repo_id, tag, title, notes, author_id) VALUES (?, ?, ?, ?, ?)",
 31		repoID, tag, title, notes, authorID)
 32	if err != nil {
 33		if isUniqueErr(err) {
 34			return 0, fmt.Errorf("a release for tag %q already exists", tag)
 35		}
 36		return 0, err
 37	}
 38	return res.LastInsertId()
 39}
 40
 41const releaseSelect = `
 42	SELECT r.id, r.repo_id, r.tag, r.title, r.notes, COALESCE(u.username, ''), r.created_at
 43	FROM releases r LEFT JOIN users u ON u.id = r.author_id`
 44
 45func (s *Store) releaseAssets(rel *Release) error {
 46	rows, err := s.DB.Query(
 47		"SELECT id, name, size, sha256, uploaded_at FROM release_assets WHERE release_id = ? ORDER BY name",
 48		rel.ID)
 49	if err != nil {
 50		return err
 51	}
 52	defer rows.Close()
 53	for rows.Next() {
 54		var a ReleaseAsset
 55		if err := rows.Scan(&a.ID, &a.Name, &a.Size, &a.SHA256, &a.UploadedAt); err != nil {
 56			return err
 57		}
 58		rel.Assets = append(rel.Assets, a)
 59	}
 60	return rows.Err()
 61}
 62
 63// UpdateRelease replaces a release's title and notes.
 64func (s *Store) UpdateRelease(repoID int64, tag, title, notes string) error {
 65	res, err := s.DB.Exec(
 66		"UPDATE releases SET title = ?, notes = ? WHERE repo_id = ? AND tag = ?",
 67		title, notes, repoID, tag)
 68	if err != nil {
 69		return err
 70	}
 71	if n, _ := res.RowsAffected(); n == 0 {
 72		return ErrNotFound
 73	}
 74	return nil
 75}
 76
 77func (s *Store) ReleaseByTag(repoID int64, tag string) (Release, error) {
 78	var r Release
 79	err := s.DB.QueryRow(releaseSelect+" WHERE r.repo_id = ? AND r.tag = ?", repoID, tag).
 80		Scan(&r.ID, &r.RepoID, &r.Tag, &r.Title, &r.Notes, &r.Author, &r.CreatedAt)
 81	if errors.Is(err, sql.ErrNoRows) {
 82		return r, ErrNotFound
 83	}
 84	if err != nil {
 85		return r, err
 86	}
 87	return r, s.releaseAssets(&r)
 88}
 89
 90// ListReleases returns releases newest-first, assets included.
 91func (s *Store) ListReleases(repoID int64) ([]Release, error) {
 92	rows, err := s.DB.Query(releaseSelect+" WHERE r.repo_id = ? ORDER BY r.created_at DESC", repoID)
 93	if err != nil {
 94		return nil, err
 95	}
 96	defer rows.Close()
 97	var out []Release
 98	for rows.Next() {
 99		var r Release
100		if err := rows.Scan(&r.ID, &r.RepoID, &r.Tag, &r.Title, &r.Notes, &r.Author, &r.CreatedAt); err != nil {
101			return nil, err
102		}
103		out = append(out, r)
104	}
105	if err := rows.Err(); err != nil {
106		return nil, err
107	}
108	for i := range out {
109		if err := s.releaseAssets(&out[i]); err != nil {
110			return nil, err
111		}
112	}
113	return out, nil
114}
115
116func (s *Store) DeleteRelease(id int64) error {
117	res, err := s.DB.Exec("DELETE FROM releases WHERE id = ?", id)
118	if err != nil {
119		return err
120	}
121	if n, _ := res.RowsAffected(); n == 0 {
122		return ErrNotFound
123	}
124	return nil
125}
126
127func (s *Store) AddReleaseAsset(releaseID int64, name string, size int64, sha256 string) error {
128	_, err := s.DB.Exec(
129		"INSERT INTO release_assets (release_id, name, size, sha256) VALUES (?, ?, ?, ?)",
130		releaseID, name, size, sha256)
131	if isUniqueErr(err) {
132		return fmt.Errorf("asset %q already exists on this release", name)
133	}
134	return err
135}
136
137func (s *Store) RemoveReleaseAsset(releaseID int64, name string) error {
138	res, err := s.DB.Exec(
139		"DELETE FROM release_assets WHERE release_id = ? AND name = ?", releaseID, name)
140	if err != nil {
141		return err
142	}
143	if n, _ := res.RowsAffected(); n == 0 {
144		return ErrNotFound
145	}
146	return nil
147}