aggregate categories from selector (#1742)
## Description Adds a PathCategories() func to selectors which returns all the path categories exhibited by the scopes within the selector. ## Type of change - [x] 🌻 Feature ## Issue(s) * #1725 ## Test Plan - [x] ⚡ Unit test
This commit is contained in:
parent
65284620ea
commit
edd0708285
@ -157,28 +157,7 @@ func FilterContainersAndFillCollections(
|
||||
collections[metadataKey] = col
|
||||
}
|
||||
|
||||
// TODO(ashmrtn): getFetchIDFunc functions should probably just return a
|
||||
// multierror and all of the error handling should just use those so that it
|
||||
// all ends up more consistent.
|
||||
merrs := multierror.Append(nil, errs)
|
||||
|
||||
col, err = makeMetadataCollection(
|
||||
qp.Credentials.AzureTenantID,
|
||||
qp.ResourceOwner,
|
||||
qp.Category,
|
||||
deltaTokens,
|
||||
statusUpdater,
|
||||
)
|
||||
if err != nil {
|
||||
merrs = multierror.Append(
|
||||
merrs,
|
||||
errors.Wrap(err, "making metadata collection"),
|
||||
)
|
||||
} else if col != nil {
|
||||
collections[metadataKey] = col
|
||||
}
|
||||
|
||||
return merrs.ErrorOrNil()
|
||||
return errs
|
||||
}
|
||||
|
||||
func IterativeCollectContactContainers(
|
||||
|
||||
@ -40,6 +40,7 @@ var (
|
||||
_ Reducer = &ExchangeRestore{}
|
||||
_ printabler = &ExchangeRestore{}
|
||||
_ resourceOwnerer = &ExchangeRestore{}
|
||||
_ pathCategorier = &ExchangeRestore{}
|
||||
)
|
||||
|
||||
// NewExchange produces a new Selector with the service set to ServiceExchange.
|
||||
@ -103,6 +104,15 @@ func (s exchange) ResourceOwners() selectorResourceOwners {
|
||||
}
|
||||
}
|
||||
|
||||
// PathCategories produces the aggregation of discrete users described by each type of scope.
|
||||
func (s exchange) PathCategories() selectorPathCategories {
|
||||
return selectorPathCategories{
|
||||
Excludes: pathCategoriesIn[ExchangeScope, exchangeCategory](s.Excludes),
|
||||
Filters: pathCategoriesIn[ExchangeScope, exchangeCategory](s.Filters),
|
||||
Includes: pathCategoriesIn[ExchangeScope, exchangeCategory](s.Includes),
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// Exclude/Includes
|
||||
|
||||
@ -210,7 +220,7 @@ func (s *exchange) Contacts(users, folders, contacts []string, opts ...option) [
|
||||
func (s *exchange) ContactFolders(users, folders []string, opts ...option) []ExchangeScope {
|
||||
var (
|
||||
scopes = []ExchangeScope{}
|
||||
os = append([]option{pathType()}, opts...)
|
||||
os = append([]option{pathComparator()}, opts...)
|
||||
)
|
||||
|
||||
scopes = append(
|
||||
@ -247,7 +257,7 @@ func (s *exchange) Events(users, calendars, events []string, opts ...option) []E
|
||||
func (s *exchange) EventCalendars(users, events []string, opts ...option) []ExchangeScope {
|
||||
var (
|
||||
scopes = []ExchangeScope{}
|
||||
os = append([]option{pathType()}, opts...)
|
||||
os = append([]option{pathComparator()}, opts...)
|
||||
)
|
||||
|
||||
scopes = append(
|
||||
@ -283,7 +293,7 @@ func (s *exchange) Mails(users, folders, mails []string, opts ...option) []Excha
|
||||
func (s *exchange) MailFolders(users, folders []string, opts ...option) []ExchangeScope {
|
||||
var (
|
||||
scopes = []ExchangeScope{}
|
||||
os = append([]option{pathType()}, opts...)
|
||||
os = append([]option{pathComparator()}, opts...)
|
||||
)
|
||||
|
||||
scopes = append(
|
||||
@ -663,7 +673,7 @@ func (s ExchangeScope) Get(cat exchangeCategory) []string {
|
||||
func (s ExchangeScope) set(cat exchangeCategory, v []string, opts ...option) ExchangeScope {
|
||||
os := []option{}
|
||||
if cat == ExchangeContactFolder || cat == ExchangeEventCalendar || cat == ExchangeMailFolder {
|
||||
os = append(os, pathType())
|
||||
os = append(os, pathComparator())
|
||||
}
|
||||
|
||||
return set(s, cat, v, append(os, opts...)...)
|
||||
|
||||
@ -39,6 +39,7 @@ var (
|
||||
_ Reducer = &OneDriveRestore{}
|
||||
_ printabler = &OneDriveRestore{}
|
||||
_ resourceOwnerer = &OneDriveRestore{}
|
||||
_ pathCategorier = &OneDriveRestore{}
|
||||
)
|
||||
|
||||
// NewOneDriveBackup produces a new Selector with the service set to ServiceOneDrive.
|
||||
@ -102,6 +103,15 @@ func (s oneDrive) ResourceOwners() selectorResourceOwners {
|
||||
}
|
||||
}
|
||||
|
||||
// PathCategories produces the aggregation of discrete users described by each type of scope.
|
||||
func (s oneDrive) PathCategories() selectorPathCategories {
|
||||
return selectorPathCategories{
|
||||
Excludes: pathCategoriesIn[OneDriveScope, oneDriveCategory](s.Excludes),
|
||||
Filters: pathCategoriesIn[OneDriveScope, oneDriveCategory](s.Filters),
|
||||
Includes: pathCategoriesIn[OneDriveScope, oneDriveCategory](s.Includes),
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// Scope Factories
|
||||
|
||||
@ -197,7 +207,7 @@ func (s *oneDrive) Users(users []string) []OneDriveScope {
|
||||
func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveScope {
|
||||
var (
|
||||
scopes = []OneDriveScope{}
|
||||
os = append([]option{pathType()}, opts...)
|
||||
os = append([]option{pathComparator()}, opts...)
|
||||
)
|
||||
|
||||
scopes = append(
|
||||
@ -447,7 +457,7 @@ func (s OneDriveScope) Get(cat oneDriveCategory) []string {
|
||||
func (s OneDriveScope) set(cat oneDriveCategory, v []string, opts ...option) OneDriveScope {
|
||||
os := []option{}
|
||||
if cat == OneDriveFolder {
|
||||
os = append(os, pathType())
|
||||
os = append(os, pathComparator())
|
||||
}
|
||||
|
||||
return set(s, cat, v, append(os, opts...)...)
|
||||
|
||||
@ -84,6 +84,19 @@ type resourceOwnerer interface {
|
||||
ResourceOwners() selectorResourceOwners
|
||||
}
|
||||
|
||||
// selectorResourceOwners aggregates all discrete path category types described
|
||||
// in the selector. Category sets are grouped by their scope type (includes,
|
||||
// excludes, filters).
|
||||
type selectorPathCategories struct {
|
||||
Includes []path.CategoryType
|
||||
Excludes []path.CategoryType
|
||||
Filters []path.CategoryType
|
||||
}
|
||||
|
||||
type pathCategorier interface {
|
||||
PathCategories() selectorPathCategories
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Selector
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -205,6 +218,7 @@ func (s Selector) Reduce(ctx context.Context, deets *details.Details) (*details.
|
||||
return r.Reduce(ctx, deets), nil
|
||||
}
|
||||
|
||||
// returns the sets of resource owners identified in each scope set.
|
||||
func (s Selector) ResourceOwners() (selectorResourceOwners, error) {
|
||||
ro, err := selectorAsIface[resourceOwnerer](s)
|
||||
if err != nil {
|
||||
@ -214,6 +228,16 @@ func (s Selector) ResourceOwners() (selectorResourceOwners, error) {
|
||||
return ro.ResourceOwners(), nil
|
||||
}
|
||||
|
||||
// returns the sets of path categories identified in each scope set.
|
||||
func (s Selector) PathCategories() (selectorPathCategories, error) {
|
||||
ro, err := selectorAsIface[pathCategorier](s)
|
||||
if err != nil {
|
||||
return selectorPathCategories{}, err
|
||||
}
|
||||
|
||||
return ro.PathCategories(), nil
|
||||
}
|
||||
|
||||
// transformer for arbitrary selector interfaces
|
||||
func selectorAsIface[T any](s Selector) (T, error) {
|
||||
var (
|
||||
@ -388,6 +412,30 @@ func resourceOwnersIn(s []scope, rootCat string) []string {
|
||||
return rs
|
||||
}
|
||||
|
||||
// produces the discrete set of path categories in the slice of scopes.
|
||||
func pathCategoriesIn[T scopeT, C categoryT](ss []scope) []path.CategoryType {
|
||||
rm := map[path.CategoryType]struct{}{}
|
||||
|
||||
for _, s := range ss {
|
||||
t := T(s)
|
||||
|
||||
lc := t.categorizer().leafCat()
|
||||
if lc == lc.unknownCat() {
|
||||
continue
|
||||
}
|
||||
|
||||
rm[lc.PathType()] = struct{}{}
|
||||
}
|
||||
|
||||
rs := []path.CategoryType{}
|
||||
|
||||
for k := range rm {
|
||||
rs = append(rs, k)
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// scope helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -424,10 +472,10 @@ func SuffixMatch() option {
|
||||
}
|
||||
}
|
||||
|
||||
// pathType is an internal-facing option. It is assumed that scope
|
||||
// constructors will provide the pathType option whenever a folder-
|
||||
// pathComparator is an internal-facing option. It is assumed that scope
|
||||
// constructors will provide the pathComparator option whenever a folder-
|
||||
// level scope (ie, a scope that compares path hierarchies) is created.
|
||||
func pathType() option {
|
||||
func pathComparator() option {
|
||||
return func(sc *scopeConfig) {
|
||||
sc.usePathFilter = true
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/src/pkg/filters"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
)
|
||||
|
||||
type SelectorSuite struct {
|
||||
@ -208,6 +209,39 @@ func (suite *SelectorSuite) TestResourceOwnersIn() {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *SelectorSuite) TestPathCategoriesIn() {
|
||||
leafCat := leafCatStub.String()
|
||||
f := filters.Identity(leafCat)
|
||||
|
||||
table := []struct {
|
||||
name string
|
||||
input []scope
|
||||
expect []path.CategoryType
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
input: nil,
|
||||
expect: []path.CategoryType{},
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
input: []scope{},
|
||||
expect: []path.CategoryType{},
|
||||
},
|
||||
{
|
||||
name: "single",
|
||||
input: []scope{{leafCat: f, scopeKeyCategory: f}},
|
||||
expect: []path.CategoryType{leafCatStub.PathType()},
|
||||
},
|
||||
}
|
||||
for _, test := range table {
|
||||
suite.T().Run(test.name, func(t *testing.T) {
|
||||
result := pathCategoriesIn[mockScope, mockCategorizer](test.input)
|
||||
assert.ElementsMatch(t, test.expect, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *SelectorSuite) TestContains() {
|
||||
t := suite.T()
|
||||
key := rootCatStub
|
||||
|
||||
@ -37,6 +37,7 @@ var (
|
||||
_ Reducer = &SharePointRestore{}
|
||||
_ printabler = &SharePointRestore{}
|
||||
_ resourceOwnerer = &SharePointRestore{}
|
||||
_ pathCategorier = &SharePointRestore{}
|
||||
)
|
||||
|
||||
// NewSharePointBackup produces a new Selector with the service set to ServiceSharePoint.
|
||||
@ -100,6 +101,15 @@ func (s sharePoint) ResourceOwners() selectorResourceOwners {
|
||||
}
|
||||
}
|
||||
|
||||
// PathCategories produces the aggregation of discrete users described by each type of scope.
|
||||
func (s sharePoint) PathCategories() selectorPathCategories {
|
||||
return selectorPathCategories{
|
||||
Excludes: pathCategoriesIn[SharePointScope, sharePointCategory](s.Excludes),
|
||||
Filters: pathCategoriesIn[SharePointScope, sharePointCategory](s.Filters),
|
||||
Includes: pathCategoriesIn[SharePointScope, sharePointCategory](s.Includes),
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------
|
||||
// Scope Factories
|
||||
|
||||
@ -210,7 +220,7 @@ func (s *sharePoint) Sites(sites []string) []SharePointScope {
|
||||
func (s *sharePoint) Libraries(sites, libraries []string, opts ...option) []SharePointScope {
|
||||
var (
|
||||
scopes = []SharePointScope{}
|
||||
os = append([]option{pathType()}, opts...)
|
||||
os = append([]option{pathComparator()}, opts...)
|
||||
)
|
||||
|
||||
scopes = append(
|
||||
@ -397,7 +407,7 @@ func (s SharePointScope) Get(cat sharePointCategory) []string {
|
||||
func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option) SharePointScope {
|
||||
os := []option{}
|
||||
if cat == SharePointLibrary {
|
||||
os = append(os, pathType())
|
||||
os = append(os, pathComparator())
|
||||
}
|
||||
|
||||
return set(s, cat, v, append(os, opts...)...)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user