Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions MyMusicBoxApi/database/db.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package database

import (
"context"
"database/sql"
"errors"
"fmt"
Expand Down Expand Up @@ -36,6 +37,7 @@ func NewBaseTableInstance() BaseTable {
}
}

// Base
func CreateDatabasConnectionPool() error {

// Will throw an error if its missing a method implementation from interface
Expand Down Expand Up @@ -149,6 +151,18 @@ func (base *BaseTable) NonScalarQuery(query string, params ...any) (error error)
return nil
}

func (base *BaseTable) QueryRow(query string) *sql.Row {
return base.DB.QueryRow(query)
}

func (base *BaseTable) QueryRowsContex(ctx context.Context, query string, params ...any) (*sql.Rows, error) {
return base.DB.QueryContext(ctx, query, params...)
}

func (base *BaseTable) QueryRows(query string) (*sql.Rows, error) {
return base.DB.QueryContext(context.Background(), query)
}

func ApplyMigrations() {
logging.Info("Applying migrations...")
// files will be sorted by filename
Expand Down
151 changes: 149 additions & 2 deletions MyMusicBoxApi/database/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package database

import (
"database/sql"
"fmt"
"musicboxapi/logging"
"regexp"
"testing"

"github.com/DATA-DOG/go-sqlmock"
_ "github.com/lib/pq"
"github.com/stretchr/testify/assert"
)

var Mock sqlmock.Sqlmock

func CreateMockDb() (*sql.DB, sqlmock.Sqlmock, error) {
db, mock, err := sqlmock.New()

Expand Down Expand Up @@ -119,3 +119,150 @@ func TestNonScalarQueryShouldThrowErrt(t *testing.T) {
t.Errorf("NonScalarQuery failed: %s", result)
}
}

func TestQueryRow(t *testing.T) {
// Arrange
query := "SELECT Id, Name, Online FROM data"
db, mock, err := CreateMockDb()

if err != nil {
logging.ErrorStackTrace(err)
return
}

base := NewBaseTableInstance()
base.DB = db

mock.ExpectQuery(query).
WillReturnRows(sqlmock.NewRows([]string{"Id", "Name", "Online"}).AddRow(1, "Test", false))

// Act
rows := base.QueryRow(query)

// Assert
err = mock.ExpectationsWereMet()

if err != nil {
t.Errorf("Expectations failed: %s", err)
}

var id int
var name string
var online bool

rows.Scan(&id, &name, &online)

assert.Equal(t, 1, id)
assert.Equal(t, "Test", name)
assert.Equal(t, false, online)
}

func TestQueryRows(t *testing.T) {
// Arrange
query := "SELECT Id, Name, Online FROM data"
db, mock, err := CreateMockDb()

if err != nil {
logging.ErrorStackTrace(err)
return
}

base := NewBaseTableInstance()
base.DB = db

mock.ExpectQuery(query).
WillReturnRows(sqlmock.NewRows([]string{"Id", "Name", "Online"}).AddRow(1, "Test", false).AddRow(2, "Test2", true))

// Act
rows, err := base.QueryRows(query)

assert.Nil(t, err)

defer rows.Close()

// Assert
err = mock.ExpectationsWereMet()

if err != nil {
t.Errorf("Expectations failed: %s", err)
}

type Data struct {
id int
name string
online bool
}

var datas []Data
var data Data

datas = make([]Data, 0)

for rows.Next() {
scanError := rows.Scan(&data.id, &data.name, &data.online)

if scanError != nil {
logging.Error(fmt.Sprintf("Scan error: %s", scanError.Error()))
continue
}

datas = append(datas, data)
}

assert.Equal(t, 2, len(datas))
}

func TestQueryRowsContext(t *testing.T) {
// Arrange
query := "SELECT Id, Name, Online FROM data"
db, mock, err := CreateMockDb()

if err != nil {
logging.ErrorStackTrace(err)
return
}

base := NewBaseTableInstance()
base.DB = db

mock.ExpectQuery(query).
WillReturnRows(sqlmock.NewRows([]string{"Id", "Name", "Online"}).AddRow(1, "Test", false).AddRow(2, "Test2", true))

// Act
rows, err := base.QueryRowsContex(t.Context(), query)

assert.Nil(t, err)

defer rows.Close()

// Assert
err = mock.ExpectationsWereMet()

if err != nil {
t.Errorf("Expectations failed: %s", err)
}

type Data struct {
id int
name string
online bool
}

var datas []Data
var data Data

datas = make([]Data, 0)

for rows.Next() {
scanError := rows.Scan(&data.id, &data.name, &data.online)

if scanError != nil {
logging.Error(fmt.Sprintf("Scan error: %s", scanError.Error()))
continue
}

datas = append(datas, data)
}

assert.Equal(t, 2, len(datas))
}
36 changes: 6 additions & 30 deletions MyMusicBoxApi/database/migrationtable.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,44 +21,20 @@ func NewMigrationTableInstance() *MigrationTable {
}
}

