Write tests for searching
This commit is contained in:
parent
0ae34829e2
commit
adfcf33e79
|
@ -0,0 +1,73 @@
|
|||
package actions
|
||||
|
||||
import (
|
||||
"github.com/photoview/photoview/api/graphql/models"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
func Search(db *gorm.DB, query string, userID int, _limitMedia *int, _limitAlbums *int) (*models.SearchResult, error) {
|
||||
limitMedia := 10
|
||||
limitAlbums := 10
|
||||
|
||||
if _limitMedia != nil {
|
||||
limitMedia = *_limitMedia
|
||||
}
|
||||
|
||||
if _limitAlbums != nil {
|
||||
limitAlbums = *_limitAlbums
|
||||
}
|
||||
|
||||
wildQuery := "%" + query + "%"
|
||||
|
||||
var media []*models.Media
|
||||
|
||||
userSubquery := db.Table("user_albums").Where("user_id = ?", userID)
|
||||
if db.Dialector.Name() == "postgres" {
|
||||
userSubquery = userSubquery.Where("album_id = \"Album\".id")
|
||||
} else {
|
||||
userSubquery = userSubquery.Where("album_id = Album.id")
|
||||
}
|
||||
|
||||
err := db.Joins("Album").
|
||||
Where("EXISTS (?)", userSubquery).
|
||||
Where("media.title LIKE ? OR media.path LIKE ?", wildQuery, wildQuery).
|
||||
Clauses(clause.OrderBy{
|
||||
Expression: clause.Expr{
|
||||
SQL: "(CASE WHEN media.title LIKE ? THEN 2 WHEN media.path LIKE ? THEN 1 END) DESC",
|
||||
Vars: []interface{}{wildQuery, wildQuery},
|
||||
WithoutParentheses: true},
|
||||
}).
|
||||
Limit(limitMedia).Find(&media).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "searching media")
|
||||
}
|
||||
|
||||
var albums []*models.Album
|
||||
|
||||
err = db.
|
||||
Where("EXISTS (?)", db.Table("user_albums").Where("user_id = ?", userID).Where("album_id = albums.id")).
|
||||
Where("albums.title LIKE ? OR albums.path LIKE ?", wildQuery, wildQuery).
|
||||
Clauses(clause.OrderBy{
|
||||
Expression: clause.Expr{
|
||||
SQL: "(CASE WHEN albums.title LIKE ? THEN 2 WHEN albums.path LIKE ? THEN 1 END) DESC",
|
||||
Vars: []interface{}{wildQuery, wildQuery},
|
||||
WithoutParentheses: true},
|
||||
}).
|
||||
Limit(limitAlbums).
|
||||
Find(&albums).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "searching albums")
|
||||
}
|
||||
|
||||
result := models.SearchResult{
|
||||
Query: query,
|
||||
Media: media,
|
||||
Albums: albums,
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package actions_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/photoview/photoview/api/graphql/models"
|
||||
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||
"github.com/photoview/photoview/api/test_utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSearch(t *testing.T) {
|
||||
db := test_utils.DatabaseTest(t)
|
||||
|
||||
user, err := models.RegisterUser(db, "user", nil, true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
rootAlbum := models.Album{
|
||||
Title: "root_album",
|
||||
Path: "/media/",
|
||||
}
|
||||
|
||||
assert.NoError(t, db.Create(&rootAlbum).Error)
|
||||
assert.NoError(t, db.Model(&rootAlbum).Association("Owners").Append(user))
|
||||
|
||||
type Result struct {
|
||||
ID int
|
||||
UserID int
|
||||
AlbumID int
|
||||
}
|
||||
|
||||
mediaTitles := []string{
|
||||
"SOME_IMAGE.jpg",
|
||||
"imageA.jpg",
|
||||
"imageB.jpg",
|
||||
"imageC.jpg",
|
||||
"movie.mp4",
|
||||
"person.png",
|
||||
"123.png",
|
||||
"ABC.gif",
|
||||
"dog.mov",
|
||||
"cat.mov",
|
||||
"IMG_3255.JPG",
|
||||
"IMG_5532.JPG",
|
||||
"IMG_5533.JPG",
|
||||
"IMG_5534.JPG",
|
||||
"IMG_5535.JPG",
|
||||
"IMG_5536.JPG",
|
||||
}
|
||||
|
||||
for _, mediaTitle := range mediaTitles {
|
||||
image := models.Media{
|
||||
Title: mediaTitle,
|
||||
Path: fmt.Sprintf("/media/%s", mediaTitle),
|
||||
AlbumID: rootAlbum.ID,
|
||||
}
|
||||
assert.NoError(t, db.Create(&image).Error)
|
||||
}
|
||||
|
||||
type SearchTest = struct {
|
||||
query string
|
||||
userID int
|
||||
limitMedia *int
|
||||
limitAlbum *int
|
||||
|
||||
expectedMediaCount int
|
||||
expectedAlbumCount int
|
||||
}
|
||||
|
||||
searchTests := []SearchTest{
|
||||
{
|
||||
query: "image",
|
||||
userID: user.ID,
|
||||
expectedMediaCount: 4,
|
||||
expectedAlbumCount: 0,
|
||||
},
|
||||
{
|
||||
query: "g",
|
||||
userID: user.ID,
|
||||
expectedMediaCount: 10,
|
||||
expectedAlbumCount: 0,
|
||||
},
|
||||
{
|
||||
query: "media",
|
||||
userID: user.ID,
|
||||
expectedMediaCount: 10,
|
||||
expectedAlbumCount: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range searchTests {
|
||||
t.Run(fmt.Sprintf("Search query: '%s'", test.query), func(t *testing.T) {
|
||||
result, err := actions.Search(db, test.query, test.userID, test.limitMedia, test.limitAlbum)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, result.Query, test.query)
|
||||
assert.Len(t, result.Albums, test.expectedAlbumCount)
|
||||
assert.Len(t, result.Media, test.expectedMediaCount)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -71,7 +71,7 @@ type MediaURL struct {
|
|||
Model
|
||||
MediaID int `gorm:"not null;index"`
|
||||
Media *Media `gorm:"constraint:OnDelete:CASCADE;"`
|
||||
MediaName string `gorm:"not null"`
|
||||
MediaName string `gorm:"not null;index"`
|
||||
Width int `gorm:"not null"`
|
||||
Height int `gorm:"not null"`
|
||||
Purpose MediaPurpose `gorm:"not null;index"`
|
||||
|
|
|
@ -4,78 +4,16 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/photoview/photoview/api/graphql/auth"
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm/clause"
|
||||
"github.com/photoview/photoview/api/graphql/models/actions"
|
||||
|
||||
"github.com/photoview/photoview/api/graphql/models"
|
||||
)
|
||||
|
||||
func (r *Resolver) Search(ctx context.Context, query string, _limitMedia *int, _limitAlbums *int) (*models.SearchResult, error) {
|
||||
func (r *Resolver) Search(ctx context.Context, query string, limitMedia *int, limitAlbums *int) (*models.SearchResult, error) {
|
||||
user := auth.UserFromContext(ctx)
|
||||
if user == nil {
|
||||
return nil, auth.ErrUnauthorized
|
||||
}
|
||||
|
||||
limitMedia := 10
|
||||
limitAlbums := 10
|
||||
|
||||
if _limitMedia != nil {
|
||||
limitMedia = *_limitMedia
|
||||
}
|
||||
|
||||
if _limitAlbums != nil {
|
||||
limitAlbums = *_limitAlbums
|
||||
}
|
||||
|
||||
wildQuery := "%" + query + "%"
|
||||
|
||||
var media []*models.Media
|
||||
|
||||
userSubquery := r.Database.Table("user_albums").Where("user_id = ?", user.ID)
|
||||
if r.Database.Dialector.Name() == "postgres" {
|
||||
userSubquery = userSubquery.Where("album_id = \"Album\".id")
|
||||
} else {
|
||||
userSubquery = userSubquery.Where("album_id = Album.id")
|
||||
}
|
||||
|
||||
err := r.Database.Joins("Album").
|
||||
Where("EXISTS (?)", userSubquery).
|
||||
Where("media.title LIKE ? OR media.path LIKE ?", wildQuery, wildQuery).
|
||||
Clauses(clause.OrderBy{
|
||||
Expression: clause.Expr{
|
||||
SQL: "(CASE WHEN media.title LIKE ? THEN 2 WHEN media.path LIKE ? THEN 1 END) DESC",
|
||||
Vars: []interface{}{wildQuery, wildQuery},
|
||||
WithoutParentheses: true},
|
||||
}).
|
||||
Limit(limitMedia).Find(&media).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "searching media")
|
||||
}
|
||||
|
||||
var albums []*models.Album
|
||||
|
||||
err = r.Database.
|
||||
Where("EXISTS (?)", r.Database.Table("user_albums").Where("user_id = ?", user.ID).Where("album_id = albums.id")).
|
||||
Where("albums.title LIKE ? OR albums.path LIKE ?", wildQuery, wildQuery).
|
||||
Clauses(clause.OrderBy{
|
||||
Expression: clause.Expr{
|
||||
SQL: "(CASE WHEN albums.title LIKE ? THEN 2 WHEN albums.path LIKE ? THEN 1 END) DESC",
|
||||
Vars: []interface{}{wildQuery, wildQuery},
|
||||
WithoutParentheses: true},
|
||||
}).
|
||||
Limit(limitAlbums).
|
||||
Find(&albums).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "searching albums")
|
||||
}
|
||||
|
||||
result := models.SearchResult{
|
||||
Query: query,
|
||||
Media: media,
|
||||
Albums: albums,
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
return actions.Search(r.Database, query, user.ID, limitMedia, limitAlbums)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue