2022-07-27 16:43:24 -08:00
|
|
|
package criteria
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
|
|
|
"github.com/onsi/gomega"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var _ = Describe("fields", func() {
|
2026-04-24 19:18:20 -08:00
|
|
|
Describe("LookupField", func() {
|
|
|
|
|
It("finds built-in fields case-insensitively", func() {
|
|
|
|
|
field, ok := LookupField("Title")
|
|
|
|
|
|
|
|
|
|
gomega.Expect(ok).To(gomega.BeTrue())
|
2026-04-28 16:22:48 -08:00
|
|
|
gomega.Expect(field.Name()).To(gomega.Equal("title"))
|
2026-04-24 19:18:20 -08:00
|
|
|
})
|
|
|
|
|
|
2026-04-28 16:22:48 -08:00
|
|
|
It("resolves aliases to their canonical field name", func() {
|
2026-04-24 19:18:20 -08:00
|
|
|
field, ok := LookupField("albumtype")
|
|
|
|
|
|
|
|
|
|
gomega.Expect(ok).To(gomega.BeTrue())
|
2026-04-28 16:22:48 -08:00
|
|
|
gomega.Expect(field.Name()).To(gomega.Equal("releasetype"))
|
2026-04-24 19:18:20 -08:00
|
|
|
gomega.Expect(field.IsTag).To(gomega.BeTrue())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
It("finds registered tag names", func() {
|
|
|
|
|
AddTagNames([]string{"task3_mood"})
|
|
|
|
|
|
|
|
|
|
field, ok := LookupField("task3_mood")
|
|
|
|
|
|
|
|
|
|
gomega.Expect(ok).To(gomega.BeTrue())
|
2026-04-28 16:22:48 -08:00
|
|
|
gomega.Expect(field.Name()).To(gomega.Equal("task3_mood"))
|
2026-04-24 19:18:20 -08:00
|
|
|
gomega.Expect(field.IsTag).To(gomega.BeTrue())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
It("marks registered numeric tags", func() {
|
|
|
|
|
AddTagNames([]string{"task3_score"})
|
|
|
|
|
AddNumericTags([]string{"task3_score"})
|
|
|
|
|
|
|
|
|
|
field, ok := LookupField("task3_score")
|
|
|
|
|
|
|
|
|
|
gomega.Expect(ok).To(gomega.BeTrue())
|
|
|
|
|
gomega.Expect(field.IsTag).To(gomega.BeTrue())
|
|
|
|
|
gomega.Expect(field.Numeric).To(gomega.BeTrue())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
It("finds registered roles", func() {
|
|
|
|
|
AddRoles([]string{"task3_producer"})
|
|
|
|
|
|
|
|
|
|
field, ok := LookupField("task3_producer")
|
|
|
|
|
|
|
|
|
|
gomega.Expect(ok).To(gomega.BeTrue())
|
2026-04-28 16:22:48 -08:00
|
|
|
gomega.Expect(field.Name()).To(gomega.Equal("task3_producer"))
|
2026-04-24 19:18:20 -08:00
|
|
|
gomega.Expect(field.IsRole).To(gomega.BeTrue())
|
2022-07-27 16:43:24 -08:00
|
|
|
})
|
2026-05-01 15:21:48 -08:00
|
|
|
|
fix(smartplaylist): support isMissing/isPresent operators on ReplayGain fields (#5585)
* fix(smartplaylist): support isMissing/isPresent operators on ReplayGain fields
ReplayGain values are stored in dedicated nullable columns (rg_album_gain,
rg_album_peak, rg_track_gain, rg_track_peak) rather than in the media_file.tags
JSON blob. The isMissing/isPresent operators previously only supported tag and
role fields, causing two failure modes:
1. Using the documented alias names (replaygain_album_gain etc.) from PR #5256:
these got registered as JSON tags from mappings.yaml, so isMissing queried
json_tree(media_file.tags, '$.replaygain_album_gain') which is always empty
-> the playlist matched ALL songs.
2. Using the canonical field names (rgalbumgain etc.): not a tag/role, so SQL
generation returned an error. Because refreshSmartPlaylist deletes old tracks
before regenerating, the abort left the playlist empty.
Fix: add Nullable bool to FieldInfo and mark the four ReplayGain fields. Add
static alias entries (replaygain_album_gain -> rgalbumgain etc.) with
Numeric+Nullable set; because AddTagNames skips names already in the field map,
these static entries take precedence over the mappings.yaml tag registration.
missingExpr now emits IS NULL / IS NOT NULL for nullable column fields instead
of the json_tree lookup.
Fixes #5584
* chore(smartplaylist): address code review feedback
- Simplify the isMissing/isPresent unsupported-field error message,
removing the internal "nullable fields" jargon
- Standardize comments on mappings.yaml (the actual filename)
- Clarify the alias precedence comment in the LookupField test
2026-06-10 17:12:31 -08:00
|
|
|
It("marks ReplayGain column fields as nullable", func() {
|
|
|
|
|
field, ok := LookupField("rgAlbumGain")
|
|
|
|
|
|
|
|
|
|
gomega.Expect(ok).To(gomega.BeTrue())
|
|
|
|
|
gomega.Expect(field.Name()).To(gomega.Equal("rgalbumgain"))
|
|
|
|
|
gomega.Expect(field.Nullable).To(gomega.BeTrue())
|
|
|
|
|
gomega.Expect(field.IsTag).To(gomega.BeFalse())
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
It("resolves replaygain_* tag names as aliases to nullable column fields", func() {
|
|
|
|
|
// AddTagNames skips names already in the field map, so the startup tag registration
|
|
|
|
|
// (from mappings.yaml) must not convert the pre-registered alias into a tag field.
|
|
|
|
|
AddTagNames([]string{"replaygain_album_gain"})
|
|
|
|
|
|
|
|
|
|
field, ok := LookupField("replaygain_album_gain")
|
|
|
|
|
|
|
|
|
|
gomega.Expect(ok).To(gomega.BeTrue())
|
|
|
|
|
gomega.Expect(field.Name()).To(gomega.Equal("rgalbumgain"))
|
|
|
|
|
gomega.Expect(field.Nullable).To(gomega.BeTrue())
|
|
|
|
|
gomega.Expect(field.IsTag).To(gomega.BeFalse())
|
|
|
|
|
})
|
|
|
|
|
|
2022-07-27 16:43:24 -08:00
|
|
|
})
|
|
|
|
|
})
|