Extract paginated collection gem
refs: CNVS-11648 Test Plan: Test the sub_accounts api endpoint and make sure the pagination is not broken. Change-Id: Ie59674a7a834698ac432307940305d6958cb73f1 Reviewed-on: https://gerrit.instructure.com/31413 QA-Review: Jeremy Putnam <jeremyp@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> Product-Review: Simon Williams <simon@instructure.com>
This commit is contained in:
parent
ec31030b0f
commit
86c8d2a7ed
|
@ -130,5 +130,6 @@ gem 'html_text_helper', :path => 'gems/html_text_helper'
|
|||
gem 'json_token', :path => 'gems/json_token'
|
||||
gem 'lti_outbound', :path => 'gems/lti_outbound'
|
||||
gem 'multipart', :path => 'gems/multipart'
|
||||
gem 'paginated_collection', :path => 'gems/paginated_collection'
|
||||
gem 'utf8_cleaner', :path => 'gems/utf8_cleaner'
|
||||
gem 'workflow', :path => 'gems/workflow'
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
|
||||
unless defined?(CANVAS_RAILS3)
|
||||
CANVAS_RAILS3 = !!ENV["CANVAS_RAILS3"] || File.exist?(File.expand_path("../../RAILS3", __FILE__))
|
||||
end
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "activesupport-suspend_callbacks"
|
||||
spec.version = '0.0.1'
|
||||
|
@ -14,7 +18,11 @@ Gem::Specification.new do |spec|
|
|||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_dependency "activesupport"
|
||||
if CANVAS_RAILS3
|
||||
spec.add_dependency "activesupport", "3.2.17"
|
||||
else
|
||||
spec.add_dependency "activesupport", "~>2.3.17"
|
||||
end
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.5"
|
||||
spec.add_development_dependency "rake"
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
#!/bin/bash
|
||||
result=0
|
||||
|
||||
echo "################ Running tests against Rails 2 ################"
|
||||
unset CANVAS_RAILS3
|
||||
bundle install
|
||||
bundle exec rspec spec
|
||||
let result=$result+$?
|
||||
|
||||
echo "################ Running tests against Rails 3 ################"
|
||||
rm -f Gemfile.lock
|
||||
export CANVAS_RAILS3=true
|
||||
bundle install
|
||||
bundle exec rspec spec
|
||||
let result=$result+$?
|
||||
|
||||
if [ $result -eq 0 ]; then
|
||||
echo "SUCCESS"
|
||||
echo "SUCCESS"
|
||||
else
|
||||
echo "FAILURE"
|
||||
echo "FAILURE"
|
||||
fi
|
||||
|
||||
exit $result
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
|
@ -0,0 +1 @@
|
|||
require "bundler/gem_tasks"
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (C) 2012 Instructure, Inc.
|
||||
# Copyright (C) 2012-2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
|
@ -48,47 +48,15 @@
|
|||
#
|
||||
# Note that the block needs to edit the AR collection in-place, because it's a
|
||||
# subclass of Array with paging information, rather than just a raw array.
|
||||
|
||||
require 'folio'
|
||||
|
||||
module PaginatedCollection
|
||||
require 'paginated_collection/proxy'
|
||||
require 'paginated_collection/collection'
|
||||
|
||||
def self.build(&block)
|
||||
raise(ArgumentError, "block required") unless block
|
||||
Proxy.new(block)
|
||||
end
|
||||
|
||||
class Collection < Array
|
||||
include Folio::Page
|
||||
end
|
||||
|
||||
class Proxy
|
||||
attr_accessor :block
|
||||
|
||||
def initialize(block)
|
||||
@block = block
|
||||
end
|
||||
|
||||
def paginate(options = {})
|
||||
execute_pager(configure_pager(new_pager, options))
|
||||
end
|
||||
|
||||
def new_pager
|
||||
PaginatedCollection::Collection.new
|
||||
end
|
||||
|
||||
def configure_pager(pager, options)
|
||||
raise(ArgumentError, "per_page required") unless options[:per_page] && options[:per_page] > 0
|
||||
current_page = options.fetch(:page) { nil }
|
||||
current_page = pager.first_page if current_page.nil?
|
||||
pager.current_page = current_page
|
||||
pager.per_page = options[:per_page]
|
||||
pager.total_entries = options[:total_entries]
|
||||
pager
|
||||
end
|
||||
|
||||
def execute_pager(pager)
|
||||
pager = @block.call(pager)
|
||||
if !pager.respond_to?(:current_page)
|
||||
raise(ArgumentError, "The PaginatedCollection block needs to return a WillPaginate-style object")
|
||||
end
|
||||
return pager
|
||||
end
|
||||
PaginatedCollection::Proxy.new(block)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
#
|
||||
# Copyright (C) 2012-2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module PaginatedCollection
|
||||
class Collection < Array
|
||||
include Folio::Page
|
||||
end
|
||||
end
|
|
@ -0,0 +1,53 @@
|
|||
#
|
||||
# Copyright (C) 2012-2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module PaginatedCollection
|
||||
class Proxy
|
||||
attr_accessor :block
|
||||
|
||||
def initialize(block)
|
||||
@block = block
|
||||
end
|
||||
|
||||
def paginate(options = {})
|
||||
execute_pager(configure_pager(new_pager, options))
|
||||
end
|
||||
|
||||
def new_pager
|
||||
PaginatedCollection::Collection.new
|
||||
end
|
||||
|
||||
def configure_pager(pager, options)
|
||||
raise(ArgumentError, "per_page required") unless options[:per_page] && options[:per_page] > 0
|
||||
current_page = options.fetch(:page) { nil }
|
||||
current_page = pager.first_page if current_page.nil?
|
||||
pager.current_page = current_page
|
||||
pager.per_page = options[:per_page]
|
||||
pager.total_entries = options[:total_entries]
|
||||
pager
|
||||
end
|
||||
|
||||
def execute_pager(pager)
|
||||
pager = @block.call(pager)
|
||||
if !pager.respond_to?(:current_page)
|
||||
raise(ArgumentError, "The PaginatedCollection block needs to return a WillPaginate-style object")
|
||||
end
|
||||
return pager
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
|
||||
unless defined?(CANVAS_RAILS3)
|
||||
require File.expand_path("../../../config/canvas_rails3", __FILE__)
|
||||
end
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "paginated_collection"
|
||||
spec.version = "1.0.0"
|
||||
spec.authors = ["Brian Palmer"]
|
||||
spec.email = ["brianp@instructure.com"]
|
||||
spec.summary = %q{Paginated Collection gem}
|
||||
|
||||
spec.files = Dir.glob("{lib}/**/*") + %w(Rakefile)
|
||||
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
||||
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
if CANVAS_RAILS3
|
||||
spec.add_dependency "folio-pagination", "0.0.7"
|
||||
spec.add_dependency "will_paginate", "3.0.4"
|
||||
spec.add_dependency "rails", "3.2.17"
|
||||
else
|
||||
spec.add_dependency "folio-pagination-legacy", "0.0.3"
|
||||
spec.add_dependency "will_paginate", "2.3.15"
|
||||
spec.add_dependency "rails", "~> 2.3"
|
||||
end
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.5"
|
||||
spec.add_development_dependency "rake"
|
||||
spec.add_development_dependency "rspec"
|
||||
spec.add_development_dependency "sqlite3"
|
||||
end
|
|
@ -0,0 +1,73 @@
|
|||
#
|
||||
# Copyright (C) 2012-2014 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe PaginatedCollection do
|
||||
describe '.build' do
|
||||
it 'returns a #paginate proxy' do
|
||||
expect { PaginatedCollection.build }.to raise_error(ArgumentError)
|
||||
proxy = PaginatedCollection.build { |pager| pager }
|
||||
expect(proxy).to be_a_kind_of(PaginatedCollection::Proxy)
|
||||
|
||||
expect(proxy.paginate(:per_page => 5).size).to eq 0
|
||||
end
|
||||
end
|
||||
|
||||
describe '#paginate' do
|
||||
it 'uses the provided collection' do
|
||||
expect { PaginatedCollection.build { |pager| [] }.paginate(:per_page => 5) }.to raise_error(ArgumentError)
|
||||
items = PaginatedCollection.build { |pager| pager.replace([1, 2]) }.paginate(:page => 1, :per_page => 5)
|
||||
expect(items).to eq [1, 2]
|
||||
expect(items.size).to eq 2
|
||||
expect(items.current_page).to eq 1
|
||||
expect(items.per_page).to eq 5
|
||||
expect(items.last_page).to eq 1
|
||||
%w(first_page next_page previous_page total_entries).each do |a|
|
||||
expect(items.send(a)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it 'uses the pager returned' do
|
||||
example_klass = Class.new(ActiveRecord::Base) do
|
||||
self.table_name = 'examples'
|
||||
end
|
||||
|
||||
3.times { example_klass.create! }
|
||||
|
||||
proxy = PaginatedCollection.build do |pager|
|
||||
result = example_klass.paginate(page: pager.current_page, per_page: pager.per_page)
|
||||
result.map! { |example| example.id }
|
||||
result
|
||||
end
|
||||
|
||||
p1 = proxy.paginate(:page => 1, :per_page => 2)
|
||||
expect(p1.current_page).to eq 1
|
||||
expect(p1.next_page).to eq 2
|
||||
expect(p1.previous_page).to be_nil
|
||||
|
||||
p2 = proxy.paginate(:page => 2, :per_page => 2)
|
||||
expect(p2.current_page).to eq 2
|
||||
expect(p2.next_page).to be_nil
|
||||
expect(p2.previous_page).to eq 1
|
||||
|
||||
expect(p1).to eq example_klass.all.map(&:id)[0, 2]
|
||||
expect(p2).to eq example_klass.all.map(&:id)[2, 1]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
require 'folio/rails'
|
||||
require 'folio/will_paginate/active_record' if defined?(CANVAS_RAILS3) && CANVAS_RAILS3
|
||||
|
||||
require 'paginated_collection'
|
||||
|
||||
require 'support/active_record'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.treat_symbols_as_metadata_keys_with_true_values = true
|
||||
config.run_all_when_everything_filtered = true
|
||||
config.filter_run :focus
|
||||
|
||||
config.color_enabled = true
|
||||
config.order = 'random'
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
require 'active_record'
|
||||
|
||||
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
||||
|
||||
ActiveRecord::Migration.verbose = false
|
||||
ActiveRecord::Schema.define(version: 1) do
|
||||
create_table :examples, force: true
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
result=0
|
||||
|
||||
echo "################ Running tests against Rails 2 ################"
|
||||
export CANVAS_RAILS3=0
|
||||
bundle install
|
||||
bundle exec rspec spec
|
||||
let result=$result+$?
|
||||
|
||||
echo "################ Running tests against Rails 3 ################"
|
||||
mv Gemfile.lock Gemfile.lock.rails2
|
||||
export CANVAS_RAILS3=true
|
||||
bundle install
|
||||
bundle exec rspec spec
|
||||
let result=$result+$?
|
||||
mv Gemfile.lock.rails2 Gemfile.lock
|
||||
|
||||
|
||||
if [ $result -eq 0 ]; then
|
||||
echo "SUCCESS"
|
||||
else
|
||||
echo "FAILURE"
|
||||
fi
|
||||
|
||||
exit $result
|
|
@ -1,62 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2012 Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
||||
|
||||
describe "PaginatedCollection" do
|
||||
describe ".build" do
|
||||
it "should return a #paginate proxy" do
|
||||
expect { PaginatedCollection.build() }.to raise_error(ArgumentError)
|
||||
proxy = PaginatedCollection.build { |pager| pager }
|
||||
proxy.should be_is_a PaginatedCollection::Proxy
|
||||
proxy.paginate(:per_page => 5).size.should == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "#paginate" do
|
||||
it "should use the provided collection" do
|
||||
expect { PaginatedCollection.build { |pager| [] }.paginate(:per_page => 5) }.to raise_error(ArgumentError)
|
||||
items = PaginatedCollection.build { |pager| pager.replace([1,2]) }.paginate(:page => 1, :per_page => 5)
|
||||
items.should == [1,2]
|
||||
items.size.should == 2
|
||||
items.current_page.should == 1
|
||||
items.per_page.should == 5
|
||||
items.last_page.should == 1
|
||||
%w(first_page next_page previous_page total_entries).each { |a| items.send(a).should be_nil }
|
||||
end
|
||||
|
||||
it "should use the pager returned" do
|
||||
3.times { user_model }
|
||||
proxy = PaginatedCollection.build do |pager|
|
||||
result = User.active.order(:id).paginate(:page => pager.current_page, :per_page => pager.per_page)
|
||||
result.map! { |u| u.id }
|
||||
result
|
||||
end
|
||||
p1 = proxy.paginate(:page => 1, :per_page => 2)
|
||||
p1.current_page.should == 1
|
||||
p1.next_page.should == 2
|
||||
p1.previous_page.should be_nil
|
||||
p2 = proxy.paginate(:page => 2, :per_page => 2)
|
||||
p2.current_page.should == 2
|
||||
p2.next_page.should be_nil
|
||||
p2.previous_page.should == 1
|
||||
p1.should == User.active.order(:id).pluck(:id)[0,2]
|
||||
p2.should == User.active.order(:id).pluck(:id)[2,1]
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue