tire 0.1.9 → 0.1.10

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.
data/lib/tire.rb CHANGED
@@ -21,6 +21,7 @@ require 'tire/index'
21
21
  require 'tire/dsl'
22
22
  require 'tire/model/naming'
23
23
  require 'tire/model/callbacks'
24
+ require 'tire/model/percolate'
24
25
  require 'tire/model/search'
25
26
  require 'tire/model/indexing'
26
27
  require 'tire/model/import'
data/lib/tire/index.rb CHANGED
@@ -44,14 +44,14 @@ module Tire
44
44
  # TODO: Infer type from the document (hash property, method)
45
45
  # TODO: Refactor common logic for getting id, JSON, into private methods
46
46
 
47
- if args.size > 1
48
- (type, document = args)
49
- else
50
- (document = args.pop; type = :document)
47
+ case args.size
48
+ when 3 then (type, document, options = args)
49
+ when 2 then (type, document = args)
50
+ else (document = args.pop; type = :document)
51
51
  end
52
52
 
53
- if document.is_a?(Hash)
54
- percolate = document.delete(:percolate)
53
+ if options
54
+ percolate = options[:percolate]
55
55
  percolate = "*" if percolate === true
56
56
  end
57
57
 
@@ -222,7 +222,17 @@ module Tire
222
222
  rescue Exception => error
223
223
  raise
224
224
  ensure
225
- curl = %Q|curl -X POST "#{Configuration.url}/_percolator/#{@name}/"|
225
+ curl = %Q|curl -X PUT "#{Configuration.url}/_percolator/#{@name}/?pretty=1" -d '#{MultiJson.encode(options)}'|
226
+ logged(error, '_percolator', curl)
227
+ end
228
+
229
+ def unregister_percolator_query(name)
230
+ @response = Configuration.client.delete "#{Configuration.url}/_percolator/#{@name}/#{name}"
231
+ MultiJson.decode(@response.body)['ok']
232
+ rescue Exception => error
233
+ raise
234
+ ensure
235
+ curl = %Q|curl -X DELETE "#{Configuration.url}/_percolator/#{@name}"|
226
236
  logged(error, '_percolator', curl)
227
237
  end
228
238
 
@@ -246,13 +256,13 @@ module Tire
246
256
  payload = { :doc => document }
247
257
  payload.update( :query => query ) if query
248
258
 
249
- @response = Configuration.client.get "#{Configuration.url}/#{@name}/#{type}/_percolate", payload.to_json
259
+ @response = Configuration.client.get "#{Configuration.url}/#{@name}/#{type}/_percolate", MultiJson.encode(payload)
250
260
  MultiJson.decode(@response.body)['matches']
251
261
 
252
262
  rescue Exception => error
253
263
  # raise
254
264
  ensure
255
- curl = %Q|curl -X POST "#{Configuration.url}/#{@name}/#{type}/_percolate"|
265
+ curl = %Q|curl -X GET "#{Configuration.url}/#{@name}/#{type}/_percolate?pretty=1" -d '#{payload.to_json}'|
256
266
  logged(error, '_percolate', curl)
257
267
  end
258
268
 
@@ -0,0 +1,40 @@
1
+ module Tire
2
+ module Model
3
+
4
+ module Percolate
5
+
6
+ module ClassMethods
7
+ def percolate!(pattern=true)
8
+ @@_percolator = pattern
9
+ self
10
+ end
11
+
12
+ def on_percolate(pattern=true,&block)
13
+ self.percolate!(pattern)
14
+ after_update_elastic_search_index(block)
15
+ end
16
+
17
+ def percolator
18
+ defined?(@@_percolator) ? @@_percolator : nil
19
+ end
20
+ end
21
+
22
+ module InstanceMethods
23
+
24
+ def percolate(&block)
25
+ index.percolate document_type, self, block
26
+ end
27
+
28
+ def percolate=(pattern)
29
+ @_percolator = pattern
30
+ end
31
+
32
+ def percolator
33
+ @_percolator || self.class.percolator || nil
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -11,6 +11,9 @@ module Tire
11
11
  extend Tire::Model::Indexing::ClassMethods
12
12
  extend Tire::Model::Import::ClassMethods
13
13
 
14
+ extend Tire::Model::Percolate::ClassMethods
15
+ include Tire::Model::Percolate::InstanceMethods
16
+
14
17
  extend ClassMethods
