fix(db): Include items with no annotation for starred=false, handle has_rating=false (#4921)
* fix(db): Include items with no annotation for starred=false, handle has_rating=false * hardcode starred instead * test: ensure albums and artists without annotations are included in starred and has_rating filters Signed-off-by: Deluan <deluan@navidrome.org> * refactor: replace starred and has_rating filters with annotationBoolFilter for consistency Signed-off-by: Deluan <deluan@navidrome.org> * fix: update annotationBoolFilter to handle boolean values correctly in SQL expressions Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org> Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
@@ -119,8 +119,8 @@ var albumFilters = sync.OnceValue(func() map[string]filterFunc {
|
|||||||
"artist_id": artistFilter,
|
"artist_id": artistFilter,
|
||||||
"year": yearFilter,
|
"year": yearFilter,
|
||||||
"recently_played": recentlyPlayedFilter,
|
"recently_played": recentlyPlayedFilter,
|
||||||
"starred": booleanFilter,
|
"starred": annotationBoolFilter("starred"),
|
||||||
"has_rating": hasRatingFilter,
|
"has_rating": annotationBoolFilter("rating"),
|
||||||
"missing": booleanFilter,
|
"missing": booleanFilter,
|
||||||
"genre_id": tagIDFilter,
|
"genre_id": tagIDFilter,
|
||||||
"role_total_id": allRolesFilter,
|
"role_total_id": allRolesFilter,
|
||||||
@@ -149,10 +149,6 @@ func recentlyPlayedFilter(string, interface{}) Sqlizer {
|
|||||||
return Gt{"play_count": 0}
|
return Gt{"play_count": 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasRatingFilter(string, interface{}) Sqlizer {
|
|
||||||
return Gt{"rating": 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func yearFilter(_ string, value interface{}) Sqlizer {
|
func yearFilter(_ string, value interface{}) Sqlizer {
|
||||||
return Or{
|
return Or{
|
||||||
And{
|
And{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
"github.com/Masterminds/squirrel"
|
||||||
|
"github.com/deluan/rest"
|
||||||
"github.com/navidrome/navidrome/conf"
|
"github.com/navidrome/navidrome/conf"
|
||||||
"github.com/navidrome/navidrome/consts"
|
"github.com/navidrome/navidrome/consts"
|
||||||
"github.com/navidrome/navidrome/model"
|
"github.com/navidrome/navidrome/model"
|
||||||
@@ -77,6 +78,82 @@ var _ = Describe("AlbumRepository", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("Filters", func() {
|
||||||
|
var albumWithoutAnnotation model.Album
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
// Create album without any annotation (no star, no rating)
|
||||||
|
albumWithoutAnnotation = model.Album{ID: "no-annotation-album", Name: "No Annotation", LibraryID: 1}
|
||||||
|
Expect(albumRepo.Put(&albumWithoutAnnotation)).To(Succeed())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
_, _ = albumRepo.executeSQL(squirrel.Delete("album").Where(squirrel.Eq{"id": albumWithoutAnnotation.ID}))
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("starred", func() {
|
||||||
|
It("false includes items without annotations", func() {
|
||||||
|
res, err := albumRepo.ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"starred": "false"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
albums := res.(model.Albums)
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, a := range albums {
|
||||||
|
if a.ID == albumWithoutAnnotation.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "Album without annotation should be included in starred=false filter")
|
||||||
|
})
|
||||||
|
|
||||||
|
It("true excludes items without annotations", func() {
|
||||||
|
res, err := albumRepo.ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"starred": "true"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
albums := res.(model.Albums)
|
||||||
|
|
||||||
|
for _, a := range albums {
|
||||||
|
Expect(a.ID).ToNot(Equal(albumWithoutAnnotation.ID))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("has_rating", func() {
|
||||||
|
It("false includes items without annotations", func() {
|
||||||
|
res, err := albumRepo.ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"has_rating": "false"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
albums := res.(model.Albums)
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, a := range albums {
|
||||||
|
if a.ID == albumWithoutAnnotation.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "Album without annotation should be included in has_rating=false filter")
|
||||||
|
})
|
||||||
|
|
||||||
|
It("true excludes items without annotations", func() {
|
||||||
|
res, err := albumRepo.ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"has_rating": "true"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
albums := res.(model.Albums)
|
||||||
|
|
||||||
|
for _, a := range albums {
|
||||||
|
Expect(a.ID).ToNot(Equal(albumWithoutAnnotation.ID))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Describe("Album.PlayCount", func() {
|
Describe("Album.PlayCount", func() {
|
||||||
// Implementation is in withAnnotation() method
|
// Implementation is in withAnnotation() method
|
||||||
DescribeTable("normalizes play count when AlbumPlayCountMode is absolute",
|
DescribeTable("normalizes play count when AlbumPlayCountMode is absolute",
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ func NewArtistRepository(ctx context.Context, db dbx.Builder) model.ArtistReposi
|
|||||||
r.registerModel(&model.Artist{}, map[string]filterFunc{
|
r.registerModel(&model.Artist{}, map[string]filterFunc{
|
||||||
"id": idFilter(r.tableName),
|
"id": idFilter(r.tableName),
|
||||||
"name": fullTextFilter(r.tableName, "mbz_artist_id"),
|
"name": fullTextFilter(r.tableName, "mbz_artist_id"),
|
||||||
"starred": booleanFilter,
|
"starred": annotationBoolFilter("starred"),
|
||||||
"role": roleFilter,
|
"role": roleFilter,
|
||||||
"missing": booleanFilter,
|
"missing": booleanFilter,
|
||||||
"library_id": artistLibraryIdFilter,
|
"library_id": artistLibraryIdFilter,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
"github.com/Masterminds/squirrel"
|
||||||
|
"github.com/deluan/rest"
|
||||||
"github.com/navidrome/navidrome/conf"
|
"github.com/navidrome/navidrome/conf"
|
||||||
"github.com/navidrome/navidrome/conf/configtest"
|
"github.com/navidrome/navidrome/conf/configtest"
|
||||||
"github.com/navidrome/navidrome/model"
|
"github.com/navidrome/navidrome/model"
|
||||||
@@ -386,6 +387,54 @@ var _ = Describe("ArtistRepository", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Describe("Filters", func() {
|
||||||
|
var artistWithoutAnnotation model.Artist
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
// Create artist without any annotation
|
||||||
|
artistWithoutAnnotation = model.Artist{ID: "no-annotation-artist", Name: "No Annotation Artist"}
|
||||||
|
err := createArtistWithLibrary(repo, &artistWithoutAnnotation, 1)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
if raw, ok := repo.(*artistRepository); ok {
|
||||||
|
_, _ = raw.executeSQL(squirrel.Delete(raw.tableName).Where(squirrel.Eq{"id": artistWithoutAnnotation.ID}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("starred", func() {
|
||||||
|
It("false includes items without annotations", func() {
|
||||||
|
res, err := repo.(model.ResourceRepository).ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"starred": "false"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
artists := res.(model.Artists)
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, a := range artists {
|
||||||
|
if a.ID == artistWithoutAnnotation.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "Artist without annotation should be included in starred=false filter")
|
||||||
|
})
|
||||||
|
|
||||||
|
It("true excludes items without annotations", func() {
|
||||||
|
res, err := repo.(model.ResourceRepository).ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"starred": "true"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
artists := res.(model.Artists)
|
||||||
|
|
||||||
|
for _, a := range artists {
|
||||||
|
Expect(a.ID).ToNot(Equal(artistWithoutAnnotation.ID))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Describe("MBID and Text Search", func() {
|
Describe("MBID and Text Search", func() {
|
||||||
var lib2 model.Library
|
var lib2 model.Library
|
||||||
var lr model.LibraryRepository
|
var lr model.LibraryRepository
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ var mediaFileFilter = sync.OnceValue(func() map[string]filterFunc {
|
|||||||
filters := map[string]filterFunc{
|
filters := map[string]filterFunc{
|
||||||
"id": idFilter("media_file"),
|
"id": idFilter("media_file"),
|
||||||
"title": fullTextFilter("media_file", "mbz_recording_id", "mbz_release_track_id"),
|
"title": fullTextFilter("media_file", "mbz_recording_id", "mbz_release_track_id"),
|
||||||
"starred": booleanFilter,
|
"starred": annotationBoolFilter("starred"),
|
||||||
"genre_id": tagIDFilter,
|
"genre_id": tagIDFilter,
|
||||||
"missing": booleanFilter,
|
"missing": booleanFilter,
|
||||||
"artists_id": artistFilter,
|
"artists_id": artistFilter,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Masterminds/squirrel"
|
"github.com/Masterminds/squirrel"
|
||||||
|
"github.com/deluan/rest"
|
||||||
"github.com/navidrome/navidrome/conf"
|
"github.com/navidrome/navidrome/conf"
|
||||||
"github.com/navidrome/navidrome/conf/configtest"
|
"github.com/navidrome/navidrome/conf/configtest"
|
||||||
"github.com/navidrome/navidrome/log"
|
"github.com/navidrome/navidrome/log"
|
||||||
@@ -417,6 +418,50 @@ var _ = Describe("MediaRepository", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("Filters", func() {
|
||||||
|
var mfWithoutAnnotation model.MediaFile
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
mfWithoutAnnotation = model.MediaFile{ID: "no-annotation-file", LibraryID: 1, Path: "/test/no-annotation.mp3", Title: "No Annotation"}
|
||||||
|
Expect(mr.Put(&mfWithoutAnnotation)).To(Succeed())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
_ = mr.Delete(mfWithoutAnnotation.ID)
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("starred", func() {
|
||||||
|
It("false includes items without annotations", func() {
|
||||||
|
res, err := mr.(model.ResourceRepository).ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"starred": "false"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
files := res.(model.MediaFiles)
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, f := range files {
|
||||||
|
if f.ID == mfWithoutAnnotation.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "MediaFile without annotation should be included in starred=false filter")
|
||||||
|
})
|
||||||
|
|
||||||
|
It("true excludes items without annotations", func() {
|
||||||
|
res, err := mr.(model.ResourceRepository).ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"starred": "true"},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
files := res.(model.MediaFiles)
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
Expect(f.ID).ToNot(Equal(mfWithoutAnnotation.ID))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Describe("Search", func() {
|
Describe("Search", func() {
|
||||||
Context("text search", func() {
|
Context("text search", func() {
|
||||||
It("finds media files by title", func() {
|
It("finds media files by title", func() {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "github.com/Masterminds/squirrel"
|
. "github.com/Masterminds/squirrel"
|
||||||
@@ -43,6 +44,19 @@ func (r sqlRepository) withAnnotation(query SelectBuilder, idField string) Selec
|
|||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func annotationBoolFilter(field string) func(string, any) Sqlizer {
|
||||||
|
return func(_ string, value any) Sqlizer {
|
||||||
|
v, ok := value.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if strings.ToLower(v) == "true" {
|
||||||
|
return Expr(fmt.Sprintf("COALESCE(%s, 0) > 0", field))
|
||||||
|
}
|
||||||
|
return Expr(fmt.Sprintf("COALESCE(%s, 0) = 0", field))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r sqlRepository) annId(itemID ...string) And {
|
func (r sqlRepository) annId(itemID ...string) And {
|
||||||
userID := loggedUser(r.ctx).ID
|
userID := loggedUser(r.ctx).ID
|
||||||
return And{
|
return And{
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
package persistence
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/Masterminds/squirrel"
|
||||||
|
"github.com/deluan/rest"
|
||||||
|
"github.com/navidrome/navidrome/model"
|
||||||
|
"github.com/navidrome/navidrome/model/request"
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Annotation Filters", func() {
|
||||||
|
var (
|
||||||
|
albumRepo *albumRepository
|
||||||
|
albumWithoutAnnotation model.Album
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
ctx := request.WithUser(context.Background(), model.User{ID: "userid", UserName: "johndoe"})
|
||||||
|
albumRepo = NewAlbumRepository(ctx, GetDBXBuilder()).(*albumRepository)
|
||||||
|
|
||||||
|
// Create album without any annotation (no star, no rating)
|
||||||
|
albumWithoutAnnotation = model.Album{ID: "no-annotation-album", Name: "No Annotation", LibraryID: 1}
|
||||||
|
Expect(albumRepo.Put(&albumWithoutAnnotation)).To(Succeed())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
_, _ = albumRepo.executeSQL(squirrel.Delete("album").Where(squirrel.Eq{"id": albumWithoutAnnotation.ID}))
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("annotationBoolFilter", func() {
|
||||||
|
DescribeTable("creates correct SQL expressions",
|
||||||
|
func(field, value string, expectedSQL string, expectedArgs []interface{}) {
|
||||||
|
sqlizer := annotationBoolFilter(field)(field, value)
|
||||||
|
sql, args, err := sqlizer.ToSql()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(sql).To(Equal(expectedSQL))
|
||||||
|
Expect(args).To(Equal(expectedArgs))
|
||||||
|
},
|
||||||
|
Entry("starred=true", "starred", "true", "COALESCE(starred, 0) > 0", []interface{}(nil)),
|
||||||
|
Entry("starred=false", "starred", "false", "COALESCE(starred, 0) = 0", []interface{}(nil)),
|
||||||
|
Entry("starred=True (case insensitive)", "starred", "True", "COALESCE(starred, 0) > 0", []interface{}(nil)),
|
||||||
|
Entry("rating=true", "rating", "true", "COALESCE(rating, 0) > 0", []interface{}(nil)),
|
||||||
|
)
|
||||||
|
|
||||||
|
It("returns nil if value is not a string", func() {
|
||||||
|
sqlizer := annotationBoolFilter("starred")("starred", 123)
|
||||||
|
Expect(sqlizer).To(BeNil())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("starredFilter", func() {
|
||||||
|
It("false includes items without annotations", func() {
|
||||||
|
albums, err := albumRepo.GetAll(model.QueryOptions{
|
||||||
|
Filters: annotationBoolFilter("starred")("starred", "false"),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, a := range albums {
|
||||||
|
if a.ID == albumWithoutAnnotation.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "Item without annotation should be included in starred=false filter")
|
||||||
|
})
|
||||||
|
|
||||||
|
It("true excludes items without annotations", func() {
|
||||||
|
albums, err := albumRepo.GetAll(model.QueryOptions{
|
||||||
|
Filters: annotationBoolFilter("starred")("starred", "true"),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
for _, a := range albums {
|
||||||
|
Expect(a.ID).ToNot(Equal(albumWithoutAnnotation.ID))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Describe("hasRatingFilter", func() {
|
||||||
|
It("false includes items without annotations", func() {
|
||||||
|
albums, err := albumRepo.GetAll(model.QueryOptions{
|
||||||
|
Filters: annotationBoolFilter("rating")("rating", "false"),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, a := range albums {
|
||||||
|
if a.ID == albumWithoutAnnotation.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "Item without annotation should be included in has_rating=false filter")
|
||||||
|
})
|
||||||
|
|
||||||
|
It("true excludes items without annotations", func() {
|
||||||
|
albums, err := albumRepo.GetAll(model.QueryOptions{
|
||||||
|
Filters: annotationBoolFilter("rating")("rating", "true"),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
for _, a := range albums {
|
||||||
|
Expect(a.ID).ToNot(Equal(albumWithoutAnnotation.ID))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("true includes items with rating > 0", func() {
|
||||||
|
// Create album with rating 1
|
||||||
|
ratedAlbum := model.Album{ID: "rated-album", Name: "Rated Album", LibraryID: 1}
|
||||||
|
Expect(albumRepo.Put(&ratedAlbum)).To(Succeed())
|
||||||
|
Expect(albumRepo.SetRating(1, ratedAlbum.ID)).To(Succeed())
|
||||||
|
defer func() {
|
||||||
|
_, _ = albumRepo.executeSQL(squirrel.Delete("annotation").Where(squirrel.Eq{"item_id": ratedAlbum.ID}))
|
||||||
|
_, _ = albumRepo.executeSQL(squirrel.Delete("album").Where(squirrel.Eq{"id": ratedAlbum.ID}))
|
||||||
|
}()
|
||||||
|
|
||||||
|
albums, err := albumRepo.GetAll(model.QueryOptions{
|
||||||
|
Filters: annotationBoolFilter("rating")("rating", "true"),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, a := range albums {
|
||||||
|
if a.ID == ratedAlbum.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "Album with rating 5 should be included in has_rating=true filter")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
It("ignores invalid filter values (not strings)", func() {
|
||||||
|
res, err := albumRepo.ReadAll(rest.QueryOptions{
|
||||||
|
Filters: map[string]any{"starred": 123},
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
albums := res.(model.Albums)
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, a := range albums {
|
||||||
|
if a.ID == albumWithoutAnnotation.ID {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expect(found).To(BeTrue(), "Item without annotation should be included when filter is ignored")
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user