ssickles-tire 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +13 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.markdown +760 -0
  6. data/Rakefile +78 -0
  7. data/examples/rails-application-template.rb +249 -0
  8. data/examples/tire-dsl.rb +876 -0
  9. data/lib/tire.rb +52 -0
  10. data/lib/tire/alias.rb +296 -0
  11. data/lib/tire/configuration.rb +30 -0
  12. data/lib/tire/dsl.rb +43 -0
  13. data/lib/tire/http/client.rb +62 -0
  14. data/lib/tire/http/clients/curb.rb +61 -0
  15. data/lib/tire/http/response.rb +27 -0
  16. data/lib/tire/index.rb +345 -0
  17. data/lib/tire/logger.rb +60 -0
  18. data/lib/tire/model/callbacks.rb +40 -0
  19. data/lib/tire/model/import.rb +26 -0
  20. data/lib/tire/model/indexing.rb +128 -0
  21. data/lib/tire/model/naming.rb +100 -0
  22. data/lib/tire/model/percolate.rb +99 -0
  23. data/lib/tire/model/persistence.rb +72 -0
  24. data/lib/tire/model/persistence/attributes.rb +143 -0
  25. data/lib/tire/model/persistence/finders.rb +66 -0
  26. data/lib/tire/model/persistence/storage.rb +71 -0
  27. data/lib/tire/model/search.rb +305 -0
  28. data/lib/tire/results/collection.rb +114 -0
  29. data/lib/tire/results/item.rb +83 -0
  30. data/lib/tire/results/pagination.rb +54 -0
  31. data/lib/tire/rubyext/hash.rb +8 -0
  32. data/lib/tire/rubyext/ruby_1_8.rb +54 -0
  33. data/lib/tire/rubyext/symbol.rb +11 -0
  34. data/lib/tire/search.rb +160 -0
  35. data/lib/tire/search/facet.rb +70 -0
  36. data/lib/tire/search/filter.rb +28 -0
  37. data/lib/tire/search/highlight.rb +37 -0
  38. data/lib/tire/search/query.rb +151 -0
  39. data/lib/tire/search/scan.rb +114 -0
  40. data/lib/tire/search/sort.rb +25 -0
  41. data/lib/tire/tasks.rb +135 -0
  42. data/lib/tire/utils.rb +17 -0
  43. data/lib/tire/version.rb +22 -0
  44. data/test/fixtures/articles/1.json +1 -0
  45. data/test/fixtures/articles/2.json +1 -0
  46. data/test/fixtures/articles/3.json +1 -0
  47. data/test/fixtures/articles/4.json +1 -0
  48. data/test/fixtures/articles/5.json +1 -0
  49. data/test/integration/active_model_indexing_test.rb +51 -0
  50. data/test/integration/active_model_searchable_test.rb +114 -0
  51. data/test/integration/active_record_searchable_test.rb +446 -0
  52. data/test/integration/boolean_queries_test.rb +43 -0
  53. data/test/integration/count_test.rb +34 -0
  54. data/test/integration/custom_score_queries_test.rb +88 -0
  55. data/test/integration/dsl_search_test.rb +22 -0
  56. data/test/integration/explanation_test.rb +44 -0
  57. data/test/integration/facets_test.rb +232 -0
  58. data/test/integration/filtered_queries_test.rb +66 -0
  59. data/test/integration/filters_test.rb +63 -0
  60. data/test/integration/fuzzy_queries_test.rb +20 -0
  61. data/test/integration/highlight_test.rb +64 -0
  62. data/test/integration/index_aliases_test.rb +122 -0
  63. data/test/integration/index_mapping_test.rb +43 -0
  64. data/test/integration/index_store_test.rb +96 -0
  65. data/test/integration/mongoid_searchable_test.rb +309 -0
  66. data/test/integration/percolator_test.rb +111 -0
  67. data/test/integration/persistent_model_test.rb +117 -0
  68. data/test/integration/query_return_version_test.rb +70 -0
  69. data/test/integration/query_string_test.rb +52 -0
  70. data/test/integration/range_queries_test.rb +36 -0
  71. data/test/integration/reindex_test.rb +46 -0
  72. data/test/integration/results_test.rb +39 -0
  73. data/test/integration/scan_test.rb +56 -0
  74. data/test/integration/sort_test.rb +36 -0
  75. data/test/integration/text_query_test.rb +39 -0
  76. data/test/models/active_model_article.rb +31 -0
  77. data/test/models/active_model_article_with_callbacks.rb +49 -0
  78. data/test/models/active_model_article_with_custom_document_type.rb +7 -0
  79. data/test/models/active_model_article_with_custom_index_name.rb +7 -0
  80. data/test/models/active_record_models.rb +122 -0
  81. data/test/models/article.rb +15 -0
  82. data/test/models/mongoid_models.rb +97 -0
  83. data/test/models/persistent_article.rb +11 -0
  84. data/test/models/persistent_article_in_namespace.rb +12 -0
  85. data/test/models/persistent_article_with_casting.rb +28 -0
  86. data/test/models/persistent_article_with_defaults.rb +11 -0
  87. data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
  88. data/test/models/supermodel_article.rb +17 -0
  89. data/test/models/validated_model.rb +11 -0
  90. data/test/test_helper.rb +88 -0
  91. data/test/unit/active_model_lint_test.rb +17 -0
  92. data/test/unit/configuration_test.rb +74 -0
  93. data/test/unit/http_client_test.rb +76 -0
  94. data/test/unit/http_response_test.rb +49 -0
  95. data/test/unit/index_alias_test.rb +275 -0
  96. data/test/unit/index_test.rb +841 -0
  97. data/test/unit/logger_test.rb +125 -0
  98. data/test/unit/model_callbacks_test.rb +116 -0
  99. data/test/unit/model_import_test.rb +71 -0
  100. data/test/unit/model_persistence_test.rb +516 -0
  101. data/test/unit/model_search_test.rb +899 -0
  102. data/test/unit/results_collection_test.rb +281 -0
  103. data/test/unit/results_item_test.rb +155 -0
  104. data/test/unit/rubyext_test.rb +60 -0
  105. data/test/unit/search_facet_test.rb +153 -0
  106. data/test/unit/search_filter_test.rb +42 -0
  107. data/test/unit/search_highlight_test.rb +46 -0
  108. data/test/unit/search_query_test.rb +242 -0
  109. data/test/unit/search_scan_test.rb +113 -0
  110. data/test/unit/search_sort_test.rb +50 -0
  111. data/test/unit/search_test.rb +455 -0
  112. data/test/unit/tire_test.rb +126 -0
  113. data/tire.gemspec +85 -0
  114. metadata +506 -0
@@ -0,0 +1,66 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class FilteredQueriesIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Filtered queries" do
9
+
10
+ should "restrict the results with a filter" do
11
+ # 2.json > Begins with "T" and is tagged "ruby"
12
+
13
+ s = Tire.search('articles-test') do
14
+ query do
15
+ filtered do
16
+ query { string 'title:T*' }
17
+ filter :terms, :tags => ['ruby']
18
+ end
19
+ end
20
+ end
21
+
22
+ assert_equal 1, s.results.count
23
+ assert_equal 'Two', s.results.first.title
24
+ end
25
+
26
+ should "restrict the results with multiple filters, chained with AND by default" do
27
+ # 2.json > Is tagged "ruby" and has 250 words
28
+
29
+ s = Tire.search('articles-test') do
30
+ query do
31
+ filtered do
32
+ query { all }
33
+ filter :terms, :tags => ['ruby', 'python']
34
+ filter :range, :words => { :from => '250', :to => '250' }
35
+ end
36
+ end
37
+ end
38
+
39
+ assert_equal 1, s.results.count
40
+ assert_equal 'Two', s.results.first.title
41
+ end
42
+
43
+ should "restrict the results with multiple OR filters" do
44
+ # 1.json > Is tagged "ruby"
45
+ # 1.json > Is tagged "ruby" and has 250 words
46
+ # 4.json > Has 250 words
47
+
48
+ s = Tire.search('articles-test') do
49
+ query do
50
+ filtered do
51
+ query { all }
52
+ filter :or, { :terms => { :tags => ['ruby', 'python'] } },
53
+ { :range => { :words => { :from => '250', :to => '250' } } }
54
+ end
55
+ end
56
+ end
57
+
58
+ assert_equal 3, s.results.count
59
+ assert_equal %w(Four One Two), s.results.map(&:title)
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class FiltersIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Filters" do
9
+
10
+ should "filter the results" do
11
+ # 2.json > Begins with "T" and is tagged "ruby"
12
+
13
+ s = Tire.search('articles-test') do
14
+ query { string 'title:T*' }
15
+ filter :terms, :tags => ['ruby']
16
+ end
17
+
18
+ assert_equal 1, s.results.count
19
+ assert_equal 'Two', s.results.first.title
20
+ end
21
+
22
+ should "filter the results with multiple 'or' filters" do
23
+ # 4.json > Begins with "F" and is tagged "erlang"
24
+
25
+ s = Tire.search('articles-test') do
26
+ query { string 'title:F*' }
27
+ filter :or, {:terms => {:tags => ['ruby']}},
28
+ {:terms => {:tags => ['erlang']}}
29
+ end
30
+
31
+ assert_equal 1, s.results.count
32
+ assert_equal 'Four', s.results.first.title
33
+ end
34
+
35
+ should "filter the results with multiple 'and' filters" do
36
+ # 5.json > Is tagged ["java", "javascript"] and is published on 2011-01-04
37
+
38
+ s = Tire.search('articles-test') do
39
+ filter :terms, :tags => ["java"]
40
+ filter :term, :published_on => "2011-01-04"
41
+ end
42
+
43
+ assert_equal 1, s.results.count
44
+ assert_equal 'Five', s.results.first.title
45
+ end
46
+
47
+ should "not influence facets" do
48
+ s = Tire.search('articles-test') do
49
+ query { string 'title:T*' }
50
+ filter :terms, :tags => ['ruby']
51
+
52
+ facet('tags') { terms :tags }
53
+ end
54
+
55
+ assert_equal 1, s.results.count
56
+ assert_equal 3, s.results.facets['tags']['terms'].size
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class FuzzyQueryIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Fuzzy query" do
9
+ should "fuzzily find article by tag" do
10
+ results = Tire.search('articles-test') { query { fuzzy :tags, 'irlang' } }.results
11
+
12
+ assert_equal 1, results.count
13
+ assert_equal ["erlang"], results.first[:tags]
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class HighlightIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Highlight" do
9
+ teardown { Tire.index('highlight-test').delete }
10
+
11
+ should "add 'highlight' field to the result item" do
12
+ # Tire::Configuration.logger STDERR, :level => 'debug'
13
+ s = Tire.search('articles-test') do
14
+ query { string 'Two' }
15
+ highlight :title
16
+ end
17
+
18
+ doc = s.results.first
19
+
20
+ assert_equal 1, doc.highlight.title.size
21
+ assert doc.highlight.title.to_s.include?('<em>'), "Highlight does not include default highlight tag"
22
+ end
23
+
24
+ should "highlight multiple fields with custom highlight tag" do
25
+ s = Tire.search('articles-test') do
26
+ query { string 'Two OR ruby' }
27
+ highlight :tags, :title, :options => { :tag => '<strong>' }
28
+ end
29
+
30
+ doc = s.results.first
31
+
32
+ assert_equal 1, doc.highlight.title.size
33
+ assert_equal "<strong>Two</strong>", doc.highlight.title.first, "Highlight does not include highlight tag"
34
+ assert_equal "<strong>ruby</strong>", doc.highlight.tags.first, "Highlight does not include highlight tag"
35
+ end
36
+
37
+ should "return entire content with highlighted fragments" do
38
+ # Tire::Configuration.logger STDERR, :level => 'debug'
39
+
40
+ content = "A Fox one day fell into a deep well and could find no means of escape. A Goat, overcome with thirst, came to the same well, and seeing the Fox, inquired if the water was good. Concealing his sad plight under a merry guise, the Fox indulged in a lavish praise of the water, saying it was excellent beyond measure, and encouraging him to descend. The Goat, mindful only of his thirst, thoughtlessly jumped down, but just as he drank, the Fox informed him of the difficulty they were both in and suggested a scheme for their common escape. \"If,\" said he, \"you will place your forefeet upon the wall and bend your head, I will run up your back and escape, and will help you out afterwards.\" The Goat readily assented and the Fox leaped upon his back. Steadying himself with the Goat horns, he safely reached the mouth of the well and made off as fast as he could. When the Goat upbraided him for breaking his promise, he turned around and cried out, \"You foolish old fellow! If you had as many brains in your head as you have hairs in your beard, you would never have gone down before you had inspected the way up, nor have exposed yourself to dangers from which you had no means of escape.\" Look before you leap."
41
+
42
+ Tire.index 'highlight-test' do
43
+ delete
44
+ create
45
+ store :id => 1, :content => content
46
+ refresh
47
+ end
48
+
49
+ s = Tire.search('highlight-test') do
50
+ query { string 'fox' }
51
+ highlight :content => { :number_of_fragments => 0 }
52
+ end
53
+
54
+ doc = s.results.first
55
+ assert_not_nil doc.highlight.content
56
+
57
+ highlight = doc.highlight.content
58
+ assert highlight.to_s.include?('<em>'), "Highlight does not include default highlight tag"
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,122 @@
1
+ require 'test_helper'
2
+
3
+ require 'active_support/core_ext/numeric'
4
+ require 'active_support/core_ext/date/calculations'
5
+
6
+ module Tire
7
+
8
+ class IndexAliasesIntegrationTest < Test::Unit::TestCase
9
+ include Test::Integration
10
+
11
+ context "With a filtered alias" do
12
+ setup do
13
+
14
+ @index = Tire.index 'index-original' do
15
+ delete
16
+ create
17
+ end
18
+
19
+ end
20
+
21
+ teardown { Tire.index('index-original').delete }
22
+
23
+ should "create the alias" do
24
+ @index.add_alias 'index-aliased'
25
+ assert_equal 1, @index.aliases.size
26
+ end
27
+
28
+ should "find only portion of documents in the filtered alias" do
29
+ Tire.index 'index-original' do
30
+ add_alias 'index-aliased', :filter => { :term => { :user => 'anne' } }
31
+ store :title => 'Document 1', :user => 'anne'
32
+ store :title => 'Document 2', :user => 'mary'
33
+
34
+ refresh
35
+ end
36
+
37
+ assert_equal 2, Tire.search('index-original') { query { all } }.results.size
38
+ assert_equal 1, Tire.search('index-aliased') { query { all } }.results.size
39
+ end
40
+
41
+ should "remove the alias" do
42
+ @index.add_alias 'index-aliased'
43
+ assert_equal 1, @index.aliases.size
44
+
45
+ @index.remove_alias 'index-aliased'
46
+ assert_equal 0, @index.aliases.size
47
+
48
+ assert_raise Tire::Search::SearchRequestFailed do
49
+ Tire.search('index-aliased') { query { all } }.results
50
+ end
51
+ end
52
+
53
+ should "retrieve a list of aliases for an index" do
54
+ @index.add_alias 'index-aliased'
55
+
56
+ assert_equal ['index-aliased'], @index.aliases.map(&:name)
57
+ end
58
+
59
+ should "retrieve the properties of an alias" do
60
+ @index.add_alias 'index-aliased', :routing => '1'
61
+
62
+ assert_equal '1', @index.aliases('index-aliased').search_routing
63
+ end
64
+ end
65
+
66
+ context "In the 'sliding window' scenario" do
67
+
68
+ setup do
69
+ WINDOW_SIZE_IN_WEEKS = 4
70
+
71
+ @indices = WINDOW_SIZE_IN_WEEKS.times.map { |number| "articles_#{number.weeks.ago.strftime('%Y-%m-%d')}" }
72
+
73
+ @indices.each_with_index do |name,i|
74
+ Tire.index(name) do
75
+ delete
76
+ create
77
+ store :title => "Document #{i}"
78
+ refresh
79
+ end
80
+ Alias.new(:name => "articles_current") { |a| a.indices(name) and a.save }
81
+ end
82
+ end
83
+
84
+ teardown do
85
+ @indices.each { |index| Tire.index(index).delete }
86
+ end
87
+
88
+ should "add a new index to alias" do
89
+ @indices << "articles_#{(WINDOW_SIZE_IN_WEEKS+1).weeks.ago.strftime('%Y-%m-%d')}"
90
+ Tire.index(@indices.last).create
91
+ Alias.new(:name => "articles_current") { |a| a.index @indices.last and a.save }
92
+
93
+ a = Alias.find("articles_current")
94
+ assert_equal 5, a.indices.size
95
+ end
96
+
97
+ should "remove the stale index from the alias" do
98
+ Alias.find("articles_current") do |a|
99
+ # Remove all indices older then 2 weeks from the alias
100
+ a.indices.delete_if do |i|
101
+ Time.parse( i.gsub(/articles_/, '') ) < 2.weeks.ago rescue false
102
+ end
103
+ a.save
104
+ end
105
+
106
+ assert_equal 2, Alias.find("articles_current").indices.size
107
+ end
108
+
109
+ should "search within the alias" do
110
+ Alias.find("articles_current") do |a|
111
+ a.indices.clear and a.indices @indices[0..1] and a.save
112
+ end
113
+
114
+ assert_equal 4, Tire.search(@indices) { query {all} }.results.size
115
+ assert_equal 2, Tire.search("articles_current") { query {all} }.results.size
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class IndexMappingIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Default mapping" do
9
+ teardown { Tire.index('mapped-index').delete; sleep 0.1 }
10
+
11
+ should "create and return the default mapping" do
12
+
13
+ index = Tire.index 'mapped-index' do
14
+ create
15
+ store :type => :article, :title => 'One'
16
+ refresh
17
+ sleep 1
18
+ end
19
+
20
+ assert_equal 'string', index.mapping['article']['properties']['title']['type'], index.mapping.inspect
21
+ assert_nil index.mapping['article']['properties']['title']['boost'], index.mapping.inspect
22
+ end
23
+ end
24
+
25
+ context "Creating index with mapping" do
26
+ teardown { Tire.index('mapped-index').delete; sleep 0.1 }
27
+
28
+ should "create the specified mapping" do
29
+
30
+ index = Tire.index 'mapped-index' do
31
+ create :mappings => { :article => { :properties => { :title => { :type => 'string', :boost => 2.0, :store => 'yes' } } } }
32
+ end
33
+
34
+ # p index.mapping
35
+ assert_equal 2.0, index.mapping['article']['properties']['title']['boost'], index.mapping.inspect
36
+ assert_equal 'yes', index.mapping['article']['properties']['title']['store'], index.mapping.inspect
37
+
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,96 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class IndexStoreIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Storing the documents in index" do
9
+
10
+ setup do
11
+ Tire.index 'articles-test-ids' do
12
+ delete
13
+ create
14
+
15
+ store :id => 1, :title => 'One'
16
+ store :id => 2, :title => 'Two'
17
+ store :id => 3, :title => 'Three'
18
+ store :id => 4, :title => 'Four'
19
+ store :id => 4, :title => 'Four'
20
+
21
+ refresh
22
+ end
23
+ end
24
+
25
+ teardown { Tire.index('articles-test-ids').delete }
26
+
27
+ should "happen in existing index" do
28
+ assert Tire.index("articles-test-ids").exists?
29
+ assert ! Tire.index("four-oh-four-index").exists?
30
+ end
31
+
32
+ should "store hashes under their IDs" do
33
+ s = Tire.search('articles-test-ids') { query { string '*' } }
34
+
35
+ assert_equal 4, s.results.count
36
+
37
+ document = Tire.index('articles-test-ids').retrieve :document, 4
38
+ assert_equal 'Four', document.title
39
+ assert_equal 2, document._version.to_i
40
+
41
+ end
42
+
43
+ end
44
+
45
+ context "Removing documents from the index" do
46
+
47
+ teardown { Tire.index('articles-test-remove').delete }
48
+
49
+ setup do
50
+ Tire.index 'articles-test-remove' do
51
+ delete
52
+ create
53
+ store :id => 1, :title => 'One'
54
+ store :id => 2, :title => 'Two'
55
+ refresh
56
+ end
57
+ end
58
+
59
+ should "remove document from the index" do
60
+ assert_equal 2, Tire.search('articles-test-remove') { query { string '*' } }.results.count
61
+
62
+ assert_nothing_raised do
63
+ assert Tire.index('articles-test-remove').remove 1
64
+ assert ! Tire.index('articles-test-remove').remove(1)
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ context "Retrieving documents from the index" do
71
+
72
+ teardown { Tire.index('articles-test-retrieve').delete }
73
+
74
+ setup do
75
+ Tire.index 'articles-test-retrieve' do
76
+ delete
77
+ create
78
+ store :id => 1, :title => 'One'
79
+ store :id => 2, :title => 'Two'
80
+ refresh
81
+ end
82
+ end
83
+
84
+ should "retrieve document from the index" do
85
+ assert_instance_of Tire::Results::Item, Tire.index('articles-test-retrieve').retrieve(:document, 1)
86
+ end
87
+
88
+ should "return nil when retrieving missing document" do
89
+ assert_nil Tire.index('articles-test-retrieve').retrieve :document, 4
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
96
+ end