15
18
  include InstanceMethods
16
19
 
@@ -81,7 +84,7 @@ module Tire
81
84
  if destroyed?
82
85
  index.remove document_type, self
83
86
  else
84
- response = index.store document_type, self
87
+ response = index.store( document_type, self, {:percolate => self.percolator} )
85
88
  self.id ||= response['_id'] if self.respond_to?(:id=)
86
89
  self.matches = response['matches']
87
90
  self
@@ -89,14 +92,17 @@ module Tire
89
92
  end
90
93
  end
91
94
 
95
+ def to_hash
96
+ self.serializable_hash
97
+ end
98
+
92
99
  def to_indexed_json
93
100
  if self.class.mapping.empty?
94
- self.serializable_hash.
95
- to_json
101
+ to_hash.to_json
96
102
  else
97
- self.serializable_hash.
98
- reject { |key, value| ! self.class.mapping.keys.map(&:to_s).include?(key.to_s) }.
99
- to_json
103
+ to_hash.
104
+ reject { |key, value| ! self.class.mapping.keys.map(&:to_s).include?(key.to_s) }.
105
+ to_json
100
106
  end
101
107
  end
102
108
 
data/lib/tire/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Tire
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.10"
3
3
  end
@@ -7,16 +7,20 @@ module Tire
7
7
 
8
8
  context "Percolator" do
9
9
  setup do
10
+ delete_registered_queries
10
11
  @index = Tire.index('percolator-test')
11
12
  @index.create
12
13
  end
13
- teardown { @index.delete }
14
+ teardown do
15
+ delete_registered_queries
16
+ @index.delete
17
+ end
14
18
 
15
19
  context "when registering a query" do
16
20
  should "register query as a Hash" do
17
21
  query = { :query => { :query_string => { :query => 'warning' } } }
18
22
  assert @index.register_percolator_query('alert', query)
19
- sleep 0.1
23
+ Tire.index('_percolator').refresh; sleep 0.1
20
24
 
21
25
  percolator = Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/alert")
22
26
  assert percolator
@@ -24,12 +28,26 @@ module Tire
24
28
 
25
29
  should "register query as block" do
26
30
  assert @index.register_percolator_query('alert') { string 'warning' }
27
- sleep 0.1
31
+ Tire.index('_percolator').refresh; sleep 0.1
28
32
 
29
33
  percolator = Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/alert")
30
34
  assert percolator
31
35
  end
32
36
 
37
+ should "unregister a query" do
38
+ query = { :query => { :query_string => { :query => 'warning' } } }
39
+ assert @index.register_percolator_query('alert', query)
40
+ Tire.index('_percolator').refresh; sleep 0.1
41
+ assert Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/alert")
42
+
43
+ assert @index.unregister_percolator_query('alert')
44
+ Tire.index('_percolator').refresh; sleep 0.1
45
+
46
+ assert_raise(RestClient::ResourceNotFound) do
47
+ Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/alert")
48
+ end
49
+ end
50
+
33
51
  end
34
52
 
35
53
  context "when percolating a document" do
@@ -37,7 +55,7 @@ module Tire
37
55
  @index.register_percolator_query('alert') { string 'warning' }
38
56
  @index.register_percolator_query('gantz') { string '"y u no match"' }
39
57
  @index.register_percolator_query('weather', :tags => ['weather']) { string 'severe' }
40
- sleep 0.1
58
+ Tire.index('_percolator').refresh; sleep 0.1
41
59
  end
42
60
 
43
61
  should "return an empty array when no query matches" do
@@ -61,26 +79,35 @@ module Tire
61
79
  @index.register_percolator_query('alert') { string 'warning' }
62
80
  @index.register_percolator_query('gantz') { string '"y u no match"' }
63
81
  @index.register_percolator_query('weather', :tags => ['weather']) { string 'severe' }
64
- sleep 0.1
82
+ Tire.index('_percolator').refresh; sleep 0.1
65
83
  end
66
84
 
67
85
  should "return an empty array when no query matches" do
68
- response = @index.store :message => 'Situation normal', :percolate => true
86
+ response = @index.store :document, {:message => 'Situation normal'}, {:percolate => true}
69
87
  assert_equal [], response['matches']
70
88
  end
71
89
 
72
90
  should "return an array of matching query names" do
