Merge pull request #1593 from coreos-inc/pagination-error

Fix various SQL errors
This commit is contained in:
josephschorr 2016-07-01 13:06:18 -04:00 committed by GitHub
commit 2122d70d00
4 changed files with 30 additions and 15 deletions

View file

@ -1,4 +1,4 @@
def paginate(query, model, descending=False, page_token=None, limit=50): def paginate(query, model, descending=False, page_token=None, limit=50, id_field='id'):
""" Paginates the given query using an ID range, starting at the optional page_token. """ 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 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 next page, if any. If descending is set to True, orders by the ID descending rather
@ -7,9 +7,9 @@ def paginate(query, model, descending=False, page_token=None, limit=50):
query = query.limit(limit + 1) query = query.limit(limit + 1)
if descending: if descending:
query = query.order_by(model.id.desc()) query = query.order_by(getattr(model, id_field).desc())
else: else:
query = query.order_by(model.id) query = query.order_by(getattr(model, id_field))
if page_token is not None: if page_token is not None:
start_id = page_token.get('start_id') start_id = page_token.get('start_id')

View file

@ -231,10 +231,12 @@ def get_visible_repositories(username, namespace=None, include_public=False):
""" Returns the repositories visible to the given user (if any). """ Returns the repositories visible to the given user (if any).
""" """
if not include_public and not username: if not include_public and not username:
return [] # Short circuit by returning a query that will find no repositories. We need to return a query
# here, as it will be modified by other queries later on.
return Repository.select().where(Repository.id == -1)
query = (Repository query = (Repository
.select(Repository.name, Repository.id.alias('id'), Repository.description, Namespace.username, .select(Repository.name, Repository.id.alias('rid'), Repository.description, Namespace.username,
Repository.visibility) Repository.visibility)
.distinct() .distinct()
.switch(Repository) .switch(Repository)
@ -394,6 +396,6 @@ def list_popular_public_repos(action_count_threshold, time_span):
.join(RepositoryActionCount) .join(RepositoryActionCount)
.where(RepositoryActionCount.date >= cutoff, .where(RepositoryActionCount.date >= cutoff,
Repository.visibility == get_public_repo_visibility()) Repository.visibility == get_public_repo_visibility())
.group_by(RepositoryActionCount.repository) .group_by(RepositoryActionCount.repository, Repository.name, Namespace.username)
.having(fn.Sum(RepositoryActionCount.count) >= action_count_threshold) .having(fn.Sum(RepositoryActionCount.count) >= action_count_threshold)
.tuples()) .tuples())

View file

@ -166,7 +166,8 @@ class RepositoryList(ApiResource):
# result in far smaller queries. # result in far smaller queries.
if not parsed_args['namespace'] and not parsed_args['starred']: 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, repo_query.c,
page_token=page_token, limit=REPOS_PER_PAGE) page_token=page_token, limit=REPOS_PER_PAGE,
id_field='rid')
else: else:
repos = list(repo_query) repos = list(repo_query)
next_page_token = None next_page_token = None

View file

@ -55,7 +55,8 @@ from endpoints.api.organization import (OrganizationList, OrganizationMember,
Organization, ApplicationInformation, Organization, ApplicationInformation,
OrganizationApplications, OrganizationApplicationResource, OrganizationApplications, OrganizationApplicationResource,
OrganizationApplicationResetClientSecret, Organization) OrganizationApplicationResetClientSecret, Organization)
from endpoints.api.repository import RepositoryList, RepositoryVisibility, Repository from endpoints.api.repository import (RepositoryList, RepositoryVisibility, Repository,
REPOS_PER_PAGE)
from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission, from endpoints.api.permission import (RepositoryUserPermission, RepositoryTeamPermission,
RepositoryTeamPermissionList, RepositoryUserPermissionList) RepositoryTeamPermissionList, RepositoryUserPermissionList)
from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement, from endpoints.api.superuser import (SuperUserLogs, SuperUserList, SuperUserManagement,
@ -1446,13 +1447,24 @@ class TestListRepos(ApiTestCase):
self.assertEquals(len(json['repositories']), 1) self.assertEquals(len(json['repositories']), 1)
def test_listrepos_asguest_withpages(self):
# Add public repos until we have enough for over 1 page.
public_user = model.user.get_user('public')
for i in range(0, REPOS_PER_PAGE):
model.repository.create_repository('public', 'publicrepo%s' % i, public_user,
visibility='public')
# Request the first page of results.
json = self.getJsonResponse(RepositoryList, params=dict(public=True))
self.assertEquals(len(json['repositories']), REPOS_PER_PAGE)
# Request the second page of results.
json = self.getJsonResponse(RepositoryList, params=dict(public=True,
next_page=json['next_page']))
self.assertGreater(len(json['repositories']), 0)
def test_listrepos_asorgmember(self): def test_listrepos_asorgmember(self):
self.login(READ_ACCESS_USER) self.login(READ_ACCESS_USER)
json = self.getJsonResponse(RepositoryList, params=dict(public=True))
# Queries: Base + the list query
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 2):
json = self.getJsonResponse(RepositoryList, params=dict(public=True))
self.assertGreater(len(json['repositories']), 0) self.assertGreater(len(json['repositories']), 0)
def test_listrepos_filter(self): def test_listrepos_filter(self):
@ -1461,7 +1473,7 @@ class TestListRepos(ApiTestCase):
params=dict(namespace=ORGANIZATION, params=dict(namespace=ORGANIZATION,
public=False)) public=False))
self.assertTrue(len(json['repositories']) > 0) self.assertGreater(len(json['repositories']), 0)
for repo in json['repositories']: for repo in json['repositories']:
self.assertEquals(ORGANIZATION, repo['namespace']) self.assertEquals(ORGANIZATION, repo['namespace'])
@ -1477,7 +1489,7 @@ class TestListRepos(ApiTestCase):
last_modified=True, last_modified=True,
popularity=True)) popularity=True))
self.assertTrue(len(json['repositories']) > 0) self.assertGreater(len(json['repositories']), 0)
for repo in json['repositories']: for repo in json['repositories']:
self.assertEquals(ORGANIZATION, repo['namespace']) self.assertEquals(ORGANIZATION, repo['namespace'])