mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
* feat(smartplaylist): add IsMissing and IsPresent operator types Add two new Expression types for detecting absent/present tags and roles in smart playlist criteria. Includes JSON marshal/unmarshal support and Walk visitor registration. * test(smartplaylist): add JSON marshal/unmarshal tests for isMissing/isPresent * feat(smartplaylist): add SQL generation for isMissing/isPresent operators Tags check json_tree(media_file.tags) for key existence. Roles check json_tree(media_file.participants) for key existence. Regular DB column fields are rejected with an error. * test(smartplaylist): add e2e tests for isMissing/isPresent operators Tests cover tag presence/absence with selective matching (grouping), universal absence (lyricist role), universal presence (composer role), and combined operator usage. * refactor(smartplaylist): use strconv.ParseBool in IsTruthy Replace hand-rolled string truthiness check with strconv.ParseBool, which correctly handles standard boolean strings and rejects unrecognized values as false. * refactor(smartplaylist): clarify missingExpr parameter naming Rename defaultNegate to checkAbsence and extract truthy local for readability. The XNOR logic (checkAbsence == truthy) is now easier to follow: isMissing passes true, isPresent passes false. * refactor(smartplaylist): reuse jsonExpr in missingExpr, improve errors - tagCond/roleCond now handle nil cond (existence-only check) - missingExpr delegates to jsonExpr(info, nil, negate) instead of building SQL manually - Better error messages: unknown fields now report the field name
38 lines
798 B
Go
38 lines
798 B
Go
package criteria
|
|
|
|
import "fmt"
|
|
|
|
type Visitor func(Expression) error
|
|
|
|
func Walk(expr Expression, visit Visitor) error {
|
|
if expr == nil {
|
|
return nil
|
|
}
|
|
if err := visit(expr); err != nil {
|
|
return err
|
|
}
|
|
switch e := expr.(type) {
|
|
case All:
|
|
for _, child := range e {
|
|
if err := Walk(child, visit); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
case Any:
|
|
for _, child := range e {
|
|
if err := Walk(child, visit); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
case Is, IsNot, Gt, Lt, Before, After, Contains, NotContains, StartsWith, EndsWith, InTheRange, InTheLast, NotInTheLast, InPlaylist, NotInPlaylist, IsMissing, IsPresent:
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("unknown criteria expression type %T", expr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Fields(expr Expression) map[string]any {
|
|
return expr.fields()
|
|
}
|