elasticsearch-model 5.1.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/README.md +18 -11
  4. data/Rakefile +27 -36
  5. data/elasticsearch-model.gemspec +5 -5
  6. data/examples/activerecord_custom_analyzer.rb +135 -0
  7. data/examples/activerecord_mapping_completion.rb +3 -18
  8. data/examples/datamapper_article.rb +11 -1
  9. data/gemfiles/3.0.gemfile +6 -1
  10. data/gemfiles/4.0.gemfile +7 -1
  11. data/gemfiles/5.0.gemfile +7 -1
  12. data/lib/elasticsearch/model/adapters/active_record.rb +7 -23
  13. data/lib/elasticsearch/model/adapters/mongoid.rb +10 -3
  14. data/lib/elasticsearch/model/importing.rb +1 -1
  15. data/lib/elasticsearch/model/indexing.rb +6 -4
  16. data/lib/elasticsearch/model/naming.rb +9 -2
  17. data/lib/elasticsearch/model/response/aggregations.rb +1 -1
  18. data/lib/elasticsearch/model/response/base.rb +3 -2
  19. data/lib/elasticsearch/model/response/pagination/kaminari.rb +109 -0
  20. data/lib/elasticsearch/model/response/pagination/will_paginate.rb +95 -0
  21. data/lib/elasticsearch/model/response/pagination.rb +2 -192
  22. data/lib/elasticsearch/model/response/result.rb +1 -1
  23. data/lib/elasticsearch/model/response/suggestions.rb +1 -1
  24. data/lib/elasticsearch/model/response.rb +11 -10
  25. data/lib/elasticsearch/model/version.rb +1 -1
  26. data/lib/elasticsearch/model.rb +15 -8
  27. data/spec/elasticsearch/model/adapter_spec.rb +119 -0
  28. data/spec/elasticsearch/model/adapters/active_record/associations_spec.rb +334 -0
  29. data/spec/elasticsearch/model/adapters/active_record/basic_spec.rb +340 -0
  30. data/spec/elasticsearch/model/adapters/active_record/dynamic_index_name_spec.rb +18 -0
  31. data/spec/elasticsearch/model/adapters/active_record/import_spec.rb +187 -0
  32. data/spec/elasticsearch/model/adapters/active_record/multi_model_spec.rb +110 -0
  33. data/spec/elasticsearch/model/adapters/active_record/namespaced_model_spec.rb +38 -0
  34. data/spec/elasticsearch/model/adapters/active_record/pagination_spec.rb +315 -0
  35. data/spec/elasticsearch/model/adapters/active_record/parent_child_spec.rb +75 -0
  36. data/spec/elasticsearch/model/adapters/active_record/serialization_spec.rb +61 -0
  37. data/spec/elasticsearch/model/adapters/active_record_spec.rb +207 -0
  38. data/spec/elasticsearch/model/adapters/default_spec.rb +41 -0
  39. data/spec/elasticsearch/model/adapters/mongoid/basic_spec.rb +267 -0
  40. data/spec/elasticsearch/model/adapters/mongoid/multi_model_spec.rb +66 -0
  41. data/spec/elasticsearch/model/adapters/mongoid_spec.rb +235 -0
  42. data/spec/elasticsearch/model/adapters/multiple_spec.rb +125 -0
  43. data/spec/elasticsearch/model/callbacks_spec.rb +33 -0
  44. data/spec/elasticsearch/model/client_spec.rb +66 -0
  45. data/spec/elasticsearch/model/hash_wrapper_spec.rb +12 -0
  46. data/spec/elasticsearch/model/importing_spec.rb +214 -0
  47. data/spec/elasticsearch/model/indexing_spec.rb +918 -0
  48. data/spec/elasticsearch/model/module_spec.rb +101 -0
  49. data/spec/elasticsearch/model/multimodel_spec.rb +55 -0
  50. data/spec/elasticsearch/model/naming_inheritance_spec.rb +184 -0
  51. data/spec/elasticsearch/model/naming_spec.rb +186 -0
  52. data/spec/elasticsearch/model/proxy_spec.rb +107 -0
  53. data/spec/elasticsearch/model/response/aggregations_spec.rb +66 -0
  54. data/spec/elasticsearch/model/response/base_spec.rb +90 -0
  55. data/spec/elasticsearch/model/response/pagination/kaminari_spec.rb +410 -0
  56. data/spec/elasticsearch/model/response/pagination/will_paginate_spec.rb +262 -0
  57. data/spec/elasticsearch/model/response/records_spec.rb +118 -0
  58. data/spec/elasticsearch/model/response/response_spec.rb +131 -0
  59. data/spec/elasticsearch/model/response/result_spec.rb +122 -0
  60. data/spec/elasticsearch/model/response/results_spec.rb +56 -0
  61. data/spec/elasticsearch/model/searching_search_request_spec.rb +112 -0
  62. data/spec/elasticsearch/model/searching_spec.rb +49 -0
  63. data/spec/elasticsearch/model/serializing_spec.rb +22 -0
  64. data/spec/spec_helper.rb +161 -0
  65. data/spec/support/app/answer.rb +33 -0
  66. data/spec/support/app/article.rb +22 -0
  67. data/spec/support/app/article_for_pagination.rb +12 -0
  68. data/spec/support/app/article_with_custom_serialization.rb +13 -0
  69. data/spec/support/app/article_with_dynamic_index_name.rb +15 -0
  70. data/spec/support/app/author.rb +9 -0
  71. data/spec/support/app/authorship.rb +4 -0
  72. data/spec/support/app/category.rb +3 -0
  73. data/spec/support/app/comment.rb +3 -0
  74. data/spec/support/app/episode.rb +11 -0
  75. data/spec/support/app/image.rb +19 -0
  76. data/spec/support/app/import_article.rb +12 -0
  77. data/spec/support/app/mongoid_article.rb +21 -0
  78. data/spec/support/app/namespaced_book.rb +10 -0
  79. data/spec/support/app/parent_and_child_searchable.rb +24 -0
  80. data/spec/support/app/post.rb +14 -0
  81. data/spec/support/app/question.rb +27 -0
  82. data/spec/support/app/searchable.rb +48 -0
  83. data/spec/support/app/series.rb +11 -0
  84. data/spec/support/app.rb +21 -0
  85. data/spec/support/model.json +1 -0
  86. metadata +134 -90
  87. data/test/integration/active_record_associations_parent_child_test.rb +0 -147
  88. data/test/integration/active_record_associations_test.rb +0 -339
  89. data/test/integration/active_record_basic_test.rb +0 -251
  90. data/test/integration/active_record_custom_serialization_test.rb +0 -67
  91. data/test/integration/active_record_import_test.rb +0 -115
  92. data/test/integration/active_record_namespaced_model_test.rb +0 -54
  93. data/test/integration/active_record_pagination_test.rb +0 -149
  94. data/test/integration/dynamic_index_name_test.rb +0 -52
  95. data/test/integration/mongoid_basic_test.rb +0 -176
  96. data/test/integration/multiple_models_test.rb +0 -176
  97. data/test/support/model.json +0 -1
  98. data/test/test_helper.rb +0 -92
  99. data/test/unit/adapter_active_record_test.rb +0 -157
  100. data/test/unit/adapter_default_test.rb +0 -41
  101. data/test/unit/adapter_mongoid_test.rb +0 -104
  102. data/test/unit/adapter_multiple_test.rb +0 -106
  103. data/test/unit/adapter_test.rb +0 -69
  104. data/test/unit/callbacks_test.rb +0 -31
  105. data/test/unit/client_test.rb +0 -27
  106. data/test/unit/hash_wrapper_test.rb +0 -13
  107. data/test/unit/importing_test.rb +0 -203
  108. data/test/unit/indexing_test.rb +0 -687
  109. data/test/unit/module_test.rb +0 -68
  110. data/test/unit/multimodel_test.rb +0 -38
  111. data/test/unit/naming_inheritance_test.rb +0 -94
  112. data/test/unit/naming_test.rb +0 -103
  113. data/test/unit/proxy_test.rb +0 -98
  114. data/test/unit/response_aggregations_test.rb +0 -46
  115. data/test/unit/response_base_test.rb +0 -40
  116. data/test/unit/response_pagination_kaminari_test.rb +0 -433
  117. data/test/unit/response_pagination_will_paginate_test.rb +0 -398
  118. data/test/unit/response_records_test.rb +0 -91
  119. data/test/unit/response_result_test.rb +0 -90
  120. data/test/unit/response_results_test.rb +0 -31
  121. data/test/unit/response_test.rb +0 -104
  122. data/test/unit/searching_search_request_test.rb +0 -78
  123. data/test/unit/searching_test.rb +0 -41
  124. data/test/unit/serializing_test.rb +0 -17
  125. /data/{test → spec}/support/model.yml +0 -0
