tire 0.5.8 → 0.6.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.
@@ -67,6 +67,23 @@ module Tire
67
67
  ImportModel.import :index => 'new_index'
68
68
  end
69
69
 
70
+ context 'Strategy' do
71
+ class ::CustomImportStrategy
72
+ include Tire::Model::Import::Strategy::Base
73
+ end
74
+
75
+ should 'return explicitly specified strategy from predefined strategies' do
76
+ strategy = Tire::Model::Import::Strategy.from_class(ImportModel, :strategy => 'WillPaginate')
77
+ assert_equal strategy.class.name, 'Tire::Model::Import::Strategy::WillPaginate'
78
+ end
79
+
80
+ should 'return custom strategy class' do
81
+ strategy = Tire::Model::Import::Strategy.from_class(ImportModel, :strategy => 'CustomImportStrategy')
82
+ assert_equal strategy.class.name, 'CustomImportStrategy'
83
+ end
84
+
85
+ end
86
+
70
87
  end
71
88
 
72
89
  end
@@ -12,6 +12,11 @@ class ModelWithIncorrectMapping
12
12
  end
13
13
  end
14
14
 
15
+ class MyModelForIndexCreate
16
+ extend ActiveModel::Naming
17
+ include Tire::Model::Search
18
+ end
19
+
15
20
  module Tire
16
21
  module Model
17
22
 
@@ -19,10 +24,44 @@ module Tire
19
24
 
20
25
  context "Model initialization" do
21
26
 
22
- should "display a warning when creating the index fails" do
23
- STDERR.expects(:puts)
24
- result = ModelWithIncorrectMapping.create_elasticsearch_index
25
- assert ! result, result.inspect
27
+ should "display a warning and not raise exception when creating the index fails" do
28
+ assert_nothing_raised do
29
+ STDERR.expects(:puts)
30
+ result = ModelWithIncorrectMapping.create_elasticsearch_index
31
+ assert ! result, result.inspect
32
+ end
33
+ end
34
+
35
+ should "re-raise non-connection related exceptions" do
36
+ Tire::Index.any_instance.expects(:exists?).raises(ZeroDivisionError)
37
+
38
+ assert_raise(ZeroDivisionError) do
39
+ result = MyModelForIndexCreate.create_elasticsearch_index
40
+ assert ! result, result.inspect
41
+ end
42
+ end
43
+
44
+ unless defined?(Curl)
45
+
46
+ should "display a warning and not raise exception when cannot connect to Elasticsearch (default client)" do
47
+ Tire::Index.any_instance.expects(:exists?).raises(Errno::ECONNREFUSED)
48
+ assert_nothing_raised do
49
+ STDERR.expects(:puts)
50
+ result = MyModelForIndexCreate.create_elasticsearch_index
51
+ assert ! result, result.inspect
52
+ end
53
+ end
54
+
55
+ else
56
+ should "display a warning and not raise exception when cannot connect to Elasticsearch (Curb client)" do
57
+ Tire::Index.any_instance.expects(:exists?).raises(::Curl::Err::HostResolutionError)
58
+ assert_nothing_raised do
59
+ STDERR.expects(:puts)
60
+ result = MyModelForIndexCreate.create_elasticsearch_index
61
+ assert ! result, result.inspect
62
+ end
63
+ end
64
+
26
65
  end
27
66
 
28
67
  end
@@ -79,6 +79,11 @@ module Tire
79
79
  assert_equal 1.0, collection.max_score
80
80
  end
81
81
 
82
+ should "return an array" do
83
+ collection = Results::Collection.new(@default_response)
84
+ assert_instance_of Array, collection.to_ary
85
+ end
86
+
82
87
  context "serialization" do
83
88
 
84
89
  should "be serialized to JSON" do
@@ -215,6 +220,32 @@ module Tire
215
220
 
216
221
  end
217
222
 
223
+ context "using fields when also returning the _source" do
224
+ setup do
225
+ Configuration.reset
226
+ @default_response = { 'hits' => { 'hits' =>
227
+ [ { '_id' => 1, '_score' => 0.5, '_index' => 'testing', '_type' => 'article',
228
+ '_source' => {
229
+ 'title' => 'Knee Deep in JSON'
230
+ },
231
+ 'fields' => {
232
+ '_parent' => '4f99f98ea2b279ec3d002522'
233
+ }
234
+ }
235
+ ] } }
236
+ collection = Results::Collection.new(@default_response)
237
+ @item = collection.first
238
+ end
239
+
240
+ should "return an individual field" do
241
+ assert_equal '4f99f98ea2b279ec3d002522', @item._parent
242
+ end
243
+
244
+ should "return fields from the _source as well" do
245
+ assert_equal 'Knee Deep in JSON', @item.title
246
+ end
247
+ end
248
+
218
249
  context "returning results with hits" do
