ssickles-tire 0.4.2 → 0.4.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/lib/tire.rb +3 -18
  2. data/lib/tire/alias.rb +35 -11
  3. data/lib/tire/index.rb +76 -34
  4. data/lib/tire/results/collection.rb +13 -38
  5. data/lib/tire/results/item.rb +0 -19
  6. data/lib/tire/rubyext/to_json.rb +21 -0
  7. data/lib/tire/search.rb +8 -7
  8. data/lib/tire/search/scan.rb +8 -8
  9. data/lib/tire/search/sort.rb +1 -1
  10. data/lib/tire/version.rb +38 -7
  11. data/test/integration/reindex_test.rb +2 -2
  12. data/test/integration/scan_test.rb +1 -1
  13. data/test/test_helper.rb +3 -27
  14. data/test/unit/index_alias_test.rb +17 -3
  15. data/test/unit/index_test.rb +18 -30
  16. data/test/unit/results_collection_test.rb +0 -60
  17. data/test/unit/results_item_test.rb +0 -37
  18. data/test/unit/rubyext_test.rb +3 -3
  19. data/test/unit/search_test.rb +6 -1
  20. data/test/unit/tire_test.rb +0 -15
  21. data/tire.gemspec +13 -30
  22. metadata +41 -153
  23. data/lib/tire/model/callbacks.rb +0 -40
  24. data/lib/tire/model/import.rb +0 -26
  25. data/lib/tire/model/indexing.rb +0 -128
  26. data/lib/tire/model/naming.rb +0 -100
  27. data/lib/tire/model/percolate.rb +0 -99
  28. data/lib/tire/model/persistence.rb +0 -72
  29. data/lib/tire/model/persistence/attributes.rb +0 -143
  30. data/lib/tire/model/persistence/finders.rb +0 -66
  31. data/lib/tire/model/persistence/storage.rb +0 -71
  32. data/lib/tire/model/search.rb +0 -305
  33. data/lib/tire/rubyext/hash.rb +0 -8
  34. data/lib/tire/rubyext/ruby_1_8.rb +0 -54
  35. data/lib/tire/rubyext/symbol.rb +0 -11
  36. data/lib/tire/utils.rb +0 -17
  37. data/test/integration/active_model_indexing_test.rb +0 -51
  38. data/test/integration/active_model_searchable_test.rb +0 -114
  39. data/test/integration/active_record_searchable_test.rb +0 -446
  40. data/test/integration/mongoid_searchable_test.rb +0 -309
  41. data/test/integration/persistent_model_test.rb +0 -117
  42. data/test/models/active_model_article.rb +0 -31
  43. data/test/models/active_model_article_with_callbacks.rb +0 -49
  44. data/test/models/active_model_article_with_custom_document_type.rb +0 -7
  45. data/test/models/active_model_article_with_custom_index_name.rb +0 -7
  46. data/test/models/active_record_models.rb +0 -122
  47. data/test/models/mongoid_models.rb +0 -97
  48. data/test/models/persistent_article.rb +0 -11
  49. data/test/models/persistent_article_in_namespace.rb +0 -12
  50. data/test/models/persistent_article_with_casting.rb +0 -28
  51. data/test/models/persistent_article_with_defaults.rb +0 -11
  52. data/test/models/persistent_articles_with_custom_index_name.rb +0 -10
  53. data/test/models/supermodel_article.rb +0 -17
  54. data/test/models/validated_model.rb +0 -11
  55. data/test/unit/active_model_lint_test.rb +0 -17
  56. data/test/unit/model_callbacks_test.rb +0 -116
  57. data/test/unit/model_import_test.rb +0 -71
  58. data/test/unit/model_persistence_test.rb +0 -516
  59. data/test/unit/model_search_test.rb +0 -899
