Skip to content

Commit f6ebf4f

Browse files
miguelffkarmi
authored andcommitted
[MODEL] Added "default per page" methods for pagination with multi model searches
Due to the fact that different models aggregated on a multimodel search could have different default values for the page size. I have opted for defaulting to Kaminari's and WillPaginate's respective default values. Problem: Elasticsearch::Model.search(query, [AAA, BBB]).page(1).results NoMethodError: undefined method `default_per_page' for #Elasticsearch::Model::Multimodel:0x007ff9dbe4f520 Fixes elastic#382 Closes elastic#408
1 parent 55af45b commit f6ebf4f

File tree

3 files changed

+397
-25
lines changed

3 files changed

+397
-25
lines changed

elasticsearch-model/lib/elasticsearch/model/response/pagination.rb

+19-3
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def #{::Kaminari.config.page_method_name}(num=nil)
3131
@records = nil
3232
@response = nil
3333
@page = [num.to_i, 1].max
34-
@per_page ||= klass.default_per_page
34+
@per_page ||= __default_per_page
3535
3636
self.search.definition.update size: @per_page,
3737
from: @per_page * (@page - 1)
@@ -48,7 +48,7 @@ def limit_value
4848
when search.definition[:size]
4949
search.definition[:size]
5050
else
51-
search.klass.default_per_page
51+
__default_per_page
5252
end
5353
end
5454

@@ -94,6 +94,14 @@ def offset(value)
9494
def total_count
9595
results.total
9696
end
97+
98+
# Returns the models's `per_page` value or the default
99+
#
100+
# @api private
101+
#
102+
def __default_per_page
103+
klass.respond_to?(:default_per_page) && klass.default_per_page || ::Kaminari.config.default_per_page
104+
end
97105
end
98106

99107
# Allow models to be paginated with the "will_paginate" gem [https://github.com/mislav/will_paginate]
@@ -126,7 +134,7 @@ def length
126134
def paginate(options)
127135
param_name = options[:param_name] || :page
128136
page = [options[param_name].to_i, 1].max
129-
per_page = (options[:per_page] || klass.per_page).to_i
137+
per_page = (options[:per_page] || __default_per_page).to_i
130138

131139
search.definition.update size: per_page,
132140
from: (page - 1) * per_page
@@ -168,6 +176,14 @@ def per_page(num = nil)
168176
def total_entries
169177
results.total
170178
end
179+
180+
# Returns the models's `per_page` value or the default
181+
#
182+
# @api private
183+
#
184+
def __default_per_page
185+
klass.respond_to?(:per_page) && klass.per_page || ::WillPaginate.per_page
186+
end
171187
end
172188
end
173189

elasticsearch-model/test/unit/response_pagination_kaminari_test.rb

+186-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
require 'test_helper'
22

33
class Elasticsearch::Model::ResponsePaginationKaminariTest < Test::Unit::TestCase
4-
context "Response pagination" do
5-
class ModelClass
6-
include ::Kaminari::ConfigurationMethods
4+
class ModelClass
5+
include ::Kaminari::ConfigurationMethods
76

8-
def self.index_name; 'foo'; end
9-
def self.document_type; 'bar'; end
10-
end
7+
def self.index_name; 'foo'; end
8+
def self.document_type; 'bar'; end
9+
end
1110

12-
RESPONSE = { 'took' => '5', 'timed_out' => false, '_shards' => {'one' => 'OK'},
13-
'hits' => { 'total' => 100, 'hits' => (1..100).to_a.map { |i| { _id: i } } } }
11+
RESPONSE = { 'took' => '5', 'timed_out' => false, '_shards' => {'one' => 'OK'},
12+
'hits' => { 'total' => 100, 'hits' => (1..100).to_a.map { |i| { _id: i } } } }
13+
14+
context "Response pagination" do
1415

1516
setup do
1617
@search = Elasticsearch::Model::Searching::SearchRequest.new ModelClass, '*'
@@ -208,4 +209,181 @@ def self.document_type; 'bar'; end
208209
end
209210
end
210211
end
212+
213+
context "Multimodel response pagination" do
214+
setup do
215+
@multimodel = Elasticsearch::Model::Multimodel.new(ModelClass)
216+
@search = Elasticsearch::Model::Searching::SearchRequest.new @multimodel, '*'
217+
@response = Elasticsearch::Model::Response::Response.new @multimodel, @search, RESPONSE
218+
@response.klass.stubs(:client).returns mock('client')
219+
end
220+
221+
should "have pagination methods" do
222+
assert_respond_to @response, :page
223+
assert_respond_to @response, :limit_value
224+
assert_respond_to @response, :offset_value
225+
assert_respond_to @response, :limit
226+
assert_respond_to @response, :offset
227+
assert_respond_to @response, :total_count
228+
end
229+
230+
context "#page method" do
231+
should "advance the from/size" do
232+
@response.klass.client
233+
.expects(:search)
234+
.with do |definition|
235+
assert_equal 25, definition[:from]
236+
assert_equal 25, definition[:size]
237+
true
238+
end
239+
.returns(RESPONSE)
240+
241+
assert_nil @response.search.definition[:from]
242+
assert_nil @response.search.definition[:size]
243+
244+
@response.page(2).to_a
245+
assert_equal 25, @response.search.definition[:from]
246+
assert_equal 25, @response.search.definition[:size]
247+
end
248+
249+
should "advance the from/size further" do
250+
@response.klass.client
251+
.expects(:search)
252+
.with do |definition|
253+
assert_equal 75, definition[:from]
254+
assert_equal 25, definition[:size]
255+
true
256+
end
257+
.returns(RESPONSE)
258+
259+
@response.page(4).to_a
260+
assert_equal 75, @response.search.definition[:from]
261+
assert_equal 25, @response.search.definition[:size]
262+
end
263+
end
264+
265+
context "limit/offset readers" do
266+
should "return the default" do
267+
assert_equal Kaminari.config.default_per_page, @response.limit_value
268+
assert_equal 0, @response.offset_value
269+
end
270+
271+
should "return the value from URL parameters" do
272+
search = Elasticsearch::Model::Searching::SearchRequest.new ModelClass, '*', size: 10, from: 50
273+
@response = Elasticsearch::Model::Response::Response.new ModelClass, search, RESPONSE
274+
275+
assert_equal 10, @response.limit_value
276+
assert_equal 50, @response.offset_value
277+
end
278+
279+
should "ignore the value from request body" do
280+
search = Elasticsearch::Model::Searching::SearchRequest.new ModelClass,
281+
{ query: { match_all: {} }, from: 333, size: 999 }
282+
@response = Elasticsearch::Model::Response::Response.new ModelClass, search, RESPONSE
283+
284+
assert_equal Kaminari.config.default_per_page, @response.limit_value
285+
assert_equal 0, @response.offset_value
286+
end
287+
end
288+
289+
context "limit setter" do
290+
setup do
291+
@response.records
292+
@response.results
293+
end
294+
295+
should "set the values" do
296+
@response.limit(35)
297+
assert_equal 35, @response.search.definition[:size]
298+
end
299+
300+
should "reset the variables" do
301+
@response.limit(35)
302+
303+
assert_nil @response.instance_variable_get(:@response)
304+
assert_nil @response.instance_variable_get(:@records)
305+
assert_nil @response.instance_variable_get(:@results)
306+
end
307+
end
308+
309+
context "with the page() and limit() methods" do
310+
setup do
311+
@response.records
312+
@response.results
313+
end
314+
315+
should "set the values" do
316+
@response.page(3).limit(35)
317+
assert_equal 35, @response.search.definition[:size]
318+
assert_equal 70, @response.search.definition[:from]
319+
end
320+
321+
should "set the values when limit is called first" do
322+
@response.limit(35).page(3)
323+
assert_equal 35, @response.search.definition[:size]
324+
assert_equal 70, @response.search.definition[:from]
325+
end
326+
327+
should "reset the instance variables" do
328+
@response.page(3).limit(35)
329+
330+
assert_nil @response.instance_variable_get(:@response)
331+
assert_nil @response.instance_variable_get(:@records)
332+
assert_nil @response.instance_variable_get(:@results)
333+
end
334+
end
335+
336+
context "offset setter" do
337+
setup do
338+
@response.records
339+
@response.results
340+
end
341+
342+
should "set the values" do
343+
@response.offset(15)
344+
assert_equal 15, @response.search.definition[:from]
345+
end
346+
347+
should "reset the variables" do
348+
@response.offset(35)
349+
350+
assert_nil @response.instance_variable_get(:@response)
351+
assert_nil @response.instance_variable_get(:@records)
352+
assert_nil @response.instance_variable_get(:@results)
353+
end
354+
end
355+
356+
context "total" do
357+
should "return the number of hits" do
358+
@response.expects(:results).returns(mock('results', total: 100))
359+
assert_equal 100, @response.total_count
360+
end
361+
end
362+
363+
context "results" do
364+
setup do
365+
@search.stubs(:execute!).returns RESPONSE
366+
end
367+
368+
should "return current page and total count" do
369+
assert_equal 1, @response.page(1).results.current_page
370+
assert_equal 100, @response.results.total_count
371+
372+
assert_equal 5, @response.page(5).results.current_page
373+
end
374+
end
375+
376+
context "records" do
377+
setup do
378+
@search.stubs(:execute!).returns RESPONSE
379+
end
380+
381+
should "return current page and total count" do
382+
assert_equal 1, @response.page(1).records.current_page
383+
assert_equal 100, @response.records.total_count
384+
385+
assert_equal 5, @response.page(5).records.current_page
386+
end
387+
end
388+
end
211389
end

0 commit comments

Comments
 (0)