migrate containerCache to graph pkg

ContainerCache is a generic resource that can
be moved to the graph package.  Service-
specific code is tied to the `populate` func,
which remains in each service/category.  This
change is a prepatory refactoring to reduce
boilerplate for sharepoint implementation.
This commit is contained in:
ryanfkeepers 2022-11-15 16:46:33 -07:00
parent 92e109d4eb
commit c97f5ea9a7
11 changed files with 108 additions and 186 deletions

View File

@ -2,66 +2,8 @@ package exchange
import ( import (
"github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/pkg/errors"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/pkg/path"
) )
// checkIDAndName is a helper function to ensure that
// the ID and name pointers are set prior to being called.
func checkIDAndName(c graph.Container) error {
idPtr := c.GetId()
if idPtr == nil || len(*idPtr) == 0 {
return errors.New("folder without ID")
}
ptr := c.GetDisplayName()
if ptr == nil || len(*ptr) == 0 {
return errors.Errorf("folder %s without display name", *idPtr)
}
return nil
}
// checkRequiredValues is a helper function to ensure that
// all the pointers are set prior to being called.
func checkRequiredValues(c graph.Container) error {
if err := checkIDAndName(c); err != nil {
return err
}
ptr := c.GetParentFolderId()
if ptr == nil || len(*ptr) == 0 {
return errors.Errorf("folder %s without parent ID", *c.GetId())
}
return nil
}
//======================================
// cachedContainer Implementations
//======================
var _ graph.CachedContainer = &cacheFolder{}
type cacheFolder struct {
graph.Container
p *path.Builder
}
//=========================================
// Required Functions to satisfy interfaces
//=====================================
func (cf cacheFolder) Path() *path.Builder {
return cf.p
}
func (cf *cacheFolder) SetPath(newPath *path.Builder) {
cf.p = newPath
}
// CalendarDisplayable is a transformative struct that aligns // CalendarDisplayable is a transformative struct that aligns
// models.Calendarable interface with the container interface. // models.Calendarable interface with the container interface.
// Calendars do not have a parentFolderID. Therefore, // Calendars do not have a parentFolderID. Therefore,

View File

