Commit 4b5774a7 authored by Imre Farkas's avatar Imre Farkas

Merge branch '35527-add-sorting-to-package-api' into 'master'

Package api sorting

Closes #35527

See merge request gitlab-org/gitlab!20963
parents 9705c1fe d434bce5
# frozen_string_literal: true
class AddSortingIndexToPackages < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :packages_packages, [:project_id, :created_at]
add_concurrent_index :packages_packages, [:project_id, :version]
add_concurrent_index :packages_packages, [:project_id, :package_type]
end
def down
remove_concurrent_index :packages_packages, [:project_id, :created_at]
remove_concurrent_index :packages_packages, [:project_id, :version]
remove_concurrent_index :packages_packages, [:project_id, :package_type]
end
end
# frozen_string_literal: true
class RemoveProjectIdIndexFromPackages < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
remove_concurrent_index :packages_packages, [:project_id]
end
def down
add_concurrent_index :packages_packages, [:project_id]
end
end
...@@ -2977,8 +2977,10 @@ ActiveRecord::Schema.define(version: 2020_01_30_161817) do ...@@ -2977,8 +2977,10 @@ ActiveRecord::Schema.define(version: 2020_01_30_161817) do
t.string "version" t.string "version"
t.integer "package_type", limit: 2, null: false t.integer "package_type", limit: 2, null: false
t.index ["name"], name: "index_packages_packages_on_name_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["name"], name: "index_packages_packages_on_name_trigram", opclass: :gin_trgm_ops, using: :gin
t.index ["project_id", "created_at"], name: "index_packages_packages_on_project_id_and_created_at"
t.index ["project_id", "name", "version", "package_type"], name: "idx_packages_packages_on_project_id_name_version_package_type" t.index ["project_id", "name", "version", "package_type"], name: "idx_packages_packages_on_project_id_name_version_package_type"
t.index ["project_id"], name: "index_packages_packages_on_project_id" t.index ["project_id", "package_type"], name: "index_packages_packages_on_project_id_and_package_type"
t.index ["project_id", "version"], name: "index_packages_packages_on_project_id_and_version"
end end
create_table "packages_tags", force: :cascade do |t| create_table "packages_tags", force: :cascade do |t|
......
...@@ -84,6 +84,7 @@ class Packages::Package < ApplicationRecord ...@@ -84,6 +84,7 @@ class Packages::Package < ApplicationRecord
def self.sort_by_attribute(method) def self.sort_by_attribute(method)
case method.to_s case method.to_s
when 'created_asc' then order_created when 'created_asc' then order_created
when 'created_at_asc' then order_created
when 'name_asc' then order_name when 'name_asc' then order_name
when 'name_desc' then order_name_desc when 'name_desc' then order_name_desc
when 'version_asc' then order_version when 'version_asc' then order_version
......
---
title: Adds sorting to package api
merge_request: 20963
author:
type: added
...@@ -20,10 +20,18 @@ module API ...@@ -20,10 +20,18 @@ module API
end end
params do params do
use :pagination use :pagination
optional :order_by, type: String, values: %w[created_at name version type], default: 'created_at',
desc: 'Return packages ordered by `created_at`, `name`, `version` or `type` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'asc',
desc: 'Return packages sorted in `asc` or `desc` order.'
end end
get ':id/packages' do get ':id/packages' do
packages = user_project.packages packages = user_project.packages
if params[:order_by] && params[:sort]
packages = packages.sort_by_attribute("#{params[:order_by]}_#{params[:sort]}")
end
present paginate(packages), with: EE::API::Entities::Package, user: current_user present paginate(packages), with: EE::API::Entities::Package, user: current_user
end end
......
...@@ -5,9 +5,9 @@ require 'spec_helper' ...@@ -5,9 +5,9 @@ require 'spec_helper'
describe API::ProjectPackages do describe API::ProjectPackages do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let!(:package1) { create(:npm_package, project: project) } let!(:package1) { create(:npm_package, project: project, version: '3.1.0', name: "@#{project.root_namespace.path}/foo1") }
let(:package_url) { "/projects/#{project.id}/packages/#{package1.id}" } let(:package_url) { "/projects/#{project.id}/packages/#{package1.id}" }
let!(:package2) { create(:npm_package, project: project) } let!(:package2) { create(:nuget_package, project: project, version: '2.0.4') }
let!(:another_package) { create(:npm_package) } let!(:another_package) { create(:npm_package) }
let(:no_package_url) { "/projects/#{project.id}/packages/0" } let(:no_package_url) { "/projects/#{project.id}/packages/0" }
let(:wrong_package_url) { "/projects/#{project.id}/packages/#{another_package.id}" } let(:wrong_package_url) { "/projects/#{project.id}/packages/#{another_package.id}" }
...@@ -68,6 +68,58 @@ describe API::ProjectPackages do ...@@ -68,6 +68,58 @@ describe API::ProjectPackages do
it_behaves_like 'returns paginated packages' it_behaves_like 'returns paginated packages'
end end
end end
context 'with sorting' do
shared_examples 'package sorting' do |order_by|
subject { get api(url), params: { sort: sort, order_by: order_by } }
context "sorting by #{order_by}" do
context 'ascending order' do
let(:sort) { 'asc' }
it 'returns the sorted packages' do
subject
expect(json_response.map { |package| package['id'] }).to eq(packages.map(&:id))
end
end
context 'descending order' do
let(:sort) { 'desc' }
it 'returns the sorted packages' do
subject
expect(json_response.map { |package| package['id'] }).to eq(packages.reverse.map(&:id))
end
end
end
end
let(:package3) { create(:maven_package, project: project, version: '1.1.1', name: 'zzz') }
before do
travel_to(1.day.ago) do
package3
end
end
it_behaves_like 'package sorting', 'name' do
let(:packages) { [package1, package2, package3] }
end
it_behaves_like 'package sorting', 'created_at' do
let(:packages) { [package3, package1, package2] }
end
it_behaves_like 'package sorting', 'version' do
let(:packages) { [package3, package2, package1] }
end
it_behaves_like 'package sorting', 'type' do
let(:packages) { [package3, package1, package2] }
end
end
end end
context 'packages feature disabled' do context 'packages feature disabled' do
......
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