219
250
  should "yield the Item result and the raw hit" do
220
251
  response = { 'hits' => { 'hits' => [ { '_id' => 1, '_score' => 0.5, '_index' => 'testing', '_type' => 'article', '_source' => { :title => 'Test', :body => 'Lorem' } } ] } }
@@ -362,7 +393,38 @@ module Tire
362
393
  assert @collection.results.empty?, 'Collection results should be empty'
363
394
  assert_equal 0, @collection.size
364
395
  end
396
+ end
397
+
398
+ context "with ActiveModel::Serializers" do
399
+ setup do
400
+ require 'active_model_serializers'
401
+
402
+ Tire::Results::Collection.send :include, ActiveModel::ArraySerializerSupport
365
403
 
404
+ class ::MyItemWithSerializer < Tire::Results::Item
405
+ include ActiveModel::SerializerSupport
406
+
407
+ def active_model_serializer
408
+ ::MyItemSerializer
409
+ end
410
+ end
411
+
412
+ class ::MyItemSerializer < ActiveModel::Serializer
413
+ attribute :title, :key => :name
414
+ attribute :author, :key => :owner
415
+ end
416
+ end
417
+
418
+ should "be serializable" do
419
+ assert_nothing_raised do
420
+ collection = Results::Collection.new(@default_response, :wrapper => ::MyItemWithSerializer)
421
+ serializer = collection.active_model_serializer.new(collection)
422
+
423
+ hash = serializer.as_json.first
424
+ assert_equal 'Test', hash[:name]
425
+ assert_equal 'John', hash[:owner]
426
+ end
427
+ end
366
428
  end
367
429
 
368
430
  end
@@ -20,7 +20,7 @@ module Tire
20
20
  :awards => { :best_fiction => { :year => '1925' } },
21
21
  :reviews => [ { :stars => 5, :comment => 'great' },
22
22
  { :stars => 3, :comment => 'decent' } ]
23
-
23
+
24
24
  end
25
25
 
26
26
  should "be initialized with a Hash or Hash like object" do
@@ -63,6 +63,15 @@ module Tire
63
63
  assert_equal 'Kafka', @document[:author][:name]
64
64
  end
65
65
 
66
+ should "retrieve simple values from read_attribute_for_serialization" do
67
+ assert_equal 'Test', @document.read_attribute_for_serialization(:title)
68
+ end
69
+
70
+ should "retrieve hash values from read_attribute_for_serialization" do
71
+ assert_equal 'Kafka', @document.read_attribute_for_serialization(:author)[:name]
72
+ end
73
+
74
+
66
75
  should "allow to retrieve value by methods" do
67
76
  assert_not_nil @document.title
68
77
  assert_equal 'Test', @document.title
@@ -171,6 +180,35 @@ module Tire
171
180
 
172
181
  end
173
182
 
183
+ context "with ActiveModel::Serializers" do
184
+ setup do
185
+ require 'active_model_serializers'
186
+
187
+ class ::MyItemWithSerializer < Tire::Results::Item
188
+ include ActiveModel::SerializerSupport
189
+ end
190
+ class ::MyItemSerializer < ActiveModel::Serializer
191
+ attribute :tags
192
+ attribute :title, :key => :name
193
+
194
+ def tags
195
+ object.tags.join('-')
196
+ end
197
+ end
198
+ end
199
+
200
+ should "be serializable" do
201
+ assert_nothing_raised do
202
+ doc = ::MyItemWithSerializer.new :title => 'Test', :tags => ['foo', 'bar']
203
+ doc_serializer = ::MyItemSerializer.new(doc)
204
+
205
+ hash = doc_serializer.as_json
206
+ assert_equal 'Test', hash[:my_item][:name]
207
+ assert_equal 'foo-bar', hash[:my_item][:tags]
208
+ end
209
+ end
210
+ end
211
+
174
212
  end
175
213
 
176
214
  end
@@ -168,6 +168,21 @@ module Tire::Search
168
168
  end
169
169
  end
170
170
 
