tire 0.1.4 → 0.1.5

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,43 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class BooleanQueriesIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Boolean queries" do
9
+
10
+ should "allow to set multiple queries per condition" do
11
+ s = Tire.search('articles-test') do
12
+ query do
13
+ boolean do
14
+ must { term :tags, 'ruby' }
15
+ must { term :tags, 'python' }
16
+ end
17
+ end
18
+ end
19
+
20
+ assert_equal 1, s.results.size
21
+ assert_equal 'Two', s.results.first.title
22
+ end
23
+
24
+ should "allow to set multiple queries for multiple conditions" do
25
+ s = Tire.search('articles-test') do
26
+ query do
27
+ boolean do
28
+ must { term :tags, 'ruby' }
29
+ should { term :tags, 'python' }
30
+ end
31
+ end
32
+ end
33
+
34
+ assert_equal 2, s.results.size
35
+ assert_equal 'Two', s.results[0].title
36
+ assert_equal 'One', s.results[1].title
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -58,6 +58,24 @@ module Tire
58
58
 
59
59
  end
60
60
 
61
+ context "date ranges" do
62
+
63
+ should "return aggregated values for all results" do
64
+ s = Tire.search('articles-test') do
65
+ query { all }
66
+ facet 'published_on' do
67
+ range :published_on, [{:to => '2010-12-31'}, {:from => '2011-01-01', :to => '2011-01-05'}]
68
+ end
69
+ end
70
+
71
+ facets = s.results.facets['published_on']['ranges']
72
+ assert_equal 2, facets.size, facets.inspect
73
+ assert_equal 0, facets.entries[0]["count"], facets.inspect
74
+ assert_equal 5, facets.entries[1]["count"], facets.inspect
75
+ end
76
+
77
+ end
78
+
61
79
  end
62
80
 
63
81
  end
@@ -1,5 +1,7 @@
1
1
  # Example ActiveModel class with custom index name
2
2
 
3
+ require File.expand_path('../active_model_article', __FILE__)
4
+
3
5
  class ActiveModelArticleWithCustomIndexName < ActiveModelArticle
4
6
  index_name 'custom-index-name'
5
7
  end
data/test/test_helper.rb CHANGED
@@ -1,9 +1,14 @@
1
1
  require 'rubygems'
2
+
3
+ require 'pathname'
2
4
  require 'test/unit'
5
+
6
+ require 'yajl/json_gem'
7
+ require 'sqlite3'
8
+
3
9
  require 'shoulda'
4
- require 'mocha'
5
10
  require 'turn' unless ENV["TM_FILEPATH"]
6
- require 'pathname'
11
+ require 'mocha'
7
12
 
8
13
  require 'tire'
9
14
 
@@ -51,6 +51,16 @@ module Tire
51
51
  assert_nothing_raised { assert @index.refresh }
52
52
  end
53
53
 
54
+ should "open the index" do
55
+ Configuration.client.expects(:post).returns(mock_response('{"ok":true,"_shards":{}}'))
56
+ assert_nothing_raised { assert @index.open }
57
+ end
58
+
59
+ should "close the index" do
60
+ Configuration.client.expects(:post).returns(mock_response('{"ok":true,"_shards":{}}'))
61
+ assert_nothing_raised { assert @index.close }
62
+ end
63
+
54
64
  context "mapping" do
55
65
 
56
66
  should "create index with mapping" do
@@ -118,7 +128,7 @@ module Tire
118
128
 
119
129
  should "store Hash it under its ID property" do
120
130
  Configuration.client.expects(:post).with("#{Configuration.url}/dummy/document/123",
121
- Yajl::Encoder.encode({:id => 123, :title => 'Test'})).
131
+ MultiJson.encode({:id => 123, :title => 'Test'})).
122
132
  returns(mock_response('{"ok":true,"_id":"123"}'))
123
133
  @index.store :id => 123, :title => 'Test'
124
134
  end
@@ -66,7 +66,7 @@ module Tire
66
66
 
67
67
  should "log request in correct format" do
