From 4a6c450644834998b3545d2e3cf5187ad4af81a6 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Thu, 25 Mar 2021 20:58:47 -0700 Subject: [PATCH] sorting on author page --- frontend/pages/authors.vue | 32 +++-- .../controller/api/v1/UsersController.java | 3 + .../extras/pagination/QueryIdentified.java | 6 - .../controller/extras/pagination/SortBy.java | 6 - .../pagination/filters/ApplicableFilters.java | 15 +++ .../pagination/{ => filters}/Filter.java | 9 +- .../extras/pagination/filters/Filters.java | 30 +++++ .../{ => filters}/ProjectCategoryFilter.java | 5 +- .../pagination/sorters/ApplicableSorters.java | 16 +++ .../pagination/sorters/SortDirection.java | 17 +++ .../extras/pagination/sorters/Sorters.java | 52 ++++++++ .../extras/resolver/PaginationResolver.java | 121 ++++++++++-------- .../papermc/hangar/db/dao/v1/UsersApiDAO.java | 4 +- .../hangar/db/extras/BindPagination.java | 68 +++------- .../model/api/requests/RequestPagination.java | 40 +++--- 15 files changed, 273 insertions(+), 151 deletions(-) delete mode 100644 src/main/java/io/papermc/hangar/controller/extras/pagination/QueryIdentified.java delete mode 100644 src/main/java/io/papermc/hangar/controller/extras/pagination/SortBy.java create mode 100644 src/main/java/io/papermc/hangar/controller/extras/pagination/filters/ApplicableFilters.java rename src/main/java/io/papermc/hangar/controller/extras/pagination/{ => filters}/Filter.java (63%) create mode 100644 src/main/java/io/papermc/hangar/controller/extras/pagination/filters/Filters.java rename src/main/java/io/papermc/hangar/controller/extras/pagination/{ => filters}/ProjectCategoryFilter.java (83%) create mode 100644 src/main/java/io/papermc/hangar/controller/extras/pagination/sorters/ApplicableSorters.java create mode 100644 src/main/java/io/papermc/hangar/controller/extras/pagination/sorters/SortDirection.java create mode 100644 src/main/java/io/papermc/hangar/controller/extras/pagination/sorters/Sorters.java diff --git a/frontend/pages/authors.vue b/frontend/pages/authors.vue index 8cd234aa..8f3d3c9b 100644 --- a/frontend/pages/authors.vue +++ b/frontend/pages/authors.vue @@ -5,6 +5,7 @@ :items="authors.result" :options.sync="options" :server-items-length="authors.pagination.count" + multi-sort :loading="loading" class="elevation-1" > @@ -33,9 +34,9 @@ import { HangarComponent } from '~/components/mixins'; }) export default class AuthorsPage extends HangarComponent { headers: DataTableHeader[] = [ - { text: '', value: 'pic' }, + { text: '', value: 'pic', sortable: false }, { text: 'Username', value: 'name' }, - { text: 'Roles', value: 'roles' }, + { text: 'Roles', value: 'roles', sortable: false }, { text: 'Joined', value: 'joinDate' }, { text: 'Projects', value: 'projectCount' }, ]; @@ -59,10 +60,15 @@ export default class AuthorsPage extends HangarComponent { } this.loading = true; - this.$api.request>('authors', false, 'get', this.requestOptions).then((authors) => { - this.authors = authors; - this.loading = false; - }); + this.$api + .request>('authors', false, 'get', this.requestOptions) + .then((authors) => { + this.authors = authors; + }) + .catch(this.$util.handleRequestError) + .finally(() => { + this.loading = false; + }); } get requestOptions() { @@ -70,12 +76,16 @@ export default class AuthorsPage extends HangarComponent { return {}; } - let sort = ''; - if (this.options.sortBy.length === 1) { - sort = this.options.sortBy[0]; - if (this.options.sortDesc[0]) { - sort = '-' + sort; + const sort: string[] = []; + for (let i = 0; i < this.options.sortBy.length; i++) { + let sortStr = this.options.sortBy[i]; + if (sortStr === 'name') { + sortStr = 'username'; // TODO how to get around this... should we change the field on User to be username? } + if (this.options.sortDesc[i]) { + sortStr = '-' + sortStr; + } + sort.push(sortStr); } return { limit: this.options.itemsPerPage, diff --git a/src/main/java/io/papermc/hangar/controller/api/v1/UsersController.java b/src/main/java/io/papermc/hangar/controller/api/v1/UsersController.java index 4d4881cc..80046e5a 100644 --- a/src/main/java/io/papermc/hangar/controller/api/v1/UsersController.java +++ b/src/main/java/io/papermc/hangar/controller/api/v1/UsersController.java @@ -2,6 +2,8 @@ package io.papermc.hangar.controller.api.v1; import io.papermc.hangar.controller.HangarController; import io.papermc.hangar.controller.api.v1.interfaces.IUsersController; +import io.papermc.hangar.controller.extras.pagination.sorters.ApplicableSorters; +import io.papermc.hangar.controller.extras.pagination.sorters.Sorters; import io.papermc.hangar.model.api.PaginatedResult; import io.papermc.hangar.model.api.User; import io.papermc.hangar.model.api.project.ProjectCompact; @@ -44,6 +46,7 @@ public class UsersController extends HangarController implements IUsersControlle } @Override + @ApplicableSorters({ Sorters.USERNAME_VALUE, Sorters.JOINED_VALUE, Sorters.PROJECT_COUNT_VALUE }) public ResponseEntity> getAuthors(@NotNull RequestPagination pagination) { return ResponseEntity.ok(usersApiService.getAuthors(pagination)); } diff --git a/src/main/java/io/papermc/hangar/controller/extras/pagination/QueryIdentified.java b/src/main/java/io/papermc/hangar/controller/extras/pagination/QueryIdentified.java deleted file mode 100644 index e849a271..00000000 --- a/src/main/java/io/papermc/hangar/controller/extras/pagination/QueryIdentified.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.papermc.hangar.controller.extras.pagination; - -public interface QueryIdentified { - - String getQueryParamName(); -} diff --git a/src/main/java/io/papermc/hangar/controller/extras/pagination/SortBy.java b/src/main/java/io/papermc/hangar/controller/extras/pagination/SortBy.java deleted file mode 100644 index 4539fc51..00000000 --- a/src/main/java/io/papermc/hangar/controller/extras/pagination/SortBy.java +++ /dev/null @@ -1,6 +0,0 @@ -package io.papermc.hangar.controller.extras.pagination; - -public interface SortBy extends QueryIdentified { - - void createSql(StringBuilder sb); -} diff --git a/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/ApplicableFilters.java b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/ApplicableFilters.java new file mode 100644 index 00000000..27a506ce --- /dev/null +++ b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/ApplicableFilters.java @@ -0,0 +1,15 @@ +package io.papermc.hangar.controller.extras.pagination.filters; + +import io.papermc.hangar.controller.extras.pagination.filters.Filter.FilterInstance; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApplicableFilters { + + Class>[] value(); +} diff --git a/src/main/java/io/papermc/hangar/controller/extras/pagination/Filter.java b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/Filter.java similarity index 63% rename from src/main/java/io/papermc/hangar/controller/extras/pagination/Filter.java rename to src/main/java/io/papermc/hangar/controller/extras/pagination/filters/Filter.java index f3351d18..a235e214 100644 --- a/src/main/java/io/papermc/hangar/controller/extras/pagination/Filter.java +++ b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/Filter.java @@ -1,10 +1,12 @@ -package io.papermc.hangar.controller.extras.pagination; +package io.papermc.hangar.controller.extras.pagination.filters; -import io.papermc.hangar.controller.extras.pagination.Filter.FilterInstance; +import io.papermc.hangar.controller.extras.pagination.filters.Filter.FilterInstance; import org.jdbi.v3.core.statement.SqlStatement; import org.springframework.web.context.request.NativeWebRequest; -public interface Filter extends QueryIdentified { +public interface Filter { + + String getQueryParamName(); default boolean supports(NativeWebRequest webRequest) { return webRequest.getParameterMap().containsKey(getQueryParamName()); @@ -13,6 +15,7 @@ public interface Filter extends QueryIdentified { F create(NativeWebRequest webRequest); interface FilterInstance { + void createSql(StringBuilder sb, SqlStatement q); } diff --git a/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/Filters.java b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/Filters.java new file mode 100644 index 00000000..b576644d --- /dev/null +++ b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/Filters.java @@ -0,0 +1,30 @@ +package io.papermc.hangar.controller.extras.pagination.filters; + +import io.papermc.hangar.controller.extras.pagination.filters.Filter.FilterInstance; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +@SuppressWarnings("unchecked") +public class Filters { + + private static final Map>, Filter> ALL_FILTERS = new HashMap<>(); + + public static final ProjectCategoryFilter PROJECT_CATEGORY_FILTER = register(new ProjectCategoryFilter()); + + private static > F register(F filter) { + ALL_FILTERS.put((Class>) filter.getClass(), filter); + return filter; + } + + public static final Class>[] TEST = new Class[] { ProjectCategoryFilter.class }; + + @NotNull + public static > T getFilter(Class filterClass) { + if (ALL_FILTERS.containsKey(filterClass)) { + return (T) ALL_FILTERS.get(filterClass); + } + throw new IllegalArgumentException(filterClass + " is not a registered filter"); + } +} diff --git a/src/main/java/io/papermc/hangar/controller/extras/pagination/ProjectCategoryFilter.java b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/ProjectCategoryFilter.java similarity index 83% rename from src/main/java/io/papermc/hangar/controller/extras/pagination/ProjectCategoryFilter.java rename to src/main/java/io/papermc/hangar/controller/extras/pagination/filters/ProjectCategoryFilter.java index aa0e34cd..928b69c1 100644 --- a/src/main/java/io/papermc/hangar/controller/extras/pagination/ProjectCategoryFilter.java +++ b/src/main/java/io/papermc/hangar/controller/extras/pagination/filters/ProjectCategoryFilter.java @@ -1,6 +1,6 @@ -package io.papermc.hangar.controller.extras.pagination; +package io.papermc.hangar.controller.extras.pagination.filters; -import io.papermc.hangar.controller.extras.pagination.ProjectCategoryFilter.ProjectCategoryFilterInstance; +import io.papermc.hangar.controller.extras.pagination.filters.ProjectCategoryFilter.ProjectCategoryFilterInstance; import io.papermc.hangar.model.common.projects.Category; import org.jdbi.v3.core.statement.SqlStatement; import org.springframework.web.context.request.NativeWebRequest; @@ -21,6 +21,7 @@ public class ProjectCategoryFilter implements Filter SORTERS = new HashMap<>(); + + public static final String JOINED_VALUE = "joinDate"; + public static final ApplySorter JOINED = register(JOINED_VALUE, (sb, dir) -> sb.append("u.join_date").append(dir)); + + public static final String USERNAME_VALUE = "username"; + public static final ApplySorter USERNAME = register(USERNAME_VALUE, (sb, dir) -> sb.append("u.name").append(dir)); + + public static final String PROJECT_COUNT_VALUE = "projectCount"; + public static final ApplySorter PROJECT_COUNT = register(PROJECT_COUNT_VALUE, (sb, dir) -> sb.append("project_count").append(dir)); + + + private static ApplySorter register(String name, ApplySorter applySorter) { + if (SORTERS.containsKey(name)) { + throw new IllegalArgumentException(name + " is already registered"); + } + SORTERS.put(name, applySorter); + return applySorter; + } + + @NotNull + public static ApplySorter getSorter(String key) { + if (SORTERS.containsKey(key)) { + return SORTERS.get(key); + } + throw new IllegalArgumentException(key + " is not a registered sorter"); + } + + @FunctionalInterface + public interface ApplySorter { + + void applySorting(StringBuilder sb, SortDirection dir); + + default Consumer ascending() { + return sb -> applySorting(sb, SortDirection.ASCENDING); + } + + default Consumer descending() { + return sb -> applySorting(sb, SortDirection.DESCENDING); + } + } +} diff --git a/src/main/java/io/papermc/hangar/controller/extras/resolver/PaginationResolver.java b/src/main/java/io/papermc/hangar/controller/extras/resolver/PaginationResolver.java index 0ce0969f..7472cb5f 100644 --- a/src/main/java/io/papermc/hangar/controller/extras/resolver/PaginationResolver.java +++ b/src/main/java/io/papermc/hangar/controller/extras/resolver/PaginationResolver.java @@ -1,91 +1,108 @@ package io.papermc.hangar.controller.extras.resolver; -import io.papermc.hangar.controller.extras.pagination.Filter; -import io.papermc.hangar.controller.extras.pagination.Filter.FilterInstance; -import io.papermc.hangar.controller.extras.pagination.ProjectCategoryFilter; +import io.papermc.hangar.controller.extras.pagination.filters.ApplicableFilters; +import io.papermc.hangar.controller.extras.pagination.filters.Filter; +import io.papermc.hangar.controller.extras.pagination.filters.Filter.FilterInstance; +import io.papermc.hangar.controller.extras.pagination.filters.Filters; +import io.papermc.hangar.controller.extras.pagination.sorters.ApplicableSorters; +import io.papermc.hangar.controller.extras.pagination.sorters.Sorters; +import io.papermc.hangar.exceptions.HangarApiException; import io.papermc.hangar.model.api.requests.RequestPagination; +import org.jetbrains.annotations.NotNull; import org.springframework.core.MethodParameter; -import org.springframework.lang.NonNull; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import java.lang.reflect.Parameter; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; +import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; +import java.util.Optional; public class PaginationResolver implements HandlerMethodArgumentResolver { private final HandlerMethodArgumentResolver delegate; -// Map, FilterConstructor> map = Map.of( -// ProjectCategoryFilter::supports, ProjectCategoryFilter::new -// ); - List> filters = List.of( - new ProjectCategoryFilter() - ); - - @FunctionalInterface - interface FilterConstructor { - Filter create(NativeWebRequest webRequest); - } - public PaginationResolver(HandlerMethodArgumentResolver delegate) { this.delegate = delegate; } @Override - public boolean supportsParameter(@NonNull MethodParameter parameter) { + public boolean supportsParameter(@NotNull MethodParameter parameter) { return delegate.supportsParameter(parameter); } @Override - public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewContainer mavContainer, @NonNull NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + public Object resolveArgument(@NotNull MethodParameter parameter, ModelAndViewContainer mavContainer, @NotNull NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Object result = delegate.resolveArgument(parameter, mavContainer, webRequest, binderFactory); - filters.forEach(f -> { - if (f.supports(webRequest)) { - FilterInstance filterInstance = f.create(webRequest); - // add filter to RequestPagination object - } - }); - if (result instanceof RequestPagination) { RequestPagination pagination = (RequestPagination) result; - Set knownParams = new HashSet<>(); - knownParams.add("limit"); - knownParams.add("offset"); - knownParams.add("sort"); - for (Parameter param : parameter.getExecutable().getParameters()) { - knownParams.add(param.getName()); - } - Map filters = new HashMap<>(); - for (String key : webRequest.getParameterMap().keySet()) { - if (!knownParams.contains(key)) { - filters.put(key, String.join(",", webRequest.getParameterValues(key))); - } - } - pagination.setFilters(filters); + Class>[] applicableFilters = Optional.ofNullable(parameter.getMethodAnnotation(ApplicableFilters.class)).map(ApplicableFilters::value).orElse(null); - String[] sorts = webRequest.getParameterMap().get("sort"); - List sort = new ArrayList<>(); - if (sorts != null && sorts.length > 0) { - for (String s : sorts) { - if (s != null && s.length() > 0) { - sort.add(s); + if (applicableFilters != null) { + for (Class> filter : applicableFilters) { + if (Filters.getFilter(filter).supports(webRequest)) { + pagination.getFilters().add(Filters.getFilter(filter).create(webRequest)); } } - pagination.setSorts(sort); } + + List applicableSorters = Optional.ofNullable(parameter.getMethodAnnotation(ApplicableSorters.class)).map(ApplicableSorters::value).map(Arrays::asList).orElse(new ArrayList<>()); + List presentSorters = Optional.ofNullable(webRequest.getParameterValues("sort")).map(Arrays::asList).orElse(new ArrayList<>()); + for (String sorter : presentSorters) { + String sortKey = sorter.startsWith("-") ? sorter.substring(1) : sorter; + if (!applicableSorters.contains(sortKey)) { + throw new HangarApiException(sortKey + " is an invalid sort type for this request"); + } + pagination.getSorters().add(sorter.startsWith("-") ? Sorters.getSorter(sortKey).descending() : Sorters.getSorter(sortKey).ascending()); + } + +// +// if (applicableSorters != null) { +// for (String sorter : applicableSorters) { +// if (webRequest.getParameterMap().containsKey(sorter)) { +// +// } +// } +// } } + + + +// if (result instanceof RequestPagination) { +// RequestPagination pagination = (RequestPagination) result; +// Set knownParams = new HashSet<>(); +// knownParams.add("limit"); +// knownParams.add("offset"); +// knownParams.add("sort"); +// for (Parameter param : parameter.getExecutable().getParameters()) { +// knownParams.add(param.getName()); +// } +// +// Map filters = new HashMap<>(); +// for (String key : webRequest.getParameterMap().keySet()) { +// if (!knownParams.contains(key)) { +// filters.put(key, String.join(",", webRequest.getParameterValues(key))); +// } +// } +// pagination.setFilters(filters); +// +// String[] sorts = webRequest.getParameterMap().get("sort"); +// List sort = new ArrayList<>(); +// if (sorts != null && sorts.length > 0) { +// for (String s : sorts) { +// if (s != null && s.length() > 0) { +// sort.add(s); +// } +// } +// pagination.setSorts(sort); +// } +// } + return result; } } diff --git a/src/main/java/io/papermc/hangar/db/dao/v1/UsersApiDAO.java b/src/main/java/io/papermc/hangar/db/dao/v1/UsersApiDAO.java index 12758e77..979168bc 100644 --- a/src/main/java/io/papermc/hangar/db/dao/v1/UsersApiDAO.java +++ b/src/main/java/io/papermc/hangar/db/dao/v1/UsersApiDAO.java @@ -4,7 +4,6 @@ import io.papermc.hangar.db.extras.BindPagination; import io.papermc.hangar.model.api.User; import io.papermc.hangar.model.api.project.ProjectCompact; import io.papermc.hangar.model.api.requests.RequestPagination; - import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper; import org.jdbi.v3.sqlobject.customizer.BindList; import org.jdbi.v3.sqlobject.customizer.Define; @@ -97,7 +96,8 @@ public interface UsersApiDAO { " FROM users u" + " WHERE u.id IN " + " (SELECT DISTINCT p.owner_id FROM projects p WHERE p.visibility != 1)" + - " ") + " " + + " ") List getAuthors(@BindPagination RequestPagination pagination); @SqlQuery("SELECT count(DISTINCT p.owner_id) FROM projects p WHERE p.visibility != 1") diff --git a/src/main/java/io/papermc/hangar/db/extras/BindPagination.java b/src/main/java/io/papermc/hangar/db/extras/BindPagination.java index 11b2be51..692fa7f7 100644 --- a/src/main/java/io/papermc/hangar/db/extras/BindPagination.java +++ b/src/main/java/io/papermc/hangar/db/extras/BindPagination.java @@ -14,7 +14,6 @@ import java.lang.annotation.Target; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.lang.reflect.Type; -import java.util.regex.Pattern; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.PARAMETER}) @@ -23,71 +22,42 @@ public @interface BindPagination { class BindPaginationFactory implements SqlStatementCustomizerFactory { - private static final Pattern valid = Pattern.compile("[a-zA-Z_]+"); - private static final Pattern dot = Pattern.compile("\\."); - @Override public SqlStatementParameterCustomizer createForParameter(final Annotation annotation, final Class sqlObjectType, final Method method, final Parameter param, final int index, final Type paramType) { return (q, arg) -> { RequestPagination pagination = (RequestPagination) arg; - StringBuilder sb = new StringBuilder(); - filter(pagination, sb, q); - sort(pagination, sb); - offsetLimit(pagination, sb, q); - - // use filters/sort here - // set the sql - q.define("pagination", sb.toString()); + filter(pagination, q); + sorters(pagination, q); + offsetLimit(pagination, q); }; } - private void filter(RequestPagination pagination, StringBuilder sb, SqlStatement q) { - pagination.getFilters().forEach((key, value) -> { - if (validate(key)) { - sb.append(" AND ").append(key).append(" = :").append(key); - q.bind(key, value); - } - }); + private void filter(RequestPagination pagination, SqlStatement q) { + StringBuilder sb = new StringBuilder(); + pagination.getFilters().forEach(filter -> filter.createSql(sb, q)); + q.define("filters", sb.toString()); } - private void sort(RequestPagination pagination, StringBuilder sb) { - if (!pagination.getSorts().isEmpty()) { + private void sorters(RequestPagination pagination, SqlStatement q) { + StringBuilder sb = new StringBuilder(); + if (!pagination.getSorters().isEmpty()) { sb.append(" ORDER BY "); - boolean first = true; - for (String sort : pagination.getSorts()) { - if (first) { - first = false; - } else { - sb.append(", "); - } - - boolean desc = sort.startsWith("-"); - if (desc) { - sort = sort.substring(1); - } - if (validate(sort)) { - sb.append(sort).append(" ").append(desc ? "DESC" : "ASC"); - } + } + var iter = pagination.getSorters().iterator(); + while (iter.hasNext()) { + iter.next().accept(sb); + if (iter.hasNext()) { + sb.append(", "); } } + q.define("sorters", sb.toString()); } - private void offsetLimit(RequestPagination pagination, StringBuilder sb, SqlStatement q) { - sb.append(" LIMIT :limit OFFSET :offset "); + private void offsetLimit(RequestPagination pagination, SqlStatement q) { q.bind("limit", pagination.getLimit()); q.bind("offset", pagination.getOffset()); - } - - private boolean validate(String key) { - if (key.contains(".")) { - String[] keys = dot.split(key); - if (keys.length == 2) { - return validate(keys[0]) && validate(keys[1]); - } else { - return false; - } - } else return valid.matcher(key).matches(); + q.define("offsetLimit", " LIMIT :limit OFFSET :offset "); } } } diff --git a/src/main/java/io/papermc/hangar/model/api/requests/RequestPagination.java b/src/main/java/io/papermc/hangar/model/api/requests/RequestPagination.java index 5f2971db..95811eab 100644 --- a/src/main/java/io/papermc/hangar/model/api/requests/RequestPagination.java +++ b/src/main/java/io/papermc/hangar/model/api/requests/RequestPagination.java @@ -1,32 +1,40 @@ package io.papermc.hangar.model.api.requests; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.papermc.hangar.controller.extras.ApiUtils; +import io.papermc.hangar.controller.extras.pagination.filters.Filter.FilterInstance; +import io.swagger.annotations.ApiModelProperty; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; - -import io.papermc.hangar.controller.extras.ApiUtils; -import io.swagger.annotations.ApiModelProperty; +import java.util.function.Consumer; public class RequestPagination { @ApiModelProperty(value = "The maximum amount of items to return", example = "1", allowEmptyValue = true, allowableValues = "range[1, 25]") private long limit = ApiUtils.limitOrDefault(null); + @ApiModelProperty(value = "Where to start searching", example = "0", allowEmptyValue = true, allowableValues = "range[0, infinity]") private long offset = 0; @JsonIgnore - private Map filters = new HashMap<>(); - @JsonIgnore - private List sorts = new ArrayList<>(); + @ApiModelProperty(hidden = true) + private final List filters; - public RequestPagination() { } + @JsonIgnore + @ApiModelProperty(hidden = true) + private final List> sorters; + + public RequestPagination() { + this.filters = new ArrayList<>(); + this.sorters = new ArrayList<>(); + } protected RequestPagination(long limit, long offset) { this.limit = limit; this.offset = offset; + this.filters = new ArrayList<>(); + this.sorters = new ArrayList<>(); } public long getLimit() { @@ -45,20 +53,12 @@ public class RequestPagination { this.offset = ApiUtils.offsetOrZero(offset); } - public Map getFilters() { + public List getFilters() { return filters; } - public void setFilters(Map filters) { - this.filters = filters; - } - - public List getSorts() { - return sorts; - } - - public void setSorts(List sorts) { - this.sorts = sorts; + public List> getSorters() { + return sorters; } @Override