From 4e1259b58a8410ccb9248421f6d4fc6bd5130640 Mon Sep 17 00:00:00 2001 From: Joseph Schorr Date: Thu, 14 Jul 2016 17:09:52 -0400 Subject: [PATCH] Fix the Repository ID in pagination problem once and for all But.... ONCE AND FOR ALL! Note: Tested on SQLite, Postgres and MySQL --- data/model/modelutil.py | 19 ++++++++++++------- endpoints/api/repository.py | 7 ++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/data/model/modelutil.py b/data/model/modelutil.py index af1e6d123..7f0594f89 100644 --- a/data/model/modelutil.py +++ b/data/model/modelutil.py @@ -1,29 +1,34 @@ -def paginate(query, model, descending=False, page_token=None, limit=50, id_field='id'): +from peewee import SQL + +def paginate(query, model, descending=False, page_token=None, limit=50, id_alias=None): """ Paginates the given query using an ID range, starting at the optional page_token. Returns a *list* of matching results along with an unencrypted page_token for the next page, if any. If descending is set to True, orders by the ID descending rather than ascending. """ - query = query.limit(limit + 1) + id_field = model.id + if id_alias is not None: + id_field = SQL(id_alias) if descending: - query = query.order_by(getattr(model, id_field).desc()) + query = query.order_by(id_field.desc()) else: - query = query.order_by(getattr(model, id_field)) + query = query.order_by(id_field) if page_token is not None: start_id = page_token.get('start_id') if start_id is not None: if descending: - query = query.where(getattr(model, id_field) <= start_id) + query = query.where(model.id <= start_id) else: - query = query.where(getattr(model, id_field) >= start_id) + query = query.where(model.id >= start_id) results = list(query) page_token = None if len(results) > limit: + start_id = results[limit].id page_token = { - 'start_id': getattr(results[limit], id_field) + 'start_id': start_id } return results[0:limit], page_token diff --git a/endpoints/api/repository.py b/endpoints/api/repository.py index aab57ea66..6950402fe 100644 --- a/endpoints/api/repository.py +++ b/endpoints/api/repository.py @@ -9,10 +9,11 @@ from datetime import timedelta, datetime from flask import request, abort from data import model +from data.database import Repository as RepositoryTable from endpoints.api import (truthy_bool, format_date, nickname, log_action, validate_json_request, require_repo_read, require_repo_write, require_repo_admin, RepositoryParamResource, resource, query_param, parse_args, ApiResource, - request_error, require_scope, path_param, page_support, parse_args, + request_error, require_scope, path_param, page_support, parse_args, query_param, truthy_bool) from endpoints.exception import Unauthorized, NotFound, InvalidRequest, ExceedsLicenseException from endpoints.api.billing import lookup_allowed_private_repos, get_namespace_plan @@ -165,9 +166,9 @@ class RepositoryList(ApiResource): # Note: We only limit repositories when there isn't a namespace or starred filter, as they # result in far smaller queries. if not parsed_args['namespace'] and not parsed_args['starred']: - repos, next_page_token = model.modelutil.paginate(repo_query, repo_query.c, + repos, next_page_token = model.modelutil.paginate(repo_query, RepositoryTable, page_token=page_token, limit=REPOS_PER_PAGE, - id_field='rid') + id_alias='rid') else: repos = list(repo_query) next_page_token = None