Add pagination support

This commit is contained in:
froge 2025-02-14 11:14:52 +10:00
parent 4c8c363946
commit 631f908871
Signed by: froge
GPG key ID: A825E09930271BFA
3 changed files with 54 additions and 3 deletions

View file

@ -22,6 +22,7 @@ func setupRouter(env *Env, spotifyID string, spotifySecret string) *gin.Engine {
// See: https://pkg.go.dev/github.com/gin-gonic/gin#Engine.SetTrustedProxies
r.SetTrustedProxies(nil)
r.Use(spotifyAuth(spotifyID, spotifySecret))
r.Use(paginator())
r.GET("/alive", env.alive)
r.GET("/artists/:artistID", env.getArtistByID)
r.GET("/artists", env.getArtistByName)

View file

@ -6,8 +6,53 @@ import (
"gorm.io/gorm/clause"
"log/slog"
"net/http"
"strconv"
)
// Pagination helper middleware
// This just checks and inserts some default pagination values
func paginator() gin.HandlerFunc {
return func(c *gin.Context) {
queryPage := c.DefaultQuery("page", "1")
queryPageSize := c.DefaultQuery("page_size", "10")
// add some defaults here if user gives us empty values
if queryPage == ""{
queryPage = "1"
}
if queryPageSize == "" {
queryPageSize = "10"
}
page, err := strconv.Atoi(queryPage)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"Error": "Failed to convert page parameter to number"})
c.Abort()
return
}
pageSize, err := strconv.Atoi(queryPageSize)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"Error": "Failed to convert page_size parameter to number"})
c.Abort()
return
}
if page < 1 || pageSize < 1 {
page, pageSize = 1, 10
}
// Calculate the correct SQL offset for this page
offset := (page - 1) * pageSize
c.Set("page", page)
c.Set("page_size", pageSize)
c.Set("page_offset", offset)
// Process request
c.Next()
}
}
func (env *Env) alive(c *gin.Context) {
c.String(http.StatusOK, "yes!")
}
@ -70,13 +115,15 @@ func (env *Env) getArtistByName(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"Error": "name parameter was not supplied"})
return
}
pageSize := c.GetInt("page_size")
pageOffset := c.GetInt("page_offset")
// Lookup this name in the DB and return any ArtistProfile objects
// NOTE: This is case insensitive for ascii on sqlite
// NOTE: However unicode is treated case sensitive due to very difficult conversions for some languages/characters
// NOTE: In future better DBs with unicode support such as postgres should be used
var artistProfiles []ArtistProfile
dbResult := env.db.Where("name LIKE ?", fmt.Sprintf("%%%s%%", artistName)).Preload("Genres").Find(&artistProfiles)
dbResult := env.db.Where("name LIKE ?", fmt.Sprintf("%%%s%%", artistName)).Preload("Genres").Offset(pageOffset).Limit(pageSize).Find(&artistProfiles)
if dbResult.Error != nil {
slog.Error("[GOMUSIC] Failed to query local database for artist name", "Name", artistName)
c.JSON(http.StatusInternalServerError, gin.H{"Error": "Failed to lookup name"})
@ -88,7 +135,10 @@ func (env *Env) getArtistByName(c *gin.Context) {
func (env *Env) getGenres(c *gin.Context) {
var genres []Genre
dbResult := env.db.Find(&genres)
pageSize := c.GetInt("page_size")
pageOffset := c.GetInt("page_offset")
dbResult := env.db.Offset(pageOffset).Limit(pageSize).Find(&genres)
if dbResult.Error != nil {
slog.Error("[GOMUSIC] Failed to query local database for genre data")
c.JSON(http.StatusInternalServerError, gin.H{"Error": "Failed to query database for genre data"})

View file

@ -97,7 +97,7 @@ func TestGetArtistByName(t *testing.T) {
assert.Fail(t, fmt.Sprintf("Could not validate and parse JSON response: %s", err.Error()))
}
// only response should be kanye
// only response should be aesop
assert.Equal(t, "Aesop Rock", resp[0].Name)
assert.Equal(t, "2fSaE6BXtQy0x7R7v9IOmZ", resp[0].SpotifyID)
}