package shows import ( "fmt" "gitlab.quimbo.fr/odwrtw/canape-sql/sqly" "gitlab.quimbo.fr/odwrtw/canape-sql/users" "github.com/Sirupsen/logrus" "github.com/jmoiron/sqlx" "github.com/odwrtw/polochon/lib" ) const ( addShowQuery = ` INSERT INTO shows (imdbid, title, rating, plot, tvdbid, year, firstaired) VALUES (:imdbid, :title, :rating, :plot, :tvdbid, :year, :firstaired) RETURNING id;` getShowQueryByImdbID = `SELECT * FROM shows WHERE imdbid=$1;` getShowQueryByID = `SELECT * FROM shows WHERE id=$1;` deleteShowQuery = `DELETE FROM shows WHERE id=$1;` addEpisodeQuery = ` INSERT INTO episodes (shows_id, title, season, episode, tvdbid, aired, plot, runtime, rating, imdbid) VALUES (:showid, :title, :season, :episode, :tvdbid, :aired, :plot, :runtime, :rating, :episodeimdbid) RETURNING id;` getEpisodesQuery = ` SELECT title, season, episode, tvdbid, aired, plot, runtime, rating, imdbid AS episodeimdbid, shows_id AS showid FROM episodes WHERE shows_id=$1;` getShowWithUserQueryByImdbID = ` SELECT shows.id, shows.imdbid, shows.title, shows.rating, shows.plot, shows.tvdbid, shows.year, shows.firstaired, COALESCE(shows_tracked.season,0) AS trackedseason, COALESCE(shows_tracked.episode,0) AS trackedepisode FROM shows LEFT JOIN shows_tracked ON shows.id=shows_tracked.shows_id AND shows_tracked.users_id=$2 WHERE shows.imdbid=$1;` getShowWithUserQueryByID = ` SELECT shows.id, shows.imdbid, shows.title, shows.rating, shows.plot, shows.tvdbid, shows.year, shows.firstaired, COALESCE(shows_tracked.season,0) AS trackedseason, COALESCE(shows_tracked.episode,0) AS trackedepisode FROM shows LEFT JOIN shows_tracked ON shows.id=shows_tracked.shows_id AND shows_tracked.users_id=$2 WHERE shows.id=$1;` ) var ( // ErrNotFound error returned when show not found in database ErrNotFound = fmt.Errorf("Not found") ) // Show represents a show type Show struct { sqly.BaseModel polochon.Show Episodes []*Episode TrackedSeason int TrackedEpisode int } // New returns a new Show with a polochon ShowConfig func New(conf polochon.ShowConfig) *Show { return &Show{Show: polochon.Show{ShowConfig: conf}} } // Get returns show details in database from id or imdbid or an error func (s *Show) Get(db *sqlx.DB) error { var err error if s.ID != "" { err = db.QueryRowx(getShowQueryByID, s.ID).StructScan(s) } else if s.ImdbID != "" { err = db.QueryRowx(getShowQueryByImdbID, s.ImdbID).StructScan(s) } else { err = fmt.Errorf("Can't get show details, you have to specify an ID or ImdbID") } if err != nil { if err.Error() == "sql: no rows in result set" { return ErrNotFound } return err } return nil } // GetAsUser returns a show with user info like tracked func (s *Show) GetAsUser(db *sqlx.DB, user *users.User) error { var err error if s.ID != "" { err = db.QueryRowx(getShowWithUserQueryByID, s.ID, user.ID).StructScan(s) } else if s.ImdbID != "" { err = db.QueryRowx(getShowWithUserQueryByImdbID, s.ImdbID, user.ID).StructScan(s) } else { err = fmt.Errorf("Can't get show details, you have to specify an ID or ImdbID") } if err != nil { if err.Error() == "sql: no rows in result set" { return ErrNotFound } return err } return nil } // GetDetails retrieves details for the show, first try to // get info from db, if not exists, use polochon.Detailer // and save informations in the database for future use func (s *Show) GetDetails(db *sqlx.DB, log *logrus.Entry) error { var err error err = s.Get(db) if err == nil { // found ok return nil } if err != ErrNotFound { // Unexpected error return err } // so we got ErrNotFound so GetDetails from a detailer err = s.Show.GetDetails(log) if err != nil { return err } s.Episodes = []*Episode{} for _, pe := range s.Show.Episodes { s.Episodes = append(s.Episodes, &Episode{ShowEpisode: *pe}) } err = s.Add(db) if err != nil { return err } return nil } // GetDetailsAsUser like GetDetails but with User context func (s *Show) GetDetailsAsUser(db *sqlx.DB, user *users.User, log *logrus.Entry) error { var err error err = s.GetAsUser(db, user) if err == nil { // found ok return nil } if err != ErrNotFound { // Unexpected error return err } err = s.Show.GetDetails(log) if err != nil { return err } s.Episodes = []*Episode{} for _, pe := range s.Show.Episodes { s.Episodes = append(s.Episodes, &Episode{ShowEpisode: *pe}) } err = s.Add(db) if err != nil { return err } return nil } // IsTracked returns true if the show is tracked use this function // after retrieve the show with GetAsUser or other *AsUser functions func (s *Show) IsTracked() bool { if s.TrackedSeason != 0 && s.TrackedEpisode != 0 { return true } return false } // Add a show in the database func (s *Show) Add(db *sqlx.DB) error { var id string r, err := db.NamedQuery(addShowQuery, s) if err != nil { return err } for r.Next() { r.Scan(&id) } s.ID = id for _, e := range s.Episodes { e.ShowID = s.ID err = e.Add(db) if err != nil { return err } } return nil } // Delete show from database func (s *Show) Delete(db *sqlx.DB) error { r, err := db.Exec(deleteShowQuery, s.ID) if err != nil { return err } count, _ := r.RowsAffected() if count != 1 { return fmt.Errorf("Unexpected number of row deleted: %d", count) } return nil } // GetEpisodes from database func (s *Show) GetEpisodes(db *sqlx.DB) error { // When retrive episode's info from database populate the s.Episodes member // and not s.Show.Episodes s.Episodes = []*Episode{} err := db.Select(&s.Episodes, getEpisodesQuery, s.ID) if err != nil { return err } return nil } // Episode represents an episode type Episode struct { sqly.BaseModel polochon.ShowEpisode ShowID string } // Add episode to the database func (e *Episode) Add(db *sqlx.DB) error { var id string r, err := db.NamedQuery(addEpisodeQuery, e) if err != nil { return err } for r.Next() { r.Scan(&id) } e.ID = id return nil }