package repository import ( "butterfliu/internal/model" "database/sql" ) type SongRepository struct { db *sql.DB } func NewSongRepository(db *sql.DB) *SongRepository { return &SongRepository{db: db} } func (r *SongRepository) GetAll() ([]model.Song, error) { rows, err := r.db.Query(` SELECT id, title, artist_id, album_id, duration, media_file_id, COALESCE(track_number, 0), COALESCE(disc_number, 0), COALESCE(genre, '') FROM songs `) if err != nil { return nil, err } defer rows.Close() songs := []model.Song{} for rows.Next() { var song model.Song if err := rows.Scan( &song.ID, &song.Title, &song.ArtistID, &song.AlbumID, &song.Duration, &song.MediaFileID, &song.TrackNumber, &song.DiscNumber, &song.Genre, ); err != nil { return nil, err } songs = append(songs, song) } return songs, nil } func (r *SongRepository) GetAllWithDetails() ([]model.SongDetail, error) { rows, err := r.db.Query(` SELECT s.id, s.title, a.name as artist_name, al.title as album_title, s.duration, mf.path FROM songs s INNER JOIN media_files mf ON s.media_file_id = mf.id INNER JOIN artists a ON s.artist_id = a.id INNER JOIN albums al ON s.album_id = al.id ORDER BY s.title `) if err != nil { return nil, err } defer rows.Close() songs := []model.SongDetail{} for rows.Next() { var song model.SongDetail if err := rows.Scan(&song.ID, &song.Title, &song.Artist, &song.Album, &song.Duration, &song.Path); err != nil { return nil, err } songs = append(songs, song) } return songs, nil } func (r *SongRepository) GetWithDetails(id int) (model.SongDetail, error) { var song model.SongDetail err := r.db.QueryRow(` SELECT s.id, s.title, a.name as artist_name, al.title as album_title, s.duration, mf.path FROM songs s INNER JOIN media_files mf ON s.media_file_id = mf.id INNER JOIN artists a ON s.artist_id = a.id INNER JOIN albums al ON s.album_id = al.id WHERE s.id = ? `, id).Scan(&song.ID, &song.Title, &song.Artist, &song.Album, &song.Duration, &song.Path) if err != nil { return model.SongDetail{}, err } return song, nil } func (r *SongRepository) Get(id int) (model.Song, error) { var song model.Song err := r.db.QueryRow(` SELECT id, title, artist_id, album_id, duration, media_file_id, COALESCE(track_number, 0), COALESCE(disc_number, 0), COALESCE(genre, '') FROM songs WHERE id = ? `, id).Scan( &song.ID, &song.Title, &song.ArtistID, &song.AlbumID, &song.Duration, &song.MediaFileID, &song.TrackNumber, &song.DiscNumber, &song.Genre, ) if err != nil { return model.Song{}, err } return song, nil } func (r *SongRepository) HasByMediaFileID(mediaFileID int) (bool, error) { var exists int err := r.db.QueryRow("SELECT 1 FROM songs WHERE media_file_id = ? LIMIT 1", mediaFileID).Scan(&exists) if err == sql.ErrNoRows { return false, nil } if err != nil { return false, err } return true, nil } func (r *SongRepository) Create(title string, artistID, albumID, duration, mediaFileID int) (model.Song, error) { result, err := r.db.Exec( "INSERT INTO songs (title, artist_id, album_id, duration, media_file_id) VALUES (?, ?, ?, ?, ?)", title, artistID, albumID, duration, mediaFileID, ) if err != nil { return model.Song{}, err } id, err := result.LastInsertId() if err != nil { return model.Song{}, err } return model.Song{ ID: int(id), Title: title, ArtistID: artistID, AlbumID: albumID, Duration: duration, MediaFileID: mediaFileID, }, nil }