tire 0.3.3 → 0.3.4

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.
@@ -0,0 +1,308 @@
1
+ require 'test_helper'
2
+
3
+ begin
4
+ require "mongo"
5
+ Mongo::Connection.new("localhost", 27017)
6
+
7
+ ENV["MONGODB_IS_AVAILABLE"] = 'true'
8
+ rescue Mongo::ConnectionFailure => e
9
+ ENV["MONGODB_IS_AVAILABLE"] = nil
10
+ end
11
+
12
+ if ENV["MONGODB_IS_AVAILABLE"]
13
+ module Tire
14
+
15
+ class MongoidSearchableIntegrationTest < Test::Unit::TestCase
16
+ include Test::Integration
17
+
18
+ def setup
19
+ super
20
+ Mongoid.configure do |config|
21
+ config.master = Mongo::Connection.new.db("tire_mongoid_integration_test")
22
+ end
23
+ end
24
+
25
+ context "Mongoid integration" do
26
+
27
+ setup do
28
+ MongoidArticle.destroy_all
29
+ Tire.index('mongoid_articles').delete
30
+
31
+ load File.expand_path('../../models/mongoid_models.rb', __FILE__)
32
+ end
33
+ teardown do
34
+ MongoidArticle.destroy_all
35
+ Tire.index('mongoid_articles').delete
36
+ end
37
+
38
+ should "configure mapping" do
39
+ assert_equal 'snowball', MongoidArticle.mapping[:title][:analyzer]
40
+ assert_equal 10, MongoidArticle.mapping[:title][:boost]
41
+
42
+ assert_equal 'snowball', MongoidArticle.tire.index.mapping['mongoid_article']['properties']['title']['analyzer']
43
+ end
44
+
45
+ should "save document into index on save and find it" do
46
+ a = MongoidArticle.new :title => 'Test'
47
+ a.save!
48
+ id = a.id
49
+
50
+ a.index.refresh
51
+
52
+ results = MongoidArticle.tire.search 'test'
53
+
54
+ assert results.any?
55
+ assert_equal 1, results.count
56
+
57
+ assert_instance_of Results::Item, results.first
58
+ assert_not_nil results.first.id
59
+ assert_equal id.to_s, results.first.id.to_s
60
+ assert results.first.persisted?, "Record should be persisted"
61
+ assert_not_nil results.first._score
62
+ assert_equal 'Test', results.first.title
63
+ end
64
+
65
+ context "with eager loading" do
66
+ setup do
67
+ MongoidArticle.destroy_all
68
+
69
+ @first_article = MongoidArticle.create! :title => "Test 1"
70
+ @second_article = MongoidArticle.create! :title => "Test 2"
71
+ @third_article = MongoidArticle.create! :title => "Test 3"
72
+ @fourth_article = MongoidArticle.create! :title => "Test 4"
73
+ @fifth_article = MongoidArticle.create! :title => "Test 5"
74
+
75
+ MongoidArticle.tire.index.refresh
76
+ end
77
+
78
+ should "load records on query search" do
79
+ results = MongoidArticle.tire.search '"Test 1"', :load => true
80
+
81
+ assert results.any?
82
+ assert_equal MongoidArticle.all.first, results.first
83
+ end
84
+
85
+ should "load records on block search" do
86
+ results = MongoidArticle.tire.search :load => true do
87
+ query { string '"Test 1"' }
88
+ end
89
+
90
+ assert_equal MongoidArticle.all.first, results.first
91
+ end
92
+
93
+ should "load records with options on query search" do
94
+ assert_equal MongoidArticle.find([@first_article[:_id]], :include => 'comments').first,
95
+ MongoidArticle.tire.search('"Test 1"',
96
+ :load => { :include => 'comments' }).results.first
97
+ end
98
+
99
+ should "return empty collection for nonmatching query" do
100
+ assert_nothing_raised do
101
+ results = MongoidArticle.tire.search :load => true do
102
+ query { string '"Hic Sunt Leones"' }
103
+ end
104
+ assert_equal 0, results.size
105
+ assert !results.any?
106
+ end
107
+ end
108
+ end
109
+
110
+ should "remove document from index on destroy" do
111
+ a = MongoidArticle.new :title => 'Test remove...'
112
+ a.save!
113
+ assert_equal 1, MongoidArticle.count
114
+
115
+ a.destroy
116
+ assert_equal 0, MongoidArticle.all.size
117
+
118
+ a.index.refresh
119
+ results = MongoidArticle.tire.search 'test'
120
+ assert_equal 0, results.count
121
+ end
122
+
123
+ should "return documents with scores" do
124
+ MongoidArticle.create! :title => 'foo'
125
+ MongoidArticle.create! :title => 'bar'
126
+
127
+ MongoidArticle.tire.index.refresh
128
+ results = MongoidArticle.tire.search 'foo OR bar^100'
129
+ assert_equal 2, results.count
130
+
131
+ assert_equal 'bar', results.first.title
132
+ end
133
+
134
+ context "with pagination" do
135
+ setup do
136
+ 1.upto(9) { |number| MongoidArticle.create :title => "Test#{number}" }
137
+ MongoidArticle.tire.index.refresh
138
+ end
139
+
140
+ context "and parameter searches" do
141
+
142
+ should "find first page with five results" do
143
+ results = MongoidArticle.tire.search 'test*', :sort => 'title', :per_page => 5, :page => 1
144
+ assert_equal 5, results.size
145
+
146
+ assert_equal 2, results.total_pages
147
+ assert_equal 1, results.current_page
148
+ assert_equal nil, results.previous_page
149
+ assert_equal 2, results.next_page
150
+
151
+ assert_equal 'Test1', results.first.title
152
+ end
153
+
154
+ should "find next page with five results" do
155
+ results = MongoidArticle.tire.search 'test*', :sort => 'title', :per_page => 5, :page => 2
156
+ assert_equal 4, results.size
157
+
158
+ assert_equal 2, results.total_pages
159
+ assert_equal 2, results.current_page
160
+ assert_equal 1, results.previous_page
161
+ assert_equal nil, results.next_page
162
+
163
+ assert_equal 'Test6', results.first.title
164
+ end
165
+
166
+ should "find not find missing page" do
167
+ results = MongoidArticle.tire.search 'test*', :sort => 'title', :per_page => 5, :page => 3
168
+ assert_equal 0, results.size
169
+
170
+ assert_equal 2, results.total_pages
171
+ assert_equal 3, results.current_page
172
+ assert_equal 2, results.previous_page
173
+ assert_equal nil, results.next_page
174
+
175
+ assert_nil results.first
176
+ end
177
+
178
+ end
179
+
180
+ context "and block searches" do
181
+ setup { @q = 'test*' }
182
+
183
+ should "find first page with five results" do
184
+ results = MongoidArticle.tire.search do |search|
185
+ search.query { |query| query.string @q }
186
+ search.sort { by :title }
187
+ search.from 0
188
+ search.size 5
189
+ end
190
+ assert_equal 5, results.size
191
+
192
+ assert_equal 2, results.total_pages
193
+ assert_equal 1, results.current_page
194
+ assert_equal nil, results.previous_page
195
+ assert_equal 2, results.next_page
196
+
197
+ assert_equal 'Test1', results.first.title
198
+ end
199
+
200
+ should "find next page with five results" do
201
+ results = MongoidArticle.tire.search do |search|
202
+ search.query { |query| query.string @q }
203
+ search.sort { by :title }
204
+ search.from 5
205
+ search.size 5
206
+ end
207
+ assert_equal 4, results.size
208
+
209
+ assert_equal 2, results.total_pages
210
+ assert_equal 2, results.current_page
211
+ assert_equal 1, results.previous_page
212
+ assert_equal nil, results.next_page
213
+
214
+ assert_equal 'Test6', results.first.title
215
+ end
216
+
217
+ should "not find a missing page" do
218
+ results = MongoidArticle.tire.search do |search|
219
+ search.query { |query| query.string @q }
220
+ search.sort { by :title }
221
+ search.from 10
222
+ search.size 5
223
+ end
224
+ assert_equal 0, results.size
225
+
226
+ assert_equal 2, results.total_pages
227
+ assert_equal 3, results.current_page
228
+ assert_equal 2, results.previous_page
229
+ assert_equal nil, results.next_page
230
+
231
+ assert_nil results.first
232
+ end
233
+
234
+ end
235
+
236
+ end
237
+
238
+ context "with proxy" do
239
+
240
+ should "allow access to Tire instance methods" do
241
+ a = MongoidClassWithTireMethods.create :title => 'One'
242
+ assert_equal "THIS IS MY INDEX!", a.index
243
+ assert_instance_of Tire::Index, a.tire.index
244
+ assert a.tire.index.exists?, "Index should exist"
245
+ end
246
+
247
+ should "allow access to Tire class methods" do
248
+ class ::MongoidClassWithTireMethods
249
+ include Mongoid::Document
250
+ def self.search(*)
251
+ "THIS IS MY SEARCH!"
252
+ end
253
+ end
254
+
255
+ MongoidClassWithTireMethods.create :title => 'One'
256
+ MongoidClassWithTireMethods.tire.index.refresh
257
+
258
+ assert_equal "THIS IS MY SEARCH!", MongoidClassWithTireMethods.search
259
+
260
+ results = MongoidClassWithTireMethods.tire.search 'one'
261
+
262
+ assert_equal 'One', results.first.title
263
+ end
264
+
265
+ end
266
+
267
+ context "within Rails" do
268
+
269
+ setup do
270
+ module ::Rails; end
271
+
272
+ a = MongoidArticle.new :title => 'Test'
273
+ c = a.comments.build :author => 'fool', :body => 'Works!'
274
+ s = a.stats.build :pageviews => 12, :period => '2011-08'
275
+ a.save!
276
+ c.save!
277
+ s.save!
278
+ @id = a.id.to_s
279
+
280
+ a.index.refresh
281
+ @item = MongoidArticle.tire.search('test').first
282
+ end
283
+
284
+ should "have access to indexed properties" do
285
+ assert_equal 'Test', @item.title
286
+ assert_equal 'fool', @item.comments.first.author
287
+ assert_equal 12, @item.stats.first.pageviews
288
+ end
289
+
290
+ should "load the underlying models" do
291
+ assert_instance_of Results::Item, @item
292
+ assert_instance_of MongoidArticle, @item.load
293
+ assert_equal 'Test', @item.load.title
294
+
295
+ assert_instance_of Results::Item, @item.comments.first
296
+ assert_instance_of MongoidComment, @item.comments.first.load
297
+ assert_equal 'fool', @item.comments.first.load.author
298
+ end
299
+
300
+ should "load the underlying model with options" do
301
+ assert_equal MongoidArticle.find(@id), @item.load(:include => 'comments')
302
+ end
303
+
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end
@@ -26,7 +26,7 @@ module Tire
26
26
  results = PersistentArticle.find [1, 2]
