Welcome to mirror list, hosted at ThFree Co, Russian Federation.

paginator_spec.rb « keyset « pagination « gitlab « lib « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 230ac01af317a675044cf30bc335fe61c82ba98b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::Pagination::Keyset::Paginator do
  let_it_be(:project_1) { create(:project, created_at: 10.weeks.ago) }
  let_it_be(:project_2) { create(:project, created_at: 2.weeks.ago) }
  let_it_be(:project_3) { create(:project, created_at: 3.weeks.ago) }
  let_it_be(:project_4) { create(:project, created_at: 5.weeks.ago) }
  let_it_be(:project_5) { create(:project, created_at: 2.weeks.ago) }

  describe 'pagination' do
    let(:per_page) { 10 }
    let(:cursor) { nil }
    let(:scope) { Project.order(created_at: :asc, id: :asc) }
    let(:expected_order) { [project_1, project_4, project_3, project_2, project_5] }

    subject(:paginator) { scope.keyset_paginate(cursor: cursor, per_page: per_page) }

    context 'when per_page is greater than the record count' do
      it { expect(paginator.records).to eq(expected_order) }
      it { is_expected.not_to have_next_page }
      it { is_expected.not_to have_previous_page }

      it 'has no next and previous cursor values' do
        expect(paginator.cursor_for_next_page).to be_nil
        expect(paginator.cursor_for_previous_page).to be_nil
      end
    end

    context 'when 0 records are returned' do
      let(:scope) { Project.where(id: non_existing_record_id).order(created_at: :asc, id: :asc) }

      it { expect(paginator.records).to be_empty }
      it { is_expected.not_to have_next_page }
      it { is_expected.not_to have_previous_page }
    end

    context 'when page size is smaller than the record count' do
      let(:per_page) { 2 }

      it { expect(paginator.records).to eq(expected_order.first(2)) }
      it { is_expected.to have_next_page }
      it { is_expected.not_to have_previous_page }

      it 'has next page cursor' do
        expect(paginator.cursor_for_next_page).not_to be_nil
      end

      it 'does not have previous page cursor' do
        expect(paginator.cursor_for_previous_page).to be_nil
      end

      context 'when on the second page' do
        let(:cursor) { scope.keyset_paginate(per_page: per_page).cursor_for_next_page }

        it { expect(paginator.records).to eq(expected_order[2...4]) }
        it { is_expected.to have_next_page }
        it { is_expected.to have_previous_page }

        context 'and then going back to the first page' do
          let(:previous_page_cursor) { scope.keyset_paginate(cursor: cursor, per_page: per_page).cursor_for_previous_page }

          subject(:paginator) { scope.keyset_paginate(cursor: previous_page_cursor, per_page: per_page) }

          it { expect(paginator.records).to eq(expected_order.first(2)) }
          it { is_expected.to have_next_page }
          it { is_expected.not_to have_previous_page }
        end
      end

      context 'when jumping to the last page' do
        let(:cursor) { scope.keyset_paginate(per_page: per_page).cursor_for_last_page }

        it { expect(paginator.records).to eq(expected_order.last(2)) }
        it { is_expected.not_to have_next_page }
        it { is_expected.to have_previous_page }

        context 'when paginating backwards' do
          let(:previous_page_cursor) { scope.keyset_paginate(cursor: cursor, per_page: per_page).cursor_for_previous_page }

          subject(:paginator) { scope.keyset_paginate(cursor: previous_page_cursor, per_page: per_page) }

          it { expect(paginator.records).to eq(expected_order[-4...-2]) }
          it { is_expected.to have_next_page }
          it { is_expected.to have_previous_page }
        end

        context 'when jumping to the first page' do
          let(:first_page_cursor) { scope.keyset_paginate(cursor: cursor, per_page: per_page).cursor_for_first_page }

          subject(:paginator) { scope.keyset_paginate(cursor: first_page_cursor, per_page: per_page) }

          it { expect(paginator.records).to eq(expected_order.first(2)) }
          it { is_expected.to have_next_page }
          it { is_expected.not_to have_previous_page }
        end
      end
    end

    describe 'default keyset direction parameter' do
      let(:cursor_converter_class) { Gitlab::Pagination::Keyset::Paginator::Base64CursorConverter }
      let(:per_page) { 2 }

      it 'exposes the direction parameter in the cursor' do
        cursor = paginator.cursor_for_next_page

        expect(cursor_converter_class.parse(cursor)[:_kd]).to eq(described_class::FORWARD_DIRECTION)
      end
    end
  end

  context 'when unsupported order is given' do
    it 'raises error' do
      scope = Project.order(path: :asc, name: :asc, id: :desc) # Cannot build 3 column order automatically

      expect { scope.keyset_paginate }.to raise_error(/does not support keyset pagination/)
    end
  end

  context 'when use_union_optimization option is true and ordering by two columns' do
    let(:scope) { Project.order(name: :asc, id: :desc) }

    it 'uses UNION queries' do
      paginator_first_page = scope.keyset_paginate(
        per_page: 2,
        keyset_order_options: { use_union_optimization: true }
      )

      paginator_second_page = scope.keyset_paginate(
        per_page: 2,
        cursor: paginator_first_page.cursor_for_next_page,
        keyset_order_options: { use_union_optimization: true }
      )

      expect_next_instances_of(Gitlab::SQL::Union, 1) do |instance|
        expect(instance.to_sql).to include(paginator_first_page.records.last.name)
      end

      paginator_second_page.records.to_a
    end
  end
end