GameOver1337 / GitClone Public
К репозиторию
9.5 KB
internal/db/queries.go
9.5 KB
1package db
2
3import (
4 "database/sql"
5 "errors"
6
7 "github.com/clancore/repo/internal/models"
8)
9
10// ---------- Users ----------
11
12func CreateUser(u *models.User) error {
13 res, err := DB.Exec(
14 `INSERT INTO users (username, email, password_hash, avatar_url) VALUES (?, ?, ?, ?)`,
15 u.Username, u.Email, u.PasswordHash, u.AvatarURL,
16 )
17 if err != nil {
18 return err
19 }
20 id, _ := res.LastInsertId()
21 u.ID = int(id)
22 return nil
23}
24
25func GetUserByUsername(username string) (*models.User, error) {
26 u := &models.User{}
27 err := DB.QueryRow(
28 `SELECT id, username, email, password_hash, avatar_url, created_at FROM users WHERE username = ?`,
29 username,
30 ).Scan(&u.ID, &u.Username, &u.Email, &u.PasswordHash, &u.AvatarURL, &u.CreatedAt)
31 if errors.Is(err, sql.ErrNoRows) {
32 return nil, nil
33 }
34 return u, err
35}
36
37func GetUserByID(id int) (*models.User, error) {
38 u := &models.User{}
39 err := DB.QueryRow(
40 `SELECT id, username, email, avatar_url, created_at FROM users WHERE id = ?`, id,
41 ).Scan(&u.ID, &u.Username, &u.Email, &u.AvatarURL, &u.CreatedAt)
42 if errors.Is(err, sql.ErrNoRows) {
43 return nil, nil
44 }
45 return u, err
46}
47
48func ListUsers() ([]*models.User, error) {
49 rows, err := DB.Query(`SELECT id, username, email, avatar_url, created_at FROM users ORDER BY id`)
50 if err != nil {
51 return nil, err
52 }
53 defer rows.Close()
54
55 var users []*models.User
56 for rows.Next() {
57 u := &models.User{}
58 if err := rows.Scan(&u.ID, &u.Username, &u.Email, &u.AvatarURL, &u.CreatedAt); err != nil {
59 return nil, err
60 }
61 users = append(users, u)
62 }
63 return users, rows.Err()
64}
65
66// ---------- Repositories ----------
67
68func CreateRepo(r *models.Repo) error {
69 res, err := DB.Exec(
70 `INSERT INTO repositories (name, owner_id, description, is_private, clone_url) VALUES (?, ?, ?, ?, ?)`,
71 r.Name, r.OwnerID, r.Description, r.IsPrivate, r.CloneURL,
72 )
73 if err != nil {
74 return err
75 }
76 id, _ := res.LastInsertId()
77 r.ID = int(id)
78 return nil
79}
80
81func GetRepoByName(owner, name string) (*models.Repo, error) {
82 r := &models.Repo{Owner: &models.User{}}
83 err := DB.QueryRow(
84 `SELECT r.id, r.name, r.owner_id, r.description, r.is_private, r.is_archived, r.clone_url, r.created_at, r.updated_at,
85 u.username, u.avatar_url
86 FROM repositories r JOIN users u ON u.id = r.owner_id
87 WHERE u.username = ? AND r.name = ?`, owner, name,
88 ).Scan(&r.ID, &r.Name, &r.OwnerID, &r.Description, &r.IsPrivate, &r.IsArchived,
89 &r.CloneURL, &r.CreatedAt, &r.UpdatedAt, &r.Owner.Username, &r.Owner.AvatarURL)
90 if errors.Is(err, sql.ErrNoRows) {
91 return nil, nil
92 }
93 return r, err
94}
95
96func GetRepoByID(id int) (*models.Repo, error) {
97 r := &models.Repo{}
98 r.Owner = &models.User{}
99 err := DB.QueryRow(
100 `SELECT r.id, r.name, r.owner_id, r.description, r.is_private, r.is_archived, r.clone_url, r.created_at, r.updated_at,
101 u.username, u.avatar_url
102 FROM repositories r JOIN users u ON u.id = r.owner_id WHERE r.id = ?`, id,
103 ).Scan(&r.ID, &r.Name, &r.OwnerID, &r.Description, &r.IsPrivate, &r.IsArchived,
104 &r.CloneURL, &r.CreatedAt, &r.UpdatedAt, &r.Owner.Username, &r.Owner.AvatarURL)
105 if errors.Is(err, sql.ErrNoRows) {
106 return nil, nil
107 }
108 return r, err
109}
110
111func ListReposByOwner(ownerID int) ([]*models.Repo, error) {
112 rows, err := DB.Query(
113 `SELECT r.id, r.name, r.owner_id, r.description, r.is_private, r.is_archived,
114 r.clone_url, r.created_at, r.updated_at, u.username, u.avatar_url
115 FROM repositories r JOIN users u ON u.id = r.owner_id
116 WHERE r.owner_id = ? ORDER BY r.updated_at DESC`, ownerID,
117 )
118 if err != nil {
119 return nil, err
120 }
121 defer rows.Close()
122 return scanRepos(rows)
123}
124
125func GetRepoByCloneName(cloneName string) (*models.Repo, error) {
126 r := &models.Repo{Owner: &models.User{}}
127 err := DB.QueryRow(
128 `SELECT r.id, r.name, r.owner_id, r.description, r.is_private, r.is_archived, r.clone_url, r.created_at, r.updated_at,
129 u.username, u.avatar_url
130 FROM repositories r JOIN users u ON u.id = r.owner_id
131 WHERE r.clone_url = ? OR r.clone_url = ?`,
132 cloneName, "http://localhost:5758/"+cloneName,
133 ).Scan(&r.ID, &r.Name, &r.OwnerID, &r.Description, &r.IsPrivate, &r.IsArchived,
134 &r.CloneURL, &r.CreatedAt, &r.UpdatedAt, &r.Owner.Username, &r.Owner.AvatarURL)
135 if errors.Is(err, sql.ErrNoRows) {
136 return nil, nil
137 }
138 return r, err
139}
140
141func ListAllPublicRepos() ([]*models.Repo, error) {
142 rows, err := DB.Query(
143 `SELECT r.id, r.name, r.owner_id, r.description, r.is_private, r.is_archived, r.clone_url, r.created_at, r.updated_at,
144 u.username, u.avatar_url
145 FROM repositories r JOIN users u ON u.id = r.owner_id
146 WHERE r.is_private = 0 ORDER BY r.updated_at DESC LIMIT 100`,
147 )
148 if err != nil {
149 return nil, err
150 }
151 defer rows.Close()
152 return scanRepos(rows)
153}
154
155func TouchRepo(id int) error {
156 _, err := DB.Exec(`UPDATE repositories SET updated_at = CURRENT_TIMESTAMP WHERE id = ?`, id)
157 return err
158}
159
160func scanRepos(rows *sql.Rows) ([]*models.Repo, error) {
161 var repos []*models.Repo
162 for rows.Next() {
163 r := &models.Repo{Owner: &models.User{}}
164 var ownerName, avatar sql.NullString
165 err := rows.Scan(&r.ID, &r.Name, &r.OwnerID, &r.Description, &r.IsPrivate, &r.IsArchived,
166 &r.CloneURL, &r.CreatedAt, &r.UpdatedAt, &ownerName, &avatar)
167 if err != nil {
168 return nil, err
169 }
170 r.Owner.Username = ownerName.String
171 r.Owner.AvatarURL = avatar.String
172 repos = append(repos, r)
173 }
174 return repos, rows.Err()
175}
176
177// ---------- Releases ----------
178
179func CreateRelease(rel *models.Release) error {
180 res, err := DB.Exec(
181 `INSERT INTO releases (repo_id, tag, title, body, is_prerelease) VALUES (?, ?, ?, ?, ?)`,
182 rel.RepoID, rel.Tag, rel.Title, rel.Body, rel.IsPrerelease,
183 )
184 if err != nil {
185 return err
186 }
187 id, _ := res.LastInsertId()
188 rel.ID = int(id)
189 return nil
190}
191
192func GetRelease(id int) (*models.Release, error) {
193 rel := &models.Release{}
194 err := DB.QueryRow(
195 `SELECT id, repo_id, tag, title, body, is_prerelease, created_at FROM releases WHERE id = ?`, id,
196 ).Scan(&rel.ID, &rel.RepoID, &rel.Tag, &rel.Title, &rel.Body, &rel.IsPrerelease, &rel.CreatedAt)
197 if errors.Is(err, sql.ErrNoRows) {
198 return nil, nil
199 }
200 return rel, err
201}
202
203func ListReleasesByRepo(repoID int, limit int) ([]*models.Release, error) {
204 rows, err := DB.Query(
205 `SELECT id, repo_id, tag, title, body, is_prerelease, created_at
206 FROM releases WHERE repo_id = ? ORDER BY id DESC LIMIT ?`, repoID, limit,
207 )
208 if err != nil {
209 return nil, err
210 }
211 defer rows.Close()
212
213 var releases []*models.Release
214 for rows.Next() {
215 rel := &models.Release{}
216 if err := rows.Scan(&rel.ID, &rel.RepoID, &rel.Tag, &rel.Title, &rel.Body,
217 &rel.IsPrerelease, &rel.CreatedAt); err != nil {
218 return nil, err
219 }
220 releases = append(releases, rel)
221 }
222 return releases, rows.Err()
223}
224
225func CountReleasesByRepo(repoID int) (int, error) {
226 var n int
227 err := DB.QueryRow(`SELECT COUNT(*) FROM releases WHERE repo_id = ?`, repoID).Scan(&n)
228 return n, err
229}
230
231func DeleteRelease(id int) error {
232 _, err := DB.Exec(`DELETE FROM releases WHERE id = ?`, id)
233 return err
234}
235
236// ---------- Builds ----------
237
238func CreateBuild(b *models.Build) error {
239 res, err := DB.Exec(
240 `INSERT INTO builds (repo_id, branch, build_type, status, log_file) VALUES (?, ?, ?, ?, ?)`,
241 b.RepoID, b.Branch, b.BuildType, b.Status, b.LogFile,
242 )
243 if err != nil {
244 return err
245 }
246 id, _ := res.LastInsertId()
247 b.ID = int(id)
248 return nil
249}
250
251func UpdateBuildStatus(id int, status string, finished bool) error {
252 if finished {
253 _, err := DB.Exec(`UPDATE builds SET status = ?, finished_at = CURRENT_TIMESTAMP WHERE id = ?`, status, id)
254 return err
255 }
256 _, err := DB.Exec(`UPDATE builds SET status = ? WHERE id = ?`, status, id)
257 return err
258}
259
260func UpdateBuildType(id int, buildType string) error {
261 _, err := DB.Exec(`UPDATE builds SET build_type = ? WHERE id = ?`, buildType, id)
262 return err
263}
264
265func ListBuildsByRepo(repoID int, limit int) ([]*models.Build, error) {
266 rows, err := DB.Query(
267 `SELECT id, repo_id, branch, build_type, status, log_file, started_at, finished_at
268 FROM builds WHERE repo_id = ? ORDER BY id DESC LIMIT ?`, repoID, limit,
269 )
270 if err != nil {
271 return nil, err
272 }
273 defer rows.Close()
274 return scanBuilds(rows)
275}
276
277func ListAllBuilds(limit int) ([]*models.Build, error) {
278 rows, err := DB.Query(
279 `SELECT id, repo_id, branch, build_type, status, log_file, started_at, finished_at
280 FROM builds ORDER BY id DESC LIMIT ?`, limit,
281 )
282 if err != nil {
283 return nil, err
284 }
285 defer rows.Close()
286 return scanBuilds(rows)
287}
288
289// ListBuildsByOwner возвращает сборки только тех репозиториев, которыми владеет пользователь.
290func ListBuildsByOwner(ownerID int, limit int) ([]*models.Build, error) {
291 rows, err := DB.Query(
292 `SELECT b.id, b.repo_id, b.branch, b.build_type, b.status, b.log_file, b.started_at, b.finished_at
293 FROM builds b JOIN repositories r ON r.id = b.repo_id
294 WHERE r.owner_id = ? ORDER BY b.id DESC LIMIT ?`, ownerID, limit,
295 )
296 if err != nil {
297 return nil, err
298 }
299 defer rows.Close()
300 return scanBuilds(rows)
301}
302
303func GetBuild(id int) (*models.Build, error) {
304 b := &models.Build{}
305 err := DB.QueryRow(
306 `SELECT id, repo_id, branch, build_type, status, log_file, started_at, finished_at
307 FROM builds WHERE id = ?`, id,
308 ).Scan(&b.ID, &b.RepoID, &b.Branch, &b.BuildType, &b.Status, &b.LogFile, &b.StartedAt, &b.FinishedAt)
309 if errors.Is(err, sql.ErrNoRows) {
310 return nil, nil
311 }
312 return b, err
313}
314
315func scanBuilds(rows *sql.Rows) ([]*models.Build, error) {
316 var builds []*models.Build
317 for rows.Next() {
318 b := &models.Build{}
319 if err := rows.Scan(&b.ID, &b.RepoID, &b.Branch, &b.BuildType, &b.Status, &b.LogFile,
320 &b.StartedAt, &b.FinishedAt); err != nil {
321 return nil, err
322 }
323 builds = append(builds, b)
324 }
325 return builds, rows.Err()
326}