27
27
 
28
28
  assert_equal 2, results.size
29
-
29
+
30
30
  end
31
31
 
32
32
  context "with pagination" do
@@ -40,10 +40,19 @@ module Tire
40
40
  results = PersistentArticle.search( :per_page => 5, :page => 1 ) { query { all } }
41
41
  assert_equal 5, results.size
42
42
 
43
+ # WillPaginate
44
+ #
43
45
  assert_equal 2, results.total_pages
44
46
  assert_equal 1, results.current_page
45
47
  assert_equal nil, results.previous_page
46
48
  assert_equal 2, results.next_page
49
+
50
+ # Kaminari
51
+ #
52
+ assert_equal 5, results.limit_value
53
+ assert_equal 9, results.total_count
54
+ assert_equal 2, results.num_pages
55
+ assert_equal 0, results.offset_value
47
56
  end
48
57
  end
49
58
 
@@ -5,14 +5,6 @@ class ActiveRecordArticle < ActiveRecord::Base
5
5
  has_many :comments, :class_name => "ActiveRecordComment", :foreign_key => "article_id"
6
6
  has_many :stats, :class_name => "ActiveRecordStat", :foreign_key => "article_id"
7
7
 
8
- # def index
9
- # "KEEP OFF MY INDEX!!!"
10
- # end
11
- #
12
- # def self.settings
13
- # "KEEP OFF MY SETTINGS!!!"
14
- # end
15
-
16
8
  include Tire::Model::Search
