searchkick-sinneduy 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +28 -0
  4. data/CHANGELOG.md +272 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +1109 -0
  8. data/Rakefile +8 -0
  9. data/ci/before_install.sh +14 -0
  10. data/gemfiles/activerecord31.gemfile +7 -0
  11. data/gemfiles/activerecord32.gemfile +7 -0
  12. data/gemfiles/activerecord40.gemfile +8 -0
  13. data/gemfiles/activerecord41.gemfile +8 -0
  14. data/gemfiles/mongoid2.gemfile +7 -0
  15. data/gemfiles/mongoid3.gemfile +6 -0
  16. data/gemfiles/mongoid4.gemfile +7 -0
  17. data/gemfiles/nobrainer.gemfile +6 -0
  18. data/lib/searchkick.rb +72 -0
  19. data/lib/searchkick/index.rb +550 -0
  20. data/lib/searchkick/logging.rb +136 -0
  21. data/lib/searchkick/model.rb +102 -0
  22. data/lib/searchkick/query.rb +567 -0
  23. data/lib/searchkick/reindex_job.rb +28 -0
  24. data/lib/searchkick/reindex_v2_job.rb +24 -0
  25. data/lib/searchkick/results.rb +158 -0
  26. data/lib/searchkick/tasks.rb +35 -0
  27. data/lib/searchkick/version.rb +3 -0
  28. data/searchkick.gemspec +28 -0
  29. data/test/autocomplete_test.rb +67 -0
  30. data/test/boost_test.rb +126 -0
  31. data/test/facets_test.rb +91 -0
  32. data/test/highlight_test.rb +58 -0
  33. data/test/index_test.rb +119 -0
  34. data/test/inheritance_test.rb +80 -0
  35. data/test/match_test.rb +163 -0
  36. data/test/model_test.rb +38 -0
  37. data/test/query_test.rb +14 -0
  38. data/test/reindex_job_test.rb +33 -0
  39. data/test/reindex_v2_job_test.rb +34 -0
  40. data/test/routing_test.rb +14 -0
  41. data/test/should_index_test.rb +34 -0
  42. data/test/similar_test.rb +20 -0
  43. data/test/sql_test.rb +327 -0
  44. data/test/suggest_test.rb +82 -0
  45. data/test/synonyms_test.rb +50 -0
  46. data/test/test_helper.rb +276 -0
  47. metadata +194 -0
