Bladeren bron

feat: repository layer to select shuffled song

Fela Maslen 4 jaren geleden
bovenliggende
commit
752920c098

+ 13 - 0
gmus-backend/pkg/repository/player.go

@@ -32,3 +32,16 @@ func GetPrevSong(db *sqlx.DB, nextSongId int) (prevSong *types.Song, err error)
 	}
 	return
 }
+
+func GetShuffledSong(db *sqlx.DB, currentSongId *int) (shuffledSong *types.Song, err error) {
+	shuffledSong = &types.Song{}
+
+	if currentSongId == nil {
+		err = db.QueryRowx(querySelectFirstShuffledSong).StructScan(shuffledSong)
+		return
+	}
+
+	err = db.QueryRowx(querySelectNextShuffledSong, *currentSongId).StructScan(shuffledSong)
+
+	return
+}

+ 31 - 0
gmus-backend/pkg/repository/player_test.go

@@ -147,4 +147,35 @@ var _ = Describe("Player repository", func() {
 			})
 		})
 	})
+
+	Describe("GetShuffledSong", func() {
+		It("should return a random song", func() {
+			result, _ := repository.GetShuffledSong(db, &ids[0])
+			Expect(result).NotTo(BeNil())
+			Expect(result.Id).To(BeElementOf(ids))
+		})
+
+		It("should not return the given song", func() {
+			// Iterate 10 times to be quite confident - it's not a mathematical proof
+			// but it doesn't need to be
+			for i := 0; i < 10; i++ {
+				result0, _ := repository.GetShuffledSong(db, &ids[0])
+				result4, _ := repository.GetShuffledSong(db, &ids[4])
+
+				Expect(result0).NotTo(BeNil())
+				Expect(result4).NotTo(BeNil())
+
+				Expect(result0.Id).NotTo(Equal(ids[0]))
+				Expect(result4.Id).NotTo(Equal(ids[4]))
+			}
+		})
+
+		Context("when no currentSongId is given", func() {
+			It("should return a random song", func() {
+				result, _ := repository.GetShuffledSong(db, nil)
+				Expect(result).NotTo(BeNil())
+				Expect(result.Id).To(BeElementOf(ids))
+			})
+		})
+	})
 })

+ 27 - 0
gmus-backend/pkg/repository/queries.go

@@ -175,6 +175,33 @@ order by
 limit 1
 `
 
+const querySelectFirstShuffledSong = `
+select
+	s.id
+	,s.track_number
+	,s.title
+	,s.artist
+	,s.album
+	,s.duration
+from songs s
+limit 1
+offset floor(random() * (select count(*) from songs))
+`
+
+const querySelectNextShuffledSong = `
+select
+	s.id
+	,s.track_number
+	,s.title
+	,s.artist
+	,s.album
+	,s.duration
+from songs s
+where s.id != $1
+limit 1
+offset floor(random() * greatest(0, ((select count(*) from songs) - 1)))
+`
+
 const queryInsertScanError = `
 insert into scan_errors (created_at, base_path, relative_path, error)
 values ($1, $2, $3, $4)