diff --git a/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/PaginationAction.java b/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/PaginationAction.java index a75f725f67..4d757bd9b8 100644 --- a/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/PaginationAction.java +++ b/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/PaginationAction.java @@ -114,7 +114,7 @@ public interface PaginationAction> extends R * The snowflake ID to skip before, this is exclusive rather than inclusive * * @throws IllegalArgumentException - * If cache is enabled and you are attempting to skip forward in time {@literal (id > last)} + * If cache is enabled, and you are attempting to skip forward in time {@literal (id > last)} * * @return The current PaginationAction for chaining convenience * @@ -146,6 +146,68 @@ public interface PaginationAction> extends R @Override M deadline(long timestamp); + /** + * The supported {@link PaginationOrder PaginationOrders} for this pagination action. + *
All enum values that are not returned will cause a throw for {@link #order(PaginationOrder)}. + * + *

Most pagination endpoints only support a single order, however some endpoints such as message pagination supports both. + * + * @return {@link EnumSet} of {@link PaginationOrder} (Modifying this set does not affect this class) + */ + @Nonnull + default EnumSet getSupportedOrders() + { + return EnumSet.allOf(PaginationOrder.class); + } + + /** + * The current iteration order. + *
This defaults to {@link PaginationOrder#BACKWARD}, meaning most recent first, for most pagination endpoints. + * + * @return The {@link PaginationOrder} + * + * @see #order(PaginationOrder) + */ + @Nonnull + PaginationOrder getOrder(); + + /** + * Configure the {@link PaginationOrder} of this pagination action. + * + *

You can only supply supported orders, see {@link #getSupportedOrders()}. + * + * @param order + * The pagination order + * + * @throws IllegalArgumentException + * If the provided pagination order is null or unsupported + * @throws IllegalStateException + * If this pagination action has already been used to retrieve entities + * + * @return The current PaginationAction implementation instance + * + * @see #getSupportedOrders() + * @see #reverse() + */ + @Nonnull + M order(@Nonnull PaginationOrder order); + + /** + * Flips the {@link #order(PaginationOrder)} of this pagination action. + * + * @throws IllegalArgumentException + * If this pagination action does not support the reversed order + * + * @return The current PaginationAction implementation instance + */ + @Nonnull + default M reverse() + { + if (getOrder() == PaginationOrder.BACKWARD) + return order(PaginationOrder.FORWARD); + return order(PaginationOrder.BACKWARD); + } + /** * The current amount of cached entities for this PaginationAction * @@ -632,6 +694,39 @@ default Stream parallelStream() @Override PaginationIterator iterator(); + /** + * Defines the pagination order for a pagination endpoint. + */ + enum PaginationOrder + { + /** + * Iterates backwards in time, listing the most recent entities first. + */ + BACKWARD("before"), + /** + * Iterates forward in time, listing the oldest entities first. + */ + FORWARD("after"); + + private final String key; + + PaginationOrder(String key) + { + this.key = key; + } + + /** + * The API query parameter key + * + * @return The query key + */ + @Nonnull + public String getKey() + { + return key; + } + } + /** * Iterator implementation for a {@link PaginationAction PaginationAction}. *
This iterator will first iterate over all currently cached entities and continue to retrieve new entities diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/AuditLogPaginationActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/AuditLogPaginationActionImpl.java index afa21cd380..467bfbf89a 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/AuditLogPaginationActionImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/AuditLogPaginationActionImpl.java @@ -37,6 +37,7 @@ import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; public class AuditLogPaginationActionImpl @@ -54,6 +55,7 @@ public AuditLogPaginationActionImpl(Guild guild) if (!guild.getSelfMember().hasPermission(Permission.VIEW_AUDIT_LOGS)) throw new InsufficientPermissionException(guild, Permission.VIEW_AUDIT_LOGS); this.guild = guild; + super.order(PaginationOrder.BACKWARD); } @Nonnull @@ -95,25 +97,24 @@ public Guild getGuild() return guild; } + @Nonnull + @Override + public EnumSet getSupportedOrders() + { + return EnumSet.of(PaginationOrder.BACKWARD); + } + @Override protected Route.CompiledRoute finalizeRoute() { Route.CompiledRoute route = super.finalizeRoute(); - final String limit = String.valueOf(this.limit.get()); - final long last = this.lastKey; - - route = route.withQueryParams("limit", limit); - if (type != null) route = route.withQueryParams("action_type", String.valueOf(type.getKey())); if (userId != null) route = route.withQueryParams("user_id", userId); - if (last != 0) - route = route.withQueryParams("before", Long.toUnsignedString(last)); - return route; } diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/MessagePaginationActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/MessagePaginationActionImpl.java index 699a60bfcf..16cec1e357 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/MessagePaginationActionImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/MessagePaginationActionImpl.java @@ -30,6 +30,7 @@ import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class MessagePaginationActionImpl @@ -63,22 +64,6 @@ public MessageChannel getChannel() return channel; } - @Override - protected Route.CompiledRoute finalizeRoute() - { - Route.CompiledRoute route = super.finalizeRoute(); - - final String limit = String.valueOf(this.getLimit()); - final long last = this.lastKey; - - route = route.withQueryParams("limit", limit); - - if (last != 0) - route = route.withQueryParams("before", Long.toUnsignedString(last)); - - return route; - } - @Override protected void handleSuccess(Response response, Request> request) { @@ -91,10 +76,6 @@ protected void handleSuccess(Response response, Request> request) { Message msg = builder.createMessage(array.getObject(i), channel, false); messages.add(msg); - if (useCache) - cached.add(msg); - last = msg; - lastKey = last.getIdLong(); } catch (ParsingException | NullPointerException e) { @@ -109,6 +90,17 @@ protected void handleSuccess(Response response, Request> request) } } + if (order == PaginationOrder.FORWARD) + Collections.reverse(messages); + if (useCache) + cached.addAll(messages); + + if (!messages.isEmpty()) + { + last = messages.get(messages.size() - 1); + lastKey = last.getIdLong(); + } + request.onSuccess(messages); } diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/PaginationActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/PaginationActionImpl.java index fc651d83a5..a112b1ca7f 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/PaginationActionImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/PaginationActionImpl.java @@ -42,6 +42,8 @@ public abstract class PaginationActionImpl> protected final int minLimit; protected final AtomicInteger limit; + protected PaginationOrder order = PaginationOrder.BACKWARD; + protected volatile long iteratorIndex = 0; protected volatile long lastKey = 0; protected volatile T last = null; @@ -109,6 +111,30 @@ public long getLastKey() return lastKey; } + @Nonnull + @Override + public PaginationOrder getOrder() + { + return order; + } + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public M order(@Nonnull PaginationAction.PaginationOrder order) + { + Checks.notNull(order, "PaginationOrder"); + if (order != this.order) + { + if (!isEmpty()) + throw new IllegalStateException("Cannot change pagination order after retrieving."); + if (!getSupportedOrders().contains(order)) + throw new IllegalArgumentException("Cannot use PaginationOrder." + order + " for this pagination endpoint."); + } + this.order = order; + return (M) this; + } + @Nonnull @Override @SuppressWarnings("unchecked") @@ -321,6 +347,24 @@ public void forEachRemaining(@Nonnull final Procedure action) } } + @Override + protected Route.CompiledRoute finalizeRoute() + { + Route.CompiledRoute route = super.finalizeRoute(); + + final String limit = String.valueOf(this.getLimit()); + final long last = this.lastKey; + + route = route.withQueryParams("limit", limit); + + if (last != 0) + route = route.withQueryParams(order.getKey(), Long.toUnsignedString(last)); + else if (order == PaginationOrder.FORWARD) + route = route.withQueryParams("after", "0"); + + return route; + } + protected List getRemainingCache() { int index = getIteratorIndex(); diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ReactionPaginationActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ReactionPaginationActionImpl.java index 0843e0732b..3fc23ddb14 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ReactionPaginationActionImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ReactionPaginationActionImpl.java @@ -30,6 +30,7 @@ import net.dv8tion.jda.internal.utils.EncodingUtil; import javax.annotation.Nonnull; +import java.util.EnumSet; import java.util.LinkedList; import java.util.List; @@ -48,18 +49,21 @@ public class ReactionPaginationActionImpl public ReactionPaginationActionImpl(MessageReaction reaction) { super(reaction.getJDA(), Route.Messages.GET_REACTION_USERS.compile(reaction.getChannel().getId(), reaction.getMessageId(), getCode(reaction)), 1, 100, 100); + super.order(PaginationOrder.FORWARD); this.reaction = reaction; } public ReactionPaginationActionImpl(Message message, String code) { super(message.getJDA(), Route.Messages.GET_REACTION_USERS.compile(message.getChannel().getId(), message.getId(), code), 1, 100, 100); + super.order(PaginationOrder.FORWARD); this.reaction = null; } public ReactionPaginationActionImpl(MessageChannel channel, String messageId, String code) { super(channel.getJDA(), Route.Messages.GET_REACTION_USERS.compile(channel.getId(), messageId, code), 1, 100, 100); + super.order(PaginationOrder.FORWARD); this.reaction = null; } @@ -81,23 +85,11 @@ public MessageReaction getReaction() return reaction; } + @Nonnull @Override - protected Route.CompiledRoute finalizeRoute() + public EnumSet getSupportedOrders() { - Route.CompiledRoute route = super.finalizeRoute(); - - String after = null; - String limit = String.valueOf(getLimit()); - long last = this.lastKey; - if (last != 0) - after = Long.toUnsignedString(last); - - route = route.withQueryParams("limit", limit); - - if (after != null) - route = route.withQueryParams("after", after); - - return route; + return EnumSet.of(PaginationOrder.FORWARD); } @Override diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java index e0733055ae..078bfdbabb 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java @@ -17,6 +17,7 @@ import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; public class ThreadChannelPaginationActionImpl extends PaginationActionImpl implements ThreadChannelPaginationAction @@ -38,6 +39,13 @@ public IThreadContainer getChannel() return channel; } + @Nonnull + @Override + public EnumSet getSupportedOrders() + { + return EnumSet.of(PaginationOrder.BACKWARD); + } + @Override protected Route.CompiledRoute finalizeRoute() {