68
68
  log = (<<-"log;").gsub(/^ +/, '')
69
- # 2011-03-19 11:00:00:L [_search] (["articles", "users"])
69
+ # 2011-03-19 11:00:00:#{RUBY_VERSION < "1.9" ? "L" : "000"} [_search] (["articles", "users"])
70
70
  #
71
71
  curl -X GET http://...
72
72
 
@@ -98,7 +98,7 @@ module Tire
98
98
  }
99
99
  json;
100
100
  log = (<<-"log;").gsub(/^\s*/, '')
101
- # 2011-03-19 11:00:00:L [200 OK] (4 msec)
101
+ # 2011-03-19 11:00:00:#{RUBY_VERSION < "1.9" ? "L" : "000"} [200 OK] (4 msec)
102
102
  #
103
103
  log;
104
104
  # log += json.split.map { |line| "# #{line}" }.join("\n")
@@ -39,9 +39,9 @@ module Tire
39
39
  context "Finders" do
40
40
 
41
41
  setup do
42
- @first = { '_id' => 1, '_source' => { :title => 'First' } }
43
- @second = { '_id' => 2, '_source' => { :title => 'Second' } }
44
- @third = { '_id' => 3, '_source' => { :title => 'Third' } }
42
+ @first = { '_id' => 1, '_version' => 1, '_index' => 'persistent_articles', '_type' => 'persistent_article', '_source' => { :title => 'First' } }
43
+ @second = { '_id' => 2, '_index' => 'persistent_articles', '_type' => 'persistent_article', '_source' => { :title => 'Second' } }
44
+ @third = { '_id' => 3, '_index' => 'persistent_articles', '_type' => 'persistent_article', '_source' => { :title => 'Third' } }
45
45
  @find_all = { 'hits' => { 'hits' => [
46
46
  @first,
47
47
  @second,
@@ -62,6 +62,18 @@ module Tire
62
62
  assert_equal 'First', document.title
63
63
  end
64
64
 
65
+ should "have _type, _index, _id, _version attributes" do
66
+ Configuration.client.expects(:get).returns(mock_response(@first.to_json))
67
+ document = PersistentArticle.find 1
68
+
69
+ assert_instance_of PersistentArticle, document
70
+ assert_equal 1, document.id
71
+ assert_equal 1, document.attributes['id']
72
+ assert_equal 'persistent_articles', document._index
73
+ assert_equal 'persistent_article', document._type
74
+ assert_equal 1, document._version
75
+ end
76
+
65
77
  should "find document by string ID" do
66
78
  Configuration.client.expects(:get).returns(mock_response(@first.to_json))
67
79
  document = PersistentArticle.find '1'
@@ -184,7 +196,7 @@ module Tire
184
196
  assert_nothing_raised { article.published_on? }
185
197
  assert ! article.published_on?
186
198
  end
187
-
199
+
188
200
  should "return true for respond_to? calls for set attributes" do
189
201
  article = PersistentArticle.new :title => 'Test'
190
202
  assert article.respond_to?(:title)
@@ -235,9 +247,15 @@ module Tire
235
247
 
236
248
  context "when creating" do
237
249
 
250
+ # TODO: Find a way to mock JSON paylod for Mocha with disregard to Hash entries ordering.
251
+ # Ruby 1.9 brings ordered Hashes, so tests were failing.
252
+
238
253
  should "save the document with generated ID in the database" do
239
254
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/",
240
- '{"title":"Test","tags":["one","two"],"published_on":null}').
255
+ RUBY_VERSION < "1.9" ?
256
+ '{"title":"Test","tags":["one","two"],"published_on":null}' :
257
+ '{"published_on":null,"tags":["one","two"],"title":"Test"}'
258
+ ).
241
259
  returns(mock_response('{"ok":true,"_id":"abc123"}'))
242
260
  article = PersistentArticle.create :title => 'Test', :tags => [:one, :two]
243
261
 
@@ -247,7 +265,10 @@ module Tire
247
265
 
248
266
  should "save the document with custom ID in the database" do
249
267
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/r2d2",
250
- '{"title":"Test","id":"r2d2","tags":null,"published_on":null}').
268
+ RUBY_VERSION < "1.9" ?
269
+ '{"title":"Test","id":"r2d2","tags":null,"published_on":null}' :
270
+ '{"id":"r2d2","published_on":null,"tags":null,"title":"Test"}'
271
+ ).
251
272
  returns(mock_response('{"ok":true,"_id":"r2d2"}'))