171
+ context "geo_distance facet" do
172
+ should "encode facet options" do
173
+ f = Facet.new('geo_distance') { geo_distance :location, {:lat => 50, :lon => 9}, [{:to => 1}] }
174
+ assert_equal({:geo_distance => {:geo_distance => {:location => {:lat => 50, :lon => 9}, :ranges => [{:to => 1}]}}}.to_json,
175
+ f.to_json)
176
+ end
177
+
178
+ should "encode custom options" do
179
+ f = Facet.new('geo_distance') { geo_distance :location, {:lat => 50, :lon => 9}, [{:to => 1}],
180
+ :unit => 'km', :value_script => 'doc["field"].value'}
181
+ assert_equal({:geo_distance => {:geo_distance => {:location => {:lat => 50, :lon => 9}, :ranges => [{:to => 1}],
182
+ :unit => "km", :value_script => 'doc["field"].value'}}}.to_json, f.to_json)
183
+ end
184
+ end
185
+
171
186
  context "filter facet" do
172
187
 
173
188
  should "encode facet options" do
@@ -68,17 +68,6 @@ module Tire::Search
68
68
  end
69
69
  end
70
70
 
71
- context "Text query" do
72
- should "allow search with a text search" do
73
- assert_equal( { :text => {'field' => {:query => 'foo'}}}, Query.new.text('field', 'foo'))
74
- end
75
-
76
- should "allow search with a different operator for text search" do
77
- assert_equal( { :text => {'field' => {:query => 'foo', :operator => 'and'}}},
78
- Query.new.text('field', 'foo', :operator => 'and'))
79
- end
80
- end
81
-
82
71
  context "Query String query" do
83
72
  should "allow search with a query string" do
84
73
  assert_equal( { :query_string => { :query => 'title:foo' } },
@@ -121,6 +110,121 @@ module Tire::Search
121
110
  end
122
111
  end
123
112
 
113
+ context 'CustomFiltersScoreQuery' do
114
+ should "not raise an error when no block is given" do
115
+ assert_nothing_raised { Query.new.custom_filters_score }
116
+ end
117
+
118
+ should "provides a default filter if no filter is given" do
119
+ query = Query.new.custom_filters_score do
120
+ query { term :foo, 'bar' }
121
+ end
122
+
123
+ f = query[:custom_filters_score]
124
+
125
+ assert_equal( { :term => { :foo => { :term => 'bar' } } }, f[:query].to_hash )
126
+ assert_equal( { :match_all => {} }, f[:filters].first[:filter])
127
+ assert_equal( 1.0, f[:filters].first[:boost])
128
+ end
129
+
130
+ should "properly encode filter with boost" do
131
+ query = Query.new.custom_filters_score do
132
+ query { term :foo, 'bar' }
133
+ filter do
134
+ filter :terms, :tags => ['ruby']
135
+ boost 2.0
136
+ end
137
+ end
138
+
139
+ f = query[:custom_filters_score]
140
+
141
+ assert_equal( { :term => { :foo => { :term => 'bar' } } }, f[:query].to_hash )
142
+ assert_equal( { :tags => ['ruby'] }, f[:filters].first[:filter][:terms])
143
+ assert_equal( 2.0, f[:filters].first[:boost])
144
+ end
145
+
146
+ should "properly encode filter with script" do
147
+ query = Query.new.custom_filters_score do
148
+ query { term :foo, 'bar' }
149
+ filter do
150
+ filter :terms, :tags => ['ruby']
151
+ script '2.0'
152
+ end
153
+ end
154
+
155
+ f = query[:custom_filters_score]
156
+
157
+ assert_equal( { :term => { :foo => { :term => 'bar' } } }, f[:query].to_hash )
158
+ assert_equal( { :tags => ['ruby'] }, f[:filters].first[:filter][:terms])
159
+ assert_equal( '2.0', f[:filters].first[:script])
160
+ end
161
+
162
+ should "properly encode multiple filters" do
163
+ query = Query.new.custom_filters_score do
164
+ query { term :foo, 'bar' }
165
+ filter do
166
+ filter :terms, :tags => ['ruby']
167
+ boost 2.0
168
+ end
169
+ filter do
170
+ filter :terms, :tags => ['python']
171
+ script '2.0'
172
+ end
173
+ end
174
+
175
+ f = query[:custom_filters_score]
176
+
177
+ assert_equal( { :term => { :foo => { :term => 'bar' } } }, f[:query].to_hash )
178
+ assert_equal( { :tags => ['ruby'] }, f[:filters].first[:filter][:terms])
179
+ assert_equal( 2.0, f[:filters].first[:boost])
180
+ assert_equal( { :tags => ['python'] }, f[:filters].last[:filter][:terms])
181
+ assert_equal( '2.0', f[:filters].last[:script])
182
+ end
183
+
184
+ should "allow setting the score_mode" do
185
+ query = Query.new.custom_filters_score do
186
+ query { term :foo, 'bar' }
187
+ score_mode 'total'
188
+ end
189
+
190
+ f = query[:custom_filters_score]
191
+
192
+ assert_equal( { :term => { :foo => { :term => 'bar' } } }, f[:query].to_hash )
193
+ assert_equal( 'total', f[:score_mode])
194
+ end
195
+
196
+ should "allow setting params" do
197
+ query = Query.new.custom_filters_score do
198
+ query { term :foo, 'bar' }
199
+ params :a => 'b'
200
+ end
201
+
202
+ f = query[:custom_filters_score]
203
+
204
+ assert_equal( { :term => { :foo => { :term => 'bar' } } }, f[:query].to_hash )
205
+ assert_equal( { :a => 'b' }, f[:params] )
206
+ end
207
+
208
+ should "allow using script parameters" do
209
+ score_script = "foo * 2"
210
+
211
+ query = Query.new.custom_filters_score do
212
+ query { string 'foo' }
213
+
214
+ params :foo => 42
215
+
216
+ filter do
217
+ filter :exists, :field => 'date'
218
+ script score_script
219
+ end
220
+ end
221
+
222
+ f = query[:custom_filters_score]
223
+
224
+ assert_equal 42, f[:params][:foo]
225
+ end
226
+ end
227
+
124
228
  context "All query" do
125
229
  should "search for all documents" do
126
230
  assert_equal( { :match_all => { } }, Query.new.all )
@@ -133,9 +237,17 @@ module Tire::Search
133
237
 
134
238
  context "IDs query" do
135
239
  should "search for documents by IDs" do
240
+ assert_equal( { :ids => { :values => [1, 2] } },
241
+ Query.new.ids([1, 2]) )
242
+ end
243
+ should "search for documents by IDs and type" do
136
244
  assert_equal( { :ids => { :values => [1, 2], :type => 'foo' } },
137
245
  Query.new.ids([1, 2], 'foo') )
138
246
  end
247
+ should "convert argument to Array" do
248
+ assert_equal( { :ids => { :values => [1] } },
249
+ Query.new.ids(1) )
250
+ end
139
251
  end
140
252
 
141
253
  context "FuzzyQuery" do
@@ -430,9 +542,12 @@ module Tire::Search
430
542
  Query.new.constant_score { query { term :attr, 'foo' } } )
