package main import ( "database/sql" "errors" _ "github.com/lib/pq" "log" ) type DB struct { database *sql.DB } func InitDatabase() *DB { connStr := "user=levyraati dbname=levyraati sslmode=disable" var err error database, err := sql.Open("postgres", connStr) if err != nil { log.Fatal(err) } _, err = database.Query("SELECT 1") if err != nil { log.Fatal(err) } return &DB{database} } func (db *DB) FindHashForUser(username string) (string, error) { var hash string err := db.database.QueryRow("SELECT u.password FROM public.user u WHERE lower(u.username) = lower($1)", username).Scan(&hash) return hash, err } func (db *DB) EntrySynced(userId, roundId int) (bool, error) { query := `UPDATE public.entry SET synced = true WHERE user_id = $1 AND round_id = $2` res, err := db.database.Exec(query, userId, roundId) if err != nil { return false, err } affected, err := res.RowsAffected() if err != nil { return false, err } if affected != 1 { return false, errors.New("Unknown entry ID") } return true, nil } func (db *DB) FindEntriesToSync() ([]*EntryToSync, error) { query := ` SELECT e.user_id, e.round_id, e.artist, e.title, e.spotify_url, p.article, u.username, r.section FROM public.entry e JOIN public."user" u ON u.id = e.user_id JOIN public.round r ON r.id = e.round_id JOIN public.panel p ON p.id = r.panel_id WHERE r.start < current_timestamp AND e.synced = false` rows, err := db.database.Query(query) if err != nil { log.Println("Error while reading songs from database:", err) return nil, err } defer rows.Close() var entries []*EntryToSync for rows.Next() { var ( userId, roundId int artist, title, spotifyURL, article, username, section string ) err := rows.Scan(&userId, &roundId, &artist, &title, &spotifyURL, &article, &username, §ion) if err != nil { log.Println("Error while scanning row:", err) return nil, err } entries = append(entries, &EntryToSync{userId, roundId, artist, title, spotifyURL, article, username, section}) } err = rows.Err() if err != nil { log.Println("Error after reading cursor:", err) return nil, err } return entries, nil } type EntryToSync struct { userId, roundId int artist, title, spotifyURL, article, username, section string } func (db *DB) FindAllEntries(username string) ([]*Song, error) { var songs []*Song query := ` SELECT r.id, r.section, e.artist, e.title, e.spotify_url, e.synced FROM public.round r LEFT JOIN public.entry e ON r.id = e.round_id LEFT JOIN public."user" u ON u.id = e.user_id AND lower(u.username) = lower($1) ORDER BY r.start ASC` rows, err := db.database.Query(query, username) if err != nil { return nil, err } defer rows.Close() for i := 0; rows.Next(); i++ { song := &Song{} songs = append(songs, song) var ( artist, title, url *string sync *bool ) err = rows.Scan(&songs[i].RoundID, &songs[i].RoundName, &artist, &title, &url, &sync) if err != nil { return nil, err } if artist != nil { song.Artist = *artist } if title != nil { song.Title = *title } if url != nil { song.URL = *url } if sync != nil { song.Sync = *sync } } return songs, nil } type Song struct { RoundID int RoundName string Title string Artist string URL string Sync bool } func (db *DB) UpdateEntry(username, round, artist, title, url string) (bool, error) { query := ` INSERT INTO public.entry SELECT id, $2, $3, $4, $5, false FROM public."user" u WHERE lower(u.username) = lower($1) ON CONFLICT (user_id, round_id) DO UPDATE SET artist = EXCLUDED.artist, title = EXCLUDED.title, spotify_url = EXCLUDED.spotify_url, synced = EXCLUDED.synced` res, err := db.database.Exec(query, username, round, artist, title, url) if err != nil { return false, err } affected, err := res.RowsAffected() if err != nil { return false, err } if affected != 1 { return false, nil } return true, nil } func (db *DB) FindAllPanels() ([]string, error) { query := ` SELECT name FROM public.panel` rows, err := db.database.Query(query) if err != nil { return nil, err } defer rows.Close() names := make([]string, 0) for i := 0; rows.Next(); i++ { var name string err := rows.Scan(&name) if err != nil { return nil, err } names = append(names, name) } return names, nil } func (db *DB) FindPlaylistBySection(sectionName string) ([]string, error) { query := ` SELECT pl.tracks FROM public.round_playlist pl JOIN public.round r ON pl.round_id = r.id WHERE r.section = $1` row := db.database.QueryRow(query, sectionName) var tracks []string err := row.Scan(&tracks) if err != nil { return nil, err } return tracks, nil } func (db *DB) UpdatePlaylistBySection(sectionName string, tracks []string) (bool, error) { query := ` INSERT INTO public.round_playlist pl SELECT r.id, $2 FROM public.round r WHERE r.section = $1 ON CONFLICT (pl.round_id) DO UPDATE SET tracks = EXCLUDED.tracks` res, err := db.database.Exec(query, sectionName, tracks) if err != nil { return false, err } affected, err := res.RowsAffected() if err != nil { return false, err } if affected != 1 { return false, nil } return true, nil }