252
273
  article = PersistentArticle.create :id => 'r2d2', :title => 'Test'
253
274
 
@@ -256,7 +277,7 @@ module Tire
256
277
 
257
278
  should "perform model validations" do
258
279
  Configuration.client.expects(:post).never
259
-
280
+
260
281
  assert ! ValidatedModel.create(:name => nil)
261
282
  end
262
283
 
@@ -266,7 +287,10 @@ module Tire
266
287
 
267
288
  should "set the id property" do
268
289
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/",
269
- {:title => 'Test', :tags => nil, :published_on => nil}.to_json).
290
+ RUBY_VERSION < "1.9" ?
291
+ {:title => 'Test', :tags => nil, :published_on => nil}.to_json :
292
+ {:published_on => nil, :tags => nil, :title => 'Test'}.to_json
293
+ ).
270
294
  returns(mock_response('{"ok":true,"_id":"1"}'))
271
295
 
272
296
  article = PersistentArticle.create :title => 'Test'
@@ -275,7 +299,10 @@ module Tire
275
299
 
276
300
  should "not set the id property if already set" do
277
301
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/123",
278
- '{"title":"Test","id":"123","tags":null,"published_on":null}').
302
+ RUBY_VERSION < "1.9" ?
303
+ '{"title":"Test","id":"123","tags":null,"published_on":null}' :
304
+ '{"id":"123","published_on":null,"tags":null,"title":"Test"}'
305
+ ).
279
306
  returns(mock_response('{"ok":true, "_id":"XXX"}'))
280
307
 
281
308
  article = PersistentArticle.create :id => '123', :title => 'Test'
@@ -290,13 +317,19 @@ module Tire
290
317
  article = PersistentArticle.new :id => 1, :title => 'Test'
291
318
 
292
319
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/1",
293
- '{"title":"Test","id":1,"tags":null,"published_on":null}').
320
+ RUBY_VERSION < "1.9" ?
321
+ '{"title":"Test","id":1,"tags":null,"published_on":null}' :
322
+ '{"id":1,"published_on":null,"tags":null,"title":"Test"}'
323
+ ).
294
324
  returns(mock_response('{"ok":true,"_id":"1"}'))
295
325
  assert article.save
296
326
 
297
327
  article.title = 'Updated'
298
328
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/1",
299
- '{"title":"Updated","id":1,"tags":null,"published_on":null}').
329
+ RUBY_VERSION < "1.9" ?
330
+ '{"title":"Updated","id":1,"tags":null,"published_on":null}' :
331
+ '{"id":1,"published_on":null,"tags":null,"title":"Updated"}'
332
+ ).
300
333
  returns(mock_response('{"ok":true,"_id":"1"}'))
301
334
  assert article.save
302
335
  end
@@ -323,7 +356,10 @@ module Tire
323
356
  article.title = 'Test'
324
357
 
325
358
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/123",
326
- '{"title":"Test","id":"123","tags":null,"published_on":null}').
359
+ RUBY_VERSION < "1.9" ?
360
+ '{"title":"Test","id":"123","tags":null,"published_on":null}' :
361
+ '{"id":"123","published_on":null,"tags":null,"title":"Test"}'
362
+ ).
327
363
  returns(mock_response('{"ok":true,"_id":"XXX"}'))
328
364
  assert article.save
329
365
  assert_equal '123', article.id
@@ -335,7 +371,10 @@ module Tire
335
371
 
336
372
  should "delete the document from the database" do
