Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
6cdd2fa2
Commit
6cdd2fa2
authored
Aug 24, 2021
by
Mark Chao
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'mmj-cursor-pager' into 'master'
Introduce CursorPager See merge request gitlab-org/gitlab!68462
parents
d48341c4
bdc7a91f
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
191 additions
and
0 deletions
+191
-0
lib/gitlab/pagination/keyset/cursor_based_request_context.rb
lib/gitlab/pagination/keyset/cursor_based_request_context.rb
+30
-0
lib/gitlab/pagination/keyset/cursor_pager.rb
lib/gitlab/pagination/keyset/cursor_pager.rb
+38
-0
spec/lib/gitlab/pagination/keyset/cursor_based_request_context_spec.rb
...ab/pagination/keyset/cursor_based_request_context_spec.rb
+60
-0
spec/lib/gitlab/pagination/keyset/cursor_pager_spec.rb
spec/lib/gitlab/pagination/keyset/cursor_pager_spec.rb
+63
-0
No files found.
lib/gitlab/pagination/keyset/cursor_based_request_context.rb
0 → 100644
View file @
6cdd2fa2
# frozen_string_literal: true
module
Gitlab
module
Pagination
module
Keyset
class
CursorBasedRequestContext
attr_reader
:request
delegate
:params
,
:header
,
to: :request
def
initialize
(
request
)
@request
=
request
end
def
per_page
params
[
:per_page
]
end
def
cursor
params
[
:cursor
]
end
def
apply_headers
(
cursor_for_next_page
)
Gitlab
::
Pagination
::
Keyset
::
HeaderBuilder
.
new
(
self
)
.
add_next_page_header
({
cursor:
cursor_for_next_page
})
end
end
end
end
end
lib/gitlab/pagination/keyset/cursor_pager.rb
0 → 100644
View file @
6cdd2fa2
# frozen_string_literal: true
module
Gitlab
module
Pagination
module
Keyset
class
CursorPager
<
Gitlab
::
Pagination
::
Base
attr_reader
:cursor_based_request_context
,
:paginator
def
initialize
(
cursor_based_request_context
)
@cursor_based_request_context
=
cursor_based_request_context
end
def
paginate
(
relation
)
@paginator
||=
relation
.
keyset_paginate
(
per_page:
cursor_based_request_context
.
per_page
,
cursor:
cursor_based_request_context
.
cursor
)
paginator
.
records
end
def
finalize
(
_records
=
[])
# can be called only after executing `paginate(relation)`
apply_headers
end
private
def
apply_headers
return
unless
paginator
.
has_next_page?
cursor_based_request_context
.
apply_headers
(
paginator
.
cursor_for_next_page
)
end
end
end
end
end
spec/lib/gitlab/pagination/keyset/cursor_based_request_context_spec.rb
0 → 100644
View file @
6cdd2fa2
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Pagination
::
Keyset
::
CursorBasedRequestContext
do
let
(
:params
)
{
{
per_page:
2
,
cursor:
'eyJuYW1lIjoiR2l0TGFiIEluc3RhbmNlIiwiaWQiOiI1MiIsIl9rZCI6Im4ifQ=='
}
}
let
(
:request
)
{
double
(
'request'
,
params:
params
)
}
describe
'#per_page'
do
subject
(
:per_page
)
{
described_class
.
new
(
request
).
per_page
}
it
{
is_expected
.
to
eq
2
}
end
describe
'#cursor'
do
subject
(
:cursor
)
{
described_class
.
new
(
request
).
cursor
}
it
{
is_expected
.
to
eq
'eyJuYW1lIjoiR2l0TGFiIEluc3RhbmNlIiwiaWQiOiI1MiIsIl9rZCI6Im4ifQ=='
}
end
describe
'#apply_headers'
do
let
(
:request
)
{
double
(
'request'
,
url:
"http://
#{
Gitlab
.
config
.
gitlab
.
host
}
/api/v4/projects?per_page=3"
,
params:
params
)
}
let
(
:params
)
{
{
per_page:
3
}
}
let
(
:cursor_for_next_page
)
{
'eyJuYW1lIjoiSDVicCIsImlkIjoiMjgiLCJfa2QiOiJuIn0='
}
subject
(
:apply_headers
)
{
described_class
.
new
(
request
).
apply_headers
(
cursor_for_next_page
)
}
it
'sets Link header with same host/path as the original request'
do
orig_uri
=
URI
.
parse
(
request
.
url
)
expect
(
request
).
to
receive
(
:header
).
once
do
|
name
,
header
|
first_link
,
_
=
/<([^>]+)>; rel="next"/
.
match
(
header
).
captures
uri
=
URI
.
parse
(
first_link
)
expect
(
name
).
to
eq
(
'Link'
)
expect
(
uri
.
host
).
to
eq
(
orig_uri
.
host
)
expect
(
uri
.
path
).
to
eq
(
orig_uri
.
path
)
end
apply_headers
end
it
'sets Link header with a cursor to the next page'
do
orig_uri
=
URI
.
parse
(
request
.
url
)
expect
(
request
).
to
receive
(
:header
).
once
do
|
name
,
header
|
first_link
,
_
=
/<([^>]+)>; rel="next"/
.
match
(
header
).
captures
query
=
CGI
.
parse
(
URI
.
parse
(
first_link
).
query
)
expect
(
name
).
to
eq
(
'Link'
)
expect
(
query
.
except
(
'cursor'
)).
to
eq
(
CGI
.
parse
(
orig_uri
.
query
).
except
(
'cursor'
))
expect
(
query
[
'cursor'
]).
to
eq
([
cursor_for_next_page
])
end
apply_headers
end
end
end
spec/lib/gitlab/pagination/keyset/cursor_pager_spec.rb
0 → 100644
View file @
6cdd2fa2
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Gitlab
::
Pagination
::
Keyset
::
CursorPager
do
let
(
:relation
)
{
Group
.
all
.
order
(
:name
,
:id
)
}
let
(
:per_page
)
{
3
}
let
(
:params
)
{
{
cursor:
nil
,
per_page:
per_page
}
}
let
(
:request
)
{
double
(
'request'
,
params:
params
)
}
let
(
:cursor_based_request_context
)
{
Gitlab
::
Pagination
::
Keyset
::
CursorBasedRequestContext
.
new
(
request
)
}
before_all
do
create_list
(
:group
,
7
)
end
describe
'#paginate'
do
subject
(
:paginated_result
)
{
described_class
.
new
(
cursor_based_request_context
).
paginate
(
relation
)
}
it
'returns the limited relation'
do
expect
(
paginated_result
).
to
eq
(
relation
.
limit
(
per_page
))
end
end
describe
'#finalize'
do
subject
(
:finalize
)
do
service
=
described_class
.
new
(
cursor_based_request_context
)
# we need to do this because `finalize` can only be called
# after `paginate` is called. Otherwise the `paginator` object won't be set.
service
.
paginate
(
relation
)
service
.
finalize
end
it
'passes information about next page to request'
do
cursor_for_next_page
=
relation
.
keyset_paginate
(
**
params
).
cursor_for_next_page
expect_next_instance_of
(
Gitlab
::
Pagination
::
Keyset
::
HeaderBuilder
,
cursor_based_request_context
)
do
|
builder
|
expect
(
builder
).
to
receive
(
:add_next_page_header
).
with
({
cursor:
cursor_for_next_page
})
end
finalize
end
context
'when retrieving the last page'
do
let
(
:relation
)
{
Group
.
where
(
'id > ?'
,
Group
.
maximum
(
:id
)
-
per_page
).
order
(
:name
,
:id
)
}
it
'does not build information about the next page'
do
expect
(
Gitlab
::
Pagination
::
Keyset
::
HeaderBuilder
).
not_to
receive
(
:new
)
finalize
end
end
context
'when retrieving an empty page'
do
let
(
:relation
)
{
Group
.
where
(
'id > ?'
,
Group
.
maximum
(
:id
)
+
1
).
order
(
:name
,
:id
)
}
it
'does not build information about the next page'
do
expect
(
Gitlab
::
Pagination
::
Keyset
::
HeaderBuilder
).
not_to
receive
(
:new
)
finalize
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment