Skip to content

Commit dabe800

Browse files
committed
[MODEL] Added first version of pagination support with Kaminari
See: https://github.com/amatsuda/kaminari
1 parent 90a3111 commit dabe800

File tree

6 files changed

+239
-0
lines changed

6 files changed

+239
-0
lines changed

Diff for: elasticsearch-model/elasticsearch-model.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Gem::Specification.new do |s|
3535
s.add_development_dependency "activerecord", "> 4.0"
3636

3737
s.add_development_dependency "oj"
38+
s.add_development_dependency "kaminari"
3839

3940
s.add_development_dependency "shoulda-context"
4041
s.add_development_dependency "mocha"

Diff for: elasticsearch-model/examples/activerecord_article.rb

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
require 'logger'
1212
require 'ansi/core'
1313
require 'active_record'
14+
require 'kaminari'
1415

1516
require 'elasticsearch/model'
1617

@@ -25,6 +26,8 @@
2526
end
2627
end
2728

29+
Kaminari::Hooks.init
30+
2831
class Article < ActiveRecord::Base
2932
end
3033

Diff for: elasticsearch-model/lib/elasticsearch/model.rb

+5
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@
2727
require 'elasticsearch/model/response/result'
2828
require 'elasticsearch/model/response/results'
2929
require 'elasticsearch/model/response/records'
30+
require 'elasticsearch/model/response/pagination'
3031

3132
require 'elasticsearch/model/version'
3233

34+
if defined?(::Kaminari)
35+
Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari
36+
end
37+
3338
module Elasticsearch
3439

3540
# Elasticsearch integration for Ruby models
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
module Elasticsearch
2+
module Model
3+
module Response
4+
5+
# Pagination for search results/records
6+
#
7+
module Pagination
8+
# Allow models to be paginated with the "kaminari" gem [https://github.com/amatsuda/kaminari]
9+
#
10+
module Kaminari
11+
def self.included(base)
12+
# Include the Kaminari modules: Configuration and paging
13+
#
14+
base.__send__ :include, ::Kaminari::ConfigurationMethods::ClassMethods
15+
base.__send__ :include, ::Kaminari::PageScopeMethods
16+
17+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
18+
# Define the `page` Kaminari method
19+
#
20+
def #{::Kaminari.config.page_method_name}(num=nil)
21+
@results = nil
22+
@records = nil
23+
@response = nil
24+
self.search.definition.update size: klass.default_per_page,
25+
from: klass.default_per_page * ([num.to_i, 1].max - 1)
26+
self
27+
end
28+
RUBY
29+
end
30+
31+
# Returns the current "limit" (`size`) value
32+
#
33+
def limit_value
34+
case
35+
when search.definition[:body] && search.definition[:body][:size]
36+
search.definition[:body][:size]
37+
when search.definition[:size]
38+
search.definition[:size]
39+
else
40+
0
41+
end
42+
end
43+
44+
# Returns the current "offset" (`from`) value
45+
#
46+
def offset_value
47+
case
48+
when search.definition[:body] && search.definition[:body][:from]
49+
search.definition[:body][:from]
50+
when search.definition[:from]
51+
search.definition[:from]
52+
else
53+
0
54+
end
55+
end
56+
57+
# Set the "limit" (`size`) value
58+
#
59+
def limit(value)
60+
@results = nil
61+
@records = nil
62+
@response = nil
63+
search.definition.update :size => value
64+
self
65+
end
66+
67+
# Set the "offset" (`from`) value
68+
#
69+
def offset(value)
70+
@results = nil
71+
@records = nil
72+
@response = nil
73+
search.definition.update :from => value
74+
self
75+
end
76+
77+
# Returns the total number of results
78+
#
79+
def total_count
80+
results.total
81+
end
82+
end
83+
end
84+
85+
end
86+
end
87+
end

Diff for: elasticsearch-model/test/test_helper.rb

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
require 'active_record'
2222
require 'active_model'
23+
24+
require 'kaminari'
25+
2326
require 'elasticsearch/model'
2427