73
- response = @index.store :message => 'Severe weather warning', :percolate => true
91
+ response = @index.store :document, {:message => 'Severe weather warning'}, {:percolate => true}
74
92
  assert_equal ['alert','weather'], response['matches'].sort
75
93
  end
76
94
 
77
95
  should "return an array of matching query names for specific percolated queries" do
78
- response = @index.store :message => 'Severe weather warning', :percolate => 'tags:weather'
96
+ response = @index.store :document, {:message => 'Severe weather warning'}, {:percolate => 'tags:weather'}
79
97
  assert_equal ['weather'], response['matches']
80
98
  end
81
99
  end
82
100
 
83
101
  end
84
102
 
103
+ private
104
+
105
+ def delete_registered_queries
106
+ Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/alert") rescue nil
107
+ Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/gantz") rescue nil
108
+ Configuration.client.get("#{Configuration.url}/_percolator/percolator-test/weather") rescue nil
109
+ end
110
+
85
111
  end
112
+
86
113
  end
@@ -232,14 +232,14 @@ module Tire
232
232
 
233
233
  should "serialize Hashes" do
234
234
  Configuration.client.expects(:post).with do |url, json|
235
- url == "#{Configuration.url}/_bulk"
236
- json =~ /"_index":"dummy"/
237
- json =~ /"_type":"document"/
238
- json =~ /"_id":"1"/
239
- json =~ /"_id":"2"/
240
- json =~ /"id":"1"/
241
- json =~ /"id":"2"/
242
- json =~ /"title":"One"/
235
+ url == "#{Configuration.url}/_bulk" &&
236
+ json =~ /"_index":"dummy"/ &&
237
+ json =~ /"_type":"document"/ &&
238
+ json =~ /"_id":"1"/ &&
239
+ json =~ /"_id":"2"/ &&
240
+ json =~ /"id":"1"/ &&
241
+ json =~ /"id":"2"/ &&
242
+ json =~ /"title":"One"/ &&
243
243
  json =~ /"title":"Two"/
244
244
  end.returns('{}')
245
245
 
@@ -249,14 +249,14 @@ module Tire
249
249
 
250
250
  should "serialize ActiveModel instances" do
251
251
  Configuration.client.expects(:post).with do |url, json|
252
- url == "#{Configuration.url}/_bulk"
253
- json =~ /"_index":"active_model_articles"/
254
- json =~ /"_type":"article"/
255
- json =~ /"_id":"1"/
256
- json =~ /"_id":"2"/
257
- json =~ /"id":"1"/
258
- json =~ /"id":"2"/
259
- json =~ /"title":"One"/
252
+ url == "#{Configuration.url}/_bulk" &&
253
+ json =~ /"_index":"active_model_articles"/ &&
254
+ json =~ /"_type":"active_model_article"/ &&
255
+ json =~ /"_id":"1"/ &&
256
+ json =~ /"_id":"2"/ &&
257
+ json =~ /"id":"1"/ &&
258
+ json =~ /"id":"2"/ &&
259
+ json =~ /"title":"One"/ &&
260
260
  json =~ /"title":"Two"/
261
261
  end.returns('{}')
262
262
 
@@ -397,7 +397,7 @@ module Tire
397
397
 
398
398
  should "register percolator query as a Hash" do
399
399
  query = { :query => { :query_string => { :query => 'foo' } } }
400
- Configuration.client.expects(:post).with do |url, payload|
400
+ Configuration.client.expects(:put).with do |url, payload|
401
401
  payload = MultiJson.decode(payload)
402
402
  url == "#{Configuration.url}/_percolator/dummy/my-query" &&
403
403
  payload['query']['query_string']['query'] == 'foo'
@@ -414,7 +414,7 @@ module Tire
414
414
  end
415
415
 
416
416
  should "register percolator query as a block" do
417
- Configuration.client.expects(:post).with do |url, payload|
417
+ Configuration.client.expects(:put).with do |url, payload|
418
418
  payload = MultiJson.decode(payload)
419
419
  url == "#{Configuration.url}/_percolator/dummy/my-query" &&
420
420
  payload['query']['query_string']['query'] == 'foo'
@@ -436,7 +436,7 @@ module Tire
436
436
  query = { :query => { :query_string => { :query => 'foo' } },
437
437
  :tags => ['alert'] }
438
438
 
