Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pagination helpers #183

Merged
merged 11 commits into from Sep 8, 2022
38 changes: 38 additions & 0 deletions _examples/pagination/examplebot.go
@@ -0,0 +1,38 @@
package main

import (
_ "embed"
"os"

"github.com/disgoorg/disgo"
"github.com/disgoorg/disgo/rest"
"github.com/disgoorg/log"
)

var token = os.Getenv("disgo_token")

func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.SetLevel(log.LevelDebug)
log.Info("starting example...")
log.Info("bot version: ", disgo.Version)

client := rest.New(rest.NewClient(token))

page := client.GetMessagesPage(817327182111571989, 1016790288607498240, 3)

var i int
for page.Next() {
for _, m := range page.Items {
println(m.ID)
}
println("---")
i++
if i >= 3 {
break
}
}
if page.Err != nil {
log.Error(page.Err)
}
}
13 changes: 13 additions & 0 deletions rest/channels.go
Expand Up @@ -28,6 +28,7 @@ type Channels interface {

GetMessage(channelID snowflake.ID, messageID snowflake.ID, opts ...RequestOpt) (*discord.Message, error)
GetMessages(channelID snowflake.ID, around snowflake.ID, before snowflake.ID, after snowflake.ID, limit int, opts ...RequestOpt) ([]discord.Message, error)
GetMessagesPage(channelID snowflake.ID, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.Message]
CreateMessage(channelID snowflake.ID, messageCreate discord.MessageCreate, opts ...RequestOpt) (*discord.Message, error)
UpdateMessage(channelID snowflake.ID, messageID snowflake.ID, messageUpdate discord.MessageUpdate, opts ...RequestOpt) (*discord.Message, error)
DeleteMessage(channelID snowflake.ID, messageID snowflake.ID, opts ...RequestOpt) error
Expand Down Expand Up @@ -128,6 +129,18 @@ func (s *channelImpl) GetMessages(channelID snowflake.ID, around snowflake.ID, b
return
}

func (s *channelImpl) GetMessagesPage(channelID snowflake.ID, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.Message] {
return Page[discord.Message]{
getItemsFunc: func(before snowflake.ID, after snowflake.ID) ([]discord.Message, error) {
return s.GetMessages(channelID, 0, before, after, limit, opts...)
},
getIDFunc: func(msg discord.Message) snowflake.ID {
return msg.ID
},
ID: startID,
}
}

func (s *channelImpl) CreateMessage(channelID snowflake.ID, messageCreate discord.MessageCreate, opts ...RequestOpt) (message *discord.Message, err error) {
body, err := messageCreate.ToBody()
if err != nil {
Expand Down
17 changes: 15 additions & 2 deletions rest/guild_scheduled_events.go
Expand Up @@ -18,7 +18,8 @@ type GuildScheduledEvents interface {
UpdateGuildScheduledEvent(guildID snowflake.ID, guildScheduledEventID snowflake.ID, guildScheduledEventUpdate discord.GuildScheduledEventUpdate, opts ...RequestOpt) (*discord.GuildScheduledEvent, error)
DeleteGuildScheduledEvent(guildID snowflake.ID, guildScheduledEventID snowflake.ID, opts ...RequestOpt) error

GetGuildScheduledEventUsers(guildID snowflake.ID, guildScheduledEventID snowflake.ID, limit int, withMember bool, before snowflake.ID, after snowflake.ID, opts ...RequestOpt) ([]discord.GuildScheduledEventUser, error)
GetGuildScheduledEventUsers(guildID snowflake.ID, guildScheduledEventID snowflake.ID, withMember bool, before snowflake.ID, after snowflake.ID, limit int, opts ...RequestOpt) ([]discord.GuildScheduledEventUser, error)
GetGuildScheduledEventUsersPage(guildID snowflake.ID, guildScheduledEventID snowflake.ID, withMember bool, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.GuildScheduledEventUser]
}

type guildScheduledEventImpl struct {
Expand Down Expand Up @@ -57,7 +58,7 @@ func (s *guildScheduledEventImpl) DeleteGuildScheduledEvent(guildID snowflake.ID
return s.client.Do(DeleteGuildScheduledEvent.Compile(nil, guildID, guildScheduledEventID), nil, nil, opts...)
}

func (s *guildScheduledEventImpl) GetGuildScheduledEventUsers(guildID snowflake.ID, guildScheduledEventID snowflake.ID, limit int, withMember bool, before snowflake.ID, after snowflake.ID, opts ...RequestOpt) (guildScheduledEventUsers []discord.GuildScheduledEventUser, err error) {
func (s *guildScheduledEventImpl) GetGuildScheduledEventUsers(guildID snowflake.ID, guildScheduledEventID snowflake.ID, withMember bool, before snowflake.ID, after snowflake.ID, limit int, opts ...RequestOpt) (guildScheduledEventUsers []discord.GuildScheduledEventUser, err error) {
mlnrDev marked this conversation as resolved.
Show resolved Hide resolved
queryValues := discord.QueryValues{}
if limit > 0 {
queryValues["limit"] = limit
Expand All @@ -74,3 +75,15 @@ func (s *guildScheduledEventImpl) GetGuildScheduledEventUsers(guildID snowflake.
err = s.client.Do(GetGuildScheduledEventUsers.Compile(nil, guildID, guildScheduledEventID), nil, &guildScheduledEventUsers, opts...)
return
}

func (s *guildScheduledEventImpl) GetGuildScheduledEventUsersPage(guildID snowflake.ID, guildScheduledEventID snowflake.ID, withMember bool, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.GuildScheduledEventUser] {
return Page[discord.GuildScheduledEventUser]{
getItemsFunc: func(before snowflake.ID, after snowflake.ID) ([]discord.GuildScheduledEventUser, error) {
return s.GetGuildScheduledEventUsers(guildID, guildScheduledEventID, withMember, before, after, limit, opts...)
},
getIDFunc: func(user discord.GuildScheduledEventUser) snowflake.ID {
return user.User.ID
},
ID: startID,
}
}
28 changes: 28 additions & 0 deletions rest/guilds.go
Expand Up @@ -32,6 +32,7 @@ type Guilds interface {
DeleteRole(guildID snowflake.ID, roleID snowflake.ID, opts ...RequestOpt) error

GetBans(guildID snowflake.ID, before snowflake.ID, after snowflake.ID, limit int, opts ...RequestOpt) ([]discord.Ban, error)
GetBansPage(guildID snowflake.ID, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.Ban]
GetBan(guildID snowflake.ID, userID snowflake.ID, opts ...RequestOpt) (*discord.Ban, error)
AddBan(guildID snowflake.ID, userID snowflake.ID, deleteMessageDuration time.Duration, opts ...RequestOpt) error
DeleteBan(guildID snowflake.ID, userID snowflake.ID, opts ...RequestOpt) error
Expand All @@ -42,6 +43,7 @@ type Guilds interface {
GetAllWebhooks(guildID snowflake.ID, opts ...RequestOpt) ([]discord.Webhook, error)

GetAuditLog(guildID snowflake.ID, userID snowflake.ID, actionType discord.AuditLogEvent, before snowflake.ID, limit int, opts ...RequestOpt) (*discord.AuditLog, error)
GetAuditLogPage(guildID snowflake.ID, userID snowflake.ID, actionType discord.AuditLogEvent, startID snowflake.ID, limit int, opts ...RequestOpt) AuditLogPage
}

type guildImpl struct {
Expand Down Expand Up @@ -144,6 +146,18 @@ func (s *guildImpl) GetBans(guildID snowflake.ID, before snowflake.ID, after sno
return
}

func (s *guildImpl) GetBansPage(guildID snowflake.ID, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.Ban] {
return Page[discord.Ban]{
getItemsFunc: func(before snowflake.ID, after snowflake.ID) (bans []discord.Ban, err error) {
return s.GetBans(guildID, before, after, limit, opts...)
},
getIDFunc: func(ban discord.Ban) snowflake.ID {
return ban.User.ID
},
ID: startID,
}
}

func (s *guildImpl) GetBan(guildID snowflake.ID, userID snowflake.ID, opts ...RequestOpt) (ban *discord.Ban, err error) {
err = s.client.Do(GetBan.Compile(nil, guildID, userID), nil, &ban, opts...)
return
Expand Down Expand Up @@ -193,3 +207,17 @@ func (s *guildImpl) GetAuditLog(guildID snowflake.ID, userID snowflake.ID, actio
err = s.client.Do(GetAuditLogs.Compile(values, guildID), nil, &auditLog, opts...)
return
}

func (s *guildImpl) GetAuditLogPage(guildID snowflake.ID, userID snowflake.ID, actionType discord.AuditLogEvent, startID snowflake.ID, limit int, opts ...RequestOpt) AuditLogPage {
return AuditLogPage{
getItems: func(before snowflake.ID) (discord.AuditLog, error) {
log, err := s.GetAuditLog(guildID, userID, actionType, before, limit, opts...)
var finalLog discord.AuditLog
if log != nil {
finalLog = *log
}
return finalLog, err
},
ID: startID,
}
}
13 changes: 13 additions & 0 deletions rest/oauth2.go
Expand Up @@ -20,6 +20,7 @@ type OAuth2 interface {
GetCurrentUser(bearerToken string, opts ...RequestOpt) (*discord.OAuth2User, error)
GetCurrentMember(bearerToken string, guildID snowflake.ID, opts ...RequestOpt) (*discord.Member, error)
GetCurrentUserGuilds(bearerToken string, before snowflake.ID, after snowflake.ID, limit int, opts ...RequestOpt) ([]discord.OAuth2Guild, error)
GetCurrentUserGuildsPage(bearerToken string, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.OAuth2Guild]
GetCurrentUserConnections(bearerToken string, opts ...RequestOpt) ([]discord.Connection, error)

SetGuildCommandPermissions(bearerToken string, applicationID snowflake.ID, guildID snowflake.ID, commandID snowflake.ID, commandPermissions []discord.ApplicationCommandPermission, opts ...RequestOpt) (*discord.ApplicationCommandPermissions, error)
Expand Down Expand Up @@ -74,6 +75,18 @@ func (s *oAuth2Impl) GetCurrentUserGuilds(bearerToken string, before snowflake.I
return
}

func (s *oAuth2Impl) GetCurrentUserGuildsPage(bearerToken string, startID snowflake.ID, limit int, opts ...RequestOpt) Page[discord.OAuth2Guild] {
return Page[discord.OAuth2Guild]{
getItemsFunc: func(before snowflake.ID, after snowflake.ID) ([]discord.OAuth2Guild, error) {
return s.GetCurrentUserGuilds(bearerToken, before, after, limit, opts...)
},
getIDFunc: func(guild discord.OAuth2Guild) snowflake.ID {
return guild.ID
},
ID: startID,
}
}

func (s *oAuth2Impl) GetCurrentUserConnections(bearerToken string, opts ...RequestOpt) (connections []discord.Connection, err error) {
err = s.client.Do(GetCurrentUserConnections.Compile(nil), nil, &connections, withBearerToken(bearerToken, opts)...)
return
Expand Down
77 changes: 77 additions & 0 deletions rest/page.go
@@ -0,0 +1,77 @@
package rest

import (
"errors"

"github.com/disgoorg/disgo/discord"
"github.com/disgoorg/snowflake/v2"
)

var ErrNoMorePages = errors.New("no more pages")

type Page[T any] struct {
getItemsFunc func(before snowflake.ID, after snowflake.ID) ([]T, error)
getIDFunc func(t T) snowflake.ID

Items []T
Err error

ID snowflake.ID
}

func (p *Page[T]) Next() bool {
if p.Err != nil {
return false
}

if len(p.Items) > 0 {
p.ID = p.getIDFunc(p.Items[0])
}

p.Items, p.Err = p.getItemsFunc(0, p.ID)
if p.Err == nil && len(p.Items) == 0 {
p.Err = ErrNoMorePages
}
return p.Err == nil
}

func (p *Page[T]) Previous() bool {
if p.Err != nil {
return false
}

if len(p.Items) > 0 {
p.ID = p.getIDFunc(p.Items[len(p.Items)-1])
}

p.Items, p.Err = p.getItemsFunc(p.ID, 0)
if p.Err == nil && len(p.Items) == 0 {
p.Err = ErrNoMorePages
}
return p.Err == nil
}

type AuditLogPage struct {
getItems func(before snowflake.ID) (discord.AuditLog, error)

discord.AuditLog
Err error

ID snowflake.ID
}

func (p *AuditLogPage) Previous() bool {
if p.Err != nil {
return false
}

if len(p.AuditLogEntries) > 0 {
p.ID = p.AuditLogEntries[len(p.AuditLogEntries)-1].ID
}

p.AuditLog, p.Err = p.getItems(p.ID)
if p.Err == nil && len(p.AuditLogEntries) == 0 {
p.Err = ErrNoMorePages
}
return p.Err == nil
}