337
373
  Configuration.client.expects(:post).with("#{Configuration.url}/persistent_articles/persistent_article/123",
338
- '{"title":"Test","id":"123","tags":null,"published_on":null}').
374
+ RUBY_VERSION < "1.9" ?
375
+ '{"title":"Test","id":"123","tags":null,"published_on":null}' :
376
+ '{"id":"123","published_on":null,"tags":null,"title":"Test"}'
377
+ ).
339
378
  returns(mock_response('{"ok":true,"_id":"123"}'))
340
379
  Configuration.client.expects(:delete).with("#{Configuration.url}/persistent_articles/persistent_article/123")
341
380
 
@@ -25,6 +25,11 @@ module Tire
25
25
  assert_equal 3, Results::Collection.new(@default_response).size
26
26
  end
27
27
 
28
+ should "allow access to items" do
29
+ assert_not_nil Results::Collection.new(@default_response)[1]
30
+ assert_equal 2, Results::Collection.new(@default_response)[1][:id]
31
+ end
32
+
28
33
  should "be initialized with parsed json" do
29
34
  assert_nothing_raised do
30
35
  collection = Results::Collection.new( @default_response )
@@ -10,13 +10,18 @@ module Tire
10
10
  @document = Results::Item.new :title => 'Test', :author => { :name => 'Kafka' }
11
11
  end
12
12
 
13
- should "be initialized with a Hash" do
13
+ should "be initialized with a Hash or Hash like object" do
14
14
  assert_raise(ArgumentError) { Results::Item.new('FUUUUUUU') }
15
15
 
16
16
  assert_nothing_raised do
17
17
  d = Results::Item.new(:id => 1)
18
18
  assert_instance_of Results::Item, d
19
19
  end
20
+
21
+ assert_nothing_raised do
22
+ class AlmostHash < Hash; end
23
+ d = Results::Item.new(AlmostHash.new(:id => 1))
24
+ end
20
25
  end
21
26
 
22
27
  should "respond to :to_indexed_json" do
@@ -6,12 +6,39 @@ module Tire
6
6
 
7
7
  context "Hash" do
8
8
 
9
- should "have to_indexed_json doing the same as to_json" do
9
+ context "with no to_json method provided" do
10
+ setup do
11
+ @hash = { :one => 1}
12
+ # Undefine the `to_json` method...
13
+ class Hash; undef_method(:to_json); end
14
+ # ... and reload the extension, so it's added
15
+ load 'tire/rubyext/hash.rb'
16
+ end
17
+
18
+ should "have its own to_json method" do
19
+ assert_respond_to( @hash, :to_json )
20
+ assert_equal '{"one":1}', @hash.to_json
21
+ end
22
+
23
+ end
24
+
25
+ should "have a to_json method from Yajl" do
26
+ assert defined?(Yajl)
27
+ assert_respond_to( {}, :to_json )
28
+ assert_equal '{"one":1}', { :one => 1}.to_json
29
+ end
30
+
31
+ should "have to_indexed_json method doing the same as to_json" do
10
32
  [{}, { 1 => 2 }, { 3 => 4, 5 => 6 }, { nil => [7,8,9] }].each do |h|
11
- assert_equal Yajl::Parser.parse(h.to_json), Yajl::Parser.parse(h.to_indexed_json)
33
+ assert_equal MultiJson.decode(h.to_json), MultiJson.decode(h.to_indexed_json)
12
34
  end
13
35
  end
14
36
 
37
+ should "properly serialize Time into JSON" do
38
+ json = { :time => Time.mktime(2011, 01, 01, 11, 00).to_json }.to_json
39
+ assert_equal '"2011-01-01T11:00:00+01:00"', MultiJson.decode(json)['time']
40
+ end
41
+
15
42
  end
16
43
 
17
44
  end
@@ -51,7 +51,7 @@ module Tire::Search
51
51
  context "date histogram" do
52
52
 
53
53
  should "encode the JSON with default values" do
54
- f = Facet.new('date') { date :published_on, :interval => 'day' }
54
+ f = Facet.new('date') { date :published_on }
55
55
  assert_equal({ :date => { :date_histogram => { :field => 'published_on', :interval => 'day' } } }.to_json, f.to_json)
