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:
Keepers 2023-06-21 10:43:33 -06:00 committed by GitHub
parent d9b5cda8f1
commit 3bcc405327
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 363 additions and 107 deletions

View File

@ -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)
}

View File

@ -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")
}

View File

@ -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)

View File

@ -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,

View File

@ -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)
}