Commit bb7bc767 authored by Andreas Brandl's avatar Andreas Brandl Committed by Ash McKenzie

Add id based filtering to projects API

This adds two new filters to the projects endpoint. It is a preparation
for keyset pagination on the id column - so why not implement this as a
standard filtering option if you have to support it anyways?
parent a2f20422
......@@ -110,7 +110,10 @@ class ProjectsFinder < UnionFinder
# rubocop: disable CodeReuse/ActiveRecord
def by_ids(items)
project_ids_relation ? items.where(id: project_ids_relation) : items
items = items.where(id: project_ids_relation) if project_ids_relation
items = items.where('id > ?', params[:id_after]) if params[:id_after]
items = items.where('id < ?', params[:id_before]) if params[:id_before]
items
end
# rubocop: enable CodeReuse/ActiveRecord
......
---
title: Add id_before, id_after filter param to projects API
merge_request: 19949
author:
type: added
......@@ -58,6 +58,8 @@ GET /projects
| `wiki_checksum_failed` | boolean | no | **(PREMIUM)** Limit projects where the wiki checksum calculation has failed ([Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/6137) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2) |
| `repository_checksum_failed` | boolean | no | **(PREMIUM)** Limit projects where the repository checksum calculation has failed ([Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/6137) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2) |
| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
| `id_after` | integer | no | Limit by project id greater than given ) |
| `id_before` | integer | no | Limit by project id less than given ) |
When `simple=true` or the user is unauthenticated this returns something like:
......@@ -304,6 +306,8 @@ GET /users/:user_id/projects
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature |
| `with_programming_language` | string | no | Limit by projects which use the given programming language |
| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
| `id_after` | integer | no | Limit by project id greater than given ) |
| `id_before` | integer | no | Limit by project id less than given ) |
```json
[
......
......@@ -479,6 +479,8 @@ module API
finder_params[:user] = params.delete(:user) if params[:user]
finder_params[:custom_attributes] = params[:custom_attributes] if params[:custom_attributes]
finder_params[:min_access_level] = params[:min_access_level] if params[:min_access_level]
finder_params[:id_after] = params[:id_after] if params[:id_after]
finder_params[:id_before] = params[:id_before] if params[:id_before]
finder_params
end
......
......@@ -61,6 +61,8 @@ module API
optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature'
optional :with_programming_language, type: String, desc: 'Limit to repositories which use the given programming language'
optional :min_access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'Limit by minimum access level of authenticated user'
optional :id_after, type: Integer, desc: 'Limit by greater than project id'
optional :id_before, type: Integer, desc: 'Limit by less than project id'
use :optional_filter_params_ee
end
......
......@@ -58,6 +58,22 @@ describe ProjectsFinder, :do_not_mock_admin_mode do
it { is_expected.to eq([internal_project]) }
end
describe 'with id_after' do
context 'only returns projects with a project id greater than given' do
let(:params) { { id_after: internal_project.id }}
it { is_expected.to eq([public_project]) }
end
end
describe 'with id_before' do
context 'only returns projects with a project id less than given' do
let(:params) { { id_before: public_project.id }}
it { is_expected.to eq([internal_project]) }
end
end
describe 'filter by visibility_level' do
before do
private_project.add_maintainer(user)
......
......@@ -362,6 +362,22 @@ describe API::Projects do
end
end
context 'and using id_after' do
it_behaves_like 'projects response' do
let(:filter) { { id_after: project2.id } }
let(:current_user) { user }
let(:projects) { [public_project, project, project2, project3].select { |p| p.id > project2.id } }
end
end
context 'and using id_before' do
it_behaves_like 'projects response' do
let(:filter) { { id_before: project2.id } }
let(:current_user) { user }
let(:projects) { [public_project, project, project2, project3].select { |p| p.id < project2.id } }
end
end
context 'and membership=true' do
it_behaves_like 'projects response' do
let(:filter) { { membership: true } }
......@@ -848,6 +864,50 @@ describe API::Projects do
expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id)
end
context 'and using id_after' do
let!(:another_public_project) { create(:project, :public, name: 'another_public_project', creator_id: user4.id, namespace: user4.namespace) }
it 'only returns projects with id_after filter given' do
get api("/users/#{user4.id}/projects?id_after=#{public_project.id}", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(another_public_project.id)
end
it 'returns both projects without a id_after filter' do
get api("/users/#{user4.id}/projects", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id, another_public_project.id)
end
end
context 'and using id_before' do
let!(:another_public_project) { create(:project, :public, name: 'another_public_project', creator_id: user4.id, namespace: user4.namespace) }
it 'only returns projects with id_before filter given' do
get api("/users/#{user4.id}/projects?id_before=#{another_public_project.id}", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id)
end
it 'returns both projects without a id_before filter' do
get api("/users/#{user4.id}/projects", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id, another_public_project.id)
end
end
it 'returns projects filtered by username' do
get api("/users/#{user4.username}/projects/", user)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment