add generic item enumeratiton iface to api (#3628)
Adds a generic item enumeration pager to the api's item_pager set. This compliments the more focused getIdsAndAdditional with something that's oriented towards single-folder, non-delta enumeration. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [ ] 🌻 Feature #### Issue(s) * #3562 #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
d9b5cda8f1
commit
3bcc405327
@ -90,19 +90,51 @@ func (c Contacts) EnumerateContainers(
|
||||
// item pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemPager = &contactPager{}
|
||||
var _ itemPager[models.Contactable] = &contactsPager{}
|
||||
|
||||
type contactPager struct {
|
||||
type contactsPager struct {
|
||||
// TODO(rkeeprs)
|
||||
}
|
||||
|
||||
func (c Contacts) NewContactsPager() itemPager[models.Contactable] {
|
||||
// TODO(rkeepers)
|
||||
return nil
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *contactsPager) getPage(ctx context.Context) (PageLinker, error) {
|
||||
// TODO(rkeepers)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *contactsPager) setNext(nextLink string) {
|
||||
// TODO(rkeepers)
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *contactsPager) valuesIn(pl PageLinker) ([]models.Contactable, error) {
|
||||
// TODO(rkeepers)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// item ID pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemIDPager = &contactIDPager{}
|
||||
|
||||
type contactIDPager struct {
|
||||
gs graph.Servicer
|
||||
builder *users.ItemContactFoldersItemContactsRequestBuilder
|
||||
options *users.ItemContactFoldersItemContactsRequestBuilderGetRequestConfiguration
|
||||
}
|
||||
|
||||
func (c Contacts) NewContactPager(
|
||||
func (c Contacts) NewContactIDsPager(
|
||||
ctx context.Context,
|
||||
userID, containerID string,
|
||||
immutableIDs bool,
|
||||
) itemPager {
|
||||
) itemIDPager {
|
||||
config := &users.ItemContactFoldersItemContactsRequestBuilderGetRequestConfiguration{
|
||||
QueryParameters: &users.ItemContactFoldersItemContactsRequestBuilderGetQueryParameters{
|
||||
Select: idAnd(parentFolderID),
|
||||
@ -118,10 +150,10 @@ func (c Contacts) NewContactPager(
|
||||
ByContactFolderId(containerID).
|
||||
Contacts()
|
||||
|
||||
return &contactPager{c.Stable, builder, config}
|
||||
return &contactIDPager{c.Stable, builder, config}
|
||||
}
|
||||
|
||||
func (p *contactPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
func (p *contactIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
resp, err := p.builder.Get(ctx, p.options)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
@ -130,24 +162,24 @@ func (p *contactPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
return EmptyDeltaLinker[models.Contactable]{PageLinkValuer: resp}, nil
|
||||
}
|
||||
|
||||
func (p *contactPager) setNext(nextLink string) {
|
||||
func (p *contactIDPager) setNext(nextLink string) {
|
||||
p.builder = users.NewItemContactFoldersItemContactsRequestBuilder(nextLink, p.gs.Adapter())
|
||||
}
|
||||
|
||||
// non delta pagers don't need reset
|
||||
func (p *contactPager) reset(context.Context) {}
|
||||
func (p *contactIDPager) reset(context.Context) {}
|
||||
|
||||
func (p *contactPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
func (p *contactIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
return toValues[models.Contactable](pl)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// delta item pager
|
||||
// delta item ID pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemPager = &contactDeltaPager{}
|
||||
var _ itemIDPager = &contactDeltaIDPager{}
|
||||
|
||||
type contactDeltaPager struct {
|
||||
type contactDeltaIDPager struct {
|
||||
gs graph.Servicer
|
||||
userID string
|
||||
containerID string
|
||||
@ -165,11 +197,11 @@ func getContactDeltaBuilder(
|
||||
return builder
|
||||
}
|
||||
|
||||
func (c Contacts) NewContactDeltaPager(
|
||||
func (c Contacts) NewContactDeltaIDsPager(
|
||||
ctx context.Context,
|
||||
userID, containerID, oldDelta string,
|
||||
immutableIDs bool,
|
||||
) itemPager {
|
||||
) itemIDPager {
|
||||
options := &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration{
|
||||
QueryParameters: &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetQueryParameters{
|
||||
Select: idAnd(parentFolderID),
|
||||
@ -184,10 +216,10 @@ func (c Contacts) NewContactDeltaPager(
|
||||
builder = getContactDeltaBuilder(ctx, c.Stable, userID, containerID, options)
|
||||
}
|
||||
|
||||
return &contactDeltaPager{c.Stable, userID, containerID, builder, options}
|
||||
return &contactDeltaIDPager{c.Stable, userID, containerID, builder, options}
|
||||
}
|
||||
|
||||
func (p *contactDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
func (p *contactDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
resp, err := p.builder.Get(ctx, p.options)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
@ -196,15 +228,15 @@ func (p *contactDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (p *contactDeltaPager) setNext(nextLink string) {
|
||||
func (p *contactDeltaIDPager) setNext(nextLink string) {
|
||||
p.builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
||||
}
|
||||
|
||||
func (p *contactDeltaPager) reset(ctx context.Context) {
|
||||
func (p *contactDeltaIDPager) reset(ctx context.Context) {
|
||||
p.builder = getContactDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options)
|
||||
}
|
||||
|
||||
func (p *contactDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
func (p *contactDeltaIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
return toValues[models.Contactable](pl)
|
||||
}
|
||||
|
||||
@ -219,8 +251,8 @@ func (c Contacts) GetAddedAndRemovedItemIDs(
|
||||
"category", selectors.ExchangeContact,
|
||||
"container_id", containerID)
|
||||
|
||||
pager := c.NewContactPager(ctx, userID, containerID, immutableIDs)
|
||||
deltaPager := c.NewContactDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||
pager := c.NewContactIDsPager(ctx, userID, containerID, immutableIDs)
|
||||
deltaPager := c.NewContactDeltaIDsPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||
|
||||
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
||||
}
|
||||
|
||||
@ -98,19 +98,51 @@ func (c Events) EnumerateContainers(
|
||||
// item pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemPager = &eventPager{}
|
||||
var _ itemPager[models.Eventable] = &eventsPager{}
|
||||
|
||||
type eventPager struct {
|
||||
type eventsPager struct {
|
||||
// TODO(rkeeprs)
|
||||
}
|
||||
|
||||
func (c Events) NewEventsPager() itemPager[models.Eventable] {
|
||||
// TODO(rkeepers)
|
||||
return nil
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *eventsPager) getPage(ctx context.Context) (PageLinker, error) {
|
||||
// TODO(rkeepers)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *eventsPager) setNext(nextLink string) {
|
||||
// TODO(rkeepers)
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *eventsPager) valuesIn(pl PageLinker) ([]models.Eventable, error) {
|
||||
// TODO(rkeepers)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// item ID pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemIDPager = &eventIDPager{}
|
||||
|
||||
type eventIDPager struct {
|
||||
gs graph.Servicer
|
||||
builder *users.ItemCalendarsItemEventsRequestBuilder
|
||||
options *users.ItemCalendarsItemEventsRequestBuilderGetRequestConfiguration
|
||||
}
|
||||
|
||||
func (c Events) NewEventPager(
|
||||
func (c Events) NewEventIDsPager(
|
||||
ctx context.Context,
|
||||
userID, containerID string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
) (itemIDPager, error) {
|
||||
options := &users.ItemCalendarsItemEventsRequestBuilderGetRequestConfiguration{
|
||||
Headers: newPreferHeaders(preferPageSize(maxNonDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||
}
|
||||
@ -123,10 +155,10 @@ func (c Events) NewEventPager(
|
||||
ByCalendarId(containerID).
|
||||
Events()
|
||||
|
||||
return &eventPager{c.Stable, builder, options}, nil
|
||||
return &eventIDPager{c.Stable, builder, options}, nil
|
||||
}
|
||||
|
||||
func (p *eventPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
func (p *eventIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
resp, err := p.builder.Get(ctx, p.options)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
@ -135,24 +167,24 @@ func (p *eventPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
return EmptyDeltaLinker[models.Eventable]{PageLinkValuer: resp}, nil
|
||||
}
|
||||
|
||||
func (p *eventPager) setNext(nextLink string) {
|
||||
func (p *eventIDPager) setNext(nextLink string) {
|
||||
p.builder = users.NewItemCalendarsItemEventsRequestBuilder(nextLink, p.gs.Adapter())
|
||||
}
|
||||
|
||||
// non delta pagers don't need reset
|
||||
func (p *eventPager) reset(context.Context) {}
|
||||
func (p *eventIDPager) reset(context.Context) {}
|
||||
|
||||
func (p *eventPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
func (p *eventIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
return toValues[models.Eventable](pl)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// delta item pager
|
||||
// delta item ID pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemPager = &eventDeltaPager{}
|
||||
var _ itemIDPager = &eventDeltaIDPager{}
|
||||
|
||||
type eventDeltaPager struct {
|
||||
type eventDeltaIDPager struct {
|
||||
gs graph.Servicer
|
||||
userID string
|
||||
containerID string
|
||||
@ -160,11 +192,11 @@ type eventDeltaPager struct {
|
||||
options *users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration
|
||||
}
|
||||
|
||||
func (c Events) NewEventDeltaPager(
|
||||
func (c Events) NewEventDeltaIDsPager(
|
||||
ctx context.Context,
|
||||
userID, containerID, oldDelta string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
) (itemIDPager, error) {
|
||||
options := &users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration{
|
||||
Headers: newPreferHeaders(preferPageSize(maxDeltaPageSize), preferImmutableIDs(immutableIDs)),
|
||||
}
|
||||
@ -177,7 +209,7 @@ func (c Events) NewEventDeltaPager(
|
||||
builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(oldDelta, c.Stable.Adapter())
|
||||
}
|
||||
|
||||
return &eventDeltaPager{c.Stable, userID, containerID, builder, options}, nil
|
||||
return &eventDeltaIDPager{c.Stable, userID, containerID, builder, options}, nil
|
||||
}
|
||||
|
||||
func getEventDeltaBuilder(
|
||||
@ -200,7 +232,7 @@ func getEventDeltaBuilder(
|
||||
return builder
|
||||
}
|
||||
|
||||
func (p *eventDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
func (p *eventDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
resp, err := p.builder.Get(ctx, p.options)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
@ -209,15 +241,15 @@ func (p *eventDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error)
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (p *eventDeltaPager) setNext(nextLink string) {
|
||||
func (p *eventDeltaIDPager) setNext(nextLink string) {
|
||||
p.builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
||||
}
|
||||
|
||||
func (p *eventDeltaPager) reset(ctx context.Context) {
|
||||
func (p *eventDeltaIDPager) reset(ctx context.Context) {
|
||||
p.builder = getEventDeltaBuilder(ctx, p.gs, p.userID, p.containerID, p.options)
|
||||
}
|
||||
|
||||
func (p *eventDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
func (p *eventDeltaIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
return toValues[models.Eventable](pl)
|
||||
}
|
||||
|
||||
@ -229,12 +261,12 @@ func (c Events) GetAddedAndRemovedItemIDs(
|
||||
) ([]string, []string, DeltaUpdate, error) {
|
||||
ctx = clues.Add(ctx, "container_id", containerID)
|
||||
|
||||
pager, err := c.NewEventPager(ctx, userID, containerID, immutableIDs)
|
||||
pager, err := c.NewEventIDsPager(ctx, userID, containerID, immutableIDs)
|
||||
if err != nil {
|
||||
return nil, nil, DeltaUpdate{}, graph.Wrap(ctx, err, "creating non-delta pager")
|
||||
}
|
||||
|
||||
deltaPager, err := c.NewEventDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||
deltaPager, err := c.NewEventDeltaIDsPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||
if err != nil {
|
||||
return nil, nil, DeltaUpdate{}, graph.Wrap(ctx, err, "creating delta pager")
|
||||
}
|
||||
|
||||
@ -61,27 +61,57 @@ func (e EmptyDeltaLinker[T]) GetValue() []T {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// generic handler for paging item ids in a container
|
||||
// generic handler for non-delta item paging in a container
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
type itemPager interface {
|
||||
type itemPager[T any] interface {
|
||||
// getPage get a page with the specified options from graph
|
||||
getPage(context.Context) (DeltaPageLinker, error)
|
||||
getPage(context.Context) (PageLinker, error)
|
||||
// setNext is used to pass in the next url got from graph
|
||||
setNext(string)
|
||||
// reset is used to clear delta url in delta pagers. When
|
||||
// reset is called, we reset the state(delta url) that we
|
||||
// currently have and start a new delta query without the token.
|
||||
reset(context.Context)
|
||||
// valuesIn gets us the values in a page
|
||||
valuesIn(PageLinker) ([]getIDAndAddtler, error)
|
||||
valuesIn(PageLinker) ([]T, error)
|
||||
}
|
||||
|
||||
type getIDAndAddtler interface {
|
||||
GetId() *string
|
||||
GetAdditionalData() map[string]any
|
||||
func enumerateItems[T any](
|
||||
ctx context.Context,
|
||||
pager itemPager[T],
|
||||
) ([]T, error) {
|
||||
var (
|
||||
result = make([]T, 0)
|
||||
// stubbed initial value to ensure we enter the loop.
|
||||
nextLink = "do-while"
|
||||
)
|
||||
|
||||
for len(nextLink) > 0 {
|
||||
// get the next page of data, check for standard errors
|
||||
resp, err := pager.getPage(ctx)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
}
|
||||
|
||||
// each category type responds with a different interface, but all
|
||||
// of them comply with GetValue, which is where we'll get our item data.
|
||||
items, err := pager.valuesIn(resp)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
}
|
||||
|
||||
result = append(result, items...)
|
||||
nextLink = NextLink(resp)
|
||||
|
||||
pager.setNext(nextLink)
|
||||
}
|
||||
|
||||
logger.Ctx(ctx).Infow("completed enumeration", "count", len(result))
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// generic handler for delta-based ittem paging in a container
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// uses a models interface compliant with { GetValues() []T }
|
||||
// to transform its results into a slice of getIDer interfaces.
|
||||
// Generics used here to handle the variation of msoft interfaces
|
||||
@ -110,16 +140,34 @@ func toValues[T any](a any) ([]getIDAndAddtler, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
type itemIDPager interface {
|
||||
// getPage get a page with the specified options from graph
|
||||
getPage(context.Context) (DeltaPageLinker, error)
|
||||
// setNext is used to pass in the next url got from graph
|
||||
setNext(string)
|
||||
// reset is used to clear delta url in delta pagers. When
|
||||
// reset is called, we reset the state(delta url) that we
|
||||
// currently have and start a new delta query without the token.
|
||||
reset(context.Context)
|
||||
// valuesIn gets us the values in a page
|
||||
valuesIn(PageLinker) ([]getIDAndAddtler, error)
|
||||
}
|
||||
|
||||
type getIDAndAddtler interface {
|
||||
GetId() *string
|
||||
GetAdditionalData() map[string]any
|
||||
}
|
||||
|
||||
func getAddedAndRemovedItemIDs(
|
||||
ctx context.Context,
|
||||
service graph.Servicer,
|
||||
pager itemPager,
|
||||
deltaPager itemPager,
|
||||
pager itemIDPager,
|
||||
deltaPager itemIDPager,
|
||||
oldDelta string,
|
||||
canMakeDeltaQueries bool,
|
||||
) ([]string, []string, DeltaUpdate, error) {
|
||||
var (
|
||||
pgr itemPager
|
||||
pgr itemIDPager
|
||||
resetDelta bool
|
||||
)
|
||||
|
||||
@ -161,17 +209,16 @@ func getAddedAndRemovedItemIDs(
|
||||
// generic controller for retrieving all item ids in a container.
|
||||
func getItemsAddedAndRemovedFromContainer(
|
||||
ctx context.Context,
|
||||
pager itemPager,
|
||||
pager itemIDPager,
|
||||
) ([]string, []string, string, error) {
|
||||
var (
|
||||
addedIDs = []string{}
|
||||
removedIDs = []string{}
|
||||
deltaURL string
|
||||
itemCount int
|
||||
page int
|
||||
)
|
||||
|
||||
itemCount := 0
|
||||
page := 0
|
||||
|
||||
for {
|
||||
// get the next page of data, check for standard errors
|
||||
resp, err := pager.getPage(ctx)
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/alcionai/clues"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -19,6 +20,8 @@ import (
|
||||
// mock impls & stubs
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// next and delta links
|
||||
|
||||
type nextLink struct {
|
||||
nextLink *string
|
||||
}
|
||||
@ -36,6 +39,8 @@ func (l deltaNextLink) GetOdataDeltaLink() *string {
|
||||
return l.deltaLink
|
||||
}
|
||||
|
||||
// mock values
|
||||
|
||||
type testPagerValue struct {
|
||||
id string
|
||||
removed bool
|
||||
@ -50,6 +55,8 @@ func (v testPagerValue) GetAdditionalData() map[string]any {
|
||||
return map[string]any{}
|
||||
}
|
||||
|
||||
// mock page
|
||||
|
||||
type testPage struct{}
|
||||
|
||||
func (p testPage) GetOdataNextLink() *string {
|
||||
@ -62,9 +69,35 @@ func (p testPage) GetOdataDeltaLink() *string {
|
||||
return ptr.To("")
|
||||
}
|
||||
|
||||
var _ itemPager = &testPager{}
|
||||
// mock item pager
|
||||
|
||||
var _ itemPager[any] = &testPager{}
|
||||
|
||||
type testPager struct {
|
||||
t *testing.T
|
||||
items []any
|
||||
pageErr error
|
||||
valuesErr error
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *testPager) getPage(ctx context.Context) (PageLinker, error) {
|
||||
return testPage{}, p.pageErr
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *testPager) setNext(nextLink string) {}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *testPager) valuesIn(pl PageLinker) ([]any, error) {
|
||||
return p.items, p.valuesErr
|
||||
}
|
||||
|
||||
// mock id pager
|
||||
|
||||
var _ itemIDPager = &testIDsPager{}
|
||||
|
||||
type testIDsPager struct {
|
||||
t *testing.T
|
||||
added []string
|
||||
removed []string
|
||||
@ -72,7 +105,7 @@ type testPager struct {
|
||||
needsReset bool
|
||||
}
|
||||
|
||||
func (p *testPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
func (p *testIDsPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
if p.errorCode != "" {
|
||||
ierr := odataerrors.NewMainError()
|
||||
ierr.SetCode(&p.errorCode)
|
||||
@ -85,8 +118,8 @@ func (p *testPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
|
||||
return testPage{}, nil
|
||||
}
|
||||
func (p *testPager) setNext(string) {}
|
||||
func (p *testPager) reset(context.Context) {
|
||||
func (p *testIDsPager) setNext(string) {}
|
||||
func (p *testIDsPager) reset(context.Context) {
|
||||
if !p.needsReset {
|
||||
require.Fail(p.t, "reset should not be called")
|
||||
}
|
||||
@ -95,7 +128,7 @@ func (p *testPager) reset(context.Context) {
|
||||
p.errorCode = ""
|
||||
}
|
||||
|
||||
func (p *testPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
func (p *testIDsPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
items := []getIDAndAddtler{}
|
||||
|
||||
for _, id := range p.added {
|
||||
@ -121,11 +154,83 @@ func TestItemPagerUnitSuite(t *testing.T) {
|
||||
suite.Run(t, &ItemPagerUnitSuite{Suite: tester.NewUnitSuite(t)})
|
||||
}
|
||||
|
||||
func (suite *ItemPagerUnitSuite) TestEnumerateItems() {
|
||||
tests := []struct {
|
||||
name string
|
||||
getPager func(*testing.T, context.Context) itemPager[any]
|
||||
expect []any
|
||||
expectErr require.ErrorAssertionFunc
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
getPager: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
) itemPager[any] {
|
||||
return &testPager{
|
||||
t: t,
|
||||
items: []any{"foo", "bar"},
|
||||
}
|
||||
},
|
||||
expect: []any{"foo", "bar"},
|
||||
expectErr: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "get values err",
|
||||
getPager: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
) itemPager[any] {
|
||||
return &testPager{
|
||||
t: t,
|
||||
valuesErr: assert.AnError,
|
||||
}
|
||||
},
|
||||
expect: nil,
|
||||
expectErr: require.Error,
|
||||
},
|
||||
{
|
||||
name: "next page err",
|
||||
getPager: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
) itemPager[any] {
|
||||
return &testPager{
|
||||
t: t,
|
||||
pageErr: assert.AnError,
|
||||
}
|
||||
},
|
||||
expect: nil,
|
||||
expectErr: require.Error,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
suite.Run(test.name, func() {
|
||||
t := suite.T()
|
||||
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
result, err := enumerateItems[any](ctx, test.getPager(t, ctx))
|
||||
test.expectErr(t, err, clues.ToCore(err))
|
||||
|
||||
require.EqualValues(t, test.expect, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() {
|
||||
tests := []struct {
|
||||
name string
|
||||
pagerGetter func(context.Context, graph.Servicer, string, string, bool) (itemPager, error)
|
||||
deltaPagerGetter func(context.Context, graph.Servicer, string, string, string, bool) (itemPager, error)
|
||||
name string
|
||||
pagerGetter func(*testing.T, context.Context, graph.Servicer, string, string, bool) (itemIDPager, error)
|
||||
deltaPagerGetter func(
|
||||
*testing.T,
|
||||
context.Context,
|
||||
graph.Servicer,
|
||||
string, string, string,
|
||||
bool,
|
||||
) (itemIDPager, error)
|
||||
added []string
|
||||
removed []string
|
||||
deltaUpdate DeltaUpdate
|
||||
@ -135,25 +240,27 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() {
|
||||
{
|
||||
name: "no prev delta",
|
||||
pagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
) (itemIDPager, error) {
|
||||
// this should not be called
|
||||
return nil, assert.AnError
|
||||
},
|
||||
deltaPagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
delta string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
return &testPager{
|
||||
t: suite.T(),
|
||||
) (itemIDPager, error) {
|
||||
return &testIDsPager{
|
||||
t: t,
|
||||
added: []string{"uno", "dos"},
|
||||
removed: []string{"tres", "quatro"},
|
||||
}, nil
|
||||
@ -166,25 +273,27 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() {
|
||||
{
|
||||
name: "with prev delta",
|
||||
pagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
) (itemIDPager, error) {
|
||||
// this should not be called
|
||||
return nil, assert.AnError
|
||||
},
|
||||
deltaPagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
delta string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
return &testPager{
|
||||
t: suite.T(),
|
||||
) (itemIDPager, error) {
|
||||
return &testIDsPager{
|
||||
t: t,
|
||||
added: []string{"uno", "dos"},
|
||||
removed: []string{"tres", "quatro"},
|
||||
}, nil
|
||||
@ -198,25 +307,27 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() {
|
||||
{
|
||||
name: "delta expired",
|
||||
pagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
) (itemIDPager, error) {
|
||||
// this should not be called
|
||||
return nil, assert.AnError
|
||||
},
|
||||
deltaPagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
delta string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
return &testPager{
|
||||
t: suite.T(),
|
||||
) (itemIDPager, error) {
|
||||
return &testIDsPager{
|
||||
t: t,
|
||||
added: []string{"uno", "dos"},
|
||||
removed: []string{"tres", "quatro"},
|
||||
errorCode: "SyncStateNotFound",
|
||||
@ -232,27 +343,29 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() {
|
||||
{
|
||||
name: "quota exceeded",
|
||||
pagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
return &testPager{
|
||||
t: suite.T(),
|
||||
) (itemIDPager, error) {
|
||||
return &testIDsPager{
|
||||
t: t,
|
||||
added: []string{"uno", "dos"},
|
||||
removed: []string{"tres", "quatro"},
|
||||
}, nil
|
||||
},
|
||||
deltaPagerGetter: func(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
gs graph.Servicer,
|
||||
user string,
|
||||
directory string,
|
||||
delta string,
|
||||
immutableIDs bool,
|
||||
) (itemPager, error) {
|
||||
return &testPager{errorCode: "ErrorQuotaExceeded"}, nil
|
||||
) (itemIDPager, error) {
|
||||
return &testIDsPager{errorCode: "ErrorQuotaExceeded"}, nil
|
||||
},
|
||||
added: []string{"uno", "dos"},
|
||||
removed: []string{"tres", "quatro"},
|
||||
@ -268,8 +381,8 @@ func (suite *ItemPagerUnitSuite) TestGetAddedAndRemovedItemIDs() {
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
pager, _ := tt.pagerGetter(ctx, graph.Service{}, "user", "directory", false)
|
||||
deltaPager, _ := tt.deltaPagerGetter(ctx, graph.Service{}, "user", "directory", tt.delta, false)
|
||||
pager, _ := tt.pagerGetter(t, ctx, graph.Service{}, "user", "directory", false)
|
||||
deltaPager, _ := tt.deltaPagerGetter(t, ctx, graph.Service{}, "user", "directory", tt.delta, false)
|
||||
|
||||
added, removed, deltaUpdate, err := getAddedAndRemovedItemIDs(
|
||||
ctx,
|
||||
|
||||
@ -121,19 +121,51 @@ func (c Mail) EnumerateContainers(
|
||||
// item pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemPager = &mailPager{}
|
||||
var _ itemPager[models.Messageable] = &mailPager{}
|
||||
|
||||
type mailPager struct {
|
||||
// TODO(rkeeprs)
|
||||
}
|
||||
|
||||
func (c Mail) NewMailPager() itemPager[models.Messageable] {
|
||||
// TODO(rkeepers)
|
||||
return nil
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *mailPager) getPage(ctx context.Context) (PageLinker, error) {
|
||||
// TODO(rkeepers)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *mailPager) setNext(nextLink string) {
|
||||
// TODO(rkeepers)
|
||||
}
|
||||
|
||||
//lint:ignore U1000 False Positive
|
||||
func (p *mailPager) valuesIn(pl PageLinker) ([]models.Messageable, error) {
|
||||
// TODO(rkeepers)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// item ID pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemIDPager = &mailIDPager{}
|
||||
|
||||
type mailIDPager struct {
|
||||
gs graph.Servicer
|
||||
builder *users.ItemMailFoldersItemMessagesRequestBuilder
|
||||
options *users.ItemMailFoldersItemMessagesRequestBuilderGetRequestConfiguration
|
||||
}
|
||||
|
||||
func (c Mail) NewMailPager(
|
||||
func (c Mail) NewMailIDsPager(
|
||||
ctx context.Context,
|
||||
userID, containerID string,
|
||||
immutableIDs bool,
|
||||
) itemPager {
|
||||
) itemIDPager {
|
||||
config := &users.ItemMailFoldersItemMessagesRequestBuilderGetRequestConfiguration{
|
||||
QueryParameters: &users.ItemMailFoldersItemMessagesRequestBuilderGetQueryParameters{
|
||||
Select: idAnd("isRead"),
|
||||
@ -149,10 +181,10 @@ func (c Mail) NewMailPager(
|
||||
ByMailFolderId(containerID).
|
||||
Messages()
|
||||
|
||||
return &mailPager{c.Stable, builder, config}
|
||||
return &mailIDPager{c.Stable, builder, config}
|
||||
}
|
||||
|
||||
func (p *mailPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
func (p *mailIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
page, err := p.builder.Get(ctx, p.options)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
@ -161,24 +193,24 @@ func (p *mailPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
return EmptyDeltaLinker[models.Messageable]{PageLinkValuer: page}, nil
|
||||
}
|
||||
|
||||
func (p *mailPager) setNext(nextLink string) {
|
||||
func (p *mailIDPager) setNext(nextLink string) {
|
||||
p.builder = users.NewItemMailFoldersItemMessagesRequestBuilder(nextLink, p.gs.Adapter())
|
||||
}
|
||||
|
||||
// non delta pagers don't have reset
|
||||
func (p *mailPager) reset(context.Context) {}
|
||||
func (p *mailIDPager) reset(context.Context) {}
|
||||
|
||||
func (p *mailPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
func (p *mailIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
return toValues[models.Messageable](pl)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// delta item pager
|
||||
// delta item ID pager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
var _ itemPager = &mailDeltaPager{}
|
||||
var _ itemIDPager = &mailDeltaIDPager{}
|
||||
|
||||
type mailDeltaPager struct {
|
||||
type mailDeltaIDPager struct {
|
||||
gs graph.Servicer
|
||||
userID string
|
||||
containerID string
|
||||
@ -204,11 +236,11 @@ func getMailDeltaBuilder(
|
||||
return builder
|
||||
}
|
||||
|
||||
func (c Mail) NewMailDeltaPager(
|
||||
func (c Mail) NewMailDeltaIDsPager(
|
||||
ctx context.Context,
|
||||
userID, containerID, oldDelta string,
|
||||
immutableIDs bool,
|
||||
) itemPager {
|
||||
) itemIDPager {
|
||||
config := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration{
|
||||
QueryParameters: &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetQueryParameters{
|
||||
Select: idAnd("isRead"),
|
||||
@ -224,10 +256,10 @@ func (c Mail) NewMailDeltaPager(
|
||||
builder = getMailDeltaBuilder(ctx, c.Stable, userID, containerID, config)
|
||||
}
|
||||
|
||||
return &mailDeltaPager{c.Stable, userID, containerID, builder, config}
|
||||
return &mailDeltaIDPager{c.Stable, userID, containerID, builder, config}
|
||||
}
|
||||
|
||||
func (p *mailDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
func (p *mailDeltaIDPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
page, err := p.builder.Get(ctx, p.options)
|
||||
if err != nil {
|
||||
return nil, graph.Stack(ctx, err)
|
||||
@ -236,11 +268,11 @@ func (p *mailDeltaPager) getPage(ctx context.Context) (DeltaPageLinker, error) {
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (p *mailDeltaPager) setNext(nextLink string) {
|
||||
func (p *mailDeltaIDPager) setNext(nextLink string) {
|
||||
p.builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(nextLink, p.gs.Adapter())
|
||||
}
|
||||
|
||||
func (p *mailDeltaPager) reset(ctx context.Context) {
|
||||
func (p *mailDeltaIDPager) reset(ctx context.Context) {
|
||||
p.builder = p.gs.
|
||||
Client().
|
||||
Users().
|
||||
@ -251,7 +283,7 @@ func (p *mailDeltaPager) reset(ctx context.Context) {
|
||||
Delta()
|
||||
}
|
||||
|
||||
func (p *mailDeltaPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
func (p *mailDeltaIDPager) valuesIn(pl PageLinker) ([]getIDAndAddtler, error) {
|
||||
return toValues[models.Messageable](pl)
|
||||
}
|
||||
|
||||
@ -266,8 +298,8 @@ func (c Mail) GetAddedAndRemovedItemIDs(
|
||||
"category", selectors.ExchangeMail,
|
||||
"container_id", containerID)
|
||||
|
||||
pager := c.NewMailPager(ctx, userID, containerID, immutableIDs)
|
||||
deltaPager := c.NewMailDeltaPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||
pager := c.NewMailIDsPager(ctx, userID, containerID, immutableIDs)
|
||||
deltaPager := c.NewMailDeltaIDsPager(ctx, userID, containerID, oldDelta, immutableIDs)
|
||||
|
||||
return getAddedAndRemovedItemIDs(ctx, c.Stable, pager, deltaPager, oldDelta, canMakeDeltaQueries)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user