56
56
  end
57
57
 
@@ -62,6 +62,13 @@ module Tire::Search
62
62
 
63
63
  end
64
64
 
65
+ context "range facet" do
66
+ should "encode facet options" do
67
+ f = Facet.new('range') { range :published_on, [{:to => '2010-12-31'}, {:from => '2011-01-01', :to => '2011-05-27'}, {:from => '2011-05-28'}]}
68
+ assert_equal({ :range => { :range => { :field => 'published_on', :ranges => [{:to => '2010-12-31'}, {:from => '2011-01-01', :to => '2011-05-27'}, {:from => '2011-05-28'}] } } }.to_json, f.to_json)
69
+ end
70
+ end
71
+
65
72
  end
66
73
 
67
74
  end
@@ -10,6 +10,11 @@ module Tire::Search
10
10
  assert_respond_to Query.new, :to_json
11
11
  end
12
12
 
13
+ should "return itself as a Hash" do
14
+ assert_respond_to Query.new, :to_hash
15
+ assert_equal( { :term => { :foo => 'bar' } }, Query.new.term(:foo, 'bar').to_hash )
16
+ end
17
+
13
18
  should "allow a block to be given" do
14
19
  assert_equal( { :term => { :foo => 'bar' } }.to_json, Query.new do
15
20
  term(:foo, 'bar')
@@ -39,6 +44,16 @@ module Tire::Search
39
44
  Query.new.string('foo', :default_field => 'title') )
40
45
  end
41
46
 
47
+ should "allow set default operator when searching with a query string" do
48
+ assert_equal( { :query_string => { :query => 'foo', :default_operator => 'AND' } },
49
+ Query.new.string('foo', :default_operator => 'AND') )
50
+ end
51
+
52
+ should "allow to set options when searching with a query string" do
53
+ assert_equal( { :query_string => { :query => 'foo', :fields => ['title.*'], :use_dis_max => true } },
54
+ Query.new.string('foo', :fields => ['title.*'], :use_dis_max => true) )
55
+ end
56
+
42
57
  should "search for all documents" do
43
58
  assert_equal( { :match_all => { } }, Query.new.all )
44
59
  end
@@ -50,6 +65,56 @@ module Tire::Search
50
65
 
51
66
  end
52
67
 
68
+ context "BooleanQuery" do
69
+
70
+ should "raise ArgumentError when no block given" do
71
+ assert_raise(ArgumentError) { Query.new.boolean }
72
+ end
73
+
74
+ should "encode options" do
75
+ query = Query.new.boolean(:minimum_number_should_match => 1) do
76
+ must { string 'foo' }
77
+ end
78
+
79
+ assert_equal 1, query[:bool][:minimum_number_should_match]
80
+ end
81
+
82
+ should "wrap single query" do
83
+ assert_equal( { :bool => {:must => [{ :query_string => { :query => 'foo' } }] }},
84
+ Query.new.boolean { must { string 'foo' } } )
85
+ end
86
+
87
+ should "wrap multiple queries for the same condition" do
88
+ query = Query.new.boolean do
89
+ must { string 'foo' }
90
+ must { string 'bar' }
91
+ end
92
+
93
+ assert_equal( 2, query[:bool][:must].size, query[:bool][:must].inspect )
94
+ assert_equal( { :query_string => {:query => 'foo'} }, query[:bool][:must].first )
95
+ assert_equal( { :query_string => {:query => 'bar'} }, query[:bool][:must].last )
96
+ end
97
+
98
+ should "wrap queries for multiple conditions" do
99
+ query = Query.new.boolean do
100
+ should { string 'foo' }
101
+ must { string 'bar' }
102
+ must { string 'baz' }
103
+ must_not { string 'fuu' }
104
+ end
105
+
106
+ assert_equal 2, query[:bool][:must].size
107
+ assert_equal 1, query[:bool][:should].size
108
+ assert_equal 1, query[:bool][:must_not].size
109
+
110
+ assert_equal( { :query_string => {:query => 'foo'} }, query[:bool][:should].first )
111
+ assert_equal( { :query_string => {:query => 'bar'} }, query[:bool][:must].first )
112
+ assert_equal( { :query_string => {:query => 'baz'} }, query[:bool][:must].last )
113
+ assert_equal( { :query_string => {:query => 'fuu'} }, query[:bool][:must_not].first )
114
+ end
115
+
116
+ end
117
+
53
118
  end