2528
require 'elasticsearch/extensions/test/cluster'
+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
require 'test_helper'
2+
3+
class Elasticsearch::Model::ResponsePaginationTest < Test::Unit::TestCase
4+
context "Response pagination" do
5+
class ModelClass
6+
include ::Kaminari::ConfigurationMethods
7+
8+
def self.index_name; 'foo'; end
9+
def self.document_type; 'bar'; end
10+
end
11+
12+
RESPONSE = { 'took' => '5', 'timed_out' => false, '_shards' => {'one' => 'OK'},
13+
'hits' => { 'total' => 100, 'hits' => [ {'_id' => 1} ] } }
14+
15+
setup do
16+
search = Elasticsearch::Model::Searching::SearchRequest.new ModelClass, '*'
17+
@response = Elasticsearch::Model::Response::Response.new ModelClass, search, RESPONSE
18+
@response.klass.stubs(:client).returns mock('client')
19+
end
20+
21+
should "have pagination methods" do
22+
assert_respond_to @response, :page
23+
assert_respond_to @response, :limit_value
24+
assert_respond_to @response, :offset_value
25+
assert_respond_to @response, :limit
26+
assert_respond_to @response, :offset
27+
assert_respond_to @response, :total_count
28+
end
29+
30+
context "#page method" do
31+
should "advance the from/size" do
32+
@response.klass.client
33+
.expects(:search)
34+
.with do |definition|
35+
assert_equal 25, definition[:from]
36+
assert_equal 25, definition[:size]
37+
end
38+
.returns(RESPONSE)
39+
40+
assert_nil @response.search.definition[:from]
41+
assert_nil @response.search.definition[:size]
42+
43+
@response.page(2).to_a
44+
assert_equal 25, @response.search.definition[:from]
45+
assert_equal 25, @response.search.definition[:size]
46+
end
47+
48+
should "advance the from/size further" do
49+
@response.klass.client
50+
.expects(:search)
51+
.with do |definition|
52+
assert_equal 75, definition[:from]
53+
assert_equal 25, definition[:size]
54+
end
55+
.returns(RESPONSE)
56+
57+
@response.page(4).to_a
58+
assert_equal 75, @response.search.definition[:from]
59+
assert_equal 25, @response.search.definition[:size]
60+
end
61+
end
62+
63+
context "limit/offset readers" do
64+
should "return the default" do
65+
assert_equal 0, @response.limit_value
66+
assert_equal 0, @response.offset_value
67+
end
68+
69+
should "return the value from URL parameters" do
70+
search = Elasticsearch::Model::Searching::SearchRequest.new ModelClass, '*', size: 10, from: 50
71+
@response = Elasticsearch::Model::Response::Response.new ModelClass, search, RESPONSE
72+
73+
assert_equal 10, @response.limit_value
74+
assert_equal 50, @response.offset_value
75+
end
76+
77+
should "return the value from body" do
78+
search = Elasticsearch::Model::Searching::SearchRequest.new ModelClass, { query: { match_all: {} }, from: 10, size: 50 }
79+
@response = Elasticsearch::Model::Response::Response.new ModelClass, search, RESPONSE
80+
81+
assert_equal 50, @response.limit_value
82+
assert_equal 10, @response.offset_value
83+
end
84+
end
85+
86+
context "limit setter" do
87+
setup do
88+
@response.records
89+
@response.results
90+
end
91+
92+
should "set the values" do
93+
@response.limit(35)
94+
assert_equal 35, @response.search.definition[:size]
95+
end
96+
97+
should "reset the variables" do
98+
assert_not_nil @response.instance_variable_get(:@response)
99+
assert_not_nil @response.instance_variable_get(:@records)
100+
assert_not_nil @response.instance_variable_get(:@results)
101+
102+
@response.limit(35)
103+
104+
assert_nil @response.instance_variable_get(:@response)
105+
assert_nil @response.instance_variable_get(:@records)
106+
assert_nil @response.instance_variable_get(:@results)
107+
end
108+
end
109+
110+
context "offset setter" do
111+
setup do
112+
@response.records
113+
@response.results
114+
end
115+
116+
should "set the values" do
117+
@response.offset(15)
118+
assert_equal 15, @response.search.definition[:from]
119+
end
120+
121+
should "reset the variables" do
122+
assert_not_nil @response.instance_variable_get(:@response)
123+
assert_not_nil @response.instance_variable_get(:@records)
124+
assert_not_nil @response.instance_variable_get(:@results)
125+
126+
@response.offset(35)
127+
128+
assert_nil @response.instance_variable_get(:@response)
129+
assert_nil @response.instance_variable_get(:@records)
130+
assert_nil @response.instance_variable_get(:@results)
131+
end
132+
end
133+
134+
context "total" do
135+
should "return the number of hits" do
136+
assert_equal 100, @response.total_count
137+
end
138+
end
139+
end
140+
end

0 commit comments

Comments
 (0)