package persistence import ( "context" "encoding/json" "fmt" "regexp" "strings" "github.com/Masterminds/squirrel" "github.com/deluan/navidrome/consts" "github.com/deluan/navidrome/log" "github.com/deluan/navidrome/model" "github.com/deluan/navidrome/utils" ) func toSqlArgs(rec interface{}) (map[string]interface{}, error) { // Convert to JSON... b, err := json.Marshal(rec) if err != nil { return nil, err } // ... then convert to map var m map[string]interface{} err = json.Unmarshal(b, &m) r := make(map[string]interface{}, len(m)) for f, v := range m { isAnnotationField := utils.StringInSlice(f, model.AnnotationFields) isBookmarkField := utils.StringInSlice(f, model.BookmarkFields) if !isAnnotationField && !isBookmarkField && v != nil { r[toSnakeCase(f)] = v } } return r, err } var matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)") var matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])") func toSnakeCase(str string) string { snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}") snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}") return strings.ToLower(snake) } func exists(subTable string, cond squirrel.Sqlizer) existsCond { return existsCond{subTable: subTable, cond: cond} } type existsCond struct { subTable string cond squirrel.Sqlizer } func (e existsCond) ToSql() (string, []interface{}, error) { sql, args, err := e.cond.ToSql() sql = fmt.Sprintf("exists (select 1 from %s where %s)", e.subTable, sql) return sql, args, err } func getMbzId(ctx context.Context, mbzIDS, entityName, name string) string { ids := strings.Fields(mbzIDS) if len(ids) == 0 { return "" } idCounts := map[string]int{} for _, id := range ids { if c, ok := idCounts[id]; ok { idCounts[id] = c + 1 } else { idCounts[id] = 1 } } var topKey string var topCount int for k, v := range idCounts { if v > topCount { topKey = k topCount = v } } if len(idCounts) > 1 && name != consts.VariousArtists { log.Warn(ctx, "Multiple MBIDs found for "+entityName, "name", name, "mbids", idCounts) } return topKey }