439
- Configuration.client.expects(:post).with do |url, payload|
439
+ Configuration.client.expects(:put).with do |url, payload|
440
440
  payload = MultiJson.decode(payload)
441
441
  url == "#{Configuration.url}/_percolator/dummy/my-query" &&
442
442
  payload['query']['query_string']['query'] == 'foo'
@@ -453,8 +453,14 @@ module Tire
453
453
  assert @index.register_percolator_query('my-query', query)
454
454
  end
455
455
 
456
+ should "unregister percolator query" do
457
+ Configuration.client.expects(:delete).with("#{Configuration.url}/_percolator/dummy/my-query").
458
+ returns(mock_response('{"ok":true,"acknowledged":true}'))
459
+ assert @index.unregister_percolator_query('my-query')
460
+ end
461
+
456
462
  should "percolate document against all registered queries" do
457
- Configuration.client.expects(:post).with do |url,payload|
463
+ Configuration.client.expects(:get).with do |url,payload|
458
464
  payload = MultiJson.decode(payload)
459
465
  url == "#{Configuration.url}/dummy/document/_percolate" &&
460
466
  payload['doc']['title'] == 'Test'
@@ -466,7 +472,7 @@ module Tire
466
472
  end
467
473
 
468
474
  should "percolate a typed document against all registered queries" do
469
- Configuration.client.expects(:post).with do |url,payload|
475
+ Configuration.client.expects(:get).with do |url,payload|
470
476
  payload = MultiJson.decode(payload)
471
477
  url == "#{Configuration.url}/dummy/article/_percolate" &&
472
478
  payload['doc']['title'] == 'Test'
@@ -478,7 +484,7 @@ module Tire
478
484
  end
479
485
 
480
486
  should "percolate document against specific queries" do
481
- Configuration.client.expects(:post).with do |url,payload|
487
+ Configuration.client.expects(:get).with do |url,payload|
482
488
  payload = MultiJson.decode(payload)
483
489
  # p [url, payload]
484
490
  url == "#{Configuration.url}/dummy/document/_percolate" &&
@@ -491,18 +497,18 @@ module Tire
491
497
  assert_equal ["alerts"], matches
492
498
  end
493
499
 
494
- context "when storing document" do
500
+ context "while storing document" do
495
501
 
496
502
  should "percolate document against all registered queries" do
497
503
  Configuration.client.expects(:post).with("#{Configuration.url}/dummy/article/?percolate=*", '{"title":"Test"}').
498
504
  returns(mock_response('{"ok":true,"_id":"test","matches":["alerts"]}'))
499
- @index.store :article, :title => 'Test', :percolate => true
505
+ @index.store :article, {:title => 'Test'}, {:percolate => true}
500
506
  end
501
507
 
502
508
  should "percolate document against specific queries" do
503
509
  Configuration.client.expects(:post).with("#{Configuration.url}/dummy/article/?percolate=tag:alerts", '{"title":"Test"}').
504
510
  returns(mock_response('{"ok":true,"_id":"test","matches":["alerts"]}'))
505
- response = @index.store :article, :title => 'Test', :percolate => 'tag:alerts'
511
+ response = @index.store :article, {:title => 'Test'}, {:percolate => 'tag:alerts'}
506
512
  assert_equal response['matches'], ['alerts']
507
513
  end
508
514
 
@@ -307,6 +307,10 @@ module Tire
307
307
  context "serialization" do
308
308
  setup { Tire::Index.any_instance.stubs(:create).returns(true) }
309
309
 
310
+ should "have to_hash" do
311
+ assert_equal( {'title' => 'Test'}, ActiveModelArticle.new( 'title' => 'Test' ).to_hash )
312
+ end
313
+
310
314
  should "serialize itself into JSON without 'root'" do
311
315
  @model = ActiveModelArticle.new 'title' => 'Test'
312
316
  assert_equal({'title' => 'Test'}.to_json, @model.to_indexed_json)
@@ -372,6 +376,121 @@ module Tire
372
376
 
373
377
  end
374
378
 
