refactor(scanner): simplify selective scan logic using slice.Filter

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan 2025-11-11 17:35:45 -05:00
parent 4386c3a876
commit fadaaf3ad1
3 changed files with 54 additions and 9 deletions

View File

@ -15,6 +15,7 @@ import (
"github.com/navidrome/navidrome/log"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/utils/run"
"github.com/navidrome/navidrome/utils/slice"
)
type scannerImpl struct {
@ -30,7 +31,6 @@ type scanState struct {
changesDetected atomic.Bool
libraries model.Libraries // Store libraries list for consistency across phases
targets map[int][]string // Optional: map[libraryID][]folderPaths for selective scans
affectedLibIDs []int // IDs of libraries involved in the scan (for GC scoping)
}
func (s *scanState) sendProgress(info *ProgressInfo) {
@ -74,7 +74,6 @@ func (s *scannerImpl) scanFolders(ctx context.Context, fullScan bool, targets []
if isSelectiveScan {
// Selective scan: filter libraries and build targets map
state.targets = make(map[int][]string)
affectedLibIDSet := make(map[int]bool)
for _, target := range targets {
folderPath := target.FolderPath
@ -82,15 +81,12 @@ func (s *scannerImpl) scanFolders(ctx context.Context, fullScan bool, targets []
folderPath = "."
}
state.targets[target.LibraryID] = append(state.targets[target.LibraryID], folderPath)
affectedLibIDSet[target.LibraryID] = true
}
for _, lib := range allLibs {
if affectedLibIDSet[lib.ID] {
libs = append(libs, lib)
state.affectedLibIDs = append(state.affectedLibIDs, lib.ID)
}
}
// Filter libraries to only those in targets
libs = slice.Filter(allLibs, func(lib model.Library) bool {
return len(state.targets[lib.ID]) > 0
})
log.Info(ctx, "Scanner: Starting selective scan", "fullScan", state.fullScan, "numLibraries", len(libs), "numTargets", len(targets))
} else {

View File

@ -171,3 +171,14 @@ func SeqFunc[I, O any](s []I, f func(I) O) iter.Seq[O] {
}
}
}
// Filter returns a new slice containing only the elements of s for which filterFunc returns true
func Filter[T any](s []T, filterFunc func(T) bool) []T {
var result []T
for _, item := range s {
if filterFunc(item) {
result = append(result, item)
}
}
return result
}

View File

@ -172,4 +172,42 @@ var _ = Describe("Slice Utils", func() {
Expect(result).To(ConsistOf("2", "4", "6", "8"))
})
})
Describe("Filter", func() {
It("returns empty slice for an empty input", func() {
filterFunc := func(v int) bool { return v > 0 }
result := slice.Filter([]int{}, filterFunc)
Expect(result).To(BeEmpty())
})
It("returns all elements when filter matches all", func() {
filterFunc := func(v int) bool { return v > 0 }
result := slice.Filter([]int{1, 2, 3, 4}, filterFunc)
Expect(result).To(HaveExactElements(1, 2, 3, 4))
})
It("returns empty slice when filter matches none", func() {
filterFunc := func(v int) bool { return v > 10 }
result := slice.Filter([]int{1, 2, 3, 4}, filterFunc)
Expect(result).To(BeEmpty())
})
It("returns only matching elements", func() {
filterFunc := func(v int) bool { return v%2 == 0 }
result := slice.Filter([]int{1, 2, 3, 4, 5, 6}, filterFunc)
Expect(result).To(HaveExactElements(2, 4, 6))
})
It("works with string slices", func() {
filterFunc := func(s string) bool { return len(s) > 3 }
result := slice.Filter([]string{"a", "abc", "abcd", "ab", "abcde"}, filterFunc)
Expect(result).To(HaveExactElements("abcd", "abcde"))
})
It("preserves order of elements", func() {
filterFunc := func(v int) bool { return v%2 == 1 }
result := slice.Filter([]int{9, 8, 7, 6, 5, 4, 3, 2, 1}, filterFunc)
Expect(result).To(HaveExactElements(9, 7, 5, 3, 1))
})
})
})