func (mt *MigrationTable) Insert(filename string, contents string) (err error) {
err = mt.NonScalarQuery("INSERT INTO Migration (filename, contents) VALUES($1, $2)", filename, contents)
func (table *MigrationTable) Insert(filename string, contents string) (err error) {
err = table.NonScalarQuery("INSERT INTO Migration (filename, contents) VALUES($1, $2)", filename, contents)
if err != nil {
logging.Error(fmt.Sprintf("Failed to insert new migration: %s", err.Error()))
}
return err
}

func (mt *MigrationTable) ApplyMigration(query string) (err error) {
transaction, err := mt.DB.Begin()

if err != nil {
logging.Error(fmt.Sprintf("Failed to begin transaction: %s", err.Error()))
logging.ErrorStackTrace(err)
return err
}

_, err = transaction.Exec(query)

if err != nil {
logging.Error(fmt.Sprintf("Failed to execute migration, rolling back: %s", err.Error()))
logging.ErrorStackTrace(err)
return err
}

err = transaction.Commit()

if err != nil {
logging.Error(fmt.Sprintf("Failed to commit migration, rolling back: %s", err.Error()))
logging.ErrorStackTrace(err)
return err
}

return err
func (table *MigrationTable) ApplyMigration(query string) (err error) {
return table.NonScalarQuery(query)
}

func (mt *MigrationTable) GetCurrentAppliedMigrationFileName() (fileName string, err error) {
row := mt.DB.QueryRow("SELECT filename FROM migration order by AppliedOn DESC LIMIT 1")
func (table *MigrationTable) GetCurrentAppliedMigrationFileName() (fileName string, err error) {
row := table.QueryRow("SELECT filename FROM migration order by AppliedOn DESC LIMIT 1")
scanError := row.Scan(&fileName)
return fileName, scanError
}
1 change: 1 addition & 0 deletions MyMusicBoxApi/database/migrationtable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func TestApplyMigration(t *testing.T) {
query := "DROP DATABSE migration"

mock.ExpectBegin()
mock.ExpectPrepare(query)
mock.ExpectExec(query).
WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectCommit()
Expand Down
24 changes: 8 additions & 16 deletions MyMusicBoxApi/database/playlistsongtable.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,12 @@ func NewPlaylistsongTableInstance() IPlaylistsongTable {
}
}

func (pt *PlaylistsongTable) FetchPlaylistSongs(ctx context.Context, playlistId int, lastKnowPosition int) (songs []models.Song, error error) {
func (table *PlaylistsongTable) FetchPlaylistSongs(ctx context.Context, playlistId int, lastKnowPosition int) (songs []models.Song, error error) {
query := `SELECT s.Id, s.Name, s.Path, s.ThumbnailPath, s.Duration, s.SourceId, s.UpdatedAt, s.CreatedAt FROM playlistsong ps
INNER JOIN song s ON s.id = ps.songid
WHERE ps.playlistid = $1 AND ps.position >= $2`

statement, err := pt.DB.Prepare(query)

if err != nil {
logging.Error(fmt.Sprintf("Prepared statement error: %s", err.Error()))
return nil, err
}
defer statement.Close()

rows, err := statement.QueryContext(ctx, playlistId, lastKnowPosition)
rows, err := table.QueryRowsContex(ctx, query, playlistId, lastKnowPosition)

if err != nil {
logging.Error(fmt.Sprintf("QueryRow error: %s", err.Error()))
Expand All @@ -63,29 +55,29 @@ func (pt *PlaylistsongTable) FetchPlaylistSongs(ctx context.Context, playlistId
return songs, nil
}

func (pt *PlaylistsongTable) InsertPlaylistSong(playlistId int, songId int) (lastInsertedId int, error error) {
func (table *PlaylistsongTable) InsertPlaylistSong(playlistId int, songId int) (lastInsertedId int, error error) {
query := `INSERT INTO PlaylistSong (SongId, PlaylistId) VALUES($1, $2) RETURNING SongId`

lastInsertedId, err := pt.InsertWithReturningId(query,
lastInsertedId, err := table.InsertWithReturningId(query,
songId,
playlistId,
)

return lastInsertedId, err
}

func (pt *PlaylistsongTable) DeleteAllPlaylistSongs(playlistId int) (error error) {
func (table *PlaylistsongTable) DeleteAllPlaylistSongs(playlistId int) (error error) {
query := `DELETE FROM PlaylistSong WHERE PlaylistId = $1`

err := pt.NonScalarQuery(query, playlistId)
err := table.NonScalarQuery(query, playlistId)

return err
}

func (pt *PlaylistsongTable) DeletePlaylistSong(playlistId int, songId int) (error error) {
func (table *PlaylistsongTable) DeletePlaylistSong(playlistId int, songId int) (error error) {
query := `DELETE FROM PlaylistSong WHERE PlaylistId = $1 and SongId = $2`

err := pt.NonScalarQuery(query, playlistId, songId)
err := table.NonScalarQuery(query, playlistId, songId)

return err
}
13 changes: 7 additions & 6 deletions MyMusicBoxApi/database/playlisttable.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ func NewPlaylistTableInstance() IPlaylistTable {
}
}

func (pt *PlaylistTable) FetchPlaylists(ctx context.Context, lastKnowPlaylistId int) (playlists []models.Playlist, error error) {
func (table *PlaylistTable) FetchPlaylists(ctx context.Context, lastKnowPlaylistId int) (playlists []models.Playlist, error error) {
query := "SELECT Id, Name, ThumbnailPath, Description, CreationDate FROM Playlist WHERE Id > $1 ORDER BY Id" // order by?

rows, err := pt.DB.QueryContext(ctx, query, lastKnowPlaylistId)
rows, err := table.QueryRowsContex(ctx, query, lastKnowPlaylistId)

if err != nil {
logging.Error(fmt.Sprintf("QueryRow error: %s", err.Error()))
logging.ErrorStackTrace(err)
return nil, err
}

Expand All @@ -53,10 +54,10 @@ func (pt *PlaylistTable) FetchPlaylists(ctx context.Context, lastKnowPlaylistId
return playlists, nil
}

func (pt *PlaylistTable) InsertPlaylist(playlist models.Playlist) (lastInsertedId int, error error) {
func (table *PlaylistTable) InsertPlaylist(playlist models.Playlist) (lastInsertedId int, error error) {
query := `INSERT INTO Playlist (name, description, thumbnailPath) VALUES ($1, $2, $3) RETURNING Id`

lastInsertedId, err := pt.InsertWithReturningId(query,
lastInsertedId, err := table.InsertWithReturningId(query,
playlist.Name,
playlist.Description,
playlist.ThumbnailPath,
Expand All @@ -65,10 +66,10 @@ func (pt *PlaylistTable) InsertPlaylist(playlist models.Playlist) (lastInsertedI
return lastInsertedId, err
}

func (pt *PlaylistTable) DeletePlaylist(playlistId int) (error error) {
func (table *PlaylistTable) DeletePlaylist(playlistId int) (error error) {
query := `DELETE FROM Playlist WHERE Id = $1`

err := pt.NonScalarQuery(query, playlistId)
err := table.NonScalarQuery(query, playlistId)

if err != nil {
logging.Error(fmt.Sprintf("Failed to delete playlist: %s", err.Error()))
Expand Down
8 changes: 4 additions & 4 deletions MyMusicBoxApi/database/songtable.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ func NewSongTableInstance() ISongTable {
}
}

func (st *SongTable) InsertSong(song *models.Song) (error error) {
func (table *SongTable) InsertSong(song *models.Song) (error error) {

query := `INSERT INTO Song (name, sourceid, path, thumbnailPath, duration) VALUES ($1, $2, $3, $4, $5) RETURNING Id`

lastInsertedId, err := st.InsertWithReturningId(query,
lastInsertedId, err := table.InsertWithReturningId(query,
song.Name,
song.SourceId,
song.Path,
Expand All @@ -47,11 +47,11 @@ func (st *SongTable) InsertSong(song *models.Song) (error error) {
return err
}

func (st *SongTable) FetchSongs(ctx context.Context) (songs []models.Song, error error) {
func (table *SongTable) FetchSongs(ctx context.Context) (songs []models.Song, error error) {

query := "SELECT Id, Name, Path, ThumbnailPath, Duration, SourceId, UpdatedAt, CreatedAt FROM Song" // order by?

rows, err := st.DB.QueryContext(ctx, query)
rows, err := table.QueryRowsContex(ctx, query)

if err != nil {
logging.Error(fmt.Sprintf("QueryRow error: %s", err.Error()))
Expand Down
Loading