Skip to content

Commit

Permalink
Merge pull request #1171 from transitland/keyset-pagination
Browse files Browse the repository at this point in the history
Implement keyset pagination
  • Loading branch information
irees authored Aug 22, 2017
2 parents 8e83a74 + 95ce2ef commit b7c1984
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
17 changes: 14 additions & 3 deletions app/controllers/concerns/json_collection_pagination.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ def paginated_collection(collection)
per_page = sort_per_page
offset = sort_offset
include_total = sort_total
min_id = sort_min_id
meta = {
sort_key: sort_key,
sort_order: sort_order,
offset: offset,
per_page: per_page,
}
qps = params.permit(query_params.keys)
Expand All @@ -22,12 +22,21 @@ def paginated_collection(collection)
# Setup prev/next links
if ['false', '∞'].include?(per_page)
data_on_page = collection.to_a
elsif min_id
# Get the current page of results, +1 to limit to check next page
data = collection.where('id > ?', min_id).limit(per_page+1).to_a
data_on_page = data[0...per_page]
meta[:sort_min_id] = data_on_page.last.id
meta_next = url_for(qps.merge(meta))
(meta[:next] = meta_next) if data.size > per_page
else
# Get the current page of results.
# Add +1 to limit to see if there is a next page.
# This will be dropped in the return.
data = collection.offset(offset).limit(per_page+1).to_a
data_on_page = data[0...per_page]
# Previous and next page
meta[:offset] = offset
meta_prev = url_for(qps.merge(meta).merge({
offset: (offset - per_page) >= 0 ? (offset - per_page) : 0,
}))
Expand All @@ -36,8 +45,6 @@ def paginated_collection(collection)
}))
(meta[:prev] = meta_prev) if offset > 0
(meta[:next] = meta_next) if data.size > per_page
# Slice data
data_on_page = data[0...per_page]
end

if include_total
Expand Down Expand Up @@ -74,6 +81,10 @@ def sort_key
(params[:sort_key].presence || :id).to_sym
end

def sort_min_id
params[:sort_min_id].presence ? params[:sort_min_id].to_i : nil
end

def sort_order
params[:sort_order].to_s == 'desc' ? :desc : :asc
end
Expand Down
19 changes: 19 additions & 0 deletions spec/controllers/json_collection_pagination_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,25 @@ def url_for(params)
})
end

it 'sort_min_id' do
idx = 1
per_page = 5
sort_min_id = @issue_ids[idx]
next_sort_min_id = @issue_ids[idx+per_page]
get :index, sort_min_id: sort_min_id, per_page: per_page
expect_json({
changesets: -> (changesets) {
expect(changesets.map { |i| i[:id] }).to eq(@issue_ids[idx+1...idx+1+per_page])
},
meta: {
sort_key: 'id',
sort_order: 'asc',
sort_min_id: next_sort_min_id,
per_page: per_page
}
})
end

it 'raises ArgumentError on invalid sort_key' do
expect {
get :index, sort_key: :unknown_key
Expand Down

0 comments on commit b7c1984

Please sign in to comment.