17
9
  include Tire::Model::Callbacks
18
10
 
@@ -28,10 +20,6 @@ class ActiveRecordArticle < ActiveRecord::Base
28
20
  end
29
21
  end
30
22
 
31
- # tire.mapping do
32
- # indexes :title, :type => 'string', :boost => 10, :analyzer => 'snowball'
33
- # end
34
-
35
23
  def to_indexed_json
36
24
  {
37
25
  :title => title,
@@ -81,3 +69,12 @@ class ActiveRecordClassWithTireMethods < ActiveRecord::Base
81
69
  end
82
70
  end
83
71
  end
72
+
73
+ class ActiveRecordClassWithDynamicIndexName < ActiveRecord::Base
74
+ include Tire::Model::Search
75
+ include Tire::Model::Callbacks
76
+
77
+ index_name do
78
+ "dynamic" + '_' + "index"
79
+ end
80
+ end
@@ -0,0 +1,98 @@
1
+ require 'rubygems'
2
+ require 'mongoid'
3
+
4
+ class MongoidArticle
5
+
6
+ include Mongoid::Document
7
+
8
+
9
+ has_many :comments, :class_name => "MongoidComment", :foreign_key => "article_id"
10
+ has_many :stats, :class_name => "MongoidStat", :foreign_key => "article_id"
11
+
12
+ # def index
13
+ # "KEEP OFF MY INDEX!!!"
14
+ # end
15
+ #
16
+ # def self.settings
17
+ # "KEEP OFF MY SETTINGS!!!"
18
+ # end
19
+
20
+ include Tire::Model::Search
21
+ include Tire::Model::Callbacks
22
+
23
+ tire do
24
+ mapping do
25
+ indexes :title, :type => 'string', :boost => 10, :analyzer => 'snowball'
26
+ indexes :created_at, :type => 'date'
27
+
28
+ indexes :comments do
29
+ indexes :author
30
+ indexes :body
31
+ end
32
+ end
33
+ end
34
+
35
+ # tire.mapping do
36
+ # indexes :title, :type => 'string', :boost => 10, :analyzer => 'snowball'
37
+ # end
38
+
39
+ def to_indexed_json
40
+ {
41
+ :title => title,
42
+ :length => length,
43
+
44
+ :comments => comments.map { |c| { :_type => 'mongoid_comment',
45
+ :_id => c.id,
46
+ :author => c.author,
47
+ :body => c.body } },
48
+ :stats => stats.map { |s| { :pageviews => s.pageviews } }
49
+ }.to_json
50
+ end
51
+
52
+ def length
53
+ title.length
54
+ end
55
+
56
+ def comment_authors
57
+ comments.map(&:author).to_sentence
58
+ end
59
+ end
60
+
61
+ class MongoidComment
62
+
63
+ include Mongoid::Document
64
+
65
+
66
+ belongs_to :article, :class_name => "MongoidArticle", :foreign_key => "article_id"
67
+ end
68
+
69
+ class MongoidStat
70
+
71
+ include Mongoid::Document
72
+
73
+
74
+ belongs_to :article, :class_name => "MongoidArticle", :foreign_key => "article_id"
75
+ end
76
+
77
+ class MongoidClassWithTireMethods
78
+
79
+ include Mongoid::Document
80
+
81
+
82
+ def self.mapping
83
+ "THIS IS MY MAPPING!"
84
+ end
85
+
86
+ def index
87
+ "THIS IS MY INDEX!"
88
+ end
89
+
90
+ include Tire::Model::Search
91
+ include Tire::Model::Callbacks
92
+
93
+ tire do
94
+ mapping do
95
+ indexes :title, :type => 'string', :analyzer => 'snowball'
96
+ end
97
+ end
98
+ end
@@ -19,6 +19,13 @@ module Tire
19
19
  assert_respond_to Client::RestClient, :head
20
20
  end
21
21
 
22
+ should "not rescue generic exceptions" do
23
+ Client::RestClient.expects(:get).raises(RuntimeError, "Something bad happened in YOUR code")
24
+ assert_raise(RuntimeError) do
25
+ Client::RestClient.get 'http://example.com'
26
+ end
27
+ end
28
+
22
29
  end
23
30
 
24
31
  end
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class ModelOne
4
- extend ActiveModel::Naming
4
+ extend ActiveModel::Naming
5
5
  include Tire::Model::Search
6
6
  include Tire::Model::Callbacks
7
7
 
@@ -11,38 +11,40 @@ end
11
11
 
12
12
  class ModelTwo
13
13
  extend ActiveModel::Naming
14
- extend ActiveModel::Callbacks
14
+ extend ActiveModel::Callbacks
15
15
  define_model_callbacks :save, :destroy
16
16
 
17
17
  include Tire::Model::Search
18
18
  include Tire::Model::Callbacks
19
19
 
20
- def save
21
- _run_save_callbacks {}
22
- end
23
-
24
- def destroy
25
- _run_destroy_callbacks { @destroyed = true }
26
- end
20
+ def save; _run_save_callbacks {}; end
21
+ def destroy; _run_destroy_callbacks { @destroyed = true }; end
27
22
 
28
23
  def destroyed?; !!@destroyed; end
29
24
  end
30
25
 
31
26
  class ModelThree
32
27
  extend ActiveModel::Naming
33
- extend ActiveModel::Callbacks
28
+ extend ActiveModel::Callbacks
34
29
  define_model_callbacks :save, :destroy
35
30
 
36
31
  include Tire::Model::Search
37
32
  include Tire::Model::Callbacks
38
33
 
39
- def save
40
- _run_save_callbacks {}
41
- end
34
+ def save; _run_save_callbacks {}; end
35
+ def destroy; _run_destroy_callbacks {}; end
36
+ end
42
37
 
43
- def destroy
44
- _run_destroy_callbacks {}
45
- end
38
+ class ModelWithoutTireAutoCallbacks
39
+ extend ActiveModel::Naming
40
+ extend ActiveModel::Callbacks
41
+ define_model_callbacks :save, :destroy
42
+
43
+ include Tire::Model::Search
44
+ # DO NOT include Callbacks
45
+
46
+ def save; _run_save_callbacks {}; end
47
+ def destroy; _run_destroy_callbacks {}; end
46
48
  end
47
49
 
48
50
  module Tire
@@ -90,6 +92,24 @@ module Tire
90
92
 
91
93
  end
92
94
 
95
+ context "Model without Tire::Callbacks included" do
96
+
97
+ should "respond to Tire update_index callbacks" do
98
+ assert_respond_to ModelWithoutTireAutoCallbacks, :after_update_elasticsearch_index
99
+ assert_respond_to ModelWithoutTireAutoCallbacks, :before_update_elasticsearch_index
100
+ end
101
+
102
+ should "not execute the update_index hooks" do
103
+ m = ModelWithoutTireAutoCallbacks.new
104
+ m.tire.expects(:update_index).never
105
+
106
+ m.save
107
+ m.destroy
108
+ end
109
+ end
110
+
111
+ # ---------------------------------------------------------------------------
112
+
93
113
  end
94
114
 
95
115
  end
@@ -287,6 +287,26 @@ module Tire
287
287
  assert_equal 'snowball', ModelWithCustomMapping.mapping[:title][:analyzer]
288
288
  end
289
289
 
290
+ should "not raise an error when defining mapping" do
291
+ Tire::Index.any_instance.unstub(:exists?)
292
+ Configuration.client.expects(:head).raises(Errno::ECONNREFUSED)
293
+
294
+ assert_nothing_raised do
295
+ class ::ModelWithCustomMapping
296
+ extend ActiveModel::Naming
297
+ extend ActiveModel::Callbacks
298
+
299
+ include Tire::Model::Search
300
+ include Tire::Model::Callbacks
301
+
302
+ mapping do
303
+ indexes :title, :type => 'string', :analyzer => 'snowball', :boost => 10
304
+ end
305
+
306
+ end
307
+ end
308
+ end
309
+
290
310
  should "define mapping for nested properties with a block" do
291
311
  expected = {
292
312
  :settings => {},
@@ -695,6 +715,29 @@ module Tire
695
715
 
696
716
  end
697
717
 
718
+ context "with dynamic index name" do
719
+ class ::ModelWithDynamicIndexName
720
+ extend ActiveModel::Naming
721
+ extend ActiveModel::Callbacks
722
+
723
+ include Tire::Model::Search
724
+ include Tire::Model::Callbacks
725
+
726
+ index_name do
727
+ "dynamic" + '_' + "index"
728
+ end
729
+ end
730
+
731
+ should "have index name as a proc" do
732
+ assert_kind_of Proc, ::ModelWithDynamicIndexName.index_name
733
+ end
734
+
735
+ should "evaluate the proc in Model.index" do
736
+ assert_equal 'dynamic_index', ::ModelWithDynamicIndexName.index.name
737
+ end
738
+
739
+ end
740
+
698
741
  end
699
742
 
700
743
  context "Results::Item" do
@@ -57,6 +57,13 @@ module Tire
57
57
  end
58
58
  end
59
59
 
60
+ should "be kaminari compatible" do
61
+ collection = Results::Collection.new(@default_response)
62
+ %w(limit_value total_count num_pages offset_value).each do |method|
63
+ assert_respond_to collection, method
64
+ end
65
+ end
66
+
60
67
  context "wrapping results" do
61
68
 
62
69
  setup do
@@ -117,7 +117,9 @@ module Tire
117
117
  STDERR.expects(:puts)
118
118
 
119
119
  s = Search::Search.new('index')
120
- assert ! s.perform
120
+ assert_raise Search::SearchRequestFailed do
121
+ s.perform
122
+ end
121
123
  end
122
124
 
123
125
  should "log request, but not response, when logger is set" do
data/tire.gemspec CHANGED
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
38
38
  s.add_development_dependency "shoulda"
39
39
  s.add_development_dependency "mocha"
40
40
  s.add_development_dependency "activerecord", "~> 3.0.7"
41
+ s.add_development_dependency "mongoid", "~> 2.2.1"
41
42
  s.add_development_dependency "sqlite3"
42
43
  s.add_development_dependency "supermodel"
43
44