add scope category to path cat type func (#1344)

## Description

Builds a scope.Category() -> path.CategoryType trans- former func into scopes to standardize the relationship between the two properties.

## Type of change

- [x] 🌻 Feature

## Issue(s)

* #1133

## Test Plan

- [x]  Unit test
This commit is contained in:
Keepers 2022-10-26 15:43:35 -06:00 committed by GitHub
parent 8559c0530b
commit 77c703cee9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 131 additions and 40 deletions

View File

@ -225,7 +225,7 @@ func GetContainers(
qp graph.QueryParams,
gs graph.Service,
) ([]graph.CachedContainer, error) {
category := graph.ScopeToPathCategory(qp.Scope)
category := qp.Scope.Category().PathType()
switch category {
case path.ContactsCategory:

View File

@ -28,7 +28,7 @@ func FilterContainersAndFillCollections(
resolver graph.ContainerResolver,
) error {
var (
category = graph.ScopeToPathCategory(qp.Scope)
category = qp.Scope.Category().PathType()
collectionType = CategoryToOptionIdentifier(category)
errs error
)

View File

@ -17,7 +17,6 @@ import (
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
)
const (
@ -70,23 +69,6 @@ func (handler *LoggingMiddleware) Intercept(
return pipeline.Next(req, middlewareIndex)
}
// ScopeToPathCategory helper function that maps selectors.ExchangeScope to path.CategoryType
func ScopeToPathCategory(scope selectors.ExchangeScope) path.CategoryType {
if scope.IncludesCategory(selectors.ExchangeMail) {
return path.EmailCategory
}
if scope.IncludesCategory(selectors.ExchangeContact) {
return path.ContactsCategory
}
if scope.IncludesCategory(selectors.ExchangeEvent) {
return path.EventsCategory
}
return path.UnknownCategory
}
func StringToPathCategory(input string) path.CategoryType {
param := strings.ToLower(input)

View File

@ -298,7 +298,7 @@ func (gc *GraphConnector) createCollections(
Credentials: gc.credentials,
}
itemCategory := graph.ScopeToPathCategory(qp.Scope)
itemCategory := qp.Scope.Category().PathType()
foldersComplete, closer := observe.MessageWithCompletion(fmt.Sprintf("∙ %s - %s:", itemCategory.String(), user))
defer closer()
@ -307,7 +307,7 @@ func (gc *GraphConnector) createCollections(
resolver, err := exchange.PopulateExchangeContainerResolver(
ctx,
qp,
graph.ScopeToPathCategory(qp.Scope),
qp.Scope.Category().PathType(),
)
if err != nil {
return nil, errors.Wrap(err, "getting folder cache")

View File

@ -466,14 +466,24 @@ const (
// append new filter cats here
)
// exchangePathSet describes the category type keys used in Exchange paths.
// The order of each slice is important, and should match the order in which
// these types appear in the canonical Path for each type.
var exchangePathSet = map[categorizer][]categorizer{
ExchangeContact: {ExchangeUser, ExchangeContactFolder, ExchangeContact},
ExchangeEvent: {ExchangeUser, ExchangeEventCalendar, ExchangeEvent},
ExchangeMail: {ExchangeUser, ExchangeMailFolder, ExchangeMail},
ExchangeUser: {ExchangeUser}, // the root category must be represented
// exchangeLeafProperties describes common metadata of the leaf categories
var exchangeLeafProperties = map[categorizer]leafProperty{
ExchangeContact: {
pathKeys: []categorizer{ExchangeUser, ExchangeContactFolder, ExchangeContact},
pathType: path.ContactsCategory,
},
ExchangeEvent: {
pathKeys: []categorizer{ExchangeUser, ExchangeEventCalendar, ExchangeEvent},
pathType: path.EventsCategory,
},
ExchangeMail: {
pathKeys: []categorizer{ExchangeUser, ExchangeMailFolder, ExchangeMail},
pathType: path.EmailCategory,
},
ExchangeUser: { // the root category must be represented, even though it isn't a leaf
pathKeys: []categorizer{ExchangeUser},
pathType: path.UnknownCategory,
},
}
func (ec exchangeCategory) String() string {
@ -551,7 +561,12 @@ func (ec exchangeCategory) pathValues(p path.Path) map[categorizer]string {
// pathKeys returns the path keys recognized by the receiver's leaf type.
func (ec exchangeCategory) pathKeys() []categorizer {
return exchangePathSet[ec.leafCat()]
return exchangeLeafProperties[ec.leafCat()].pathKeys
}
// PathType converts the category's leaf type into the matching path.CategoryType.
func (ec exchangeCategory) PathType() path.CategoryType {
return exchangeLeafProperties[ec.leafCat()].pathType
}
// ---------------------------------------------------------------------------

View File

@ -1394,3 +1394,34 @@ func (suite *ExchangeSelectorSuite) TestCategoryFromItemType() {
})
}
}
func (suite *ExchangeSelectorSuite) TestCategory_PathType() {
table := []struct {
cat exchangeCategory
pathType path.CategoryType
}{
{ExchangeCategoryUnknown, path.UnknownCategory},
{ExchangeContact, path.ContactsCategory},
{ExchangeContactFolder, path.ContactsCategory},
{ExchangeEvent, path.EventsCategory},
{ExchangeEventCalendar, path.EventsCategory},
{ExchangeMail, path.EmailCategory},
{ExchangeMailFolder, path.EmailCategory},
{ExchangeUser, path.UnknownCategory},
{ExchangeFilterMailSender, path.EmailCategory},
{ExchangeFilterMailSubject, path.EmailCategory},
{ExchangeFilterMailReceivedAfter, path.EmailCategory},
{ExchangeFilterMailReceivedBefore, path.EmailCategory},
{ExchangeFilterContactName, path.ContactsCategory},
{ExchangeFilterEventOrganizer, path.EventsCategory},
{ExchangeFilterEventRecurs, path.EventsCategory},
{ExchangeFilterEventStartsAfter, path.EventsCategory},
{ExchangeFilterEventStartsBefore, path.EventsCategory},
{ExchangeFilterEventSubject, path.EventsCategory},
}
for _, test := range table {
suite.T().Run(test.cat.String(), func(t *testing.T) {
assert.Equal(t, test.pathType, test.cat.PathType())
})
}
}

View File

@ -62,6 +62,15 @@ func (mc mockCategorizer) pathKeys() []categorizer {
return []categorizer{rootCatStub, leafCatStub}
}
func (mc mockCategorizer) PathType() path.CategoryType {
switch mc {
case leafCatStub:
return path.EventsCategory
default:
return path.UnknownCategory
}
}
func stubPathValues() map[categorizer]string {
return map[categorizer]string{
rootCatStub: rootCatStub.String(),

View File

@ -288,12 +288,16 @@ const (
FileFilterModifiedBefore oneDriveCategory = "FileFilterModifiedBefore"
)
// oneDrivePathSet describes the category type keys used in OneDrive paths.
// The order of each slice is important, and should match the order in which
// these types appear in the canonical Path for each type.
var oneDrivePathSet = map[categorizer][]categorizer{
OneDriveItem: {OneDriveUser, OneDriveFolder, OneDriveItem},
OneDriveUser: {OneDriveUser}, // the root category must be represented
// oneDriveLeafProperties describes common metadata of the leaf categories
var oneDriveLeafProperties = map[categorizer]leafProperty{
OneDriveItem: {
pathKeys: []categorizer{OneDriveUser, OneDriveFolder, OneDriveItem},
pathType: path.FilesCategory,
},
OneDriveUser: { // the root category must be represented, even though it isn't a leaf
pathKeys: []categorizer{OneDriveUser},
pathType: path.UnknownCategory,
},
}
func (c oneDriveCategory) String() string {
@ -350,7 +354,12 @@ func (c oneDriveCategory) pathValues(p path.Path) map[categorizer]string {
// pathKeys returns the path keys recognized by the receiver's leaf type.
func (c oneDriveCategory) pathKeys() []categorizer {
return oneDrivePathSet[c.leafCat()]
return oneDriveLeafProperties[c.leafCat()].pathKeys
}
// PathType converts the category's leaf type into the matching path.CategoryType.
func (c oneDriveCategory) PathType() path.CategoryType {
return oneDriveLeafProperties[c.leafCat()].pathType
}
// ---------------------------------------------------------------------------

View File

@ -336,3 +336,24 @@ func (suite *OneDriveSelectorSuite) TestOneDriveScope_MatchesInfo() {
})
}
}
func (suite *OneDriveSelectorSuite) TestCategory_PathType() {
table := []struct {
cat oneDriveCategory
pathType path.CategoryType
}{
{OneDriveCategoryUnknown, path.UnknownCategory},
{OneDriveUser, path.UnknownCategory},
{OneDriveItem, path.FilesCategory},
{OneDriveFolder, path.FilesCategory},
{FileFilterCreatedAfter, path.FilesCategory},
{FileFilterCreatedBefore, path.FilesCategory},
{FileFilterModifiedAfter, path.FilesCategory},
{FileFilterModifiedBefore, path.FilesCategory},
}
for _, test := range table {
suite.T().Run(test.cat.String(), func(t *testing.T) {
assert.Equal(t, test.pathType, test.cat.PathType())
})
}
}

View File

@ -11,9 +11,29 @@ import (
)
// ---------------------------------------------------------------------------
// interfaces
// types & interfaces
// ---------------------------------------------------------------------------
// leafProperty describes metadata associated with a leaf categorizer
type leafProperty struct {
// pathKeys describes the categorizer keys used to map scope type to a value
// extracted from a path.Path.
// The order of the slice is important, and should match the order in which
// these types appear in the path.Path for each type.
// Ex: given: exchangeMail
// categoryPath => [ExchangeUser, ExchangeMailFolder, ExchangeMail]
// suggests that scopes involving exchange mail will need to match a user,
// mailFolder, and mail; appearing in the path in that order.
pathKeys []categorizer
// pathType produces the path.CategoryType representing this leafType.
// This allows the scope to type to be compared using the more commonly recognized
// path category consts.
// Ex: given: exchangeMail
// pathType => path.EmailCategory
pathType path.CategoryType
}
type (
// categorizer recognizes service specific item categories.
categorizer interface {
@ -54,6 +74,10 @@ type (
// ids in a path with the same keys that it uses to retrieve those values from a scope,
// so that the two can be compared.
pathKeys() []categorizer
// PathType converts the category's leaf type into the matching path.CategoryType.
// Exported due to common use by consuming packages.
PathType() path.CategoryType
}
// categoryT is the generic type interface of a categorizer
categoryT interface {
@ -84,7 +108,7 @@ type (
scope map[string]filters.Filter
// scoper describes the minimum necessary interface that a soundly built scope should
// comply with.
// comply with to be usable by selector generics.
scoper interface {
// Every scope is expected to contain a reference to its category. This allows users
// to evaluate structs with a call to myscope.Category(). Category() is expected to