431
543
  end
432
544
 
433
- should "wrap filter" do
434
- assert_equal( { :constant_score => {:filter => { :term => { :attr => 'foo' } } } },
435
- Query.new.constant_score { filter :term, :attr => 'foo' } )
545
+ should "wrap multiple filters" do
546
+ assert_equal( { :constant_score => {:filter => {:and => [ { :term => { :attr => 'foo' } }, { :term => { :attr => 'bar' } } ] } } },
547
+ Query.new.constant_score do
548
+ filter :term, :attr => 'foo'
549
+ filter :term, :attr => 'bar'
550
+ end )
436
551
  end
437
552
 
438
553
  should "wrap the boost" do
@@ -41,6 +41,19 @@ module Tire
41
41
  end
42
42
  end
43
43
 
44
+ should "convert params objects to hash" do
45
+ class ::MyParamsObject;
46
+ def initialize(hash)
47
+ @hash = hash
48
+ end
49
+ def to_hash
50
+ @hash
51
+ end
52
+ end
53
+
54
+ Tire.search 'dummy', ::MyParamsObject.new(:foo => 'bar')
55
+ end
56
+
44
57
  should "extract URL parameters from options" do
45
58
  payload = { :query => { :match => { :foo => 'bar' } } }
46
59
 
data/tire.gemspec CHANGED
@@ -41,6 +41,7 @@ Gem::Specification.new do |s|
41
41
  s.add_development_dependency "mocha", "~> 0.13"
42
42
  s.add_development_dependency "minitest", "~> 2.12"
43
43
  s.add_development_dependency "activerecord", ">= 3.0"
44
+ s.add_development_dependency "active_model_serializers"
44
45
  s.add_development_dependency "mongoid", "~> 2.2"
45
46
  s.add_development_dependency "redis-persistence"
46
47
  s.add_development_dependency "faraday"