54
119
 
55
120
  end
@@ -100,7 +100,7 @@ module Tire
100
100
  _score
101
101
  end
102
102
  end
103
- hash = JSON.load( s.to_json )
103
+ hash = MultiJson.decode( s.to_json )
104
104
  assert_equal [{'title' => 'desc'}, '_score'], hash['sort']
105
105
  end
106
106
 
@@ -182,7 +182,7 @@ module Tire
182
182
  size 5
183
183
  from 3
184
184
  end
185
- hash = JSON.load( s.to_json )
185
+ hash = MultiJson.decode( s.to_json )
186
186
  assert_equal 5, hash['size']
187
187
  assert_equal 3, hash['from']
188
188
  end
@@ -213,12 +213,48 @@ module Tire
213
213
  s = Search::Search.new('index') do
214
214
  fields :title
215
215
  end
216
- hash = JSON.load( s.to_json )
216
+ hash = MultiJson.decode( s.to_json )
217
217
  assert_equal 'title', hash['fields']
218
218
  end
219
219
 
220
220
  end
221
221
 
222
+ context "boolean queries" do
223
+
224
+ should "wrap other queries" do
225
+ # TODO: Try to get rid of the `boolean` method
226
+ #
227
+ # TODO: Try to get rid of multiple `should`, `must`, invocations, and wrap queries like this:
228
+ # boolean do
229
+ # should do
230
+ # string 'foo'
231
+ # string 'bar'
232
+ # end
233
+ # end
234
+ s = Search::Search.new('index') do
235
+ query do
236
+ boolean do
237
+ should { string 'foo' }
238
+ should { string 'moo' }
239
+ must { string 'title:bar' }
240
+ must { terms :tags, ['baz'] }
241
+ end
242
+ end
243
+ end
244
+
245
+ hash = MultiJson.decode(s.to_json)
246
+ query = hash['query']['bool']
247
+ # p hash
248
+
249
+ assert_equal 2, query['should'].size
250
+ assert_equal 2, query['must'].size
251
+
252
+ assert_equal( { 'query_string' => { 'query' => 'foo' } }, query['should'].first)
253
+ assert_equal( { 'terms' => { 'tags' => ['baz'] } }, query['must'].last)
254
+ end
255
+
256
+ end
257
+
222
258
  end
223
259
 
224
260
  end
data/tire.gemspec CHANGED
@@ -27,16 +27,18 @@ Gem::Specification.new do |s|
27
27
  s.add_dependency "rake", "~> 0.8.0"
28
28
  s.add_dependency "bundler", "~> 1.0.0"
29
29
  s.add_dependency "rest-client", "~> 1.6.0"
30
- s.add_dependency "yajl-ruby", "> 0.8.0"
31
- s.add_dependency "activemodel", "> 3.0.0"
30
+ s.add_dependency "multi_json", "~> 1.0"
31
+ s.add_dependency "activemodel", "~> 3.0.7"
32
32
 
33
+ s.add_development_dependency "yajl-ruby", "~> 0.8.0"
33
34
  s.add_development_dependency "turn"
34
35
  s.add_development_dependency "shoulda"
35
36
  s.add_development_dependency "mocha"
36
37
  s.add_development_dependency "sdoc"
37
38
  s.add_development_dependency "rcov"
38
- s.add_development_dependency "activerecord"
39
+ s.add_development_dependency "activerecord", "~> 3.0.7"
39
40
  s.add_development_dependency "supermodel"
41
+ s.add_development_dependency "sqlite3"
40
42
 
41
43
  s.description = <<-DESC
42
44
  Tire is a Ruby client for the ElasticSearch search engine/database.