109 lines
3.2 KiB
Go
109 lines
3.2 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"time"
|
|
)
|
|
|
|
type CloneJobStatus string
|
|
|
|
const (
|
|
CloneJobPending CloneJobStatus = "pending"
|
|
CloneJobRunning CloneJobStatus = "running"
|
|
CloneJobCompleted CloneJobStatus = "completed"
|
|
CloneJobFailed CloneJobStatus = "failed"
|
|
)
|
|
|
|
type CloneJob struct {
|
|
ID int64
|
|
RepoID int64
|
|
Status CloneJobStatus
|
|
StartedAt *time.Time
|
|
FinishedAt *time.Time
|
|
Error *string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type CloneJobStore interface {
|
|
CreateCloneJob(ctx context.Context, repoID int64) (int64, error)
|
|
GetCloneJob(ctx context.Context, id int64) (*CloneJob, error)
|
|
GetLatestCloneJob(ctx context.Context, repoID int64) (*CloneJob, error)
|
|
HasRunningCloneJob(ctx context.Context, repoID int64) (bool, error)
|
|
MarkCloneJobStarted(ctx context.Context, id int64) error
|
|
MarkCloneJobFinished(ctx context.Context, id int64, status CloneJobStatus, errMsg *string) error
|
|
}
|
|
|
|
type SQLiteCloneJobStore struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewCloneJobStore(db *sql.DB) *SQLiteCloneJobStore {
|
|
return &SQLiteCloneJobStore{db: db}
|
|
}
|
|
|
|
func (s *SQLiteCloneJobStore) CreateCloneJob(ctx context.Context, repoID int64) (int64, error) {
|
|
res, err := s.db.ExecContext(ctx, `INSERT INTO clone_jobs (repo_id) VALUES (?)`, repoID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return res.LastInsertId()
|
|
}
|
|
|
|
func (s *SQLiteCloneJobStore) GetCloneJob(ctx context.Context, id int64) (*CloneJob, error) {
|
|
row := s.db.QueryRowContext(ctx,
|
|
`SELECT id, repo_id, status, started_at, finished_at, error, created_at FROM clone_jobs WHERE id = ?`, id)
|
|
return scanCloneJob(row)
|
|
}
|
|
|
|
func (s *SQLiteCloneJobStore) GetLatestCloneJob(ctx context.Context, repoID int64) (*CloneJob, error) {
|
|
row := s.db.QueryRowContext(ctx,
|
|
`SELECT id, repo_id, status, started_at, finished_at, error, created_at FROM clone_jobs WHERE repo_id = ? ORDER BY created_at DESC LIMIT 1`, repoID)
|
|
return scanCloneJob(row)
|
|
}
|
|
|
|
func (s *SQLiteCloneJobStore) HasRunningCloneJob(ctx context.Context, repoID int64) (bool, error) {
|
|
var count int
|
|
err := s.db.QueryRowContext(ctx,
|
|
`SELECT COUNT(*) FROM clone_jobs WHERE repo_id = ? AND status IN ('pending','running')`, repoID,
|
|
).Scan(&count)
|
|
return count > 0, err
|
|
}
|
|
|
|
func (s *SQLiteCloneJobStore) MarkCloneJobStarted(ctx context.Context, id int64) error {
|
|
_, err := s.db.ExecContext(ctx,
|
|
`UPDATE clone_jobs SET status='running', started_at=CURRENT_TIMESTAMP WHERE id=?`, id)
|
|
return err
|
|
}
|
|
|
|
func (s *SQLiteCloneJobStore) MarkCloneJobFinished(ctx context.Context, id int64, status CloneJobStatus, errMsg *string) error {
|
|
_, err := s.db.ExecContext(ctx,
|
|
`UPDATE clone_jobs SET status=?, finished_at=CURRENT_TIMESTAMP, error=? WHERE id=?`,
|
|
status, errMsg, id)
|
|
return err
|
|
}
|
|
|
|
func scanCloneJob(row *sql.Row) (*CloneJob, error) {
|
|
var j CloneJob
|
|
var startedAt, finishedAt sql.NullTime
|
|
var errMsg sql.NullString
|
|
|
|
err := row.Scan(&j.ID, &j.RepoID, &j.Status, &startedAt, &finishedAt, &errMsg, &j.CreatedAt)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, ErrNotFound
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if startedAt.Valid {
|
|
j.StartedAt = &startedAt.Time
|
|
}
|
|
if finishedAt.Valid {
|
|
j.FinishedAt = &finishedAt.Time
|
|
}
|
|
if errMsg.Valid {
|
|
j.Error = &errMsg.String
|
|
}
|
|
return &j, nil
|
|
}
|