@@ -1,899 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ModelWithIndexCallbacks
4
- extend ActiveModel::Naming
5
- extend ActiveModel::Callbacks
6
-
7
- include Tire::Model::Search
8
- include Tire::Model::Callbacks
9
-
10
- def destroyed?; false; end
11
- def serializable_hash; {:one => 1}; end
12
- end
13
-
14
- module Tire
15
- module Model
16
-
17
- class SearchTest < Test::Unit::TestCase
18
-
19
- context "Model::Search" do
20
-
21
- setup do
22
- @stub = stub('search') { stubs(:query).returns(self); stubs(:perform).returns(self); stubs(:results).returns([]) }
23
- Tire::Index.any_instance.stubs(:exists?).returns(false)
24
- end
25
-
26
- teardown do
27
- ActiveModelArticleWithCustomIndexName.index_name 'custom-index-name'
28
- end
29
-
30
- should "have the search method" do
31
- assert_respond_to ActiveModelArticle, :search
32
- end
33
-
34
- should "have the callback methods for update index defined" do
35
- assert_respond_to ::ModelWithIndexCallbacks, :before_update_elasticsearch_index
36
- assert_respond_to ::ModelWithIndexCallbacks, :after_update_elasticsearch_index
37
- end
38
-
39
- should "limit searching in index for documents matching the model 'document_type'" do
40
- Tire::Search::Search.
41
- expects(:new).
42
- with(ActiveModelArticle.index_name, { :type => ActiveModelArticle.document_type }).
43
- returns(@stub).
44
- twice
45
-
46
- ActiveModelArticle.search 'foo'
47
- ActiveModelArticle.search { query { string 'foo' } }
48
- end
49
-
50
- should "search in custom name" do
51
- first = 'custom-index-name'
52
- second = 'another-custom-index-name'
53
- expected_options = { :type => ActiveModelArticleWithCustomIndexName.document_type }
54
-
55
- Tire::Search::Search.expects(:new).with(first, expected_options).returns(@stub).twice
56
- ActiveModelArticleWithCustomIndexName.index_name first
57
- ActiveModelArticleWithCustomIndexName.search 'foo'
58
- ActiveModelArticleWithCustomIndexName.search { query { string 'foo' } }
59
-
60
- Tire::Search::Search.expects(:new).with(second, expected_options).returns(@stub).twice
61
- ActiveModelArticleWithCustomIndexName.index_name second
62
- ActiveModelArticleWithCustomIndexName.search 'foo'
63
- ActiveModelArticleWithCustomIndexName.search { query { string 'foo' } }
64
-
65
- Tire::Search::Search.expects(:new).with(first, expected_options).returns(@stub).twice
66
- ActiveModelArticleWithCustomIndexName.index_name first
67
- ActiveModelArticleWithCustomIndexName.search 'foo'
68
- ActiveModelArticleWithCustomIndexName.search { query { string 'foo' } }
69
- end
70
-
71
- should "search in custom type" do
72
- name = ActiveModelArticleWithCustomDocumentType.index_name
73
- Tire::Search::Search.expects(:new).with(name, { :type => 'my_custom_type' }).returns(@stub).twice
74
-
75
- ActiveModelArticleWithCustomDocumentType.search 'foo'
76
- ActiveModelArticleWithCustomDocumentType.search { query { string 'foo' } }
77
- end
78
-
79
- should "allow to pass custom document type" do
80
- Tire::Search::Search.
81
- expects(:new).
82
- with(ActiveModelArticle.index_name, { :type => 'custom_type' }).
83
- returns(@stub).
84
- twice
85
-
86
- ActiveModelArticle.search 'foo', :type => 'custom_type'
87
- ActiveModelArticle.search( :type => 'custom_type' ) { query { string 'foo' } }
88
- end
89
-
90
- should "allow to pass custom index name" do
91
- Tire::Search::Search.
92
- expects(:new).
93
- with('custom_index', { :type => ActiveModelArticle.document_type }).
94
- returns(@stub).
95
- twice
96
-
97
- ActiveModelArticle.search 'foo', :index => 'custom_index'
98
- ActiveModelArticle.search( :index => 'custom_index' ) do
99
- query { string 'foo' }
100
- end
101
- end
102
-
103
- should "allow to refresh index" do
104
- Index.any_instance.expects(:refresh)
105
-
106
- ActiveModelArticle.index.refresh
107
- end
108
-
109
- should "wrap results in instances of the wrapper class" do
110
- response = { 'hits' => { 'hits' => [{'_id' => 1, '_score' => 0.8, '_source' => { 'title' => 'Article' }}] } }
111
- Configuration.client.expects(:get).returns(mock_response(response.to_json))
112
-
113
- collection = ActiveModelArticle.search 'foo'
114
- assert_instance_of Results::Collection, collection
115
-
116
- document = collection.first
117
-
118
- assert_instance_of Results::Item, document
119
- assert_not_nil document._score
120
- assert_equal 1, document.id
121
- assert_equal 'Article', document.title
122
- end
123
-
124
- context "searching with a block" do
125
- setup do
126
- Tire::Search::Search.any_instance.expects(:perform).returns(@stub)
127
- end
128
-
129
- should "pass on whatever block it received" do
130
- Tire::Search::Query.any_instance.expects(:string).with('foo').returns(@stub)
131
-
132
- ActiveModelArticle.search { query { string 'foo' } }
133
- end
134
-
135
- should "allow to pass block with argument to query, allowing to use local variables from outer scope" do
136
- Tire::Search::Query.any_instance.expects(:instance_eval).never
137
- Tire::Search::Query.any_instance.expects(:string).with('foo').returns(@stub)
138
-
139
- my_query = 'foo'
140
- ActiveModelArticle.search do
141
- query do |query|
142
- query.string(my_query)
143
- end
144
- end
145
- end
146
-
147
- should "allow to pass :page and :per_page options" do
148
- Tire::Search::Search.any_instance.expects(:size).with(10)
149
- Tire::Search::Search.any_instance.expects(:from).with(20)
150
-
151
- ActiveModelArticle.search :per_page => 10, :page => 3 do
152
- query { string 'foo' }
153
- end
154
- end
155
-
156
- end
157
-
158
- context "searching with query string" do
159
-
160
- setup do
161
- @q = 'foo AND bar'
162
-
163
- Tire::Search::Query.any_instance.expects(:string).at_least_once.with(@q).returns(@stub)
164
- Tire::Search::Search.any_instance.expects(:perform).at_least_once.returns(@stub)
165
- end
166
-
167
- should "search for query string" do
168
- ActiveModelArticle.search @q
169
- end
170
-
171
- should "allow to pass :order option" do
172
- Tire::Search::Sort.any_instance.expects(:by).with('title', nil)
173
-
174
- ActiveModelArticle.search @q, :order => 'title'
175
- end
176
-
177
- should "allow to pass :sort option as :order option" do
178
- Tire::Search::Sort.any_instance.expects(:by).with('title', nil)
179
-
180
- ActiveModelArticle.search @q, :sort => 'title'
181
- end
182
-
183
- should "allow to specify sort direction" do
184
- Tire::Search::Sort.any_instance.expects(:by).with('title', 'DESC')
185
-
186
- ActiveModelArticle.search @q, :order => 'title DESC'
187
- end
188
-
189
- should "allow to specify more fields to sort on" do
190
- Tire::Search::Sort.any_instance.expects(:by).with('title', 'DESC')
191
- Tire::Search::Sort.any_instance.expects(:by).with('author.name', nil)
192
-
193
- ActiveModelArticle.search @q, :order => ['title DESC', 'author.name']
194
- end
195
-
196
- should "allow to specify number of results per page" do
197
- Tire::Search::Search.any_instance.expects(:size).with(20)
198
-
199
- ActiveModelArticle.search @q, :per_page => 20
200
- end
201
-
202
- should "allow to specify first page in paginated results" do
203
- Tire::Search::Search.any_instance.expects(:size).with(10)
204
- Tire::Search::Search.any_instance.expects(:from).with(0)
205
-
206
- ActiveModelArticle.search @q, :per_page => 10, :page => 1
207
- end
208
-
209
- should "allow to specify page further in paginated results" do
210
- Tire::Search::Search.any_instance.expects(:size).with(10)
211
- Tire::Search::Search.any_instance.expects(:from).with(20)
212
-
213
- ActiveModelArticle.search @q, :per_page => 10, :page => 3
214
- end
215
-
216
- should "allow to limit returned fields" do
217
- Tire::Search::Search.any_instance.expects(:fields).with(["id"])
218
- ActiveModelArticle.search @q, :fields => 'id'
219
-
220
- Tire::Search::Search.any_instance.expects(:fields).with(["id", "title"])
221
- ActiveModelArticle.search @q, :fields => ['id', 'title']
222
- end
223
-
224
- end
225
-
226
- should "not set callback when hooks are missing" do
227
- @model = ActiveModelArticle.new
228
- @model.expects(:update_elasticsearch_index).never
229
-
230
- @model.save
231
- end
232
-
233
- should_eventually "not define destroyed? if class already implements it" do
234
- load File.expand_path('../../models/active_model_article_with_callbacks.rb', __FILE__)
235
-
236
- # TODO: Find a way how to break the old implementation:
237
- # if base.respond_to?(:before_destroy) && !base.respond_to?(:destroyed?)
238
- ActiveModelArticleWithCallbacks.expects(:class_eval).never
239
- end
240
-
241
- should "fire :after_save callbacks" do
242
- @model = ActiveModelArticleWithCallbacks.new
243
- @model.tire.expects(:update_index)
244
-
245
- @model.save
246
- end
247
-
248
- should "fire :after_destroy callbacks" do
249
- @model = ActiveModelArticleWithCallbacks.new
250
- @model.tire.expects(:update_index)
251
-
252
- @model.destroy
253
- end
254
-
255
- should "store the record in index on :update_elasticsearch_index when saved" do
256
- @model = ActiveModelArticleWithCallbacks.new
257
- Tire::Index.any_instance.expects(:store).returns({})
258
-
259
- @model.save
260
- end
261
-
262
- should "remove the record from index on :update_elasticsearch_index when destroyed" do
263
- @model = ActiveModelArticleWithCallbacks.new
264
- i = mock('index') { expects(:remove) }
265
- Tire::Index.expects(:new).with('active_model_article_with_callbacks').returns(i)
266
-
267
- @model.destroy
268
- end
269
-
270
- context "with custom mapping" do
271
-
272
- should "create the index with mapping" do
273
- expected = {
274
- :settings => {},
275
- :mappings => { :model_with_custom_mapping => {
276
- :properties => { :title => { :type => 'string', :analyzer => 'snowball', :boost => 10 } }
277
- }}
278
- }
279
-
280
- Tire::Index.any_instance.expects(:create).with(expected)
281
-
282
- class ::ModelWithCustomMapping
283
- extend ActiveModel::Naming
284
- extend ActiveModel::Callbacks
285
-
286
- include Tire::Model::Search
287
- include Tire::Model::Callbacks
288
-
289
- mapping do
290
- indexes :title, :type => 'string', :analyzer => 'snowball', :boost => 10
291
- end
292
-
293
- end
294
-
295
- assert_equal 'snowball', ModelWithCustomMapping.mapping[:title][:analyzer]
296
- end
297
-
298
- should "create the index with proper mapping options" do
299
- expected = {
300
- :settings => {},
301
- :mappings => {
302
- :model_with_custom_mapping_and_options => {
303
- :_source => { :compress => true },
304
- :_all => { :enabled => false },
305
- :properties => { :title => { :type => 'string', :analyzer => 'snowball', :boost => 10 } }
306
- }
307
- }
308
- }
309
-
310
- Tire::Index.any_instance.expects(:create).with(expected)
311
-
312
- class ::ModelWithCustomMappingAndOptions
313
- extend ActiveModel::Naming
314
- extend ActiveModel::Callbacks
315
-
316
- include Tire::Model::Search
317
- include Tire::Model::Callbacks
318
-
319
- mapping :_source => { :compress => true }, :_all => { :enabled => false } do
320
- indexes :title, :type => 'string', :analyzer => 'snowball', :boost => 10
321
- end
322
-
323
- end
324
-
325
- assert_equal 'snowball', ModelWithCustomMappingAndOptions.mapping[:title][:analyzer]
326
- assert_equal true, ModelWithCustomMappingAndOptions.mapping_options[:_source][:compress]
327
- assert_equal false, ModelWithCustomMappingAndOptions.mapping_options[:_all][:enabled]
328
- end
329
-
330
- should "not raise an error when defining mapping" do
331
- Tire::Index.any_instance.unstub(:exists?)
332
- Configuration.client.expects(:head).raises(Errno::ECONNREFUSED)
333
-
334
- assert_nothing_raised do
335
- class ::ModelWithCustomMapping
336
- extend ActiveModel::Naming
337
- extend ActiveModel::Callbacks
338
-
339
- include Tire::Model::Search
340
- include Tire::Model::Callbacks
341
-
342
- mapping do
343
- indexes :title, :type => 'string', :analyzer => 'snowball', :boost => 10
344
- end
345
-
346
- end
347
- end
348
- end
349
-
350
- should "define mapping for nested properties with a block" do
351
- expected = {
352
- :settings => {},
353
- :mappings => { :model_with_nested_mapping => {
354
- :properties => {
355
- :title => { :type => 'string' },
356
- :author => {
357
- :type => 'object',
358
- :properties => {
359
- :first_name => { :type => 'string' },
360
- :last_name => { :type => 'string', :boost => 100 },
361
- :posts => {
362
- :type => 'object',
363
- :properties => {
364
- :title => { :type => 'string', :boost => 10 }
365
- }
366
- }
367
- }
368
- }
369
- }
370
- }
371
- }}
372
-
373
- Tire::Index.any_instance.expects(:create).with(expected)
374
-
375
- class ::ModelWithNestedMapping
376
- extend ActiveModel::Naming
377
- extend ActiveModel::Callbacks
378
-
379
- include Tire::Model::Search
380
- include Tire::Model::Callbacks
381
-
382
- mapping do
383
- indexes :title, :type => 'string'
384
- indexes :author do
385
- indexes :first_name, :type => 'string'
386
- indexes :last_name, :type => 'string', :boost => 100
387
-
388
- indexes :posts do
389
- indexes :title, :type => 'string', :boost => 10
390
- end
391
- end
392
- end
393
-
394
- end
395
-
396
- assert_not_nil ModelWithNestedMapping.mapping[:author][:properties][:last_name]
397
- assert_equal 100, ModelWithNestedMapping.mapping[:author][:properties][:last_name][:boost]
398
- assert_equal 10, ModelWithNestedMapping.mapping[:author][:properties][:posts][:properties][:title][:boost]
399
- end
400
-
401
- should "define mapping for nested documents" do
402
- class ::ModelWithNestedDocuments
403
- extend ActiveModel::Naming
404
- extend ActiveModel::Callbacks
405
-
406
- include Tire::Model::Search
407
- include Tire::Model::Callbacks
408
-
409
- mapping do
410
- indexes :comments, :type => 'nested', :include_in_parent => true do
411
- indexes :author_name
412
- indexes :body, :boost => 100
413
- end
414
- end
415
-
416
- end
417
-
418
- assert_equal 'nested', ModelWithNestedDocuments.mapping[:comments][:type]
419
- assert_not_nil ModelWithNestedDocuments.mapping[:comments][:properties][:author_name]
420
- assert_equal 100, ModelWithNestedDocuments.mapping[:comments][:properties][:body][:boost]
421
- end
422
-
423
- end
424
-
425
- context "with settings" do
426
-
427
- should "create the index with settings and mappings" do
428
- expected_settings = {
429
- :settings => { :number_of_shards => 1, :number_of_replicas => 1 }
430
- }
431
-
432
- Tire::Index.any_instance.expects(:create).with do |expected|
433
- expected[:settings][:number_of_shards] == 1 &&
434
- expected[:mappings].size > 0
435
- end
436
-
437
- class ::ModelWithCustomSettings
438
- extend ActiveModel::Naming
439
- extend ActiveModel::Callbacks
440
-
441
- include Tire::Model::Search
442
- include Tire::Model::Callbacks
443
-
444
- settings :number_of_shards => 1, :number_of_replicas => 1 do
445
- mapping do
446
- indexes :title, :type => 'string'
447
- end
448
- end
449
-
450
- end
451
-
452
- assert_instance_of Hash, ModelWithCustomSettings.settings
453
- assert_equal 1, ModelWithCustomSettings.settings[:number_of_shards]
454
- end
455
-
456
- end
457
-
458
- context "with index update callbacks" do
459
- setup do
460
- class ::ModelWithIndexCallbacks
461
- _update_elasticsearch_index_callbacks.clear
462
- def notify; end
463
- end
464
-
465
- response = { 'ok' => true,
466
- '_id' => 1,
467
- 'matches' => ['foo'] }
468
- Configuration.client.expects(:post).returns(mock_response(response.to_json))
469
- end
470
-
471
- should "run the callback defined as block" do
472
- class ::ModelWithIndexCallbacks
473
- after_update_elasticsearch_index { self.go! }
474
- end
475
-
476
- @model = ::ModelWithIndexCallbacks.new
477
- @model.expects(:go!)
478
-
479
- @model.update_elasticsearch_index
480
- end
481
-
482
- should "run the callback defined as symbol" do
483
- class ::ModelWithIndexCallbacks
484
- after_update_elasticsearch_index :notify
485
-
486
- def notify; self.go!; end
487
- end
488
-
489
- @model = ::ModelWithIndexCallbacks.new
490
- @model.expects(:go!)
491
-
492
- @model.update_elasticsearch_index
493
- end
494
-
495
- should "set the 'matches' property from percolated response" do
496
- @model = ::ModelWithIndexCallbacks.new
497
- @model.update_elasticsearch_index
498
-
499
- assert_equal ['foo'], @model.matches
500
- end
501
-
502
- end
503
-
504
- context "serialization" do
505
- setup { Tire::Index.any_instance.stubs(:create).returns(true) }
506
-
507
- should "have to_hash" do
508
- assert_equal( {'title' => 'Test'}, ActiveModelArticle.new( 'title' => 'Test' ).to_hash )
509
- end
510
-
511
- should "not redefine to_hash if already defined" do
512
- class ::ActiveModelArticleWithToHash < ActiveModelArticle
513
- def to_hash; { :foo => 'bar' }; end
514
- end
515
- assert_equal 'bar', ::ActiveModelArticleWithToHash.new(:title => 'Test').to_hash[:foo]
516
-
517
- class ::ActiveModelArticleWithToHashFromSuperclass < Hash
518
- include Tire::Model::Search
519
- include Tire::Model::Callbacks
520
- end
521
- assert_equal( {}, ::ActiveModelArticleWithToHashFromSuperclass.new(:title => 'Test').to_hash)
522
- end
523
-
524
- should "serialize itself into JSON without 'root'" do
525
- @model = ActiveModelArticle.new 'title' => 'Test'
526
- assert_equal({'title' => 'Test'}.to_json, @model.to_indexed_json)
527
- end
528
-
529
- should "not include the ID property in serialized document (_source)" do
530
- @model = ActiveModelArticle.new 'id' => 1, 'title' => 'Test'
531
- assert_nil MultiJson.decode(@model.to_indexed_json)[:id]
532
- assert_nil MultiJson.decode(@model.to_indexed_json)['id']
533
- end
534
-
535
- should "not include the type property in serialized document (_source)" do
536
- @model = ActiveModelArticle.new 'type' => 'foo', 'title' => 'Test'
537
- assert_nil MultiJson.decode(@model.to_indexed_json)[:type]
538
- assert_nil MultiJson.decode(@model.to_indexed_json)['type']
539
- end
540
-
541
- should "serialize itself with serializable_hash when no mapping is set" do
542
-
543
- class ::ModelWithoutMapping
544
- extend ActiveModel::Naming
545
- extend ActiveModel::Callbacks
546
- include ActiveModel::Serialization
547
- include Tire::Model::Search
548
- include Tire::Model::Callbacks
549
-
550
- # Do NOT configure any mapping
551
-
552
- attr_reader :attributes
553
-
554
- def initialize(attributes = {}); @attributes = attributes; end
555
-
556
- def method_missing(name, *args, &block)
557
- attributes[name.to_sym] || attributes[name.to_s] || super
558
- end
559
- end
560
-
561
- model = ::ModelWithoutMapping.new :one => 1, :two => 2
562
- assert_equal( {:one => 1, :two => 2}, model.serializable_hash )
563
-
564
- # Bot properties are returned
565
- assert_equal( {:one => 1, :two => 2}.to_json, model.to_indexed_json )
566
- end
567
-
568
- should "serialize only mapped properties when mapping is set" do
569
-
570
- class ::ModelWithMapping
571
- extend ActiveModel::Naming
572
- extend ActiveModel::Callbacks
573
- include ActiveModel::Serialization
574
- include Tire::Model::Search
575
- include Tire::Model::Callbacks
576
-
577
- mapping do
578
- # ONLY index the 'one' attribute
579
- indexes :one, :type => 'string', :analyzer => 'keyword'
580
- end
581
-
582
- attr_reader :attributes
583
-
584
- def initialize(attributes = {}); @attributes = attributes; end
585
-
586
- def method_missing(name, *args, &block)
587
- attributes[name.to_sym] || attributes[name.to_s] || super
588
- end
589
- end
590
-
591
- model = ::ModelWithMapping.new :one => 1, :two => 2
592
- assert_equal( {:one => 1, :two => 2}, model.serializable_hash )
593
-
594
- # Only the mapped property is returned
595
- assert_equal( {:one => 1}.to_json, model.to_indexed_json )
596
-
597
- end
598
-
599
- should "serialize mapped properties when mapping procs are set" do
600
- class ::ModelWithMappingProcs
601
- extend ActiveModel::Naming
602
- extend ActiveModel::Callbacks
603
- include ActiveModel::Serialization
604
- include Tire::Model::Search
605
- include Tire::Model::Callbacks
606
-
607
- mapping do
608
- indexes :one, :type => 'string', :analyzer => 'keyword'
609
- indexes :two, :type => 'string', :analyzer => 'keyword', :as => proc { one * 2 }
610
- indexes :three, :type => 'string', :analyzer => 'keyword', :as => 'one + 2'
611
- end
612
-
613
- attr_reader :attributes
614
-
615
- def initialize(attributes = {}); @attributes = attributes; end
616
-
617
- def method_missing(name, *args, &block)
618
- attributes[name.to_sym] || attributes[name.to_s] || super
619
- end
620
- end
621
-
622
- model = ::ModelWithMappingProcs.new :one => 1, :two => 1, :three => 1
623
- hash = model.serializable_hash
624
- document = MultiJson.decode(model.to_indexed_json)
625
-
626
- assert_equal 1, hash[:one]
627
- assert_equal 1, hash[:two]
628
- assert_equal 1, hash[:three]
629
-
630
- assert_equal 1, document['one']
631
- assert_equal 2, document['two']
632
- assert_equal 3, document['three']
633
- end
634
-
635
- end
636
-
637
- context "with percolation" do
638
- setup do
639
- class ::ActiveModelArticleWithCallbacks; percolate!(false); end
640
- @article = ::ActiveModelArticleWithCallbacks.new :title => 'Test'
641
- end
642
-
643
- should "return matching queries on percolate" do
644
- Tire::Index.any_instance.expects(:percolate).returns(["alert"])
645
-
646
- assert_equal ['alert'], @article.percolate
647
- end
648
-
649
- should "pass the arguments to percolate" do
650
- filter = lambda { string 'tag:alerts' }
651
-
652
- Tire::Index.any_instance.expects(:percolate).with do |doc,query|
653
- # p [doc,query]
654
- doc == @article &&
655
- query == filter
656
- end.returns(["alert"])
657
-
658
- assert_equal ['alert'], @article.percolate(&filter)
659
- end
660
-
661
- should "mark the instance for percolation on index update" do
662
- @article.percolate = true
663
-
664
- Tire::Index.any_instance.expects(:store).with do |doc,options|
665
- # p [doc,options]
666
- options[:percolate] == true
667
- end.returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
668
-
669
- @article.update_elasticsearch_index
670
- end
671
-
672
- should "not percolate document on index update when not set for percolation" do
673
- Tire::Index.any_instance.expects(:store).with do |doc,options|
674
- # p [doc,options]
675
- options[:percolate] == nil
676
- end.returns(MultiJson.decode('{"ok":true,"_id":"test"}'))
677
-
678
- @article.update_elasticsearch_index
679
- end
680
-
681
- should "set the default percolator pattern" do
682
- class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
683
- percolate!
684
- end
685
-
686
- assert_equal true, ::ActiveModelArticleWithCallbacks.percolator
687
- end
688
-
689
- should "set the percolator pattern" do
690
- class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
691
- percolate! 'tags:alert'
692
- end
693
-
694
- assert_equal 'tags:alert', ::ActiveModelArticleWithCallbacks.percolator
695
- end
696
-
697
- should "mark the class for percolation on index update" do
698
- class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
699
- percolate!
700
- end
701
-
702
- Tire::Index.any_instance.expects(:store).with do |doc,options|
703
- # p [doc,options]
704
- options[:percolate] == true
705
- end.returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
706
-
707
- percolated = ActiveModelArticleWithPercolation.new :title => 'Percolate me!'
708
- percolated.update_elasticsearch_index
709
- end
710
-
711
- should "execute the 'on_percolate' callback" do
712
- $test__matches = nil
713
- class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
714
- on_percolate { $test__matches = matches }
715
- end
716
- percolated = ActiveModelArticleWithPercolation.new :title => 'Percolate me!'
717
-
718
- Tire::Index.any_instance.expects(:store).
719
- with do |doc,options|
720
- doc == percolated &&
721
- options[:percolate] == true
722
- end.
723
- returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
724
-
725
- percolated.update_elasticsearch_index
726
-
727
- assert_equal ['alerts'], $test__matches
728
- end
729
-
730
- should "execute the 'on_percolate' callback for specific pattern" do
731
- $test__matches = nil
732
- class ::ActiveModelArticleWithPercolation < ::ActiveModelArticleWithCallbacks
733
- on_percolate('tags:alert') { $test__matches = self.matches }
734
- end
735
- percolated = ActiveModelArticleWithPercolation.new :title => 'Percolate me!'
736
-
737
- Tire::Index.any_instance.expects(:store).
738
- with do |doc,options|
739
- doc == percolated &&
740
- options[:percolate] == 'tags:alert'
741
- end.
742
- returns(MultiJson.decode('{"ok":true,"_id":"test","matches":["alerts"]}'))
743
-
744
- percolated.update_elasticsearch_index
745
-
746
- assert_equal ['alerts'], $test__matches
747
- end
748
-
749
- end
750
-
751
- context "proxy" do
752
-
753
- should "have the proxy to class methods" do
754
- assert_respond_to ActiveModelArticle, :tire
755
- assert_instance_of Tire::Model::Search::ClassMethodsProxy, ActiveModelArticle.tire
756
- end
757
-
758
- should "have the proxy to instance methods" do
759
- assert_respond_to ActiveModelArticle.new, :tire
760
- assert_instance_of Tire::Model::Search::InstanceMethodsProxy, ActiveModelArticle.new.tire
761
- end
762
-
763
- should "NOT overload existing top-level class methods" do
764
- assert_equal "THIS IS MY MAPPING!", ActiveRecordClassWithTireMethods.mapping
765
- assert_equal 'snowball', ActiveRecordClassWithTireMethods.tire.mapping[:title][:analyzer]
766
- end
767
-
768
- should "NOT overload existing top-level instance methods" do
769
- ActiveRecordClassWithTireMethods.stubs(:columns).returns([])
770
- ActiveRecordClassWithTireMethods.stubs(:column_defaults).returns({})
771
- assert_equal "THIS IS MY INDEX!", ActiveRecordClassWithTireMethods.new.index
772
- assert_equal 'active_record_class_with_tire_methods',
773
- ActiveRecordClassWithTireMethods.new.tire.index.name
774
- end
775
-
776
- end
777
-
778
- context "with index prefix" do
779
- class ::ModelWithoutPrefix
780
- extend ActiveModel::Naming
781
- extend ActiveModel::Callbacks
782
-
783
- include Tire::Model::Search
784
- include Tire::Model::Callbacks
785
- end
786
- class ::ModelWithPrefix
787
- extend ActiveModel::Naming
788
- extend ActiveModel::Callbacks
789
-
790
- include Tire::Model::Search
791
- include Tire::Model::Callbacks
792
-
793
- tire.index_prefix 'custom_prefix'
794
- end
795
-
796
- class ::OtherModelWithPrefix
797
- extend ActiveModel::Naming
798
- extend ActiveModel::Callbacks
799
-
800
- include Tire::Model::Search
801
- include Tire::Model::Callbacks
802
-
803
- index_prefix 'other_custom_prefix'
804
- end
805
-
806
- teardown do
807
- # FIXME: Depends on the interface itself
808
- Model::Search.index_prefix nil
809
- end
810
-
811
- should "return nil by default" do
812
- assert_nil Model::Search.index_prefix
813
- end
814
-
815
- should "allow to set and retrieve the value" do
816
- assert_nothing_raised { Model::Search.index_prefix 'app_environment' }
817
- assert_equal 'app_environment', Model::Search.index_prefix
818
- end
819
-
820
- should "allow to reset the value" do
821
- Model::Search.index_prefix 'prefix'
822
- Model::Search.index_prefix nil
823
- assert_nil Model::Search.index_prefix
824
- end
825
-
826
- should "not add any prefix by default" do
827
- assert_equal 'model_without_prefixes', ModelWithoutPrefix.index_name
828
- end
829
-
830
- should "add general and custom prefixes to model index names" do
831
- Model::Search.index_prefix 'general_prefix'
832
- assert_equal 'general_prefix_model_without_prefixes', ModelWithoutPrefix.index_name
833
- assert_equal 'custom_prefix_model_with_prefixes', ModelWithPrefix.index_name
834
- assert_equal 'other_custom_prefix_other_model_with_prefixes', OtherModelWithPrefix.index_name
835
- end
836
-
837
- end
838
-
839
- context "with dynamic index name" do
840
- class ::ModelWithDynamicIndexName
841
- extend ActiveModel::Naming
842
- extend ActiveModel::Callbacks
843
-
844
- include Tire::Model::Search
845
- include Tire::Model::Callbacks
846
-
847
- index_name do
848
- "dynamic" + '_' + "index"
849
- end
850
- end
851
-
852
- should "have index name as a proc" do
853
- assert_kind_of Proc, ::ModelWithDynamicIndexName.index_name
854
- end
855
-
856
- should "evaluate the proc in Model.index" do
857
- assert_equal 'dynamic_index', ::ModelWithDynamicIndexName.index.name
858
- end
859
-
860
- end
861
-
862
- end
863
-
864
- context "Results::Item" do
865
-
866
- setup do
867
- module ::Rails
868
- end
869
-
870
- class ::FakeRailsModel
871
- extend ActiveModel::Naming
872
- include ActiveModel::Conversion
873
- def self.find(*args); new; end
874
- end
875
-
876
- @document = Results::Item.new :id => 1, :_type => 'fake_rails_model', :title => 'Test'
877
- end
878
-
879
- should "load the 'real' instance from the corresponding model" do
880
- assert_respond_to @document, :load
881
- assert_instance_of FakeRailsModel, @document.load
882
- end
883
-
884
- should "pass the ID to the corresponding model's find method" do
885
- FakeRailsModel.expects(:find).with(1).returns(FakeRailsModel.new)
886
- @document.load
887
- end
888
-
889
- should "pass the options to the corresponding model's find method" do
890
- FakeRailsModel.expects(:find).with(1, {:include => 'everything'}).returns(FakeRailsModel.new)
891
- @document.load :include => 'everything'
892
- end
893
-
894
- end
895
-
896
- end
897
-
898
- end
899
- end