@@ -0,0 +1,187 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord Importing' do
4
+
5
+ before(:all) do
6
+ ActiveRecord::Schema.define(:version => 1) do
7
+ create_table :import_articles do |t|
8
+ t.string :title
9
+ t.integer :views
10
+ t.string :numeric # For the sake of invalid data sent to Elasticsearch
11
+ t.datetime :created_at, :default => 'NOW()'
12
+ end
13
+ end
14
+
15
+ ImportArticle.delete_all
16
+ ImportArticle.__elasticsearch__.client.cluster.health(wait_for_status: 'yellow')
17
+ end
18
+
19
+ before do
20
+ ImportArticle.__elasticsearch__.create_index!
21
+ end
22
+
23
+ after do
24
+ clear_indices(ImportArticle)
25
+ clear_tables(ImportArticle)
26
+ end
27
+
28
+ describe '#import' do
29
+
30
+ context 'when no search criteria is specified' do
31
+
32
+ before do
33
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
34
+ ImportArticle.import
35
+ ImportArticle.__elasticsearch__.refresh_index!
36
+ end
37
+
38
+ it 'imports all documents' do
39
+ expect(ImportArticle.search('*').results.total).to eq(10)
40
+ end
41
+ end
42
+
43
+ context 'when batch size is specified' do
44
+
45
+ before do
46
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
47
+ end
48
+
49
+ let!(:batch_count) do
50
+ batches = 0
51
+ errors = ImportArticle.import(batch_size: 5) do |response|
52
+ batches += 1
53
+ end
54
+ ImportArticle.__elasticsearch__.refresh_index!
55
+ batches
56
+ end
57
+
58
+ it 'imports using the batch size' do
59
+ expect(batch_count).to eq(2)
60
+ end
61
+
62
+ it 'imports all the documents' do
63
+ expect(ImportArticle.search('*').results.total).to eq(10)
64
+ end
65
+ end
66
+
67
+ context 'when a scope is specified' do
68
+
69
+ before do
70
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
71
+ ImportArticle.import(scope: 'popular', force: true)
72
+ ImportArticle.__elasticsearch__.refresh_index!
73
+ end
74
+
75
+ it 'applies the scope' do
76
+ expect(ImportArticle.search('*').results.total).to eq(5)
77
+ end
78
+ end
79
+
80
+ context 'when a query is specified' do
81
+
82
+ before do
83
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
84
+ ImportArticle.import(query: -> { where('views >= 3') })
85
+ ImportArticle.__elasticsearch__.refresh_index!
86
+ end
87
+
88
+ it 'applies the query' do
89
+ expect(ImportArticle.search('*').results.total).to eq(7)
90
+ end
91
+ end
92
+
93
+ context 'when there are invalid documents' do
94
+
95
+ let!(:result) do
96
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
97
+ new_article
98
+ batches = 0
99
+ errors = ImportArticle.__elasticsearch__.import(batch_size: 5) do |response|
100
+ batches += 1
101
+ end
102
+ ImportArticle.__elasticsearch__.refresh_index!
103
+ { batch_size: batches, errors: errors}
104
+ end
105
+
106
+ let(:new_article) do
107
+ ImportArticle.create!(title: "Test INVALID", numeric: "INVALID")
108
+ end
109
+
110
+ it 'does not import them' do
111
+ expect(ImportArticle.search('*').results.total).to eq(10)
112
+ expect(result[:batch_size]).to eq(3)
113
+ expect(result[:errors]).to eq(1)
114
+ end
115
+ end
116
+
117
+ context 'when a transform proc is specified' do
118
+
119
+ before do
120
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
121
+ ImportArticle.import( transform: ->(a) {{ index: { data: { name: a.title, foo: 'BAR' } }}} )
122
+ ImportArticle.__elasticsearch__.refresh_index!
123
+ end
124
+
125
+ it 'transforms the documents' do
126
+ expect(ImportArticle.search('*').results.first._source.keys).to include('name')
127
+ expect(ImportArticle.search('*').results.first._source.keys).to include('foo')
128
+ end
129
+
130
+ it 'imports all documents' do
131
+ expect(ImportArticle.search('test').results.total).to eq(10)
132
+ expect(ImportArticle.search('bar').results.total).to eq(10)
133
+ end
134
+ end
135
+
136
+ context 'when the model has a default scope' do
137
+
138
+ around(:all) do |example|
139
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
140
+ ImportArticle.instance_eval { default_scope { where('views > 3') } }
141
+ example.run
142
+ ImportArticle.default_scopes.pop
143
+ end
144
+
145
+ before do
146
+ ImportArticle.__elasticsearch__.import
147
+ ImportArticle.__elasticsearch__.refresh_index!
148
+ end
149
+
150
+ it 'uses the default scope' do
151
+ expect(ImportArticle.search('*').results.total).to eq(6)
152
+ end
153
+ end
154
+
155
+ context 'when there is a default scope and a query specified' do
156
+
157
+ around(:all) do |example|
158
+ 10.times { |i| ImportArticle.create! title: 'Test', views: "#{i}" }
159
+ ImportArticle.instance_eval { default_scope { where('views > 3') } }
160
+ example.run
161
+ ImportArticle.default_scopes.pop
162
+ end
163
+
164
+ before do
165
+ ImportArticle.import(query: -> { where('views <= 4') })
166
+ ImportArticle.__elasticsearch__.refresh_index!
167
+ end
168
+
169
+ it 'combines the query and the default scope' do
170
+ expect(ImportArticle.search('*').results.total).to eq(1)
171
+ end
172
+ end
173
+
174
+ context 'when the batch is empty' do
175
+
176
+ before do
177
+ ImportArticle.delete_all
178
+ ImportArticle.import
179
+ ImportArticle.__elasticsearch__.refresh_index!
180
+ end
181
+
182
+ it 'does not make any requests to create documents' do
183
+ expect(ImportArticle.search('*').results.total).to eq(0)
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord MultiModel' do
4
+
5
+ before(:all) do
6
+ ActiveRecord::Schema.define do
7
+ create_table Episode.table_name do |t|
8
+ t.string :name
9
+ t.datetime :created_at, :default => 'NOW()'
10
+ end
11
+
12
+ create_table Series.table_name do |t|
13
+ t.string :name
14
+ t.datetime :created_at, :default => 'NOW()'
15
+ end
16
+ end
17
+ end
18
+
19
+ before do
20
+ models = [ Episode, Series ]
21
+ clear_tables(models)
22
+ models.each do |model|
23
+ model.__elasticsearch__.create_index! force: true
24
+ model.create name: "The #{model.name}"
25
+ model.create name: "A great #{model.name}"
26
+ model.create name: "The greatest #{model.name}"
27
+ model.__elasticsearch__.refresh_index!
28
+ end
29
+ end
30
+
31
+ after do
32
+ clear_indices(Episode, Series)
33
+ clear_tables(Episode, Series)
34
+ end
35
+
36
+ context 'when the search is across multimodels' do
37
+
38
+ let(:search_result) do
39
+ Elasticsearch::Model.search(%q<"The greatest Episode"^2 OR "The greatest Series">, [Series, Episode])
40
+ end
41
+
42
+ it 'executes the search across models' do
43
+ expect(search_result.results.size).to eq(2)
44
+ expect(search_result.records.size).to eq(2)
45
+ end
46
+
47
+ describe '#results' do
48
+
49
+ it 'returns an instance of Elasticsearch::Model::Response::Result' do
50
+ expect(search_result.results[0]).to be_a(Elasticsearch::Model::Response::Result)
51
+ expect(search_result.results[1]).to be_a(Elasticsearch::Model::Response::Result)
52
+ end
53
+
54
+ it 'returns the correct model instance' do
55
+ expect(search_result.results[0].name).to eq('The greatest Episode')
56
+ expect(search_result.results[1].name).to eq('The greatest Series')
57
+ end
58
+
59
+ it 'provides access to the results' do
60
+ expect(search_result.results[0].name).to eq('The greatest Episode')
61
+ expect(search_result.results[0].name?).to be(true)
62
+ expect(search_result.results[0].boo?).to be(false)
63
+
64
+ expect(search_result.results[1].name).to eq('The greatest Series')
65
+ expect(search_result.results[1].name?).to be(true)
66
+ expect(search_result.results[1].boo?).to be(false)
67
+ end
68
+ end
69
+
70
+ describe '#records' do
71
+
72
+ it 'returns an instance of Elasticsearch::Model::Response::Result' do
73
+ expect(search_result.records[0]).to be_a(Episode)
74
+ expect(search_result.records[1]).to be_a(Series)
75
+ end
76
+
77
+ it 'returns the correct model instance' do
78
+ expect(search_result.records[0].name).to eq('The greatest Episode')
79
+ expect(search_result.records[1].name).to eq('The greatest Series')
80
+ end
81
+
82
+ context 'when the data store is changed' do
83
+
84
+ before do
85
+ Series.find_by_name("The greatest Series").delete
86
+ Series.__elasticsearch__.refresh_index!
87
+ end
88
+
89
+ it 'only returns matching records' do
90
+ expect(search_result.results.size).to eq(2)
91
+ expect(search_result.records.size).to eq(1 )
92
+ expect(search_result.records[0].name).to eq('The greatest Episode')
93
+ end
94
+ end
95
+ end
96
+
97
+ describe 'pagination' do
98
+
99
+ let(:search_result) do
100
+ Elasticsearch::Model.search('series OR episode', [Series, Episode])
101
+ end
102
+
103
+ it 'properly paginates the results' do
104
+ expect(search_result.page(1).per(3).results.size).to eq(3)
105
+ expect(search_result.page(2).per(3).results.size).to eq(3)
106
+ expect(search_result.page(3).per(3).results.size).to eq(0)
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord Namespaced Model' do
4
+
5
+ before(:all) do
6
+ ActiveRecord::Schema.define(:version => 1) do
7
+ create_table :books do |t|
8
+ t.string :title
9
+ end
10
+ end
11
+
12
+ MyNamespace::Book.delete_all
13
+ MyNamespace::Book.__elasticsearch__.create_index!(force: true)
14
+ MyNamespace::Book.create!(title: 'Test')
15
+ MyNamespace::Book.__elasticsearch__.refresh_index!
16
+ end
17
+
18
+ after do
19
+ clear_indices(MyNamespace::Book)
20
+ clear_tables(MyNamespace::Book)
21
+ end
22
+
23
+ context 'when the model is namespaced' do
24
+
25
+ it 'has the proper index name' do
26
+ expect(MyNamespace::Book.index_name).to eq('my_namespace-books')
27
+ end
28
+
29
+ it 'has the proper document type' do
30
+ expect(MyNamespace::Book.document_type).to eq('book')
31
+ end
32
+
33
+ it 'saves the document into the index' do
34
+ expect(MyNamespace::Book.search('title:test').results.size).to eq(1)
35
+ expect(MyNamespace::Book.search('title:test').results.first.title).to eq('Test')
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,315 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Elasticsearch::Model::Adapter::ActiveRecord Pagination' do
4
+
5
+ before(:all) do
6
+ ActiveRecord::Schema.define(:version => 1) do
7
+ create_table ArticleForPagination.table_name do |t|
8
+ t.string :title
9
+ t.datetime :created_at, :default => 'NOW()'
10
+ t.boolean :published
11
+ end
12
+ end
13
+
14
+ Kaminari::Hooks.init if defined?(Kaminari::Hooks)
15
+
16
+ ArticleForPagination.__elasticsearch__.create_index! force: true
17
+
18
+ 68.times do |i|
19
+ ArticleForPagination.create! title: "Test #{i}", published: (i % 2 == 0)
20
+ end
21
+
22
+ ArticleForPagination.import
23
+ ArticleForPagination.__elasticsearch__.refresh_index!
24
+ end
25
+
26
+ context 'when no other page is specified' do
27
+
28
+ let(:records) do
29
+ ArticleForPagination.search('title:test').page(1).records
30
+ end
31
+
32
+ describe '#size' do
33
+
34
+ it 'returns the correct size' do
35
+ expect(records.size).to eq(25)
36
+ end
37
+ end
38
+
39
+ describe '#current_page' do
40
+
41
+ it 'returns the correct current page' do
42
+ expect(records.current_page).to eq(1)
43
+ end
44
+ end
45
+
46
+ describe '#prev_page' do
47
+
48
+ it 'returns the correct previous page' do
49
+ expect(records.prev_page).to be_nil
50
+ end
51
+ end
52
+
53
+ describe '#next_page' do
54
+
55
+ it 'returns the correct next page' do
56
+ expect(records.next_page).to eq(2)
57
+ end
58
+ end
59
+
60
+ describe '#total_pages' do
61
+
62
+ it 'returns the correct total pages' do
63
+ expect(records.total_pages).to eq(3)
64
+ end
65
+ end
66
+
67
+ describe '#first_page?' do
68
+
69
+ it 'returns the correct first page' do
70
+ expect(records.first_page?).to be(true)
71
+ end
72
+ end
73
+
74
+ describe '#last_page?' do
75
+
76
+ it 'returns the correct last page' do
77
+ expect(records.last_page?).to be(false)
78
+ end
79
+ end
80
+
81
+ describe '#out_of_range?' do
82
+
83
+ it 'returns whether the pagination is out of range' do
84
+ expect(records.out_of_range?).to be(false)
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'when a specific page is specified' do
90
+
91
+ let(:records) do
92
+ ArticleForPagination.search('title:test').page(2).records
93
+ end
94
+
95
+ describe '#size' do
96
+
97
+ it 'returns the correct size' do
98
+ expect(records.size).to eq(25)
99
+ end
100
+ end
101
+
102
+ describe '#current_page' do
103
+
104
+ it 'returns the correct current page' do
105
+ expect(records.current_page).to eq(2)
106
+ end
107
+ end
108
+
109
+ describe '#prev_page' do
110
+
111
+ it 'returns the correct previous page' do
112
+ expect(records.prev_page).to eq(1)
113
+ end
114
+ end
115
+
116
+ describe '#next_page' do
117
+
118
+ it 'returns the correct next page' do
119
+ expect(records.next_page).to eq(3)
120
+ end
121
+ end
122
+
123
+ describe '#total_pages' do
124
+
125
+ it 'returns the correct total pages' do
126
+ expect(records.total_pages).to eq(3)
127
+ end
128
+ end
129
+
130
+ describe '#first_page?' do
131
+
132
+ it 'returns the correct first page' do
133
+ expect(records.first_page?).to be(false)
134
+ end
135
+ end
136
+
137
+ describe '#last_page?' do
138
+
139
+ it 'returns the correct last page' do
140
+ expect(records.last_page?).to be(false)
141
+ end
142
+ end
143
+
144
+ describe '#out_of_range?' do
145
+
146
+ it 'returns whether the pagination is out of range' do
147
+ expect(records.out_of_range?).to be(false)
148
+ end
149
+ end
150
+ end
151
+
152
+ context 'when a the last page is specified' do
153
+
154
+ let(:records) do
155
+ ArticleForPagination.search('title:test').page(3).records
156
+ end
157
+
158
+ describe '#size' do
159
+
160
+ it 'returns the correct size' do
161
+ expect(records.size).to eq(18)
162
+ end
163
+ end
164
+
165
+ describe '#current_page' do
166
+
167
+ it 'returns the correct current page' do
168
+ expect(records.current_page).to eq(3)
169
+ end
170
+ end
171
+
172
+ describe '#prev_page' do
173
+
174
+ it 'returns the correct previous page' do
175
+ expect(records.prev_page).to eq(2)
176
+ end
177
+ end
178
+
179
+ describe '#next_page' do
180
+
181
+ it 'returns the correct next page' do
182
+ expect(records.next_page).to be_nil
183
+ end
184
+ end
185
+
186
+ describe '#total_pages' do
187
+
188
+ it 'returns the correct total pages' do
189
+ expect(records.total_pages).to eq(3)
190
+ end
191
+ end
192
+
193
+ describe '#first_page?' do
194
+
195
+ it 'returns the correct first page' do
196
+ expect(records.first_page?).to be(false)
197
+ end
198
+ end
199
+
200
+ describe '#last_page?' do
201
+
202
+ it 'returns the correct last page' do
203
+ expect(records.last_page?).to be(true)
204
+ end
205
+ end
206
+
207
+ describe '#out_of_range?' do
208
+
209
+ it 'returns whether the pagination is out of range' do
210
+ expect(records.out_of_range?).to be(false)
211
+ end
212
+ end
213
+ end
214
+
215
+ context 'when an invalid page is specified' do
216
+
217
+ let(:records) do
218
+ ArticleForPagination.search('title:test').page(6).records
219
+ end
220
+
221
+ describe '#size' do
222
+
223
+ it 'returns the correct size' do
224
+ expect(records.size).to eq(0)
225
+ end
226
+ end
227
+
228
+ describe '#current_page' do
229
+
230
+ it 'returns the correct current page' do
231
+ expect(records.current_page).to eq(6)
232
+ end
233
+ end
234
+
235
+ describe '#next_page' do
236
+
237
+ it 'returns the correct next page' do
238
+ expect(records.next_page).to be_nil
239
+ end
240
+ end
241
+
242
+ describe '#total_pages' do
243
+
244
+ it 'returns the correct total pages' do
245
+ expect(records.total_pages).to eq(3)
246
+ end
247
+ end
248
+
249
+ describe '#first_page?' do
250
+
251
+ it 'returns the correct first page' do
252
+ expect(records.first_page?).to be(false)
253
+ end
254
+ end
255
+
256
+ describe '#last_page?' do
257
+
258
+ it 'returns whether it is the last page', if: !(Kaminari::VERSION < '1') do
259
+ expect(records.last_page?).to be(false)
260
+ end
261
+
262
+ it 'returns whether it is the last page', if: Kaminari::VERSION < '1' do
263
+ expect(records.last_page?).to be(true) # Kaminari returns current_page >= total_pages in version < 1.0
264
+ end
265
+ end
266
+
267
+ describe '#out_of_range?' do
268
+
269
+ it 'returns whether the pagination is out of range' do
270
+ expect(records.out_of_range?).to be(true)
271
+ end
272
+ end
273
+ end
274
+
275
+ context 'when a scope is also specified' do
276
+
277
+ let(:records) do
278
+ ArticleForPagination.search('title:test').page(2).records.published
279
+ end
280
+
281
+ describe '#size' do
282
+
283
+ it 'returns the correct size' do
284
+ expect(records.size).to eq(12)
285
+ end
286
+ end
287
+ end
288
+
289
+ context 'when a sorting is specified' do
290
+
291
+ let(:search) do
292
+ ArticleForPagination.search({ query: { match: { title: 'test' } }, sort: [ { id: 'desc' } ] })
293
+ end
294
+
295
+ it 'applies the sort' do
296
+ expect(search.page(2).records.first.id).to eq(43)
297
+ expect(search.page(3).records.first.id).to eq(18)
298
+ expect(search.page(2).per(5).records.first.id).to eq(63)
299
+ end
300
+ end
301
+
302
+ context 'when the model has a specific default per page set' do
303
+
304
+ around do |example|
305
+ original_default = ArticleForPagination.instance_variable_get(:@_default_per_page)
306
+ ArticleForPagination.paginates_per 50
307
+ example.run
308
+ ArticleForPagination.paginates_per original_default
309
+ end
310
+
311
+ it 'uses the default per page setting' do
312
+ expect(ArticleForPagination.search('*').page(1).records.size).to eq(50)
313
+ end
314
+ end
315
+ end