1
0
dwelling-radio/internal/statistics/statistics.go

139 lines
2.6 KiB
Go

package statistics
import (
"database/sql"
"dwelling-radio/internal/radio"
"fmt"
"time"
"github.com/pkg/errors"
)
const MostListenedDateFormat string = "02 January 2006 at 15:04:05 MST"
type Statistics interface {
Add(*radio.Song) error
LastNSongs(n int64) ([]radio.Song, error)
MostNPopularSongs(n int64) ([]radio.Song, error)
MostSimultaneousListeners() (radio.Song, error)
Close() error
}
type ErrPrepareStmt struct {
Name string
}
func (e ErrPrepareStmt) Error() string {
return fmt.Sprintf("failed to prepare an SQL statement '%s'", e.Name)
}
var ErrNoSong = errors.New("no song was passed (a struct is nil or empty)")
var ErrSongNotAdded = errors.New("song was not added")
type BaseStatistics struct {
Db *sql.DB
DbDateFormat string
StmtHistoryAdd *sql.Stmt
StmtSongAdd *sql.Stmt
StmtLastNSongs *sql.Stmt
StmtMostPopularSongs *sql.Stmt
StmtMostSimultaneousListeners *sql.Stmt
}
func (s *BaseStatistics) Add(song *radio.Song) error {
if song == nil || song.Artist == "" || song.Title == "" {
return ErrNoSong
}
tx, err := s.Db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
row := tx.Stmt(s.StmtSongAdd).QueryRow(song.Artist, song.Title)
if row.Err() != nil {
return row.Err()
}
var songID int64
if err := row.Scan(&songID); err != nil {
return err
}
_, err = tx.Stmt(s.StmtHistoryAdd).Exec(song.StartAt.UTC().Format(s.DbDateFormat),
songID, song.Listeners, song.PeakListeners)
if err != nil {
return errors.Wrap(err, ErrSongNotAdded.Error())
}
tx.Commit()
return nil
}
func (s *BaseStatistics) LastNSongs(n int64) ([]radio.Song, error) {
if n == 0 {
return nil, nil
}
tx, err := s.Db.Begin()
if err != nil {
return nil, err
}
defer tx.Rollback()
rows, err := tx.Stmt(s.StmtLastNSongs).Query(n)
if err != nil {
return nil, err
}
songs := make([]radio.Song, n)
i := 0
for rows.Next() {
var startAt string
if err := rows.Scan(&startAt, &songs[i].Artist, &songs[i].Title,
&songs[i].Listeners, &songs[i].PeakListeners); err != nil {
return nil, err
}
songs[i].StartAt, err = time.Parse(s.DbDateFormat, startAt)
if err != nil {
return nil, err
}
i++
}
tx.Commit()
if i == 0 {
return nil, nil
}
lst := make([]radio.Song, i)
copy(lst, songs[:])
return lst, nil
}
func (s *BaseStatistics) MostNPopularSongs(n int64) ([]radio.Song, error) {
if n == 0 {
return nil, nil
}
return nil, nil
}
func (s *BaseStatistics) MostSimultaneousListeners() (radio.Song, error) {
return radio.Song{}, nil
}
func (s *BaseStatistics) Close() error {
return s.Db.Close()
}