From 91d1168ee995ee7191351f6bc1c1503acd7780a5 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Sun, 21 Feb 2016 19:56:01 +0100 Subject: [PATCH] Add movies --- movies/movies.go | 107 ++++++++++++++++++++++++++++++++++++++ movies/movies_test.go | 80 ++++++++++++++++++++++++++++ sql/0001_initial.down.sql | 1 + sql/0001_initial.up.sql | 18 +++++++ 4 files changed, 206 insertions(+) create mode 100644 movies/movies.go create mode 100644 movies/movies_test.go diff --git a/movies/movies.go b/movies/movies.go new file mode 100644 index 0000000..327762e --- /dev/null +++ b/movies/movies.go @@ -0,0 +1,107 @@ +package movies + +import ( + "fmt" + + "github.com/Sirupsen/logrus" + "github.com/jmoiron/sqlx" + "github.com/odwrtw/polochon/lib" + "gitlab.quimbo.fr/odwrtw/canape-sql/sqly" +) + +const ( + addMovieQuery = ` + INSERT INTO movies (imdbid, title, rating, votes, plot, tmdbid, year, originaltitle, runtime, sorttitle, tagline) + VALUES (:imdbid, :title, :rating, :votes, :plot, :tmdbid, :year, :originaltitle, :runtime, :sorttitle, :tagline) + RETURNING id;` + + getMovieQueryByImdbID = `SELECT * FROM movies WHERE imdbid=$1;` + getMovieQueryByID = `SELECT * FROM movies WHERE id=$1;` + deleteMovieQuery = `DELETE FROM movies WHERE id=$1;` +) + +var ( + // ErrNotFound error returned when show not found in database + ErrNotFound = fmt.Errorf("Not found") +) + +// Movie represents a movie +type Movie struct { + sqly.BaseModel + polochon.Movie +} + +// Get returns show details in database from id or imdbid or an error +func (m *Movie) Get(db *sqlx.DB) error { + var err error + if m.ID != "" { + err = db.QueryRowx(getMovieQueryByID, m.ID).StructScan(m) + } else if m.ImdbID != "" { + err = db.QueryRowx(getMovieQueryByImdbID, m.ImdbID).StructScan(m) + } else { + err = fmt.Errorf("Can't get movie 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 movie, first try to +// get info from db, if not exists, use polochon.Detailer +// and save informations in the database for future use +func (m *Movie) GetDetails(db *sqlx.DB, log *logrus.Entry) error { + var err error + err = m.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 = m.Movie.GetDetails(log) + if err != nil { + return err + } + + err = m.Add(db) + if err != nil { + return err + } + return nil +} + +// Add a movie in the database +func (m *Movie) Add(db *sqlx.DB) error { + var id string + r, err := db.NamedQuery(addMovieQuery, m) + if err != nil { + return err + } + for r.Next() { + r.Scan(&id) + } + m.ID = id + + return nil +} + +// Delete movie from database +func (m *Movie) Delete(db *sqlx.DB) error { + r, err := db.Exec(deleteMovieQuery, m.ID) + if err != nil { + return err + } + count, _ := r.RowsAffected() + if count != 1 { + return fmt.Errorf("Unexpected number of row deleted: %d", count) + } + return nil +} diff --git a/movies/movies_test.go b/movies/movies_test.go new file mode 100644 index 0000000..d2797b1 --- /dev/null +++ b/movies/movies_test.go @@ -0,0 +1,80 @@ +package movies + +import ( + "fmt" + "os" + "testing" + + "github.com/Sirupsen/logrus" + "github.com/jmoiron/sqlx" + _ "github.com/lib/pq" + _ "github.com/mattes/migrate/driver/postgres" + "github.com/odwrtw/polochon/lib" + "github.com/odwrtw/polochon/modules/mock" + "gitlab.quimbo.fr/odwrtw/canape-sql/sqly" +) + +var db *sqlx.DB +var pgdsn string + +func init() { + var err error + + pgdsn = os.Getenv("POSTGRES_DSN") + db, err = sqlx.Connect("postgres", pgdsn) + + if err != nil { + fmt.Printf("Unavailable PG tests:\n %v\n", err) + os.Exit(1) + } +} + +func TestIntegrate(t *testing.T) { + sqly.RunWithLastestMigration(db, pgdsn, t, func(db *sqlx.DB, t *testing.T) { + detailer, _ := mock.NewDetailer(nil) + polochonConfig := polochon.MovieConfig{ + Detailers: []polochon.Detailer{ + detailer, + }, + } + movie := Movie{ + Movie: polochon.Movie{ + MovieConfig: polochonConfig, + ImdbID: "tt12345", + }, + } + + log := logrus.NewEntry(logrus.New()) + err := movie.GetDetails(db, log) + if err != nil { + t.Fatal(err) + } + + // Get it + movie = Movie{ + Movie: polochon.Movie{ + MovieConfig: polochonConfig, + ImdbID: "tt12345", + }, + } + err = movie.Get(db) + if err != nil { + t.Fatal(err) + } + if movie.Title != fmt.Sprintf("Movie %s", movie.ImdbID) { + t.Fatalf("Unexpected movie's title: %s", movie.Title) + } + + // Delete it + err = movie.Delete(db) + if err != nil { + t.Fatal(err) + } + + // Get it again + err = movie.Get(db) + if err != ErrNotFound { + t.Fatalf("Unexpected error: %q", err) + } + }) +} diff --git a/sql/0001_initial.down.sql b/sql/0001_initial.down.sql index 9bb2c81..30a200f 100644 --- a/sql/0001_initial.down.sql +++ b/sql/0001_initial.down.sql @@ -1,3 +1,4 @@ +DROP TABLE movies; DROP TABLE shows_tracked; DROP TABLE episodes; DROP TABLE shows; diff --git a/sql/0001_initial.up.sql b/sql/0001_initial.up.sql index bcd9461..1dc0d31 100644 --- a/sql/0001_initial.up.sql +++ b/sql/0001_initial.up.sql @@ -69,3 +69,21 @@ CREATE TABLE shows_tracked ( ); CREATE INDEX ON shows_tracked (shows_id, users_id); CREATE INDEX ON shows_tracked (users_id); + +CREATE TABLE movies ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + imdbid text NOT NULL UNIQUE, + title text NOT NULL, + rating real NOT NULL, + votes integer NOT NULL, + plot text NOT NULL, + tmdbid integer NOT NULL, + year smallint NOT NULL, + originaltitle text NOT NULL, + runtime integer NOT NULL, + sorttitle text NOT NULL, + tagline text NOT NULL, + LIKE base INCLUDING DEFAULTS +); +CREATE INDEX ON movies (imdbid); +CREATE TRIGGER update_movies BEFORE UPDATE ON movies FOR EACH ROW EXECUTE PROCEDURE update_modified_column();