package store import ( "context" "database/sql" "errors" "time" ) var ErrNotFound = errors.New("not found") type Repo struct { ID int64 `db:"id"` Name string `db:"name"` Type string `db:"type"` SourceURL string `db:"source_url"` Frozen bool `db:"frozen"` SyncMode string `db:"sync_mode"` Config string `db:"config"` CreatedAt time.Time `db:"created_at"` } type RepoStore interface { CreateRepo(ctx context.Context, r *Repo) (int64, error) ListRepos(ctx context.Context) ([]Repo, error) GetRepo(ctx context.Context, id int64) (*Repo, error) GetRepoByName(ctx context.Context, name string) (*Repo, error) DeleteRepo(ctx context.Context, id int64) error UpdateRepoSyncMode(ctx context.Context, id int64, mode string) error UpdateRepo(ctx context.Context, id int64, sourceURL, syncMode, config string) error } type SQLiteRepoStore struct { db *sql.DB } func NewRepoStore(db *sql.DB) *SQLiteRepoStore { return &SQLiteRepoStore{db: db} } func (s *SQLiteRepoStore) CreateRepo(ctx context.Context, r *Repo) (int64, error) { res, err := s.db.ExecContext(ctx, `INSERT INTO repos (name, type, source_url, frozen, sync_mode, config) VALUES (?, ?, ?, ?, ?, ?)`, r.Name, r.Type, r.SourceURL, r.Frozen, r.SyncMode, r.Config, ) if err != nil { return 0, err } return res.LastInsertId() } func (s *SQLiteRepoStore) ListRepos(ctx context.Context) ([]Repo, error) { rows, err := s.db.QueryContext(ctx, `SELECT id, name, type, source_url, frozen, sync_mode, config, created_at FROM repos ORDER BY created_at DESC`) if err != nil { return nil, err } defer rows.Close() var repos []Repo for rows.Next() { var r Repo if err := rows.Scan(&r.ID, &r.Name, &r.Type, &r.SourceURL, &r.Frozen, &r.SyncMode, &r.Config, &r.CreatedAt); err != nil { return nil, err } repos = append(repos, r) } return repos, rows.Err() } func (s *SQLiteRepoStore) GetRepo(ctx context.Context, id int64) (*Repo, error) { var r Repo err := s.db.QueryRowContext(ctx, `SELECT id, name, type, source_url, frozen, sync_mode, config, created_at FROM repos WHERE id = ?`, id, ).Scan(&r.ID, &r.Name, &r.Type, &r.SourceURL, &r.Frozen, &r.SyncMode, &r.Config, &r.CreatedAt) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } if err != nil { return nil, err } return &r, nil } func (s *SQLiteRepoStore) GetRepoByName(ctx context.Context, name string) (*Repo, error) { var r Repo err := s.db.QueryRowContext(ctx, `SELECT id, name, type, source_url, frozen, sync_mode, config, created_at FROM repos WHERE name = ?`, name, ).Scan(&r.ID, &r.Name, &r.Type, &r.SourceURL, &r.Frozen, &r.SyncMode, &r.Config, &r.CreatedAt) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } if err != nil { return nil, err } return &r, nil } func (s *SQLiteRepoStore) DeleteRepo(ctx context.Context, id int64) error { res, err := s.db.ExecContext(ctx, `DELETE FROM repos WHERE id = ?`, id) if err != nil { return err } n, err := res.RowsAffected() if err != nil { return err } if n == 0 { return ErrNotFound } return nil } func (s *SQLiteRepoStore) UpdateRepo(ctx context.Context, id int64, sourceURL, syncMode, config string) error { res, err := s.db.ExecContext(ctx, `UPDATE repos SET source_url = ?, sync_mode = ?, config = ? WHERE id = ?`, sourceURL, syncMode, config, id, ) if err != nil { return err } n, _ := res.RowsAffected() if n == 0 { return ErrNotFound } return nil } func (s *SQLiteRepoStore) UpdateRepoSyncMode(ctx context.Context, id int64, mode string) error { res, err := s.db.ExecContext(ctx, `UPDATE repos SET sync_mode = ? WHERE id = ?`, mode, id) if err != nil { return err } n, _ := res.RowsAffected() if n == 0 { return ErrNotFound } return nil }