package models import ( "database/sql" "fmt" "time" "github.com/jmoiron/sqlx" polochon "github.com/odwrtw/polochon/lib" "github.com/sirupsen/logrus" ) const ( upsertEpisodeQuery = ` INSERT INTO episodes (show_imdb_id, show_tvdb_id, title, season, episode, tvdb_id, aired, plot, runtime, rating, imdb_id) VALUES (:show_imdb_id, :show_tvdb_id, :title, :season, :episode, :tvdb_id, :aired, :plot, :runtime, :rating, :imdb_id) ON CONFLICT (show_imdb_id, season, episode) DO UPDATE SET show_imdb_id=:show_imdb_id, show_tvdb_id=:show_tvdb_id, title=:title, season=:season, episode=:episode, tvdb_id=:tvdb_id, aired=:aired, plot=:plot, runtime=:runtime, rating=:rating, imdb_id=:imdb_id RETURNING id;` getEpisodesQuery = ` SELECT * FROM episodes WHERE show_imdb_id=$1;` getEpisodeQuery = ` SELECT s.title show_title, e.* FROM shows s , episodes e WHERE s.imdb_id = e.show_imdb_id AND e.show_imdb_id=$1 AND e.season=$2 AND e.episode=$3;` ) // episodeDB represents the Episode in the DB type episodeDB struct { ID string `db:"id"` TvdbID int `db:"tvdb_id"` ImdbID string `db:"imdb_id"` ShowImdbID string `db:"show_imdb_id"` ShowTvdbID int `db:"show_tvdb_id"` ShowTitle string `db:"show_title"` Season int `db:"season"` Episode int `db:"episode"` Title string `db:"title"` Rating float32 `db:"rating"` Plot string `db:"plot"` Thumb string `db:"thumb"` Runtime int `db:"runtime"` Aired string `db:"aired"` Created time.Time `db:"created_at"` Updated time.Time `db:"updated_at"` } // getEpisodeDB returns an episodeDB from a polochon.ShowEpisode func getEpisodeDB(db *sqlx.DB, episode *polochon.ShowEpisode) (*episodeDB, error) { var episodeDB episodeDB err := db.QueryRowx(getEpisodeQuery, episode.ShowImdbID, episode.Season, episode.Episode).StructScan(&episodeDB) if err != nil { return &episodeDB, err } return &episodeDB, nil } // NewEpisodeFromDB returns a new polochon ShowEpisode from an episodeDB func NewEpisodeFromDB(eDB *episodeDB) *polochon.ShowEpisode { pEpisode := polochon.ShowEpisode{} FillEpisodeFromDB(eDB, &pEpisode) return &pEpisode } // FillEpisodeFromDB fills a ShowEpisode from an episodeDB func FillEpisodeFromDB(eDB *episodeDB, pEpisode *polochon.ShowEpisode) { // Keep the data that never changes but only if we have it updateIfNonEmpty(&pEpisode.EpisodeImdbID, eDB.ImdbID) updateIfNonEmpty(&pEpisode.ShowImdbID, eDB.ShowImdbID) updateIfNonEmpty(&pEpisode.ShowTitle, eDB.ShowTitle) updateIfNonZeroInt(&pEpisode.TvdbID, eDB.TvdbID) updateIfNonZeroInt(&pEpisode.ShowTvdbID, eDB.ShowTvdbID) pEpisode.Season = eDB.Season pEpisode.Episode = eDB.Episode pEpisode.Title = eDB.Title pEpisode.Rating = eDB.Rating pEpisode.Plot = eDB.Plot pEpisode.Runtime = eDB.Runtime pEpisode.Aired = eDB.Aired pEpisode.Thumb = imageURL(fmt.Sprintf( "shows/%s/%d-%d.jpg", eDB.ShowImdbID, eDB.Season, eDB.Episode, )) } // GetEpisode gets an episode and fills the polochon episode func GetEpisode(db *sqlx.DB, pEpisode *polochon.ShowEpisode) error { episodeDB, err := getEpisodeDB(db, pEpisode) if err != nil { return err } FillEpisodeFromDB(episodeDB, pEpisode) return nil } // GetEpisodes gets show's episodes and fills the polochon show func GetEpisodes(db *sqlx.DB, pShow *polochon.Show, log *logrus.Entry) error { // Get the episodes var episodesDB = []*episodeDB{} err := db.Select(&episodesDB, getEpisodesQuery, pShow.ImdbID) if err != nil { return err } if len(episodesDB) == 0 { log.Debug("got no episodes") return nil } log.Debugf("got %d episodes", len(episodesDB)) for _, episodeDB := range episodesDB { episode := NewEpisodeFromDB(episodeDB) pShow.Episodes = append(pShow.Episodes, episode) } return nil } // updateFromEpisode will update the episodeDB from a ShowEpisode // We just make sure to never update the episodeDB with empty value func (e *episodeDB) updateFromEpisode(showEpisode *polochon.ShowEpisode) { updateIfNonEmpty(&e.ImdbID, showEpisode.EpisodeImdbID) updateIfNonEmpty(&e.ShowImdbID, showEpisode.ShowImdbID) updateIfNonEmpty(&e.Title, showEpisode.Title) updateIfNonEmpty(&e.Plot, showEpisode.Plot) updateIfNonEmpty(&e.Thumb, showEpisode.Thumb) updateIfNonEmpty(&e.Aired, showEpisode.Aired) updateIfNonZeroInt(&e.TvdbID, showEpisode.TvdbID) updateIfNonZeroInt(&e.ShowTvdbID, showEpisode.ShowTvdbID) updateIfNonZeroInt(&e.Season, showEpisode.Season) updateIfNonZeroInt(&e.Episode, showEpisode.Episode) updateIfNonZeroInt(&e.Runtime, showEpisode.Runtime) updateIfNonZeroFloat(&e.Rating, showEpisode.Rating) } // UpsertEpisode upserts the episode func UpsertEpisode(db *sqlx.DB, showEpisode *polochon.ShowEpisode) error { // Try to get the episode episodeDB, err := getEpisodeDB(db, showEpisode) // Return only if the error is != sql.ErrNoRows if err != nil { if err != sql.ErrNoRows { return err } } // Update the episodeDB from the showEpisode we have episodeDB.updateFromEpisode(showEpisode) r, err := db.NamedQuery(upsertEpisodeQuery, episodeDB) if err != nil { return err } defer r.Close() return nil }