package db import ( "context" "database/sql" "errors" "strings" ) type Label struct { ID int64 RepoID int64 Name string Color string CreatedAt string } // placeholders returns "?, ?, ?" for an IN clause of n values. func placeholders(n int) string { return strings.TrimSuffix(strings.Repeat("?, ", n), ", ") } func int64Args(ids []int64) []any { args := make([]any, len(ids)) for i, id := range ids { args[i] = id } return args } func (d *DB) ListLabels(ctx context.Context, repoID int64) ([]Label, error) { rows, err := d.QueryContext(ctx, `SELECT id, repo_id, name, color, created_at FROM labels WHERE repo_id = ? ORDER BY name ASC`, repoID) if err != nil { return nil, err } defer rows.Close() return scanLabels(rows) } func scanLabels(rows *sql.Rows) ([]Label, error) { var out []Label for rows.Next() { var l Label if err := rows.Scan(&l.ID, &l.RepoID, &l.Name, &l.Color, &l.CreatedAt); err != nil { return nil, err } out = append(out, l) } return out, rows.Err() } // LabelInRepo returns the label only when it belongs to the given repo. func (d *DB) LabelInRepo(ctx context.Context, id, repoID int64) (*Label, error) { var l Label err := d.QueryRowContext(ctx, `SELECT id, repo_id, name, color, created_at FROM labels WHERE id = ? AND repo_id = ?`, id, repoID).Scan(&l.ID, &l.RepoID, &l.Name, &l.Color, &l.CreatedAt) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, err } return &l, nil } func (d *DB) CreateLabel(ctx context.Context, repoID int64, name, color, createdAt string) error { _, err := d.ExecContext(ctx, `INSERT INTO labels (repo_id, name, color, created_at) VALUES (?, ?, ?, ?)`, repoID, name, color, createdAt) return err } func (d *DB) DeleteLabel(ctx context.Context, id int64) error { _, err := d.ExecContext(ctx, `DELETE FROM labels WHERE id = ?`, id) return err }