searchkick 2.3.2 → 5.2.1

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.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +377 -84
  3. data/LICENSE.txt +1 -1
  4. data/README.md +859 -602
  5. data/lib/searchkick/bulk_reindex_job.rb +13 -9
  6. data/lib/searchkick/controller_runtime.rb +40 -0
  7. data/lib/searchkick/hash_wrapper.rb +12 -0
  8. data/lib/searchkick/index.rb +281 -356
  9. data/lib/searchkick/index_cache.rb +30 -0
  10. data/lib/searchkick/index_options.rb +487 -281
  11. data/lib/searchkick/indexer.rb +15 -8
  12. data/lib/searchkick/log_subscriber.rb +57 -0
  13. data/lib/searchkick/middleware.rb +9 -2
  14. data/lib/searchkick/model.rb +72 -118
  15. data/lib/searchkick/multi_search.rb +9 -10
  16. data/lib/searchkick/process_batch_job.rb +12 -15
  17. data/lib/searchkick/process_queue_job.rb +22 -13
  18. data/lib/searchkick/query.rb +458 -217
  19. data/lib/searchkick/railtie.rb +7 -0
  20. data/lib/searchkick/record_data.rb +128 -0
  21. data/lib/searchkick/record_indexer.rb +164 -0
  22. data/lib/searchkick/reindex_queue.rb +51 -9
  23. data/lib/searchkick/reindex_v2_job.rb +10 -32
  24. data/lib/searchkick/relation.rb +247 -0
  25. data/lib/searchkick/relation_indexer.rb +155 -0
  26. data/lib/searchkick/results.rb +201 -82
  27. data/lib/searchkick/version.rb +1 -1
  28. data/lib/searchkick/where.rb +11 -0
  29. data/lib/searchkick.rb +269 -97
  30. data/lib/tasks/searchkick.rake +37 -0
  31. metadata +24 -178
  32. data/.gitignore +0 -22
  33. data/.travis.yml +0 -39
  34. data/Gemfile +0 -16
  35. data/Rakefile +0 -20
  36. data/benchmark/Gemfile +0 -23
  37. data/benchmark/benchmark.rb +0 -97
  38. data/lib/searchkick/logging.rb +0 -242
  39. data/lib/searchkick/tasks.rb +0 -33
  40. data/searchkick.gemspec +0 -28
  41. data/test/aggs_test.rb +0 -197
  42. data/test/autocomplete_test.rb +0 -75
  43. data/test/boost_test.rb +0 -202
  44. data/test/callbacks_test.rb +0 -59
  45. data/test/ci/before_install.sh +0 -17
  46. data/test/errors_test.rb +0 -19
  47. data/test/gemfiles/activerecord31.gemfile +0 -7
  48. data/test/gemfiles/activerecord32.gemfile +0 -7
  49. data/test/gemfiles/activerecord40.gemfile +0 -8
  50. data/test/gemfiles/activerecord41.gemfile +0 -8
  51. data/test/gemfiles/activerecord42.gemfile +0 -7
  52. data/test/gemfiles/activerecord50.gemfile +0 -7
  53. data/test/gemfiles/apartment.gemfile +0 -8
  54. data/test/gemfiles/cequel.gemfile +0 -8
  55. data/test/gemfiles/mongoid2.gemfile +0 -7
  56. data/test/gemfiles/mongoid3.gemfile +0 -6
  57. data/test/gemfiles/mongoid4.gemfile +0 -7
  58. data/test/gemfiles/mongoid5.gemfile +0 -7
  59. data/test/gemfiles/mongoid6.gemfile +0 -12
  60. data/test/gemfiles/nobrainer.gemfile +0 -8
  61. data/test/gemfiles/parallel_tests.gemfile +0 -8
  62. data/test/geo_shape_test.rb +0 -175
  63. data/test/highlight_test.rb +0 -78
  64. data/test/index_test.rb +0 -166
  65. data/test/inheritance_test.rb +0 -83
  66. data/test/marshal_test.rb +0 -8
  67. data/test/match_test.rb +0 -276
  68. data/test/misspellings_test.rb +0 -56
  69. data/test/model_test.rb +0 -42
  70. data/test/multi_search_test.rb +0 -36
  71. data/test/multi_tenancy_test.rb +0 -22
  72. data/test/order_test.rb +0 -46
  73. data/test/pagination_test.rb +0 -70
  74. data/test/partial_reindex_test.rb +0 -58
  75. data/test/query_test.rb +0 -35
  76. data/test/records_test.rb +0 -10
  77. data/test/reindex_test.rb +0 -64
  78. data/test/reindex_v2_job_test.rb +0 -32
  79. data/test/routing_test.rb +0 -23
  80. data/test/should_index_test.rb +0 -32
  81. data/test/similar_test.rb +0 -28
  82. data/test/sql_test.rb +0 -214
  83. data/test/suggest_test.rb +0 -95
  84. data/test/support/kaminari.yml +0 -21
  85. data/test/synonyms_test.rb +0 -67
  86. data/test/test_helper.rb +0 -567
  87. data/test/where_test.rb +0 -223