@@ -0,0 +1,38 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestModel < Minitest::Test
4
+
5
+ def test_disable_callbacks_model
6
+ store_names ["product a"]
7
+
8
+ Product.disable_search_callbacks
9
+ assert !Product.search_callbacks?
10
+
11
+ store_names ["product b"]
12
+ assert_search "product", ["product a"]
13
+
14
+ Product.enable_search_callbacks
15
+ Product.reindex
16
+
17
+ assert_search "product", ["product a", "product b"]
18
+ end
19
+
20
+ def test_disable_callbacks_global
21
+ # make sure callbacks default to on
22
+ assert Searchkick.callbacks?
23
+
24
+ store_names ["product a"]
25
+
26
+ Searchkick.disable_callbacks
27
+ assert !Searchkick.callbacks?
28
+
29
+ store_names ["product b"]
30
+ assert_search "product", ["product a"]
31
+
32
+ Searchkick.enable_callbacks
33
+ Product.reindex
34
+
35
+ assert_search "product", ["product a", "product b"]
36
+ end
37
+
38
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestQuery < Minitest::Test
4
+
5
+ def test_basic
6
+ store_names ["Milk", "Apple"]
7
+ query = Product.search("milk", execute: false)
8
+ # query.body = {query: {match_all: {}}}
9
+ # query.body = {query: {match: {name: "Apple"}}}
10
+ query.body[:query] = {match_all: {}}
11
+ assert_equal ["Apple", "Milk"], query.execute.map(&:name).sort
12
+ end
13
+
14
+ end
@@ -0,0 +1,33 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestReindexJob < Minitest::Test
4
+
5
+ def setup
6
+ super
7
+ Searchkick.disable_callbacks
8
+ end
9
+
10
+ def teardown
11
+ Searchkick.enable_callbacks
12
+ end
13
+
14
+ def test_create
15
+ product = Product.create!(name: "Boom")
16
+ Product.searchkick_index.refresh
17
+ assert_search "*", []
18
+ Searchkick::ReindexJob.new("Product", product.id.to_s).perform
19
+ Product.searchkick_index.refresh
20
+ assert_search "*", ["Boom"]
21
+ end
22
+
23
+ def test_destroy
24
+ product = Product.create!(name: "Boom")
25
+ Product.reindex
26
+ assert_search "*", ["Boom"]
27
+ product.destroy
28
+ Searchkick::ReindexJob.new("Product", product.id.to_s).perform
29
+ Product.searchkick_index.refresh
30
+ assert_search "*", []
31
+ end
32
+
33
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestReindexV2Job < Minitest::Test
4
+
5
+ def setup
6
+ skip unless defined?(ActiveJob)
7
+ super
8
+ Searchkick.disable_callbacks
9
+ end
10
+
11
+ def teardown
12
+ Searchkick.enable_callbacks
13
+ end
14
+
15
+ def test_create
16
+ product = Product.create!(name: "Boom")
17
+ Product.searchkick_index.refresh
18
+ assert_search "*", []
19
+ Searchkick::ReindexV2Job.perform_later("Product", product.id.to_s)
20
+ Product.searchkick_index.refresh
21
+ assert_search "*", ["Boom"]
22
+ end
23
+
24
+ def test_destroy
25
+ product = Product.create!(name: "Boom")
26
+ Product.reindex
27
+ assert_search "*", ["Boom"]
28
+ product.destroy
29
+ Searchkick::ReindexV2Job.perform_later("Product", product.id.to_s)
30
+ Product.searchkick_index.refresh
31
+ assert_search "*", []
32
+ end
33
+
34
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestRouting < Minitest::Test
4
+
5
+ def test_routing_query
6
+ query = Store.search("Dollar Tree", routing: "Dollar Tree", execute: false)
7
+ assert_equal query.params[:routing], "Dollar Tree"
8
+ end
9
+
10
+ def test_routing_mappings
11
+ index_options = Store.searchkick_index.index_options
12
+ assert_equal index_options[:mappings][:_default_][:_routing], {required: true, path: "name"}
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestShouldIndex < Minitest::Test
4
+
5
+ def test_basic
6
+ store_names ["INDEX", "DO NOT INDEX"]
7
+ assert_search "index", ["INDEX"]
8
+ end
9
+
10
+ def test_default_true
11
+ assert Animal.new.should_index?
12
+ end
13
+
14
+ def test_change_to_true
15
+ store_names ["DO NOT INDEX"]
16
+ assert_search "index", []
17
+ product = Product.first
18
+ product.name = "INDEX"
19
+ product.save!
20
+ Product.searchkick_index.refresh
21
+ assert_search "index", ["INDEX"]
22
+ end
23
+
24
+ def test_change_to_false
25
+ store_names ["INDEX"]
26
+ assert_search "index", ["INDEX"]
27
+ product = Product.first
28
+ product.name = "DO NOT INDEX"
29
+ product.save!
30
+ Product.searchkick_index.refresh
31
+ assert_search "index", []
32
+ end
33
+
34
+ end
@@ -0,0 +1,20 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestSimilar < Minitest::Test
4
+
5
+ def test_similar
6
+ store_names ["Annie's Naturals Organic Shiitake & Sesame Dressing"]
7
+ assert_search "Annie's Naturals Shiitake & Sesame Vinaigrette", ["Annie's Naturals Organic Shiitake & Sesame Dressing"], similar: true
8
+ end
9
+
10
+ def test_fields
11
+ store_names ["1% Organic Milk", "2% Organic Milk", "Popcorn"]
12
+ assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"]).map(&:name)
13
+ end
14
+
15
+ def test_order
16
+ store_names ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"]
17
+ assert_order "Lucerne Fat Free Chocolate Milk", ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"], similar: true
18
+ end
19
+
20
+ end
@@ -0,0 +1,327 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestSql < Minitest::Test
4
+
5
+ def test_limit
6
+ store_names ["Product A", "Product B", "Product C", "Product D"]
7
+ assert_order "product", ["Product A", "Product B"], order: {name: :asc}, limit: 2
8
+ end
9
+
10
+ def test_no_limit
11
+ names = 20.times.map { |i| "Product #{i}" }
12
+ store_names names
13
+ assert_search "product", names
14
+ end
15
+
16
+ def test_offset
17
+ store_names ["Product A", "Product B", "Product C", "Product D"]
18
+ assert_order "product", ["Product C", "Product D"], order: {name: :asc}, offset: 2
19
+ end
20
+
21
+ def test_pagination
22
+ store_names ["Product A", "Product B", "Product C", "Product D", "Product E", "Product F"]
23
+ products = Product.search("product", order: {name: :asc}, page: 2, per_page: 2, padding: 1)
24
+ assert_equal ["Product D", "Product E"], products.map(&:name)
25
+ assert_equal "product", products.entry_name
26
+ assert_equal 2, products.current_page
27
+ assert_equal 1, products.padding
28
+ assert_equal 2, products.per_page
29
+ assert_equal 2, products.size
30
+ assert_equal 2, products.length
31
+ assert_equal 3, products.total_pages
32
+ assert_equal 6, products.total_count
33
+ assert_equal 6, products.total_entries
34
+ assert_equal 2, products.limit_value
35
+ assert_equal 3, products.offset_value
36
+ assert_equal 3, products.offset
37
+ assert_equal 3, products.next_page
38
+ assert_equal 1, products.previous_page
39
+ assert_equal 1, products.prev_page
40
+ assert !products.first_page?
41
+ assert !products.last_page?
42
+ assert !products.empty?
43
+ assert products.any?
44
+ end
45
+
46
+ def test_pagination_nil_page
47
+ store_names ["Product A", "Product B", "Product C", "Product D", "Product E"]
48
+ products = Product.search("product", order: {name: :asc}, page: nil, per_page: 2)
49
+ assert_equal ["Product A", "Product B"], products.map(&:name)
50
+ assert_equal 1, products.current_page
51
+ assert products.first_page?
52
+ end
53
+
54
+ def test_where
55
+ now = Time.now
56
+ store [
57
+ {name: "Product A", store_id: 1, in_stock: true, backordered: true, created_at: now, orders_count: 4, user_ids: [1, 2, 3]},
58
+ {name: "Product B", store_id: 2, in_stock: true, backordered: false, created_at: now - 1, orders_count: 3, user_ids: [1]},
59
+ {name: "Product C", store_id: 3, in_stock: false, backordered: true, created_at: now - 2, orders_count: 2, user_ids: [1, 3]},
60
+ {name: "Product D", store_id: 4, in_stock: false, backordered: false, created_at: now - 3, orders_count: 1}
61
+ ]
62
+ assert_search "product", ["Product A", "Product B"], where: {in_stock: true}
63
+ # date
64
+ assert_search "product", ["Product A"], where: {created_at: {gt: now - 1}}
65
+ assert_search "product", ["Product A", "Product B"], where: {created_at: {gte: now - 1}}
66
+ assert_search "product", ["Product D"], where: {created_at: {lt: now - 2}}
67
+ assert_search "product", ["Product C", "Product D"], where: {created_at: {lte: now - 2}}
68
+ # integer
69
+ assert_search "product", ["Product A"], where: {store_id: {lt: 2}}
70
+ assert_search "product", ["Product A", "Product B"], where: {store_id: {lte: 2}}
71
+ assert_search "product", ["Product D"], where: {store_id: {gt: 3}}
72
+ assert_search "product", ["Product C", "Product D"], where: {store_id: {gte: 3}}
73
+ # range
74
+ assert_search "product", ["Product A", "Product B"], where: {store_id: 1..2}
75
+ assert_search "product", ["Product A"], where: {store_id: 1...2}
76
+ assert_search "product", ["Product A", "Product B"], where: {store_id: [1, 2]}
77
+ assert_search "product", ["Product B", "Product C", "Product D"], where: {store_id: {not: 1}}
78
+ assert_search "product", ["Product C", "Product D"], where: {store_id: {not: [1, 2]}}
79
+ assert_search "product", ["Product A"], where: {user_ids: {lte: 2, gte: 2}}
80
+ # or
81
+ assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{in_stock: true}, {store_id: 3}]]}
82
+ assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{orders_count: [2, 4]}, {store_id: [1, 2]}]]}
83
+ assert_search "product", ["Product A", "Product D"], where: {or: [[{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]]}
84
+ # all
85
+ assert_search "product", ["Product A", "Product C"], where: {user_ids: {all: [1, 3]}}
86
+ assert_search "product", [], where: {user_ids: {all: [1, 2, 3, 4]}}
87
+ # any / nested terms
88
+ assert_search "product", ["Product B", "Product C"], where: {user_ids: {not: [2], in: [1, 3]}}
89
+ # not / exists
90
+ assert_search "product", ["Product D"], where: {user_ids: nil}
91
+ assert_search "product", ["Product A", "Product B", "Product C"], where: {user_ids: {not: nil}}
92
+ assert_search "product", ["Product A", "Product C", "Product D"], where: {user_ids: [3, nil]}
93
+ assert_search "product", ["Product B"], where: {user_ids: {not: [3, nil]}}
94
+ end
95
+
96
+ def test_regexp
97
+ store_names ["Product A"]
98
+ assert_search "*", ["Product A"], where: {name: /Pro.+/}
99
+ end
100
+
101
+ def test_where_string
102
+ store [
103
+ {name: "Product A", color: "RED"}
104
+ ]
105
+ assert_search "product", ["Product A"], where: {color: "RED"}
106
+ end
107
+
108
+ def test_where_nil
109
+ store [
110
+ {name: "Product A"},
111
+ {name: "Product B", color: "red"}
112
+ ]
113
+ assert_search "product", ["Product A"], where: {color: nil}
114
+ end
115
+
116
+ def test_where_id
117
+ store_names ["Product A"]
118
+ product = Product.last
119
+ assert_search "product", ["Product A"], where: {id: product.id.to_s}
120
+ end
121
+
122
+ def test_where_empty
123
+ store_names ["Product A"]
124
+ assert_search "product", ["Product A"], where: {}
125
+ end
126
+
127
+ def test_where_empty_array
128
+ store_names ["Product A"]
129
+ assert_search "product", [], where: {store_id: []}
130
+ end
131
+
132
+ # http://elasticsearch-users.115913.n3.nabble.com/Numeric-range-quey-or-filter-in-an-array-field-possible-or-not-td4042967.html
133
+ # https://gist.github.com/jprante/7099463
134
+ def test_where_range_array
135
+ store [
136
+ {name: "Product A", user_ids: [11, 23, 13, 16, 17, 23.6]},
137
+ {name: "Product B", user_ids: [1, 2, 3, 4, 5, 6, 7, 8, 8.9, 9.1, 9.4]},
138
+ {name: "Product C", user_ids: [101, 230, 150, 200]}
139
+ ]
140
+ assert_search "product", ["Product A"], where: {user_ids: {gt: 10, lt: 23.9}}
141
+ end
142
+
143
+ def test_where_range_array_again
144
+ store [
145
+ {name: "Product A", user_ids: [19, 32, 42]},
146
+ {name: "Product B", user_ids: [13, 40, 52]}
147
+ ]
148
+ assert_search "product", ["Product A"], where: {user_ids: {gt: 26, lt: 36}}
149
+ end
150
+
151
+ def test_near
152
+ store [
153
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
154
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
155
+ ]
156
+ assert_search "san", ["San Francisco"], where: {location: {near: [37.5, -122.5]}}
157
+ end
158
+
159
+ def test_near_within
160
+ store [
161
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
162
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
163
+ {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
164
+ ]
165
+ assert_search "san", ["San Francisco", "San Antonio"], where: {location: {near: [37, -122], within: "2000mi"}}
166
+ end
167
+
168
+ def test_top_left_bottom_right
169
+ store [
170
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
171
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
172
+ ]
173
+ assert_search "san", ["San Francisco"], where: {location: {top_left: [38, -123], bottom_right: [37, -122]}}
174
+ end
175
+
176
+ def test_multiple_locations
177
+ store [
178
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
179
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
180
+ ]
181
+ assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}}
182
+ end
183
+
184
+ def test_order_hash
185
+ store_names ["Product A", "Product B", "Product C", "Product D"]
186
+ assert_order "product", ["Product D", "Product C", "Product B", "Product A"], order: {name: :desc}
187
+ end
188
+
189
+ def test_order_string
190
+ store_names ["Product A", "Product B", "Product C", "Product D"]
191
+ assert_order "product", ["Product A", "Product B", "Product C", "Product D"], order: "name"
192
+ end
193
+
194
+ def test_order_id
195
+ store_names ["Product A", "Product B"]
196
+ product_a = Product.where(name: "Product A").first
197
+ product_b = Product.where(name: "Product B").first
198
+ assert_order "product", [product_a, product_b].sort_by(&:id).map(&:name), order: {id: :asc}
199
+ end
200
+
201
+ def test_order_multiple
202
+ store [
203
+ {name: "Product A", color: "blue", store_id: 1},
204
+ {name: "Product B", color: "red", store_id: 3},
205
+ {name: "Product C", color: "red", store_id: 2}
206
+ ]
207
+ assert_order "product", ["Product A", "Product B", "Product C"], order: {color: :asc, store_id: :desc}
208
+ end
209
+
210
+ def test_order_ignore_unmapped
211
+ assert_order "product", [], order: {not_mapped: {ignore_unmapped: true}}, conversions: false
212
+ end
213
+
214
+ def test_order_array
215
+ store [{name: "San Francisco", latitude: 37.7833, longitude: -122.4167}]
216
+ assert_order "francisco", ["San Francisco"], order: [{_geo_distance: {location: "0,0"}}], conversions: false
217
+ end
218
+
219
+ def test_partial
220
+ store_names ["Honey"]
221
+ assert_search "fresh honey", []
222
+ assert_search "fresh honey", ["Honey"], partial: true
223
+ end
224
+
225
+ def test_operator
226
+ store_names ["Honey"]
227
+ assert_search "fresh honey", []
228
+ assert_search "fresh honey", ["Honey"], operator: "or"
229
+ end
230
+
231
+ def test_misspellings
232
+ store_names ["abc", "abd", "aee"]
233
+ assert_search "abc", ["abc"], misspellings: false
234
+ end
235
+
236
+ def test_misspellings_distance
237
+ store_names ["abbb", "aabb"]
238
+ assert_search "aaaa", ["aabb"], misspellings: {distance: 2}
239
+ end
240
+
241
+ def test_fields
242
+ store [
243
+ {name: "red", color: "light blue"},
244
+ {name: "blue", color: "red fish"}
245
+ ]
246
+ assert_search "blue", ["red"], fields: ["color"]
247
+ end
248
+
249
+ def test_non_existent_field
250
+ store_names ["Milk"]
251
+ assert_search "milk", [], fields: ["not_here"]
252
+ end
253
+
254
+ def test_fields_both_match
255
+ store [
256
+ {name: "Blue A", color: "red"},
257
+ {name: "Blue B", color: "light blue"}
258
+ ]
259
+ assert_first "blue", "Blue B", fields: [:name, :color]
260
+ end
261
+
262
+ def test_big_decimal
263
+ store [
264
+ {name: "Product", latitude: 100.0}
265
+ ]
266
+ assert_search "product", ["Product"], where: {latitude: {gt: 99}}
267
+ end
268
+
269
+ # load
270
+
271
+ def test_load_default
272
+ store_names ["Product A"]
273
+ assert_kind_of Product, Product.search("product").first
274
+ end
275
+
276
+ def test_load_false
277
+ store_names ["Product A"]
278
+ assert_kind_of Hash, Product.search("product", load: false).first
279
+ end
280
+
281
+ def test_load_false_methods
282
+ store_names ["Product A"]
283
+ assert_equal "Product A", Product.search("product", load: false).first.name
284
+ end
285
+
286
+ def test_load_false_with_include
287
+ store_names ["Product A"]
288
+ assert_kind_of Hash, Product.search("product", load: false, include: [:store]).first
289
+ end
290
+
291
+ # select
292
+
293
+ def test_select
294
+ store [{name: "Product A", store_id: 1}]
295
+ result = Product.search("product", load: false, select: [:name, :store_id]).first
296
+ assert_equal %w[id name store_id], result.keys.reject { |k| k.start_with?("_") }.sort
297
+ assert_equal ["Product A"], result.name # this is not great
298
+ end
299
+
300
+ def test_select_array
301
+ store [{name: "Product A", user_ids: [1, 2]}]
302
+ result = Product.search("product", load: false, select: [:user_ids]).first
303
+ assert_equal [1, 2], result.user_ids
304
+ end
305
+
306
+ def test_select_all
307
+ store [{name: "Product A", user_ids: [1, 2]}]
308
+ hit = Product.search("product", select: true).hits.first
309
+ assert_equal hit["_source"]["name"], "Product A"
310
+ assert_equal hit["_source"]["user_ids"], [1, 2]
311
+ end
312
+
313
+ def test_nested_object
314
+ aisle = {"id" => 1, "name" => "Frozen"}
315
+ store [{name: "Product A", aisle: aisle}]
316
+ assert_equal aisle, Product.search("product", load: false).first.aisle.to_hash
317
+ end
318
+
319
+ # TODO see if Mongoid is loaded
320
+ unless defined?(Mongoid) || defined?(NoBrainer)
321
+ def test_include
322
+ store_names ["Product A"]
323
+ assert Product.search("product", include: [:store]).first.association(:store).loaded?
324
+ end
325
+ end
326
+
327
+ end