mirror of
https://github.com/samuelncui/yatm.git
synced 2026-11-08 12:26:33 +00:00
Remove test-only Library wrappers
WalkSelectedFiles had no caller. DeletePositions, GetPositionByFileID, MGetFile, MatchFileRows, ValidateFilesQuery, MatchLiveFiles, TrackingCandidatesPage, ReadFileTracking, ImportArchivedInventory and MoveFileToPath were only called by tests, which now use the batch and compiled-query methods production uses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bc0ee85151
commit
4814bd8beb
21 files changed
+53
-220
No files matched your search
@@ -206,7 +206,9 @@ func TestLibrarySearchCatalogContentAndPagination(t *testing.T) {
|
||||
allIDs = append(allIDs, file.ID)
|
||||
}
|
||||
require.Equal(t, test.want, allIDs)
|
||||
matches, err := api.lib.MatchFileRows(ctx, idsToMatch, entity.FileScope_FILE_SCOPE_ALL, test.query)
|
||||
compiled, err := api.lib.CompileFilesQuery(test.query)
|
||||
require.NoError(t, err)
|
||||
matches, err := api.lib.MatchFileQueryRows(ctx, idsToMatch, entity.FileScope_FILE_SCOPE_ALL, compiled)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, matches, len(test.want))
|
||||
for _, id := range test.want {
|
||||
|
||||
@@ -186,8 +186,9 @@ func TestConcurrentFirstRemoveInitializesTrashWithoutSerializingPhysicalMoves(t
|
||||
for index, file := range files {
|
||||
original, err := f.exe.Lib().GetFileLocation(ctx, file.ID)
|
||||
require.NoError(t, err)
|
||||
tracking, err := f.exe.Lib().ReadFileTracking(ctx, file.ID)
|
||||
keys, err := f.exe.Lib().ReadFileTrackingKeys(ctx, []int64{file.ID})
|
||||
require.NoError(t, err)
|
||||
tracking := keys[file.ID]
|
||||
if index < 2 {
|
||||
require.Nil(t, original)
|
||||
require.Empty(t, tracking)
|
||||
|
||||
@@ -437,8 +437,9 @@ func TestScanDetachedMatchingRequiresEarlierObservedAbsence(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
old, err := f.exe.Lib().LocationOriginalsPage(ctx, f.locations[0].ID, "", 10)
|
||||
require.NoError(t, err)
|
||||
keys, err := f.exe.Lib().ReadFileTracking(ctx, old[0].FileID)
|
||||
tracking, err := f.exe.Lib().ReadFileTrackingKeys(ctx, []int64{old[0].FileID})
|
||||
require.NoError(t, err)
|
||||
keys := tracking[old[0].FileID]
|
||||
if len(keys) == 0 {
|
||||
t.Skip("filesystem provides no native tracking identity")
|
||||
}
|
||||
|
||||
@@ -81,9 +81,10 @@ func TestNativeRelocationPreservesOpaqueObservedSignature(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
rows, err := exe.Lib().LocationOriginalsPage(ctx, source.ID, "", 10)
|
||||
require.NoError(t, err)
|
||||
keys, err := exe.Lib().TrackingCandidatesPage(ctx, source, 0, 10)
|
||||
require.NoError(t, err)
|
||||
row := rows[0]
|
||||
tracking, err := exe.Lib().ReadFileTrackingKeys(ctx, []int64{row.FileID})
|
||||
require.NoError(t, err)
|
||||
keys := tracking[row.FileID]
|
||||
row.Signature = []byte{0, 255, 42}
|
||||
observation := &library.ObservedEntry{Path: row.Path, FileID: row.FileID, Size: row.Size, Mode: row.Mode,
|
||||
MtimeNS: row.MtimeNS, Hash: row.Hash, Signature: row.Signature, TrackingKeys: keys}
|
||||
|
||||
@@ -313,27 +313,6 @@ func archiveDirectoryPrefix(directory string) string {
|
||||
return directory + "/"
|
||||
}
|
||||
|
||||
// ImportArchivedInventory is reserved for explicit inventory-import workflows and fixtures.
|
||||
// Archive and Volume Scan must not invoke this to infer logical identity from signatures.
|
||||
// Each invocation creates new organization; callers select this one-shot import explicitly.
|
||||
func (l *Library) ImportArchivedInventory(ctx context.Context) error {
|
||||
var after int64
|
||||
for {
|
||||
var ids []int64
|
||||
if err := l.readDB().WithContext(ctx).Model(ModelPosition).Where("id > ? AND is_dir = ?", after, false).
|
||||
Where("signature IS NOT NULL").Order("id").Limit(batchSize).Pluck("id", &ids).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
if _, err := l.ImportArchivePositions(ctx, ids); err != nil {
|
||||
return err
|
||||
}
|
||||
after = ids[len(ids)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// CreateArchiveFile allocates a raw input's logical identity before any physical transfer.
|
||||
func (l *Library) CreateArchiveFile(ctx context.Context, targetPath string) (*File, error) {
|
||||
if err := entity.ValidateRelativePath(targetPath); err != nil {
|
||||
|
||||
@@ -199,11 +199,6 @@ func (l *Library) MoveFile(ctx context.Context, file *File) error {
|
||||
return l.moveTree(ctx, file, file.Name)
|
||||
}
|
||||
|
||||
// MoveFileToPath resolves a shared relative shortcut without pre-creating directories.
|
||||
func (l *Library) MoveFileToPath(ctx context.Context, file *File, targetPath string) error {
|
||||
return l.moveTree(ctx, file, targetPath)
|
||||
}
|
||||
|
||||
func validateFileParent(tx *gorm.DB, parentID, movingID int64) error {
|
||||
// Follow only the bounded destination ancestry; no whole-tree query or filesystem access is needed.
|
||||
seen := make(map[int64]struct{})
|
||||
@@ -303,10 +298,6 @@ func (l *Library) newTrash(ctx context.Context, tx *gorm.DB) (*File, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Library) MGetFile(ctx context.Context, ids ...int64) (map[int64]*File, error) {
|
||||
return l.mGetFile(ctx, l.readDB().WithContext(ctx), ids...)
|
||||
}
|
||||
|
||||
func (l *Library) mGetFile(ctx context.Context, tx *gorm.DB, ids ...int64) (map[int64]*File, error) {
|
||||
// Keep the persistence read independent from the compatibility projection.
|
||||
files, err := readFileRows(tx, ids...)
|
||||
|
||||
@@ -67,7 +67,7 @@ func TestOriginalPublicationRetainsExistingCoverageAsOwnVersion(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
_, err = lib.DeleteLocation(ctx, location.ID, false)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, lib.DeletePositions(ctx, copy.ID))
|
||||
require.NoError(t, lib.db.Delete(&Position{}, copy.ID).Error)
|
||||
versions, _, err = lib.ListFileVersions(ctx, file.ID, 0, 10)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []*FileVersion{saved}, versions)
|
||||
|
||||
@@ -127,7 +127,9 @@ func TestFileQueryNumericNegationFactsAndUnknowns(t *testing.T) {
|
||||
|
||||
// An observed linked entry has no regular-file size, independently of Catalog membership.
|
||||
t.Run("Location", func(t *testing.T) {
|
||||
indexes, err := lib.MatchLiveFiles(ctx, test.query, rows)
|
||||
compiled, err := lib.CompileFilesQuery(test.query)
|
||||
require.NoError(t, err)
|
||||
indexes, err := lib.MatchLiveQuery(ctx, compiled, rows)
|
||||
require.NoError(t, err)
|
||||
var names []string
|
||||
for _, index := range indexes {
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
package library
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/samuelncui/yatm/entity"
|
||||
)
|
||||
|
||||
// WalkSelectedFiles expands logical selections in bounded pages with full Library-relative paths.
|
||||
func (l *Library) WalkSelectedFiles(ctx context.Context, ids []int64, yield func(*File, string) error) error {
|
||||
// Keep only explicit root identities; descendants need no whole-tree visited set.
|
||||
selected := make(map[int64]struct{}, len(ids))
|
||||
for _, id := range ids {
|
||||
if id <= 0 {
|
||||
return fmt.Errorf("invalid selected File ID %d", id)
|
||||
}
|
||||
selected[id] = struct{}{}
|
||||
}
|
||||
ordered := make([]int64, 0, len(selected))
|
||||
for id := range selected {
|
||||
ordered = append(ordered, id)
|
||||
}
|
||||
sort.Slice(ordered, func(i, j int) bool { return ordered[i] < ordered[j] })
|
||||
|
||||
// Resolve complete root paths and remove roots already covered by another selected ancestor.
|
||||
for _, id := range ordered {
|
||||
file, err := l.GetFile(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parts := []string{file.Name}
|
||||
parentID := file.ParentID
|
||||
covered := false
|
||||
for parentID != 0 {
|
||||
if len(parts) > 256 {
|
||||
return fmt.Errorf("selected Library path exceeds 256 levels or is cyclic")
|
||||
}
|
||||
if _, ok := selected[parentID]; ok {
|
||||
covered = true
|
||||
break
|
||||
}
|
||||
parent, err := l.GetFile(ctx, parentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parts = append(parts, parent.Name)
|
||||
parentID = parent.ParentID
|
||||
}
|
||||
if covered {
|
||||
continue
|
||||
}
|
||||
for left, right := 0, len(parts)-1; left < right; left, right = left+1, right-1 {
|
||||
parts[left], parts[right] = parts[right], parts[left]
|
||||
}
|
||||
if err := l.walkSelected(ctx, file, strings.Join(parts, "/"), 0, yield); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Library) walkSelected(ctx context.Context, file *File, target string, depth int, yield func(*File, string) error) error {
|
||||
// Validate every resulting logical target before descending or yielding content.
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
if depth > 256 {
|
||||
return fmt.Errorf("selected Library tree exceeds 256 levels")
|
||||
}
|
||||
if err := entity.ValidateRelativePath(target); err != nil {
|
||||
return err
|
||||
}
|
||||
if !fs.FileMode(file.Mode).IsDir() {
|
||||
if !fs.FileMode(file.Mode).IsRegular() {
|
||||
return fmt.Errorf("selected File is not regular, file_id=%d", file.ID)
|
||||
}
|
||||
return yield(file, target)
|
||||
}
|
||||
|
||||
// Retain one bounded direct-child page at each active depth.
|
||||
var after string
|
||||
for {
|
||||
rows, err := l.ListPage(ctx, file.ID, after, batchSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(rows) == 0 {
|
||||
return nil
|
||||
}
|
||||
for _, row := range rows {
|
||||
if err := l.walkSelected(ctx, row, path.Join(target, row.Name), depth+1, yield); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
after = rows[len(rows)-1].Name
|
||||
}
|
||||
}
|
||||
@@ -47,12 +47,6 @@ type FileTrackingKey struct {
|
||||
LocationID int64 `gorm:"index" json:"location_id"`
|
||||
}
|
||||
|
||||
// ReadFileTracking reads only identity evidence for an explicitly selected original.
|
||||
func (l *Library) ReadFileTracking(ctx context.Context, fileID int64) ([]*FileTrackingKey, error) {
|
||||
keys, err := l.ReadFileTrackingKeys(ctx, []int64{fileID})
|
||||
return keys[fileID], err
|
||||
}
|
||||
|
||||
// ReadFileTrackingKeys reads the retained evidence of several Files at once, keyed by File ID, so a
|
||||
// caller that already holds recorded associations does not query once per row.
|
||||
func (l *Library) ReadFileTrackingKeys(ctx context.Context, fileIDs []int64) (map[int64][]*FileTrackingKey, error) {
|
||||
@@ -69,17 +63,3 @@ func (l *Library) ReadFileTrackingKeys(ctx context.Context, fileIDs []int64) (ma
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// TrackingCandidatesPage excludes every original still bound to another Location.
|
||||
// A retained key without a FileLocation is eligible only after a successful removal.
|
||||
func (l *Library) TrackingCandidatesPage(ctx context.Context, location *Location, after int64, limit int) ([]*FileTrackingKey, error) {
|
||||
ids := l.readDB().WithContext(ctx).Model(&FileTrackingKey{}).Select("file_tracking_keys.file_id").
|
||||
Joins("JOIN locations ON locations.id = file_tracking_keys.location_id").
|
||||
Joins("LEFT JOIN file_locations ON file_locations.file_id = file_tracking_keys.file_id").
|
||||
Where("file_tracking_keys.file_id > ? AND locations.executor_id = ?", after, location.ExecutorID).
|
||||
Where("file_locations.file_id IS NULL OR file_locations.location_id = ?", location.ID).
|
||||
Group("file_tracking_keys.file_id").Order("file_tracking_keys.file_id").Limit(limit)
|
||||
var keys []*FileTrackingKey
|
||||
err := l.readDB().WithContext(ctx).Where("file_id IN (?)", ids).Order("file_id, kind").Find(&keys).Error
|
||||
return keys, err
|
||||
}
|
||||
@@ -69,7 +69,7 @@ func TestListParentsRetainsDeepRootAndRejectsInvalidAncestry(t *testing.T) {
|
||||
require.ErrorContains(t, err, "exceeds")
|
||||
}
|
||||
|
||||
func TestMoveFileToPathRollsBackNestedDirectories(t *testing.T) {
|
||||
func TestMoveFileToNestedPathRollsBackNestedDirectories(t *testing.T) {
|
||||
// A nested rename may allocate directories before discovering the final destination is a descendant.
|
||||
ctx := context.Background()
|
||||
lib := newJSONLTestLibrary(t)
|
||||
@@ -79,7 +79,8 @@ func TestMoveFileToPathRollsBackNestedDirectories(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Keep the failed allocation, original root and child inside one rollback boundary.
|
||||
require.Error(t, lib.MoveFileToPath(ctx, root, "root/new/renamed"))
|
||||
root.Name = "root/new/renamed"
|
||||
require.Error(t, lib.MoveFile(ctx, root))
|
||||
created, err := lib.GetByName(ctx, root.ID, "new")
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, created)
|
||||
@@ -92,14 +93,15 @@ func TestMoveFileToPathRollsBackNestedDirectories(t *testing.T) {
|
||||
require.Equal(t, root.ID, storedChild.ParentID)
|
||||
}
|
||||
|
||||
func TestMoveFileToPathCreatesValidNestedDestination(t *testing.T) {
|
||||
func TestMoveFileToNestedPathCreatesValidNestedDestination(t *testing.T) {
|
||||
// A normal nested move keeps the File identity and user metadata while allocating its target directories.
|
||||
ctx := context.Background()
|
||||
lib := newJSONLTestLibrary(t)
|
||||
file := &File{Name: "before.txt", Note: "keep organization"}
|
||||
require.NoError(t, lib.SaveFile(ctx, file))
|
||||
id := file.ID
|
||||
require.NoError(t, lib.MoveFileToPath(ctx, file, "folder/sub/after.txt"))
|
||||
file.Name = "folder/sub/after.txt"
|
||||
require.NoError(t, lib.MoveFile(ctx, file))
|
||||
require.Equal(t, id, file.ID)
|
||||
require.Equal(t, "after.txt", file.Name)
|
||||
|
||||
@@ -113,13 +115,14 @@ func TestMoveFileToPathCreatesValidNestedDestination(t *testing.T) {
|
||||
require.Nil(t, old)
|
||||
}
|
||||
|
||||
func TestMoveFileToPathPreservesWhitespaceInsideComponents(t *testing.T) {
|
||||
func TestMoveFileToNestedPathPreservesWhitespaceInsideComponents(t *testing.T) {
|
||||
// Whitespace inside a validated full target path belongs to the logical name component.
|
||||
ctx := context.Background()
|
||||
lib := newJSONLTestLibrary(t)
|
||||
file := &File{Name: "before.txt"}
|
||||
require.NoError(t, lib.SaveFile(ctx, file))
|
||||
require.NoError(t, lib.MoveFileToPath(ctx, file, "folder /after.txt"))
|
||||
file.Name = "folder /after.txt"
|
||||
require.NoError(t, lib.MoveFile(ctx, file))
|
||||
|
||||
// Resolving the directory directly avoids any presentation-level path normalization.
|
||||
parent, err := lib.GetFile(ctx, file.ParentID)
|
||||
@@ -136,7 +139,8 @@ func TestMoveFileRequiresExistingSource(t *testing.T) {
|
||||
lib := newJSONLTestLibrary(t)
|
||||
file := &File{ID: 99999, Name: "missing.txt"}
|
||||
require.ErrorIs(t, lib.MoveFile(ctx, file), ErrFileNotFound)
|
||||
require.ErrorIs(t, lib.MoveFileToPath(ctx, file, "new/missing.txt"), ErrFileNotFound)
|
||||
file.Name = "new/missing.txt"
|
||||
require.ErrorIs(t, lib.MoveFile(ctx, file), ErrFileNotFound)
|
||||
|
||||
// Both entry points leave an empty catalog rather than inventing the requested source identity.
|
||||
rows, err := lib.List(ctx, 0)
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestFileVersionOwnsArchivedFactsWithoutCopyOwnership(t *testing.T) {
|
||||
require.Len(t, copies[one.ID], 1)
|
||||
require.Len(t, copies[two.ID], 1)
|
||||
require.Equal(t, copy.ID, copies[one.ID][0].ID)
|
||||
require.NoError(t, lib.DeletePositions(ctx, copy.ID))
|
||||
require.NoError(t, lib.db.Delete(&Position{}, copy.ID).Error)
|
||||
kept, err := lib.GetFileVersion(ctx, version.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, signature, kept.Signature)
|
||||
|
||||
@@ -9,15 +9,6 @@ import (
|
||||
"github.com/samuelncui/yatm/entity"
|
||||
)
|
||||
|
||||
// MatchFileRows applies Library catalog predicates to one bounded traversal batch.
|
||||
func (l *Library) MatchFileRows(ctx context.Context, ids []int64, scope entity.FileScope, query string) (map[int64]bool, error) {
|
||||
compiled, err := l.CompileFilesQuery(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l.MatchFileQueryRows(ctx, ids, scope, compiled)
|
||||
}
|
||||
|
||||
// MatchFileQueryRows shares catalog filtering with Search without recompiling each traversal batch.
|
||||
func (l *Library) MatchFileQueryRows(ctx context.Context, ids []int64, scope entity.FileScope, query *FilesQuery) (map[int64]bool, error) {
|
||||
// Empty traversal batches require no catalog read.
|
||||
|
||||
@@ -292,7 +292,7 @@ func TestLibraryLegacyImportConvertsDirectoryModeAtTheBoundary(t *testing.T) {
|
||||
require.NoError(t, lib.Import(ctx, bytes.NewReader(backup), false))
|
||||
|
||||
// The current catalog persists explicit types and keeps the original hierarchy.
|
||||
files, err := lib.MGetFile(ctx, TrashFileID, 9, 10)
|
||||
files, err := lib.ReadFileRows(ctx, []int64{TrashFileID, 9, 10})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, entity.FileKind_FILE_KIND_DIRECTORY, files[TrashFileID].Kind)
|
||||
require.Equal(t, entity.FileKind_FILE_KIND_DIRECTORY, files[9].Kind)
|
||||
|
||||
@@ -30,7 +30,8 @@ func TestLibraryPathsPreserveLiteralUTF8(t *testing.T) {
|
||||
// A replacement name is literal too; it never denotes a backslash-separated path.
|
||||
file := &File{ParentID: directory.ID, Name: "before", Kind: entity.FileKind_FILE_KIND_REGULAR}
|
||||
require.NoError(t, lib.SaveFile(ctx, file))
|
||||
require.NoError(t, lib.MoveFileToPath(ctx, file, name))
|
||||
file.Name = name
|
||||
require.NoError(t, lib.MoveFile(ctx, file))
|
||||
require.Equal(t, name, file.Name)
|
||||
require.Equal(t, directory.ID, file.ParentID)
|
||||
found, err = lib.GetByPath(ctx, directory.ID, name)
|
||||
|
||||
@@ -112,22 +112,6 @@ func (l *Library) CompileFilesQuery(query string) (*FilesQuery, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ValidateFilesQuery shares the predicate compiler with every Files read.
|
||||
func (l *Library) ValidateFilesQuery(query string) error {
|
||||
_, err := l.CompileFilesQuery(query)
|
||||
return err
|
||||
}
|
||||
|
||||
// MatchLiveFiles evaluates the ordinary query compiler over bound observations, not a cached tree.
|
||||
// It returns matching input indexes without persisting the rows or reading the filesystem.
|
||||
func (l *Library) MatchLiveFiles(ctx context.Context, query string, rows []LiveQueryRow) ([]int, error) {
|
||||
compiled, err := l.CompileFilesQuery(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l.MatchLiveQuery(ctx, compiled, rows)
|
||||
}
|
||||
|
||||
// MatchLiveQuery evaluates one compiled predicate over a bounded batch of observations.
|
||||
func (l *Library) MatchLiveQuery(ctx context.Context, query *FilesQuery, rows []LiveQueryRow) ([]int, error) {
|
||||
// An empty predicate accepts the observed batch without an extra Catalog read.
|
||||
|
||||
@@ -38,13 +38,17 @@ func TestLiveQueriesShareCatalogGrammarWithoutAdmission(t *testing.T) {
|
||||
{"location:9", []int{}},
|
||||
} {
|
||||
t.Run(test.query, func(t *testing.T) {
|
||||
matched, err := lib.MatchLiveFiles(ctx, test.query, rows)
|
||||
compiled, err := lib.CompileFilesQuery(test.query)
|
||||
require.NoError(t, err)
|
||||
matched, err := lib.MatchLiveQuery(ctx, compiled, rows)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.want, matched)
|
||||
})
|
||||
}
|
||||
require.Error(t, lib.ValidateFilesQuery("unsupported:value"))
|
||||
require.Error(t, lib.ValidateFilesQuery("has:invalid"))
|
||||
_, err := lib.CompileFilesQuery("unsupported:value")
|
||||
require.Error(t, err)
|
||||
_, err = lib.CompileFilesQuery("has:invalid")
|
||||
require.Error(t, err)
|
||||
var count int64
|
||||
require.NoError(t, db.Model(ModelFile).Count(&count).Error)
|
||||
require.Equal(t, int64(1), count)
|
||||
@@ -56,7 +60,9 @@ func TestLiveQueryAcrossProjectionBatches(t *testing.T) {
|
||||
for index := range rows {
|
||||
rows[index] = LiveQueryRow{Name: fmt.Sprintf("item-%d", index), Size: int64(index), MtimeNS: time.Now().UnixNano()}
|
||||
}
|
||||
matched, err := lib.MatchLiveFiles(context.Background(), "size:[128 TO 130]", rows)
|
||||
compiled, err := lib.CompileFilesQuery("size:[128 TO 130]")
|
||||
require.NoError(t, err)
|
||||
matched, err := lib.MatchLiveQuery(context.Background(), compiled, rows)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []int{128, 129, 130}, matched)
|
||||
}
|
||||
@@ -248,8 +248,9 @@ func TestLocationConfigurationKeepsTrackingEvidence(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Len(t, rows, 1)
|
||||
fileID := rows[0].FileID
|
||||
before, err := l.ReadFileTracking(ctx, fileID)
|
||||
tracking, err := l.ReadFileTrackingKeys(ctx, []int64{fileID})
|
||||
require.NoError(t, err)
|
||||
before := tracking[fileID]
|
||||
require.Len(t, before, 1)
|
||||
|
||||
// Both a rule change and a root change keep the evidence and the association.
|
||||
@@ -259,8 +260,9 @@ func TestLocationConfigurationKeepsTrackingEvidence(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, s.RootPath, updated.RootPath)
|
||||
require.Equal(t, "/future", updated.Config.Ignore.Text)
|
||||
after, err := l.ReadFileTracking(ctx, fileID)
|
||||
tracking, err = l.ReadFileTrackingKeys(ctx, []int64{fileID})
|
||||
require.NoError(t, err)
|
||||
after := tracking[fileID]
|
||||
require.Len(t, after, 1)
|
||||
require.Equal(t, before[0].KeyValue, after[0].KeyValue)
|
||||
remaining, err := l.LocationOriginalsPage(ctx, s.ID, "", 10)
|
||||
|
||||
@@ -102,8 +102,9 @@ func TestSingleAndBatchObservationPreserveTrackingDecisions(t *testing.T) {
|
||||
entry.TrackingKeys = nil
|
||||
_, err = admit()
|
||||
require.NoError(t, err)
|
||||
keys, err := lib.ReadFileTracking(ctx, original.FileID)
|
||||
tracking, err := lib.ReadFileTrackingKeys(ctx, []int64{original.FileID})
|
||||
require.NoError(t, err)
|
||||
keys := tracking[original.FileID]
|
||||
require.Len(t, keys, 1)
|
||||
after, err := lib.GetLocation(ctx, location.ID)
|
||||
require.NoError(t, err)
|
||||
@@ -114,8 +115,9 @@ func TestSingleAndBatchObservationPreserveTrackingDecisions(t *testing.T) {
|
||||
cleared, err := admit()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, original.FileID, cleared.FileID)
|
||||
keys, err = lib.ReadFileTracking(ctx, original.FileID)
|
||||
tracking, err = lib.ReadFileTrackingKeys(ctx, []int64{original.FileID})
|
||||
require.NoError(t, err)
|
||||
keys = tracking[original.FileID]
|
||||
require.Empty(t, keys)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -85,14 +85,6 @@ func (l *Library) SavePosition(ctx context.Context, position *Position) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (l *Library) GetPositionByFileID(ctx context.Context, fileID int64) ([]*Position, error) {
|
||||
results, err := l.MGetPositionByFileID(ctx, fileID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return results[fileID], nil
|
||||
}
|
||||
|
||||
// GetPosition returns one physical Position by its Library identity.
|
||||
func (l *Library) GetPosition(ctx context.Context, id int64) (*Position, error) {
|
||||
position := new(Position)
|
||||
@@ -185,13 +177,6 @@ func (l *Library) ListMediaFilePositions(
|
||||
return positions, nil
|
||||
}
|
||||
|
||||
func (l *Library) DeletePositions(ctx context.Context, ids ...int64) error {
|
||||
if err := l.db.WithContext(ctx).Where("id IN (?)", ids).Delete(ModelPosition).Error; err != nil {
|
||||
return fmt.Errorf("delete positions failed, %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildPositionTree adds directly queryable parent paths and derived directory rows to a sorted manifest.
|
||||
func BuildPositionTree(ctx context.Context, source PositionSource, yield func(*Position) error) error {
|
||||
if source == nil {
|
||||
|
||||
@@ -36,7 +36,10 @@ func TestApplyScanUpdatesPhysicalPositionsAtomically(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, lib.ImportArchivedInventory(ctx))
|
||||
var archived []int64
|
||||
require.NoError(t, lib.db.Model(ModelPosition).Where("is_dir = ? AND signature IS NOT NULL", false).Order("id").Pluck("id", &archived).Error)
|
||||
_, err = lib.ImportArchivePositions(ctx, archived)
|
||||
require.NoError(t, err)
|
||||
oldFile, err := lib.GetByPath(ctx, Root.ID, "Unforged/Volume/changed.txt")
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -75,9 +78,9 @@ func TestApplyScanUpdatesPhysicalPositionsAtomically(t *testing.T) {
|
||||
parents, err := lib.ListParents(ctx, preserved.ID)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, int64(TrashFileID), parents[0].ID)
|
||||
copies, err := lib.GetPositionByFileID(ctx, oldFile.ID)
|
||||
copies, err := lib.MGetPositionByFileID(ctx, oldFile.ID)
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, copies)
|
||||
require.Empty(t, copies[oldFile.ID])
|
||||
}
|
||||
|
||||
func TestApplyScanRollsBackInvalidDiff(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user