@ -12,10 +12,10 @@ import (
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
) )
var _ graph.ContainerResolver = &contactFolderCache{} var _ graph.ContainerPopulater = &contactFolderCache{}
type contactFolderCache struct { type contactFolderCache struct {
*containerResolver *graph.ContainerCache
gs graph.Service gs graph.Service
userID string userID string
} }
@ -44,12 +44,11 @@ func (cfc *contactFolderCache) populateContactRoot(
"fetching root contact folder: "+support.ConnectorStackErrorTrace(err)) "fetching root contact folder: "+support.ConnectorStackErrorTrace(err))
} }
temp := cacheFolder{ temp := graph.NewCacheFolder(
Container: f, f,
p: path.Builder{}.Append(baseContainerPath...), path.Builder{}.Append(baseContainerPath...))
}
if err := cfc.addFolder(temp); err != nil { if err := cfc.ContainerCache.AddFolder(temp); err != nil {
return errors.Wrap(err, "adding cache root") return errors.Wrap(err, "adding cache root")
} }
@ -105,11 +104,11 @@ func (cfc *contactFolderCache) Populate(
} }
for _, entry := range containers { for _, entry := range containers {
temp := cacheFolder{ temp := graph.CacheFolder{
Container: entry, Container: entry,
} }
err = cfc.addFolder(temp) err = cfc.ContainerCache.AddFolder(temp)
if err != nil { if err != nil {
errs = support.WrapAndAppend( errs = support.WrapAndAppend(
"cache build in cfc.Populate", "cache build in cfc.Populate",
@ -118,7 +117,7 @@ func (cfc *contactFolderCache) Populate(
} }
} }
if err := cfc.populatePaths(ctx); err != nil { if err := cfc.ContainerCache.PopulatePaths(ctx); err != nil {
errs = support.WrapAndAppend( errs = support.WrapAndAppend(
"contacts resolver", "contacts resolver",
err, err,
@ -138,8 +137,8 @@ func (cfc *contactFolderCache) init(
return errors.New("m365 folderID required for base folder") return errors.New("m365 folderID required for base folder")
} }
if cfc.containerResolver == nil { if cfc.ContainerCache == nil {
cfc.containerResolver = newContainerResolver() cfc.ContainerCache = graph.NewContainerCache()
} }
return cfc.populateContactRoot(ctx, baseNode, baseContainerPath) return cfc.populateContactRoot(ctx, baseNode, baseContainerPath)

View File

@ -12,10 +12,10 @@ import (
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
) )
var _ graph.ContainerResolver = &eventCalendarCache{} var _ graph.ContainerPopulater = &eventCalendarCache{}
type eventCalendarCache struct { type eventCalendarCache struct {
*containerResolver *graph.ContainerCache
gs graph.Service gs graph.Service
userID string userID string
} }
@ -28,8 +28,8 @@ func (ecc *eventCalendarCache) Populate(
baseID string, baseID string,
baseContainerPath ...string, baseContainerPath ...string,
) error { ) error {
if ecc.containerResolver == nil { if ecc.ContainerCache == nil {
ecc.containerResolver = newContainerResolver() ecc.ContainerCache = graph.NewContainerCache()
} }
options, err := optionsForCalendars([]string{"name"}) options, err := optionsForCalendars([]string{"name"})
@ -76,7 +76,7 @@ func (ecc *eventCalendarCache) Populate(
} }
for _, container := range directories { for _, container := range directories {
if err := checkIDAndName(container); err != nil { if err := graph.CheckIDAndName(container); err != nil {
iterateErr = support.WrapAndAppend( iterateErr = support.WrapAndAppend(
"adding folder to cache", "adding folder to cache",
err, err,
@ -86,12 +86,11 @@ func (ecc *eventCalendarCache) Populate(
continue continue
} }
temp := cacheFolder{ temp := graph.NewCacheFolder(
Container: container, container,
p: path.Builder{}.Append(*container.GetDisplayName()), path.Builder{}.Append(*container.GetDisplayName()))
}
if err := ecc.addFolder(temp); err != nil { if err := ecc.ContainerCache.AddFolder(temp); err != nil {
iterateErr = support.WrapAndAppend( iterateErr = support.WrapAndAppend(
"failure adding "+*container.GetDisplayName(), "failure adding "+*container.GetDisplayName(),
err, err,
@ -104,23 +103,22 @@ func (ecc *eventCalendarCache) Populate(
// AddToCache adds container to map in field 'cache' // AddToCache adds container to map in field 'cache'
// @returns error iff the required values are not accessible. // @returns error iff the required values are not accessible.
func (ecc *eventCalendarCache) AddToCache(ctx context.Context, f graph.Container) error { func (ecc *eventCalendarCache) AddToCache(ctx context.Context, c graph.Container) error {
if err := checkIDAndName(f); err != nil { if err := graph.CheckIDAndName(c); err != nil {
return errors.Wrap(err, "adding cache folder") return errors.Wrap(err, "adding cache folder")
} }
temp := cacheFolder{ temp := graph.NewCacheFolder(
Container: f, c,
p: path.Builder{}.Append(*f.GetDisplayName()), path.Builder{}.Append(*c.GetDisplayName()))
}
if err := ecc.addFolder(temp); err != nil { if err := ecc.ContainerCache.AddFolder(temp); err != nil {
return errors.Wrap(err, "adding cache folder") return errors.Wrap(err, "adding cache folder")
} }
// Populate the path for this entry so calls to PathInCache succeed no matter // Populate the path for this entry so calls to PathInCache succeed no matter
// when they're made. // when they're made.
_, err := ecc.IDToPath(ctx, *f.GetId()) _, err := ecc.ContainerCache.IDToPath(ctx, *c.GetId())
if err != nil { if err != nil {
return errors.Wrap(err, "adding cache entry") return errors.Wrap(err, "adding cache entry")
} }

View File

@ -494,7 +494,7 @@ func (suite *ExchangeServiceSuite) TestGetContainerIDFromCache() {
t = suite.T() t = suite.T()
user = tester.M365UserID(t) user = tester.M365UserID(t)
connector = loadService(t) connector = loadService(t)
directoryCaches = make(map[path.CategoryType]graph.ContainerResolver) directoryCaches = make(map[path.CategoryType]graph.ContainerPopulater)
folderName = tester.DefaultTestRestoreDestination().ContainerName folderName = tester.DefaultTestRestoreDestination().ContainerName
tests = []struct { tests = []struct {
name string name string

View File

@ -50,14 +50,14 @@ func (suite *CacheResolverSuite) TestPopulate() {
ctx, flush := tester.NewContext() ctx, flush := tester.NewContext()
defer flush() defer flush()
eventFunc := func(t *testing.T) graph.ContainerResolver { eventFunc := func(t *testing.T) graph.ContainerPopulater {
return &eventCalendarCache{ return &eventCalendarCache{
userID: tester.M365UserID(t), userID: tester.M365UserID(t),
gs: suite.gs, gs: suite.gs,
} }
} }
contactFunc := func(t *testing.T) graph.ContainerResolver { contactFunc := func(t *testing.T) graph.ContainerPopulater {
return &contactFolderCache{ return &contactFolderCache{
userID: tester.M365UserID(t), userID: tester.M365UserID(t),
gs: suite.gs, gs: suite.gs,
@ -66,7 +66,7 @@ func (suite *CacheResolverSuite) TestPopulate() {
tests := []struct { tests := []struct {
name, folderName, root, basePath string name, folderName, root, basePath string
resolverFunc func(t *testing.T) graph.ContainerResolver resolverFunc func(t *testing.T) graph.ContainerPopulater
canFind assert.BoolAssertionFunc canFind assert.BoolAssertionFunc
}{ }{
{ {

View File

@ -12,13 +12,13 @@ import (
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
) )
var _ graph.ContainerResolver = &mailFolderCache{} var _ graph.ContainerPopulater = &mailFolderCache{}
// mailFolderCache struct used to improve lookup of directories within exchange.Mail // mailFolderCache struct used to improve lookup of directories within exchange.Mail
// cache map of cachedContainers where the key = M365ID // cache map of cachedContainers where the key = M365ID
// nameLookup map: Key: DisplayName Value: ID // nameLookup map: Key: DisplayName Value: ID
type mailFolderCache struct { type mailFolderCache struct {
*containerResolver *graph.ContainerCache
gs graph.Service gs graph.Service
userID string userID string
} }
@ -51,12 +51,11 @@ func (mc *mailFolderCache) populateMailRoot(
return errors.Wrap(err, "fetching root folder"+support.ConnectorStackErrorTrace(err)) return errors.Wrap(err, "fetching root folder"+support.ConnectorStackErrorTrace(err))
} }
temp := cacheFolder{ temp := graph.NewCacheFolder(
Container: f, f,
p: path.Builder{}.Append(baseContainerPath...), path.Builder{}.Append(baseContainerPath...))
}
if err := mc.addFolder(temp); err != nil { if err := mc.ContainerCache.AddFolder(temp); err != nil {
return errors.Wrap(err, "initializing mail resolver") return errors.Wrap(err, "initializing mail resolver")
} }
@ -95,14 +94,14 @@ func (mc *mailFolderCache) Populate(
} }
for _, f := range resp.GetValue() { for _, f := range resp.GetValue() {
temp := cacheFolder{ temp := graph.CacheFolder{
Container: f, Container: f,
} }
// Use addFolder instead of AddToCache to be conservative about path // Use addFolder instead of AddToCache to be conservative about path
// population. The fetch order of the folders could cause failures while // population. The fetch order of the folders could cause failures while
// trying to resolve paths, so put it off until we've gotten all folders. // trying to resolve paths, so put it off until we've gotten all folders.
if err := mc.addFolder(temp); err != nil { if err := mc.ContainerCache.AddFolder(temp); err != nil {
errs = multierror.Append(errs, errors.Wrap(err, "delta fetch")) errs = multierror.Append(errs, errors.Wrap(err, "delta fetch"))
continue continue
} }
@ -119,7 +118,7 @@ func (mc *mailFolderCache) Populate(
query = msfolderdelta.NewDeltaRequestBuilder(link, mc.gs.Adapter()) query = msfolderdelta.NewDeltaRequestBuilder(link, mc.gs.Adapter())
} }
if err := mc.populatePaths(ctx); err != nil { if err := mc.ContainerCache.PopulatePaths(ctx); err != nil {
errs = multierror.Append(errs, errors.Wrap(err, "mail resolver")) errs = multierror.Append(errs, errors.Wrap(err, "mail resolver"))
} }
@ -138,8 +137,8 @@ func (mc *mailFolderCache) init(
return errors.New("m365 folder ID required for base folder") return errors.New("m365 folder ID required for base folder")
} }
if mc.containerResolver == nil { if mc.ContainerCache == nil {
mc.containerResolver = newContainerResolver() mc.ContainerCache = graph.NewContainerCache()
} }
return mc.populateMailRoot(ctx, baseNode, baseContainerPath) return mc.populateMailRoot(ctx, baseNode, baseContainerPath)

View File

@ -26,6 +26,7 @@ type exchangeService struct {
///------------------------------------------------------------ ///------------------------------------------------------------
// Functions to comply with graph.Service Interface // Functions to comply with graph.Service Interface
//------------------------------------------------------- //-------------------------------------------------------
func (es *exchangeService) Client() *msgraphsdk.GraphServiceClient { func (es *exchangeService) Client() *msgraphsdk.GraphServiceClient {
return &es.client return &es.client
} }
@ -232,7 +233,7 @@ func PopulateExchangeContainerResolver(
qp graph.QueryParams, qp graph.QueryParams,
) (graph.ContainerResolver, error) { ) (graph.ContainerResolver, error) {
var ( var (
res graph.ContainerResolver res graph.ContainerPopulater
cacheRoot string cacheRoot string
service, err = createService(qp.Credentials, qp.FailFast) service, err = createService(qp.Credentials, qp.FailFast)
) )

View File

@ -292,7 +292,7 @@ func RestoreExchangeDataCollections(
) (*support.ConnectorOperationStatus, error) { ) (*support.ConnectorOperationStatus, error) {
var ( var (
// map of caches... but not yet... // map of caches... but not yet...
directoryCaches = make(map[string]map[path.CategoryType]graph.ContainerResolver) directoryCaches = make(map[string]map[path.CategoryType]graph.ContainerPopulater)
metrics support.CollectionMetrics metrics support.CollectionMetrics
errs error errs error
// TODO policy to be updated from external source after completion of refactoring // TODO policy to be updated from external source after completion of refactoring
@ -308,7 +308,7 @@ func RestoreExchangeDataCollections(
userCaches := directoryCaches[userID] userCaches := directoryCaches[userID]
if userCaches == nil { if userCaches == nil {
directoryCaches[userID] = make(map[path.CategoryType]graph.ContainerResolver) directoryCaches[userID] = make(map[path.CategoryType]graph.ContainerPopulater)
userCaches = directoryCaches[userID] userCaches = directoryCaches[userID]
} }
@ -432,7 +432,7 @@ func GetContainerIDFromCache(
gs graph.Service, gs graph.Service,
directory path.Path, directory path.Path,
destination string, destination string,
caches map[path.CategoryType]graph.ContainerResolver, caches map[path.CategoryType]graph.ContainerPopulater,
) (string, error) { ) (string, error) {
var ( var (
newCache = false newCache = false
@ -512,7 +512,7 @@ func GetContainerIDFromCache(
func establishMailRestoreLocation( func establishMailRestoreLocation(
ctx context.Context, ctx context.Context,
folders []string, folders []string,
mfc graph.ContainerResolver, mfc graph.ContainerPopulater,
user string, user string,
service graph.Service, service graph.Service,
isNewCache bool, isNewCache bool,
@ -569,7 +569,7 @@ func establishMailRestoreLocation(
func establishContactsRestoreLocation( func establishContactsRestoreLocation(
ctx context.Context, ctx context.Context,
folders []string, folders []string,
cfc graph.ContainerResolver, cfc graph.ContainerPopulater,
user string, user string,
gs graph.Service, gs graph.Service,
isNewCache bool, isNewCache bool,
@ -602,7 +602,7 @@ func establishContactsRestoreLocation(
func establishEventsRestoreLocation( func establishEventsRestoreLocation(
ctx context.Context, ctx context.Context,
folders []string, folders []string,
ecc graph.ContainerResolver, // eventCalendarCache ecc graph.ContainerPopulater, // eventCalendarCache
user string, user string,
gs graph.Service, gs graph.Service,
isNewCache bool, isNewCache bool,

View File

@ -1,7 +1,6 @@
package graph package graph
import ( import (
"github.com/microsoftgraph/msgraph-sdk-go/models"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
@ -16,9 +15,9 @@ type CachedContainer interface {
SetPath(*path.Builder) SetPath(*path.Builder)
} }
// checkRequiredValues is a helper function to ensure that // CheckIDAndName is a helper function to ensure that
// all the pointers are set prior to being called. // the ID and name pointers are set prior to being called.
func CheckRequiredValues(c Container) error { func CheckIDAndName(c Container) error {
idPtr := c.GetId() idPtr := c.GetId()
if idPtr == nil || len(*idPtr) == 0 { if idPtr == nil || len(*idPtr) == 0 {
return errors.New("folder without ID") return errors.New("folder without ID")
@ -29,9 +28,19 @@ func CheckRequiredValues(c Container) error {
return errors.Errorf("folder %s without display name", *idPtr) return errors.Errorf("folder %s without display name", *idPtr)
} }
ptr = c.GetParentFolderId() return nil
}
// CheckRequiredValues is a helper function to ensure that
// all the pointers are set prior to being called.
func CheckRequiredValues(c Container) error {
if err := CheckIDAndName(c); err != nil {
return err
}
ptr := c.GetParentFolderId()
if ptr == nil || len(*ptr) == 0 { if ptr == nil || len(*ptr) == 0 {
return errors.Errorf("folder %s without parent ID", *idPtr) return errors.Errorf("folder %s without parent ID", *c.GetId())
} }
return nil return nil
@ -58,10 +67,6 @@ func NewCacheFolder(c Container, pb *path.Builder) CacheFolder {
return cf return cf
} }
//=========================================
// Required Functions to satisfy interfaces
//=========================================
func (cf CacheFolder) Path() *path.Builder { func (cf CacheFolder) Path() *path.Builder {
return cf.p return cf.p
} }
@ -69,41 +74,3 @@ func (cf CacheFolder) Path() *path.Builder {
func (cf *CacheFolder) SetPath(newPath *path.Builder) { func (cf *CacheFolder) SetPath(newPath *path.Builder) {
cf.p = newPath cf.p = newPath
} }
// CalendarDisplayable is a transformative struct that aligns
// models.Calendarable interface with the container interface.
// Calendars do not have the 2 of the
type CalendarDisplayable struct {
models.Calendarable
parentID string
}
// GetDisplayName returns the *string of the calendar name
func (c CalendarDisplayable) GetDisplayName() *string {
return c.GetName()
}
// GetParentFolderId returns the default calendar name address
// EventCalendars have a flat hierarchy and Calendars are rooted
// at the default
//nolint:revive
func (c CalendarDisplayable) GetParentFolderId() *string {
return &c.parentID
}
// CreateCalendarDisplayable helper function to create the
// calendarDisplayable during msgraph-sdk-go iterative process
// @param entry is the input supplied by pageIterator.Iterate()
// @param parentID of Calendar sets. Only populate when used with
// EventCalendarCache
func CreateCalendarDisplayable(entry any, parentID string) *CalendarDisplayable {
calendar, ok := entry.(models.Calendarable)
if !ok {
return nil
}
return &CalendarDisplayable{
Calendarable: calendar,
parentID: parentID,
}
}

View File

@ -1,4 +1,4 @@
package exchange package graph
import ( import (
"context" "context"
@ -6,21 +6,28 @@ import (
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
) )
func newContainerResolver() *containerResolver { var _ ContainerResolver = &ContainerCache{}
return &containerResolver{
cache: map[string]graph.CachedContainer{}, type populatorFunc func(
ctx context.Context,
baseID string,
baseContainerPath ...string,
)
type ContainerCache struct {
cache map[string]CachedContainer
}
func NewContainerCache() *ContainerCache {
return &ContainerCache{
cache: map[string]CachedContainer{},
} }
} }
type containerResolver struct { func (cr *ContainerCache) IDToPath(
cache map[string]graph.CachedContainer
}
func (cr *containerResolver) IDToPath(
ctx context.Context, ctx context.Context,
folderID string, folderID string,
) (*path.Builder, error) { ) (*path.Builder, error) {
@ -48,7 +55,7 @@ func (cr *containerResolver) IDToPath(
// PathInCache utility function to return m365ID of folder if the pathString // PathInCache utility function to return m365ID of folder if the pathString
// matches the path of a container within the cache. A boolean function // matches the path of a container within the cache. A boolean function
// accompanies the call to indicate whether the lookup was successful. // accompanies the call to indicate whether the lookup was successful.
func (cr *containerResolver) PathInCache(pathString string) (string, bool) { func (cr *ContainerCache) PathInCache(pathString string) (string, bool) {
if len(pathString) == 0 || cr == nil { if len(pathString) == 0 || cr == nil {
return "", false return "", false
} }
@ -66,17 +73,17 @@ func (cr *containerResolver) PathInCache(pathString string) (string, bool) {
return "", false return "", false
} }
// addFolder adds a folder to the cache with the given ID. If the item is // AddFolder adds a folder to the cache with the given ID. If the item is
// already in the cache does nothing. The path for the item is not modified. // already in the cache does nothing. The path for the item is not modified.
func (cr *containerResolver) addFolder(cf cacheFolder) error { func (cr *ContainerCache) AddFolder(cf CacheFolder) error {
// Only require a non-nil non-empty parent if the path isn't already // Only require a non-nil non-empty parent if the path isn't already
// populated. // populated.
if cf.p != nil { if cf.p != nil {
if err := checkIDAndName(cf.Container); err != nil { if err := CheckIDAndName(cf.Container); err != nil {
return errors.Wrap(err, "adding item to cache") return errors.Wrap(err, "adding item to cache")
} }
} else { } else {
if err := checkRequiredValues(cf.Container); err != nil { if err := CheckRequiredValues(cf.Container); err != nil {
return errors.Wrap(err, "adding item to cache") return errors.Wrap(err, "adding item to cache")
} }
} }
@ -90,8 +97,9 @@ func (cr *containerResolver) addFolder(cf cacheFolder) error {
return nil return nil
} }
func (cr *containerResolver) Items() []graph.CachedContainer { // Items returns the list of Containers in the cache.
res := make([]graph.CachedContainer, 0, len(cr.cache)) func (cr *ContainerCache) Items() []CachedContainer {
res := make([]CachedContainer, 0, len(cr.cache))
for _, c := range cr.cache { for _, c := range cr.cache {
res = append(res, c) res = append(res, c)
@ -102,12 +110,12 @@ func (cr *containerResolver) Items() []graph.CachedContainer {
// AddToCache adds container to map in field 'cache' // AddToCache adds container to map in field 'cache'
// @returns error iff the required values are not accessible. // @returns error iff the required values are not accessible.
func (cr *containerResolver) AddToCache(ctx context.Context, f graph.Container) error { func (cr *ContainerCache) AddToCache(ctx context.Context, f Container) error {
temp := cacheFolder{ temp := CacheFolder{
Container: f, Container: f,
} }
if err := cr.addFolder(temp); err != nil { if err := cr.AddFolder(temp); err != nil {
return errors.Wrap(err, "adding cache folder") return errors.Wrap(err, "adding cache folder")
} }
@ -121,10 +129,10 @@ func (cr *containerResolver) AddToCache(ctx context.Context, f graph.Container)
return nil return nil
} }
func (cr *containerResolver) populatePaths(ctx context.Context) error { // PopulatePaths ensures that all items in the cache can construct valid paths.
func (cr *ContainerCache) PopulatePaths(ctx context.Context) error {
var errs *multierror.Error var errs *multierror.Error
// Populate all folder paths.
for _, f := range cr.Items() { for _, f := range cr.Items() {
_, err := cr.IDToPath(ctx, *f.GetId()) _, err := cr.IDToPath(ctx, *f.GetId())
if err != nil { if err != nil {

View File

@ -60,11 +60,6 @@ type ContainerResolver interface {
// to that container. The path has a similar format to paths on the local // to that container. The path has a similar format to paths on the local
// file system. // file system.
IDToPath(ctx context.Context, m365ID string) (*path.Builder, error) IDToPath(ctx context.Context, m365ID string) (*path.Builder, error)
// Populate performs initialization steps for the resolver
// @param ctx is necessary param for Graph API tracing
// @param baseFolderID represents the M365ID base that the resolver will
// conclude its search. Default input is "".
Populate(ctx context.Context, baseFolderID string, baseContainerPather ...string) error
// PathInCache performs a look up of a path reprensentation // PathInCache performs a look up of a path reprensentation
// and returns the m365ID of directory iff the pathString // and returns the m365ID of directory iff the pathString
@ -77,3 +72,16 @@ type ContainerResolver interface {
// Items returns the containers in the cache. // Items returns the containers in the cache.
Items() []CachedContainer Items() []CachedContainer
} }
// ContainerPopulater houses functions for populating and retrieving info
// about containers from remote APIs (i.e. resolve folder paths with Graph
// API). Populaters may cache information about containers.
type ContainerPopulater interface {
ContainerResolver
// Populate performs initialization steps for the populater
// @param ctx is necessary param for Graph API tracing
// @param baseFolderID represents the M365ID base that the
// populater will conclude its search. Default input is "".
Populate(ctx context.Context, baseFolderID string, baseContainerPather ...string) error
}