@@ -1,242 +0,0 @@
1
- # based on https://gist.github.com/mnutt/566725
2
- require "active_support/core_ext/module/attr_internal"
3
-
4
- module Searchkick
5
- module QueryWithInstrumentation
6
- def execute_search
7
- name = searchkick_klass ? "#{searchkick_klass.name} Search" : "Search"
8
- event = {
9
- name: name,
10
- query: params
11
- }
12
- ActiveSupport::Notifications.instrument("search.searchkick", event) do
13
- super
14
- end
15
- end
16
- end
17
-
18
- module IndexWithInstrumentation
19
- def store(record)
20
- event = {
21
- name: "#{record.searchkick_klass.name} Store",
22
- id: search_id(record)
23
- }
24
- if Searchkick.callbacks_value == :bulk
25
- super
26
- else
27
- ActiveSupport::Notifications.instrument("request.searchkick", event) do
28
- super
29
- end
30
- end
31
- end
32
-
33
- def remove(record)
34
- name = record && record.searchkick_klass ? "#{record.searchkick_klass.name} Remove" : "Remove"
35
- event = {
36
- name: name,
37
- id: search_id(record)
38
- }
39
- if Searchkick.callbacks_value == :bulk
40
- super
41
- else
42
- ActiveSupport::Notifications.instrument("request.searchkick", event) do
43
- super
44
- end
45
- end
46
- end
47
-
48
- def update_record(record, method_name)
49
- event = {
50
- name: "#{record.searchkick_klass.name} Update",
51
- id: search_id(record)
52
- }
53
- if Searchkick.callbacks_value == :bulk
54
- super
55
- else
56
- ActiveSupport::Notifications.instrument("request.searchkick", event) do
57
- super
58
- end
59
- end
60
- end
61
-
62
- def bulk_index(records)
63
- if records.any?
64
- event = {
65
- name: "#{records.first.searchkick_klass.name} Import",
66
- count: records.size
67
- }
68
- event[:id] = search_id(records.first) if records.size == 1
69
- if Searchkick.callbacks_value == :bulk
70
- super
71
- else
72
- ActiveSupport::Notifications.instrument("request.searchkick", event) do
73
- super
74
- end
75
- end
76
- end
77
- end
78
- alias_method :import, :bulk_index
79
-
80
- def bulk_update(records, *args)
81
- if records.any?
82
- event = {
83
- name: "#{records.first.searchkick_klass.name} Update",
84
- count: records.size
85
- }
86
- event[:id] = search_id(records.first) if records.size == 1
87
- if Searchkick.callbacks_value == :bulk
88
- super
89
- else
90
- ActiveSupport::Notifications.instrument("request.searchkick", event) do
91
- super
92
- end
93
- end
94
- end
95
- end
96
-
97
- def bulk_delete(records)
98
- if records.any?
99
- event = {
100
- name: "#{records.first.searchkick_klass.name} Delete",
101
- count: records.size
102
- }
103
- event[:id] = search_id(records.first) if records.size == 1
104
- if Searchkick.callbacks_value == :bulk
105
- super
106
- else
107
- ActiveSupport::Notifications.instrument("request.searchkick", event) do
108
- super
109
- end
110
- end
111
- end
112
- end
113
- end
114
-
115
- module IndexerWithInstrumentation
116
- def perform
117
- if Searchkick.callbacks_value == :bulk
118
- event = {
119
- name: "Bulk",
120
- count: queued_items.size
121
- }
122
- ActiveSupport::Notifications.instrument("request.searchkick", event) do
123
- super
124
- end
125
- else
126
- super
127
- end
128
- end
129
- end
130
-
131
- module SearchkickWithInstrumentation
132
- def multi_search(searches, **options)
133
- event = {
134
- name: "Multi Search",
135
- body: searches.flat_map { |q| [q.params.except(:body).to_json, q.body.to_json] }.map { |v| "#{v}\n" }.join
136
- }
137
- ActiveSupport::Notifications.instrument("multi_search.searchkick", event) do
138
- super
139
- end
140
- end
141
- end
142
-
143
- # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/log_subscriber.rb
144
- class LogSubscriber < ActiveSupport::LogSubscriber
145
- def self.runtime=(value)
146
- Thread.current[:searchkick_runtime] = value
147
- end
148
-
149
- def self.runtime
150
- Thread.current[:searchkick_runtime] ||= 0
151
- end
152
-
153
- def self.reset_runtime
154
- rt = runtime
155
- self.runtime = 0
156
- rt
157
- end
158
-
159
- def search(event)
160
- self.class.runtime += event.duration
161
- return unless logger.debug?
162
-
163
- payload = event.payload
164
- name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
165
- type = payload[:query][:type]
166
- index = payload[:query][:index].is_a?(Array) ? payload[:query][:index].join(",") : payload[:query][:index]
167
-
168
- # no easy way to tell which host the client will use
169
- host = Searchkick.client.transport.hosts.first
170
- debug " #{color(name, YELLOW, true)} curl #{host[:protocol]}://#{host[:host]}:#{host[:port]}/#{CGI.escape(index)}#{type ? "/#{type.map { |t| CGI.escape(t) }.join(',')}" : ''}/_search?pretty -d '#{payload[:query][:body].to_json}'"
171
- end
172
-
173
- def request(event)
174
- self.class.runtime += event.duration
175
- return unless logger.debug?
176
-
177
- payload = event.payload
178
- name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
179
-
180
- debug " #{color(name, YELLOW, true)} #{payload.except(:name).to_json}"
181
- end
182
-
183
- def multi_search(event)
184
- self.class.runtime += event.duration
185
- return unless logger.debug?
186
-
187
- payload = event.payload
188
- name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
189
-
190
- # no easy way to tell which host the client will use
191
- host = Searchkick.client.transport.hosts.first
192
- debug " #{color(name, YELLOW, true)} curl #{host[:protocol]}://#{host[:host]}:#{host[:port]}/_msearch?pretty -d '#{payload[:body]}'"
193
- end
194
- end
195
-
196
- # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/controller_runtime.rb
197
- module ControllerRuntime
198
- extend ActiveSupport::Concern
199
-
200
- protected
201
-
202
- attr_internal :searchkick_runtime
203
-
204
- def process_action(action, *args)
205
- # We also need to reset the runtime before each action
206
- # because of queries in middleware or in cases we are streaming
207
- # and it won't be cleaned up by the method below.
208
- Searchkick::LogSubscriber.reset_runtime
209
- super
210
- end
211
-
212
- def cleanup_view_runtime
213
- searchkick_rt_before_render = Searchkick::LogSubscriber.reset_runtime
214
- runtime = super
215
- searchkick_rt_after_render = Searchkick::LogSubscriber.reset_runtime
216
- self.searchkick_runtime = searchkick_rt_before_render + searchkick_rt_after_render
217
- runtime - searchkick_rt_after_render
218
- end
219
-
220
- def append_info_to_payload(payload)
221
- super
222
- payload[:searchkick_runtime] = (searchkick_runtime || 0) + Searchkick::LogSubscriber.reset_runtime
223
- end
224
-
225
- module ClassMethods
226
- def log_process_action(payload)
227
- messages = super
228
- runtime = payload[:searchkick_runtime]
229
- messages << ("Searchkick: %.1fms" % runtime.to_f) if runtime.to_f > 0
230
- messages
231
- end
232
- end
233
- end
234
- end
235
- Searchkick::Query.send(:prepend, Searchkick::QueryWithInstrumentation)
236
- Searchkick::Index.send(:prepend, Searchkick::IndexWithInstrumentation)
237
- Searchkick::Indexer.send(:prepend, Searchkick::IndexerWithInstrumentation)
238
- Searchkick.singleton_class.send(:prepend, Searchkick::SearchkickWithInstrumentation)
239
- Searchkick::LogSubscriber.attach_to :searchkick
240
- ActiveSupport.on_load(:action_controller) do
241
- include Searchkick::ControllerRuntime
242
- end
@@ -1,33 +0,0 @@
1
- require "rake"
2
-
3
- namespace :searchkick do
4
- desc "reindex model"
5
- task reindex: :environment do
6
- if ENV["CLASS"]
7
- klass = ENV["CLASS"].constantize rescue nil
8
- if klass
9
- klass.reindex
10
- else
11
- abort "Could not find class: #{ENV['CLASS']}"
12
- end
13
- else
14
- abort "USAGE: rake searchkick:reindex CLASS=Product"
15
- end
16
- end
17
-
18
- if defined?(Rails)
19
-
20
- namespace :reindex do
21
- desc "reindex all models"
22
- task all: :environment do
23
- Rails.application.eager_load!
24
- Searchkick.models.each do |model|
25
- puts "Reindexing #{model.name}..."
26
- model.reindex
27
- end
28
- puts "Reindex complete"
29
- end
30
- end
31
-
32
- end
33
- end
data/searchkick.gemspec DELETED
@@ -1,28 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "searchkick/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "searchkick"
8
- spec.version = Searchkick::VERSION
9
- spec.authors = ["Andrew Kane"]
10
- spec.email = ["andrew@chartkick.com"]
11
- spec.description = "Intelligent search made easy"
12
- spec.summary = "Searchkick learns what your users are looking for. As more people search, it gets smarter and the results get better. It’s friendly for developers - and magical for your users."
13
- spec.homepage = "https://github.com/ankane/searchkick"
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features|benchmark)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_dependency "activemodel", ">= 4.1"
22
- spec.add_dependency "elasticsearch", ">= 1"
23
- spec.add_dependency "hashie"
24
-
25
- spec.add_development_dependency "bundler"
26
- spec.add_development_dependency "rake"
27
- spec.add_development_dependency "minitest"
28
- end
data/test/aggs_test.rb DELETED
@@ -1,197 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class AggsTest < Minitest::Test
4
- def setup
5
- super
6
- store [
7
- {name: "Product Show", latitude: 37.7833, longitude: 12.4167, store_id: 1, in_stock: true, color: "blue", price: 21, created_at: 2.days.ago},
8
- {name: "Product Hide", latitude: 29.4167, longitude: -98.5000, store_id: 2, in_stock: false, color: "green", price: 25, created_at: 2.days.from_now},
9
- {name: "Product B", latitude: 43.9333, longitude: -122.4667, store_id: 2, in_stock: false, color: "red", price: 5, created_at: Time.now},
10
- {name: "Foo", latitude: 43.9333, longitude: 12.4667, store_id: 3, in_stock: false, color: "yellow", price: 15, created_at: Time.now}
11
- ]
12
- end
13
-
14
- def test_basic
15
- assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: [:store_id])
16
- end
17
-
18
- def test_where
19
- assert_equal ({1 => 1}), store_agg(aggs: {store_id: {where: {in_stock: true}}})
20
- end
21
-
22
- def test_order
23
- agg = Product.search("Product", aggs: {color: {order: {"_term" => "desc"}}}).aggs["color"]
24
- assert_equal %w(red green blue), agg["buckets"].map { |b| b["key"] }
25
- end
26
-
27
- def test_field
28
- assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: {store_id: {}})
29
- assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: {store_id: {field: "store_id"}})
30
- assert_equal ({1 => 1, 2 => 2}), store_agg({aggs: {store_id_new: {field: "store_id"}}}, "store_id_new")
31
- end
32
-
33
- def test_min_doc_count
34
- assert_equal ({2 => 2}), store_agg(aggs: {store_id: {min_doc_count: 2}})
35
- end
36
-
37
- def test_no_aggs
38
- assert_nil Product.search("*").aggs
39
- end
40
-
41
- def test_limit
42
- agg = Product.search("Product", aggs: {store_id: {limit: 1}}).aggs["store_id"]
43
- assert_equal 1, agg["buckets"].size
44
- # assert_equal 3, agg["doc_count"]
45
- assert_equal(1, agg["sum_other_doc_count"])
46
- end
47
-
48
- def test_ranges
49
- price_ranges = [{to: 10}, {from: 10, to: 20}, {from: 20}]
50
- agg = Product.search("Product", aggs: {price: {ranges: price_ranges}}).aggs["price"]
51
-
52
- assert_equal 3, agg["buckets"].size
53
- assert_equal 10.0, agg["buckets"][0]["to"]
54
- assert_equal 20.0, agg["buckets"][2]["from"]
55
- assert_equal 1, agg["buckets"][0]["doc_count"]
56
- assert_equal 0, agg["buckets"][1]["doc_count"]
57
- assert_equal 2, agg["buckets"][2]["doc_count"]
58
- end
59
-
60
- def test_date_ranges
61
- ranges = [{to: 1.day.ago}, {from: 1.day.ago, to: 1.day.from_now}, {from: 1.day.from_now}]
62
- agg = Product.search("Product", aggs: {created_at: {date_ranges: ranges}}).aggs["created_at"]
63
-
64
- assert_equal 1, agg["buckets"][0]["doc_count"]
65
- assert_equal 1, agg["buckets"][1]["doc_count"]
66
- assert_equal 1, agg["buckets"][2]["doc_count"]
67
- end
68
-
69
- def test_query_where
70
- assert_equal ({1 => 1}), store_agg(where: {in_stock: true}, aggs: [:store_id])
71
- end
72
-
73
- def test_two_wheres
74
- assert_equal ({2 => 1}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false}}})
75
- end
76
-
77
- def test_where_override
78
- assert_equal ({}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false, color: "blue"}}})
79
- assert_equal ({2 => 1}), store_agg(where: {color: "blue"}, aggs: {store_id: {where: {in_stock: false, color: "red"}}})
80
- end
81
-
82
- def test_skip
83
- assert_equal ({1 => 1, 2 => 2}), store_agg(where: {store_id: 2}, aggs: [:store_id])
84
- end
85
-
86
- def test_skip_complex
87
- assert_equal ({1 => 1, 2 => 1}), store_agg(where: {store_id: 2, price: {gt: 5}}, aggs: [:store_id])
88
- end
89
-
90
- def test_multiple
91
- assert_equal ({"store_id" => {1 => 1, 2 => 2}, "color" => {"blue" => 1, "green" => 1, "red" => 1}}), store_multiple_aggs(aggs: [:store_id, :color])
92
- end
93
-
94
- def test_smart_aggs_false
95
- assert_equal ({2 => 2}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false}}}, smart_aggs: false)
96
- assert_equal ({2 => 2}), store_agg(where: {color: "blue"}, aggs: {store_id: {where: {in_stock: false}}}, smart_aggs: false)
97
- end
98
-
99
- def test_aggs_group_by_date
100
- store [{name: "Old Product", created_at: 3.years.ago}]
101
- products =
102
- Product.search("Product", {
103
- where: {
104
- created_at: {lt: Time.now}
105
- },
106
- aggs: {
107
- products_per_year: {
108
- date_histogram: {
109
- field: :created_at,
110
- interval: :year
111
- }
112
- }
113
- }
114
- })
115
-
116
- assert_equal 4, products.aggs["products_per_year"]["buckets"].size
117
- end
118
-
119
- def test_aggs_avg
120
- products =
121
- Product.search("*", {
122
- aggs: {
123
- avg_price: {
124
- avg: {
125
- field: :price
126
- }
127
- }
128
- }
129
- })
130
- assert_equal 16.5, products.aggs["avg_price"]["value"]
131
- end
132
-
133
- def test_aggs_cardinality
134
- products =
135
- Product.search("*", {
136
- aggs: {
137
- total_stores: {
138
- cardinality: {
139
- field: :store_id
140
- }
141
- }
142
- }
143
- })
144
- assert_equal 3, products.aggs["total_stores"]["value"]
145
- end
146
-
147
- def test_aggs_min_max
148
- products =
149
- Product.search("*", {
150
- aggs: {
151
- min_price: {
152
- min: {
153
- field: :price
154
- }
155
- },
156
- max_price: {
157
- max: {
158
- field: :price
159
- }
160
- }
161
- }
162
- })
163
- assert_equal 5, products.aggs["min_price"]["value"]
164
- assert_equal 25, products.aggs["max_price"]["value"]
165
- end
166
-
167
- def test_aggs_sum
168
- products =
169
- Product.search("*", {
170
- aggs: {
171
- sum_price: {
172
- sum: {
173
- field: :price
174
- }
175
- }
176
- }
177
- })
178
- assert_equal 66, products.aggs["sum_price"]["value"]
179
- end
180
-
181
- protected
182
-
183
- def buckets_as_hash(agg)
184
- Hash[agg["buckets"].map { |v| [v["key"], v["doc_count"]] }]
185
- end
186
-
187
- def store_agg(options, agg_key = "store_id")
188
- buckets = Product.search("Product", options).aggs[agg_key]
189
- buckets_as_hash(buckets)
190
- end
191
-
192
- def store_multiple_aggs(options)
193
- Hash[Product.search("Product", options).aggs.map do |field, filtered_agg|
194
- [field, buckets_as_hash(filtered_agg)]
195
- end]
196
- end
197
- end
@@ -1,75 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class AutocompleteTest < Minitest::Test
4
- def test_autocomplete
5
- store_names ["Hummus"]
6
- assert_search "hum", ["Hummus"], match: :text_start
7
- end
8
-
9
- def test_autocomplete_two_words
10
- store_names ["Organic Hummus"]
11
- assert_search "hum", [], match: :text_start
12
- end
13
-
14
- def test_autocomplete_fields
15
- store_names ["Hummus"]
16
- assert_search "hum", ["Hummus"], match: :text_start, fields: [:name]
17
- end
18
-
19
- def test_text_start
20
- store_names ["Where in the World is Carmen San Diego"]
21
- assert_search "where in the world is", ["Where in the World is Carmen San Diego"], fields: [{name: :text_start}]
22
- assert_search "in the world", [], fields: [{name: :text_start}]
23
- end
24
-
25
- def test_text_middle
26
- store_names ["Where in the World is Carmen San Diego"]
27
- assert_search "where in the world is", ["Where in the World is Carmen San Diego"], fields: [{name: :text_middle}]
28
- assert_search "n the wor", ["Where in the World is Carmen San Diego"], fields: [{name: :text_middle}]
29
- assert_search "men san diego", ["Where in the World is Carmen San Diego"], fields: [{name: :text_middle}]
30
- assert_search "world carmen", [], fields: [{name: :text_middle}]
31
- end
32
-
33
- def test_text_end
34
- store_names ["Where in the World is Carmen San Diego"]
35
- assert_search "men san diego", ["Where in the World is Carmen San Diego"], fields: [{name: :text_end}]
36
- assert_search "carmen san", [], fields: [{name: :text_end}]
37
- end
38
-
39
- def test_word_start
40
- store_names ["Where in the World is Carmen San Diego"]
41
- assert_search "car san wor", ["Where in the World is Carmen San Diego"], fields: [{name: :word_start}]
42
- end
43
-
44
- def test_word_middle
45
- store_names ["Where in the World is Carmen San Diego"]
46
- assert_search "orl", ["Where in the World is Carmen San Diego"], fields: [{name: :word_middle}]
47
- end
48
-
49
- def test_word_end
50
- store_names ["Where in the World is Carmen San Diego"]
51
- assert_search "rld men ego", ["Where in the World is Carmen San Diego"], fields: [{name: :word_end}]
52
- end
53
-
54
- def test_word_start_multiple_words
55
- store_names ["Dark Grey", "Dark Blue"]
56
- assert_search "dark grey", ["Dark Grey"], fields: [{name: :word_start}]
57
- end
58
-
59
- def test_word_start_exact
60
- store_names ["Back Scratcher", "Backpack"]
61
- assert_order "back", ["Back Scratcher", "Backpack"], fields: [{name: :word_start}]
62
- end
63
-
64
- def test_word_start_exact_martin
65
- store_names ["Martina", "Martin"]
66
- assert_order "martin", ["Martin", "Martina"], fields: [{name: :word_start}]
67
- end
68
-
69
- # TODO find a better place
70
-
71
- def test_exact
72
- store_names ["hi@example.org"]
73
- assert_search "hi@example.org", ["hi@example.org"], fields: [{name: :exact}]
74
- end
75
- end