379
+ context "with percolation" do
380
+ setup do
381
+ class ::ActiveModelArticleWithCallbacks; percolate!(false); end
382
+ @article = ::ActiveModelArticleWithCallbacks.new :title => 'Test'
383
+ end
384
+
385
+ should "return matching queries on percolate" do
386
+ Tire::Index.any_instance.expects(:percolate).returns(["alert"])
387
+
388
+ assert_equal ['alert'], @article.percolate
389
+ end
390
+
391
+ should "pass the arguments to percolate" do
392
+ filter = lambda { string 'tag:alerts' }
393
+
394
+ Tire::Index.any_instance.expects(:percolate).with do |type,doc,query|
395
+ # p [type,doc,query]
396
+ type == 'active_model_article_with_callbacks' &&
397
+ doc == @article &&
398
+ query == filter
399
+ end.returns(["alert"])
400
+
401
+ assert_equal ['alert'], @article.percolate(&filter)
402
+ end
403
+
404
+ should "mark the instance for percolation on index update" do
405
+ @article.percolate = true
406
+
407
+ Tire::Index.any_instance.expects(:store).with do |type,doc,options|
408
+ # p [type,doc,options]
409
+ options[:percolate] == true
410
+ end.returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
411
+
412
+ @article.update_elastic_search_index
413
+ end
414
+
415
+ should "not percolate document on index update when not set for percolation" do
416
+ Tire::Index.any_instance.expects(:store).with do |type,doc,options|
417
+ # p [type,doc,options]
418
+ options[:percolate] == nil
419
+ end.returns(MultiJson.decode('{"ok":true,"_id":"test"}'))
420
+
421
+ @article.update_elastic_search_index
422
+ end
423
+
424
+ should "set the default percolator pattern" do
425
+ class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
426
+ percolate!
427
+ end
428
+
429
+ assert_equal true, ::ActiveModelArticleWithCallbacks.percolator
430
+ end
431
+
432
+ should "set the percolator pattern" do
433
+ class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
434
+ percolate! 'tags:alert'
435
+ end
436
+
437
+ assert_equal 'tags:alert', ::ActiveModelArticleWithCallbacks.percolator
438
+ end
439
+
440
+ should "mark the class for percolation on index update" do
441
+ class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
442
+ percolate!
443
+ end
444
+
445
+ Tire::Index.any_instance.expects(:store).with do |type,doc,options|
446
+ # p [type,doc,options]
447
+ options[:percolate] == true
448
+ end.returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
449
+
450
+ percolated = ActiveModelArticleWithPercolation.new :title => 'Percolate me!'
451
+ percolated.update_elastic_search_index
452
+ end
453
+
454
+ should "execute the 'on_percolate' callback" do
455
+ $test__matches = nil
456
+ class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
457
+ on_percolate { $test__matches = matches }
458
+ end
459
+ percolated = ActiveModelArticleWithPercolation.new :title => 'Percolate me!'
460
+
461
+ Tire::Index.any_instance.expects(:store).
462
+ with do |type,doc,options|
463
+ doc == percolated &&
464
+ options[:percolate] == true
465
+ end.
466
+ returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
467
+
468
+ percolated.update_elastic_search_index
469
+
470
+ assert_equal ['alerts'], $test__matches
471
+ end
472
+
473
+ should "execute the 'on_percolate' callback for specific pattern" do
474
+ $test__matches = nil
475
+ class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
476
+ on_percolate('tags:alert') { $test__matches = self.matches }
477
+ end
478
+ percolated = ActiveModelArticleWithPercolation.new :title => 'Percolate me!'
479
+
480
+ Tire::Index.any_instance.expects(:store).
481
+ with do |type,doc,options|
482
+ doc == percolated &&
483
+ options[:percolate] == 'tags:alert'
484
+ end.
485
+ returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
486
+
487
+ percolated.update_elastic_search_index
488
+
489
+ assert_equal ['alerts'], $test__matches
490
+ end
491
+
492
+ end
493
+
375
494
  end
376
495
 
377
496
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tire
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 9
10
- version: 0.1.9
9
+ - 10
10
+ version: 0.1.10
11
11
  platform: ruby
12
12
  authors:
13
13
  - Karel Minarik
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-13 00:00:00 +02:00
18
+ date: 2011-06-14 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -269,6 +269,7 @@ files:
269
269
  - lib/tire/model/import.rb
270
270
  - lib/tire/model/indexing.rb
271
271
  - lib/tire/model/naming.rb
272
+ - lib/tire/model/percolate.rb
272
273
  - lib/tire/model/persistence.rb
273
274
  - lib/tire/model/persistence/attributes.rb
274
275
  - lib/tire/model/persistence/finders.rb