add delta tree (#4692)

introduces the delta tree in drive collections

---

#### Does this PR need a docs update or release note?

- [x]  No

#### Issue(s)

* #4689

#### Test Plan

- [x]  Unit test
This commit is contained in:
Keepers 2023-11-15 19:16:00 -07:00 committed by GitHub
parent 6fe6c9586d
commit dbdd3f236c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 136 additions and 0 deletions

View File

@ -0,0 +1,80 @@
package drive
import (
"time"
"github.com/alcionai/corso/src/pkg/path"
)
// folderyMcFolderFace owns our delta processing tree.
type folderyMcFolderFace struct {
// tenant/service/resource/category/driveID
// (or whatever variant the service defines)
// allows the tree to focus only on folder structure,
// and minimizes the possibility of multi-prefix path bugs.
prefix path.Path
// the root of the tree;
// new, moved, and notMoved collections
collections *nodeyMcNodeFace
// the majority of operations we perform can be handled with
// a folder ID lookup instead of re-walking the entire tree.
// Ex: adding a new file to its parent folder.
folderIDToNode map[string]*nodeyMcNodeFace
// tombstones don't need to form a tree.
// we only need the folder ID and their previous path.
tombstones map[string]path.Path
// it's just a sensible place to store the data, since we're
// already pushing file additions through the api.
excludeFileIDs map[string]struct{}
}
func newFolderyMcFolderFace(
prefix path.Path,
) *folderyMcFolderFace {
return &folderyMcFolderFace{
prefix: prefix,
folderIDToNode: map[string]*nodeyMcNodeFace{},
tombstones: map[string]path.Path{},
excludeFileIDs: map[string]struct{}{},
}
}
type nodeyMcNodeFace struct {
// required for mid-enumeration folder moves, else we have to walk
// the tree completely to remove the node from its old parent.
parent *nodeyMcNodeFace
// the microsoft item ID. Mostly because we might as well
// attach that to the node if we're also attaching the dir.
id string
// single directory name, not a path
name string
// only contains the folders starting at and including '/root:'
prev path.Path
// map folderID -> node
childDirs map[string]*nodeyMcNodeFace
// items are keyed by item ID
items map[string]time.Time
// for special handling protocols around packages
isPackage bool
}
func newNodeyMcNodeFace(
parent *nodeyMcNodeFace,
id, name string,
prev path.Path,
isPackage bool,
) *nodeyMcNodeFace {
return &nodeyMcNodeFace{
parent: parent,
id: id,
name: name,
prev: prev,
childDirs: map[string]*nodeyMcNodeFace{},
items: map[string]time.Time{},
isPackage: isPackage,
}
}

View File

@ -0,0 +1,56 @@
package drive
import (
"testing"
"github.com/alcionai/clues"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/path"
)
type DeltaTreeUnitSuite struct {
tester.Suite
}
func TestDeltaTreeUnitSuite(t *testing.T) {
suite.Run(t, &DeltaTreeUnitSuite{Suite: tester.NewUnitSuite(t)})
}
func (suite *DeltaTreeUnitSuite) TestNewFolderyMcFolderFace() {
var (
t = suite.T()
p, err = path.BuildPrefix("t", "r", path.OneDriveService, path.FilesCategory)
)
require.NoError(t, err, clues.ToCore(err))
folderFace := newFolderyMcFolderFace(p)
assert.Equal(t, p, folderFace.prefix)
assert.Nil(t, folderFace.collections)
assert.NotNil(t, folderFace.folderIDToNode)
assert.NotNil(t, folderFace.tombstones)
assert.NotNil(t, folderFace.excludeFileIDs)
}
func (suite *DeltaTreeUnitSuite) TestNewNodeyMcNodeFace() {
var (
t = suite.T()
parent = &nodeyMcNodeFace{}
p, err = path.Build("t", "r", path.SharePointService, path.LibrariesCategory, false, "drive-id", "root:")
)
require.NoError(t, err, clues.ToCore(err))
nodeFace := newNodeyMcNodeFace(parent, "id", "name", p, true)
assert.Equal(t, parent, nodeFace.parent)
assert.Equal(t, "id", nodeFace.id)
assert.Equal(t, "name", nodeFace.name)
assert.Equal(t, p, nodeFace.prev)
assert.True(t, nodeFace.isPackage)
assert.NotNil(t, nodeFace.childDirs)
assert.NotNil(t, nodeFace.items)
}