package repo import ( "fmt" "slices" "strings" "github.com/ditatompel/xmr-nodes/internal/database" "github.com/google/uuid" ) type ProberRepository interface { AddProber(name string) error Update(id int, name string) error Probers(q ProbersQueryParams) (Probers, error) CheckApi(key string) (Prober, error) Delete(id int) error } type ProberRepo struct { db *database.DB } type Prober struct { Id int64 `json:"id" db:"id"` Name string `json:"name" db:"name"` ApiKey uuid.UUID `json:"api_key" db:"api_key"` LastSubmitTs int64 `json:"last_submit_ts" db:"last_submit_ts"` } type ProbersQueryParams struct { Name string ApiKey string RowsPerPage int Page int SortBy string SortDirection string } type Probers struct { TotalRows int `json:"total_rows"` RowsPerPage int `json:"rows_per_page"` CurrentPage int `json:"current_page"` NextPage int `json:"next_page"` Items []*Prober `json:"items"` } func NewProberRepo(db *database.DB) ProberRepository { return &ProberRepo{db} } func (repo *ProberRepo) AddProber(name string) error { query := `INSERT INTO tbl_prober (name, api_key, last_submit_ts) VALUES (?, ?, ?)` _, err := repo.db.Exec(query, name, uuid.New(), 0) if err != nil { return err } return nil } func (repo *ProberRepo) Update(id int, name string) error { query := `UPDATE tbl_prober SET name = ? WHERE id = ?` _, err := repo.db.Exec(query, name, id) return err } func (repo *ProberRepo) Delete(id int) error { query := `DELETE FROM tbl_prober WHERE id = ?` _, err := repo.db.Exec(query, id) return err } func (repo *ProberRepo) Probers(q ProbersQueryParams) (Probers, error) { queryParams := []interface{}{} whereQueries := []string{} where := "" if q.Name != "" { whereQueries = append(whereQueries, "name LIKE ?") queryParams = append(queryParams, "%"+q.Name+"%") } if q.ApiKey != "" { whereQueries = append(whereQueries, "api_key LIKE ?") queryParams = append(queryParams, "%"+q.ApiKey+"%") } if len(whereQueries) > 0 { where = "WHERE " + strings.Join(whereQueries, " AND ") } probers := Probers{} queryTotalRows := fmt.Sprintf("SELECT COUNT(id) AS total_rows FROM tbl_prober %s", where) err := repo.db.QueryRow(queryTotalRows, queryParams...).Scan(&probers.TotalRows) if err != nil { return probers, err } queryParams = append(queryParams, q.RowsPerPage, (q.Page-1)*q.RowsPerPage) allowedSort := []string{"id", "last_submit_ts"} sortBy := "id" if slices.Contains(allowedSort, q.SortBy) { sortBy = q.SortBy } sortDirection := "DESC" if q.SortDirection == "asc" { sortDirection = "ASC" } query := fmt.Sprintf("SELECT id, name, api_key, last_submit_ts FROM tbl_prober %s ORDER BY %s %s LIMIT ? OFFSET ?", where, sortBy, sortDirection) row, err := repo.db.Query(query, queryParams...) if err != nil { return probers, err } defer row.Close() probers.RowsPerPage = q.RowsPerPage probers.CurrentPage = q.Page probers.NextPage = q.Page + 1 for row.Next() { prober := Prober{} err = row.Scan(&prober.Id, &prober.Name, &prober.ApiKey, &prober.LastSubmitTs) if err != nil { return probers, err } probers.Items = append(probers.Items, &prober) } return probers, nil } func (repo *ProberRepo) CheckApi(key string) (Prober, error) { prober := Prober{} query := `SELECT id, name, api_key, last_submit_ts FROM tbl_prober WHERE api_key = ? LIMIT 1` err := repo.db.QueryRow(query, key).Scan(&prober.Id, &prober.Name, &prober.ApiKey, &prober.LastSubmitTs) return prober, err }