searchkick 0.3.2 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff1b17b6561440bad2ebe3c20d1606b13d579310
4
- data.tar.gz: 50475abfd988e11bca0b04385a4ec264bac80467
3
+ metadata.gz: 84aa6414f91ce1c76d0c247e9a11dfce4417c2ee
4
+ data.tar.gz: f072c08de08bac3808112ad165199b98b5b2e507
5
5
  SHA512:
6
- metadata.gz: 19e25e2f81fb811f7bf1964cb59a5deccfc6386d10640279bfe6cfb7bb81a1611691ebd6ccb8879c7dcbec4f530d5ccf2fae089e19cc8f783409985092d2315b
7
- data.tar.gz: be76d99160e570515a3120ecb517a6faef29f2b3b95eb4ebc6556cbe2839d3554faa7295ff72ccc14caf82fb817b65e2286a74377fd95137d68c6666383bc26f
6
+ metadata.gz: b866b6ba7f26bca01b13043c42ae1e9917b664be9bf77ce0c269dde30298fc8d2a08a54ce247dd465e500ebe8e122e804685ab4855984c1a09088b46422900e7
7
+ data.tar.gz: ab9bae0de9a80123cb85e0a34f221b6dce56efc91471c3037fbce10b2c7e284635291704965c1894c419e3b7610da8e1ffa4d83cde4a76039a530ef0b26e7407
data/.gitignore CHANGED
@@ -3,7 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
- Gemfile.lock
6
+ *.lock
7
7
  InstalledFiles
8
8
  _yardoc
9
9
  coverage
data/.travis.yml CHANGED
@@ -4,6 +4,7 @@ rvm:
4
4
  - 2.0.0
5
5
  services:
6
6
  - elasticsearch
7
+ - mongodb
7
8
  script: bundle exec rake test
8
9
  before_script:
9
10
  - psql -c 'create database searchkick_test;' -U postgres
@@ -11,3 +12,7 @@ notifications:
11
12
  email:
12
13
  on_success: never
13
14
  on_failure: change
15
+ gemfile:
16
+ - Gemfile
17
+ - gemfiles/mongoid3.gemfile
18
+ - gemfiles/mongoid4.gemfile
data/CHANGELOG.md CHANGED
@@ -1,3 +1,28 @@
1
+ ## 0.4.1
2
+
3
+ - Fixed issue w/ inheritance mapping
4
+
5
+ ## 0.4.0
6
+
7
+ - Added support for Mongoid 4
8
+ - Added support for multiple locations
9
+
10
+ ## 0.3.5
11
+
12
+ - Added facet ranges
13
+ - Added all operator
14
+
15
+ ## 0.3.4
16
+
17
+ - Added highlighting
18
+ - Added :distance option to misspellings
19
+ - Fixed issue w/ BigDecimal serialization
20
+
21
+ ## 0.3.3
22
+
23
+ - Better error messages
24
+ - Added where: {field: nil} queries
25
+
1
26
  ## 0.3.2
2
27
 
3
28
  - Added support for single table inheritance
data/Gemfile CHANGED
@@ -3,7 +3,5 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in searchkick.gemspec
4
4
  gemspec
5
5
 
6
- # gem "mongoid", github: "mongoid/mongoid"
7
- # gem "mongoid", "~> 3.1.0"
8
6
  # gem "activerecord", "~> 3.2.0"
9
7
  # gem "activerecord", "~> 3.1.0"
data/README.md CHANGED
@@ -29,7 +29,7 @@ Plus:
29
29
 
30
30
  ## Get Started
31
31
 
32
- [Install Elasticsearch](http://www.elasticsearch.org/guide/reference/setup/installation/). For Homebrew, use:
32
+ [Install Elasticsearch](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup.html). For Homebrew, use:
33
33
 
34
34
  ```sh
35
35
  brew install elasticsearch
@@ -87,6 +87,7 @@ where: {
87
87
  aisle_id: [25, 30], # in
88
88
  store_id: {not: 2}, # not
89
89
  aisle_id: {not: [25, 30]}, # not in
90
+ user_ids: {all: [1, 3]}, # all elements in array
90
91
  or: [
91
92
  [{in_stock: true}, {backordered: true}]
92
93
  ]
@@ -111,6 +112,14 @@ Boost by a field
111
112
  boost: "orders_count" # give popular documents a little boost
112
113
  ```
113
114
 
115
+ ### Get Everything
116
+
117
+ Use a `*` for the query.
118
+
119
+ ```ruby
120
+ Product.search "*"
121
+ ```
122
+
114
123
  ### Pagination
115
124
 
116
125
  Plays nicely with kaminari and will_paginate.
@@ -152,7 +161,13 @@ Call `Product.reindex` after changing synonyms.
152
161
  By default, Searchkick handles misspelled queries by returning results with an [edit distance](http://en.wikipedia.org/wiki/Levenshtein_distance) of one. To turn off this feature, use:
153
162
 
154
163
  ```ruby
155
- Product.search "zuchini", misspellings: false
164
+ Product.search "zuchini", misspellings: false # no zucchini
165
+ ```
166
+
167
+ You can also change the edit distance with:
168
+
169
+ ```ruby
170
+ Product.search "zucini", misspellings: {distance: 2} # zucchini
156
171
  ```
157
172
 
158
173
  ### Indexing
@@ -342,6 +357,37 @@ Advanced
342
357
  Product.search "2% Milk", facets: {store_id: {where: {in_stock: true}, limit: 10}}
343
358
  ```
344
359
 
360
+ Ranges
361
+
362
+ ```ruby
363
+ price_ranges = [{to: 20}, {from: 20, to: 50}, {from: 50}]
364
+ Product.search "*", facets: {price: {ranges: price_ranges}}
365
+ ```
366
+
367
+ ### Highlight
368
+
369
+ Highlight the search query in the results.
370
+
371
+ ```ruby
372
+ bands = Band.search "cinema", fields: [:name], highlight: true
373
+ ```
374
+
375
+ **Note:** The `fields` option is required.
376
+
377
+ View the highlighted fields with:
378
+
379
+ ```ruby
380
+ bands.with_details.each do |band, details|
381
+ puts details[:highlight][:name] # "Two Door <em>Cinema</em> Club"
382
+ end
383
+ ```
384
+
385
+ To change the tag, use:
386
+
387
+ ```ruby
388
+ Band.search "cinema", fields: [:name], highlight: {tag: "<strong>"}
389
+ ```
390
+
345
391
  ### Similar Items
346
392
 
347
393
  Find similar items.
@@ -360,7 +406,7 @@ class City < ActiveRecord::Base
360
406
  searchkick locations: ["location"]
361
407
 
362
408
  def search_data
363
- to_hash.merge location: [latitude, longitude]
409
+ attributes.merge location: [latitude, longitude]
364
410
  end
365
411
  end
366
412
  ```
@@ -377,6 +423,35 @@ Bounded by a box
377
423
  City.search "san", where: {location: {top_left: [38, -123], bottom_right: [37, -122]}}
378
424
  ```
379
425
 
426
+ ## Inheritance
427
+
428
+ Searchkick supports single table inheritance.
429
+
430
+ ```ruby
431
+ class Dog < Animal
432
+ end
433
+ ```
434
+
435
+ The parent and child model can both reindex.
436
+
437
+ ```ruby
438
+ Animal.reindex
439
+ Dog.reindex # equivalent
440
+ ```
441
+
442
+ And to search, use:
443
+
444
+ ```ruby
445
+ Animal.search "*" # all animals
446
+ Dog.search "*" # just dogs
447
+ ```
448
+
449
+ **Note:** The `suggest` option retrieves suggestions from the parent at the moment.
450
+
451
+ ```ruby
452
+ Dog.search "airbudd", suggest: true # suggestions for all animals
453
+ ```
454
+
380
455
  ## Deployment
381
456
 
382
457
  Searchkick uses `ENV["ELASTICSEARCH_URL"]` for the Elasticsearch server. This defaults to `http://localhost:9200`.
@@ -419,29 +494,6 @@ Then deploy and reindex:
419
494
  rake searchkick:reindex CLASS=Product
420
495
  ```
421
496
 
422
- ## Inheritance
423
-
424
- Searchkick supports single table inheritance.
425
-
426
- ```ruby
427
- class Dog < Animal
428
- end
429
- ```
430
-
431
- The parent and child model can both reindex.
432
-
433
- ```ruby
434
- Animal.reindex
435
- Dog.reindex # equivalent
436
- ```
437
-
438
- And to search, use:
439
-
440
- ```ruby
441
- Animal.search "*" # all animals
442
- Dog.search "*" # just dogs
443
- ```
444
-
445
497
  ## Reference
446
498
 
447
499
  Searchkick requires Elasticsearch `0.90.0` or higher.
@@ -528,7 +580,7 @@ rake searchkick:reindex:all
528
580
 
529
581
  ```ruby
530
582
  class Product < ActiveRecord::Base
531
- searchkick
583
+ searchkick
532
584
  end
533
585
  ```
534
586
 
@@ -560,7 +612,6 @@ Thanks to Karel Minarik for [Tire](https://github.com/karmi/tire), Jaroslav Kali
560
612
 
561
613
  ## TODO
562
614
 
563
- - Analytics for searches and conversions
564
615
  - Generate autocomplete predictions from past search queries
565
616
  - Automatic failover
566
617
  - Make Searchkick work with any language
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in searchkick.gemspec
4
+ gemspec path: "../"
5
+
6
+ gem "mongoid", "~> 3.1.0"
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in searchkick.gemspec
4
+ gemspec path: "../"
5
+
6
+ gem "mongoid", github: "mongoid/mongoid"
@@ -43,6 +43,9 @@ module Searchkick
43
43
  # stringify fields
44
44
  source = source.inject({}){|memo,(k,v)| memo[k.to_s] = v; memo}
45
45
 
46
+ # Mongoid 4 hack
47
+ source["_id"] = source["_id"].to_s if source["_id"]
48
+
46
49
  options = self.class.searchkick_options
47
50
 
48
51
  # conversions
@@ -53,14 +56,45 @@ module Searchkick
53
56
 
54
57
  # hack to prevent generator field doesn't exist error
55
58
  (options[:suggest] || []).map(&:to_s).each do |field|
56
- source[field] = "a" if !source[field]
59
+ source[field] = nil if !source[field]
57
60
  end
58
61
 
59
62
  # locations
60
63
  (options[:locations] || []).map(&:to_s).each do |field|
61
- source[field] = source[field].map(&:to_f).reverse if source[field]
64
+ if source[field]
65
+ if source[field].first.is_a?(Array) # array of arrays
66
+ source[field] = source[field].map{|a| a.map(&:to_f).reverse }
67
+ else
68
+ source[field] = source[field].map(&:to_f).reverse
69
+ end
70
+ end
62
71
  end
63
72
 
73
+ # change all BigDecimal values to floats due to
74
+ # https://github.com/rails/rails/issues/6033
75
+ # possible loss of precision :/
76
+ cast_big_decimal =
77
+ proc do |obj|
78
+ case obj
79
+ when BigDecimal
80
+ obj.to_f
81
+ when Hash
82
+ obj.each do |k, v|
83
+ obj[k] = cast_big_decimal.call(v)
84
+ end
85
+ when Enumerable
86
+ obj.map! do |v|
87
+ cast_big_decimal.call(v)
88
+ end
89
+ else
90
+ obj
91
+ end
92
+ end
93
+
94
+ cast_big_decimal.call(source)
95
+
96
+ # p search_data
97
+
64
98
  source.to_json
65
99
  end
66
100
 
@@ -35,6 +35,8 @@ module Searchkick
35
35
  searchkick_import(index) # import after swap
36
36
  end
37
37
 
38
+ index.refresh
39
+
38
40
  true
39
41
  end
40
42
 
@@ -203,6 +205,8 @@ module Searchkick
203
205
  fields: {
204
206
  field => {type: "string", index: "not_analyzed"},
205
207
  "analyzed" => {type: "string", index: "analyzed"}
208
+ # term_vector: "with_positions_offsets" for fast / correct highlighting
209
+ # http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-highlighting.html#_fast_vector_highlighter
206
210
  }
207
211
  }
208
212
  if autocomplete.include?(field)
@@ -221,7 +225,7 @@ module Searchkick
221
225
  end
222
226
 
223
227
  mappings = {
224
- searchkick_klass.document_type.to_sym => {
228
+ _default_: {
225
229
  properties: mapping,
226
230
  # https://gist.github.com/kimchy/2898285
227
231
  dynamic_templates: [
@@ -9,6 +9,16 @@ module Searchkick
9
9
  end
10
10
  end
11
11
 
12
+ def with_details
13
+ each_with_hit.map do |model, hit|
14
+ details = {}
15
+ if hit["highlight"]
16
+ details[:highlight] = Hash[ hit["highlight"].map{|k, v| [k.sub(/\.analyzed\z/, "").to_sym, v.first] } ]
17
+ end
18
+ [model, details]
19
+ end
20
+ end
21
+
12
22
  # fixes deprecation warning
13
23
  def __find_records_by_ids(klass, ids)
14
24
  @options[:load] === true ? klass.find(ids) : klass.includes(@options[:load][:include]).find(ids)
@@ -70,9 +70,10 @@ module Searchkick
70
70
  {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search2")}
71
71
  ]
72
72
  if options[:misspellings] != false
73
+ distance = (options[:misspellings].is_a?(Hash) && options[:misspellings][:distance]) || 1
73
74
  queries.concat [
74
- {multi_match: shared_options.merge(fuzziness: 1, max_expansions: 3, analyzer: "searchkick_search")},
75
- {multi_match: shared_options.merge(fuzziness: 1, max_expansions: 3, analyzer: "searchkick_search2")}
75
+ {multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search")},
76
+ {multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search2")}
76
77
  ]
77
78
  end
78
79
  payload = {
@@ -160,6 +161,8 @@ module Searchkick
160
161
  proc do |where|
161
162
  filters = []
162
163
  (where || {}).each do |field, value|
164
+ field = :_id if field.to_s == "id"
165
+
163
166
  if field == :or
164
167
  value.each do |or_clause|
165
168
  filters << {or: or_clause.map{|or_statement| {and: where_filters.call(or_statement)} }}
@@ -200,6 +203,8 @@ module Searchkick
200
203
  else
201
204
  filters << {not: {term: {field => op_value}}}
202
205
  end
206
+ elsif op == :all
207
+ filters << {terms: {field => op_value, execution: "and"}}
203
208
  else
204
209
  range_query =
205
210
  case op
@@ -218,7 +223,11 @@ module Searchkick
218
223
  end
219
224
  end
220
225
  else
221
- filters << {term: {field => value}}
226
+ if value.nil?
227
+ filters << {missing: {"field" => field, existence: true, null_value: true}}
228
+ else
229
+ filters << {term: {field => value}}
230
+ end
222
231
  end
223
232
  end
224
233
  end
@@ -245,12 +254,22 @@ module Searchkick
245
254
  facets.each do |field, facet_options|
246
255
  # ask for extra facets due to
247
256
  # https://github.com/elasticsearch/elasticsearch/issues/1305
248
- payload[:facets][field] = {
249
- terms: {
250
- field: field,
251
- size: facet_options[:limit] ? facet_options[:limit] + 150 : 100000
257
+
258
+ if facet_options[:ranges]
259
+ payload[:facets][field] = {
260
+ range: {
261
+ field.to_sym => facet_options[:ranges]
262
+ }
252
263
  }
253
- }
264
+ else
265
+ payload[:facets][field] = {
266
+ terms: {
267
+ field: field,
268
+ size: facet_options[:limit] ? facet_options[:limit] + 150 : 100000
269
+ }
270
+ }
271
+ end
272
+
254
273
  facet_limits[field] = facet_options[:limit] if facet_options[:limit]
255
274
 
256
275
  # offset is not possible
@@ -284,6 +303,17 @@ module Searchkick
284
303
  end
285
304
  end
286
305
 
306
+ # highlight
307
+ if options[:highlight]
308
+ payload[:highlight] = {
309
+ fields: Hash[ fields.map{|f| [f, {}] } ]
310
+ }
311
+ if options[:highlight].is_a?(Hash) and tag = options[:highlight][:tag]
312
+ payload[:highlight][:pre_tags] = [tag]
313
+ payload[:highlight][:post_tags] = [tag.to_s.gsub(/\A</, "</")]
314
+ end
315
+ end
316
+
287
317
  # An empty array will cause only the _id and _type for each hit to be returned
288
318
  # http://www.elasticsearch.org/guide/reference/api/search/fields/
289
319
  payload[:fields] = [] if load
@@ -291,7 +321,18 @@ module Searchkick
291
321
  tire_options = {load: load, payload: payload, size: per_page, from: offset}
292
322
  tire_options[:type] = document_type if self != searchkick_klass
293
323
  search = Tire::Search::Search.new(index_name, tire_options)
294
- response = search.json
324
+ begin
325
+ response = search.json
326
+ rescue Tire::Search::SearchRequestFailed => e
327
+ status_code = e.message[0..3].to_i
328
+ if status_code == 404
329
+ raise "Index missing - run #{searchkick_klass.name}.reindex"
330
+ elsif status_code == 500 and (e.message.include?("IllegalArgumentException[minimumSimilarity >= 1]") or e.message.include?("No query registered for [multi_match]"))
331
+ raise "Upgrade Elasticsearch to 0.90.0 or greater"
332
+ else
333
+ raise e
334
+ end
335
+ end
295
336
 
296
337
  # apply facet limit in client due to
297
338
  # https://github.com/elasticsearch/elasticsearch/issues/1305
@@ -9,7 +9,7 @@ module Searchkick
9
9
  # TODO deep merge method
10
10
  options[:where] ||= {}
11
11
  options[:where][:_id] ||= {}
12
- options[:where][:_id][:not] = id
12
+ options[:where][:_id][:not] = id.to_s
13
13
  options[:limit] ||= 10
14
14
  options[:similar] = true
15
15
  self.class.search(like_text, options)
@@ -23,8 +23,10 @@ namespace :searchkick do
23
23
  task :all => :environment do
24
24
  Rails.application.eager_load!
25
25
  (Searchkick::Reindex.instance_variable_get(:@descendents) || []).each do |model|
26
+ puts "Reindexing #{model.name}..."
26
27
  model.reindex
27
28
  end
29
+ puts "Reindex complete"
28
30
  end
29
31
  end
30
32
 
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.1"
3
3
  end
data/searchkick.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
  spec.add_development_dependency "rake"
26
- spec.add_development_dependency "minitest"
26
+ spec.add_development_dependency "minitest", "~> 4.7"
27
27
  spec.add_development_dependency "activerecord"
28
28
  spec.add_development_dependency "pg"
29
29
  end
data/test/facets_test.rb CHANGED
@@ -5,9 +5,9 @@ class TestFacets < Minitest::Unit::TestCase
5
5
  def setup
6
6
  super
7
7
  store [
8
- {name: "Product Show", store_id: 1, in_stock: true, color: "blue"},
9
- {name: "Product Hide", store_id: 2, in_stock: false, color: "green"},
10
- {name: "Product B", store_id: 2, in_stock: false, color: "red"}
8
+ {name: "Product Show", store_id: 1, in_stock: true, color: "blue", price: 21},
9
+ {name: "Product Hide", store_id: 2, in_stock: false, color: "green", price: 25},
10
+ {name: "Product B", store_id: 2, in_stock: false, color: "red", price: 5}
11
11
  ]
12
12
  end
13
13
 
@@ -26,4 +26,15 @@ class TestFacets < Minitest::Unit::TestCase
26
26
  assert_equal 1, facet["other"]
27
27
  end
28
28
 
29
+ def test_ranges
30
+ price_ranges = [{to: 10}, {from: 10, to: 20}, {from: 20}]
31
+ facet = Product.search("Product", facets: {price: {ranges: price_ranges}}).facets["price"]
32
+
33
+ assert_equal 3, facet["ranges"].size
34
+ assert_equal 10.0, facet["ranges"][0]["to"]
35
+ assert_equal 20.0, facet["ranges"][2]["from"]
36
+ assert_equal 1, facet["ranges"][0]["count"]
37
+ assert_equal 0, facet["ranges"][1]["count"]
38
+ assert_equal 2, facet["ranges"][2]["count"]
39
+ end
29
40
  end
@@ -0,0 +1,22 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestHighlight < Minitest::Unit::TestCase
4
+
5
+ def test_basic
6
+ store_names ["Two Door Cinema Club"]
7
+ assert_equal "Two Door <em>Cinema</em> Club", Product.search("cinema", fields: [:name], highlight: true).with_details.first[1][:highlight][:name]
8
+ end
9
+
10
+ def test_tag
11
+ store_names ["Two Door Cinema Club"]
12
+ assert_equal "Two Door <strong>Cinema</strong> Club", Product.search("cinema", fields: [:name], highlight: {tag: "<strong>"}).with_details.first[1][:highlight][:name]
13
+ end
14
+
15
+ def test_multiple_fields
16
+ store [{name: "Two Door Cinema Club", color: "Cinema Orange"}]
17
+ highlight = Product.search("cinema", fields: [:name, :color], highlight: true).with_details.first[1][:highlight]
18
+ assert_equal "Two Door <em>Cinema</em> Club", highlight[:name]
19
+ assert_equal "<em>Cinema</em> Orange", highlight[:color]
20
+ end
21
+
22
+ end
@@ -30,4 +30,28 @@ class TestInheritance < Minitest::Unit::TestCase
30
30
  assert_equal 2, Animal.search("bear").size
31
31
  end
32
32
 
33
+ def test_child_autocomplete
34
+ store_names ["Max"], Cat
35
+ store_names ["Mark"], Dog
36
+ assert_equal ["Max"], Cat.search("ma", fields: [:name], autocomplete: true).map(&:name)
37
+ end
38
+
39
+ def test_parent_autocomplete
40
+ store_names ["Max"], Cat
41
+ store_names ["Bear"], Dog
42
+ assert_equal ["Bear"], Animal.search("bea", fields: [:name], autocomplete: true).map(&:name).sort
43
+ end
44
+
45
+ # def test_child_suggest
46
+ # store_names ["Shark"], Cat
47
+ # store_names ["Sharp"], Dog
48
+ # assert_equal ["shark"], Cat.search("shar", fields: [:name], suggest: true).suggestions
49
+ # end
50
+
51
+ def test_parent_suggest
52
+ store_names ["Shark"], Cat
53
+ store_names ["Tiger"], Dog
54
+ assert_equal ["tiger"], Animal.search("tige", fields: [:name], suggest: true).suggestions.sort
55
+ end
56
+
33
57
  end
data/test/sql_test.rb CHANGED
@@ -39,7 +39,7 @@ class TestSql < Minitest::Unit::TestCase
39
39
  now = Time.now
40
40
  store [
41
41
  {name: "Product A", store_id: 1, in_stock: true, backordered: true, created_at: now, orders_count: 4, user_ids: [1, 2, 3]},
42
- {name: "Product B", store_id: 2, in_stock: true, backordered: false, created_at: now - 1, orders_count: 3},
42
+ {name: "Product B", store_id: 2, in_stock: true, backordered: false, created_at: now - 1, orders_count: 3, user_ids: [1]},
43
43
  {name: "Product C", store_id: 3, in_stock: false, backordered: true, created_at: now - 2, orders_count: 2},
44
44
  {name: "Product D", store_id: 4, in_stock: false, backordered: false, created_at: now - 3, orders_count: 1},
45
45
  ]
@@ -64,15 +64,30 @@ class TestSql < Minitest::Unit::TestCase
64
64
  assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{in_stock: true}, {store_id: 3}]]}
65
65
  assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{orders_count: [2, 4]}, {store_id: [1, 2]}]]}
66
66
  assert_search "product", ["Product A", "Product D"], where: {or: [[{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]]}
67
- # array
68
- assert_search "product", ["Product A"], where: {user_ids: 2}
67
+ # all
68
+ assert_search "product", ["Product A"], where: {user_ids: {all: [1, 3]}}
69
+ assert_search "product", [], where: {user_ids: {all: [1, 2, 3, 4]}}
69
70
  end
70
71
 
71
72
  def test_where_string
72
73
  store [
73
74
  {name: "Product A", color: "RED"}
74
75
  ]
75
- assert_search "product", ["Product A"], where: {color: ["RED"]}
76
+ assert_search "product", ["Product A"], where: {color: "RED"}
77
+ end
78
+
79
+ def test_where_nil
80
+ store [
81
+ {name: "Product A"},
82
+ {name: "Product B", color: "red"}
83
+ ]
84
+ assert_search "product", ["Product A"], where: {color: nil}
85
+ end
86
+
87
+ def test_where_id
88
+ store_names ["Product A"]
89
+ product = Product.last
90
+ assert_search "product", ["Product A"], where: {id: product.id.to_s}
76
91
  end
77
92
 
78
93
  def test_near
@@ -100,6 +115,14 @@ class TestSql < Minitest::Unit::TestCase
100
115
  assert_search "san", ["San Francisco"], where: {location: {top_left: [38, -123], bottom_right: [37, -122]}}
101
116
  end
102
117
 
118
+ def test_multiple_locations
119
+ store [
120
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
121
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
122
+ ]
123
+ assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}}
124
+ end
125
+
103
126
  def test_order_hash
104
127
  store_names ["Product A", "Product B", "Product C", "Product D"]
105
128
  assert_order "product", ["Product D", "Product C", "Product B", "Product A"], order: {name: :desc}
@@ -121,6 +144,11 @@ class TestSql < Minitest::Unit::TestCase
121
144
  assert_search "abc", ["abc"], misspellings: false
122
145
  end
123
146
 
147
+ def test_misspellings_distance
148
+ store_names ["abbb", "aabb"]
149
+ assert_search "aaaa", ["aabb"], misspellings: {distance: 2}
150
+ end
151
+
124
152
  def test_fields
125
153
  store [
126
154
  {name: "red", color: "light blue"},
@@ -142,6 +170,13 @@ class TestSql < Minitest::Unit::TestCase
142
170
  assert_first "blue", "Blue B", fields: [:name, :color]
143
171
  end
144
172
 
173
+ def test_big_decimal
174
+ store [
175
+ {name: "Product", latitude: 100.0}
176
+ ]
177
+ assert_search "product", ["Product"], where: {latitude: {gt: 99}}
178
+ end
179
+
145
180
  # load
146
181
 
147
182
  def test_load_default
@@ -159,9 +194,12 @@ class TestSql < Minitest::Unit::TestCase
159
194
  assert_kind_of Tire::Results::Item, Product.search("product", load: false, include: [:store]).first
160
195
  end
161
196
 
162
- def test_include
163
- store_names ["Product A"]
164
- assert Product.search("product", include: [:store]).first.association(:store).loaded?
197
+ # TODO see if Mongoid is loaded
198
+ if !defined?(Mongoid)
199
+ def test_include
200
+ store_names ["Product A"]
201
+ assert Product.search("product", include: [:store]).first.association(:store).loaded?
202
+ end
165
203
  end
166
204
 
167
205
  end
data/test/suggest_test.rb CHANGED
@@ -4,17 +4,17 @@ class TestSuggest < Minitest::Unit::TestCase
4
4
 
5
5
  def test_basic
6
6
  store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
7
- assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark"
7
+ assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [:name]
8
8
  end
9
9
 
10
10
  def test_perfect
11
11
  store_names ["Tiger Shark", "Great White Shark"]
12
- assert_suggest "Tiger Shark", nil # no correction
12
+ assert_suggest "Tiger Shark", nil, fields: [:name] # no correction
13
13
  end
14
14
 
15
15
  def test_phrase
16
16
  store_names ["Big Tiger Shark", "Tiger Sharp Teeth", "Tiger Sharp Mind"]
17
- assert_suggest "How to catch a big tiger shar", "how to catch a big tiger shark"
17
+ assert_suggest "How to catch a big tiger shar", "how to catch a big tiger shark", fields: [:name]
18
18
  end
19
19
 
20
20
  def test_without_option
data/test/test_helper.rb CHANGED
@@ -11,14 +11,24 @@ Tire.configure do
11
11
  pretty true
12
12
  end
13
13
 
14
- if ENV["MONGOID"]
14
+ if defined?(Mongoid)
15
15
  Mongoid.configure do |config|
16
16
  config.connect_to "searchkick_test"
17
17
  end
18
18
 
19
19
  class Product
20
20
  include Mongoid::Document
21
- # include Mongoid::Attributes::Dynamic
21
+ include Mongoid::Timestamps
22
+
23
+ field :name
24
+ field :store_id, type: Integer
25
+ field :in_stock, type: Boolean
26
+ field :backordered, type: Boolean
27
+ field :orders_count, type: Integer
28
+ field :price, type: Integer
29
+ field :color
30
+ field :latitude, type: BigDecimal
31
+ field :longitude, type: BigDecimal
22
32
  end
23
33
 
24
34
  class Store
@@ -27,6 +37,8 @@ if ENV["MONGOID"]
27
37
 
28
38
  class Animal
29
39
  include Mongoid::Document
40
+
41
+ field :name
30
42
  end
31
43
 
32
44
  class Dog < Animal
@@ -53,6 +65,7 @@ else
53
65
  t.boolean :in_stock
54
66
  t.boolean :backordered
55
67
  t.integer :orders_count
68
+ t.integer :price
56
69
  t.string :color
57
70
  t.decimal :latitude, precision: 10, scale: 7
58
71
  t.decimal :longitude, precision: 10, scale: 7
@@ -99,17 +112,17 @@ class Product
99
112
  suggest: [:name, :color],
100
113
  conversions: "conversions",
101
114
  personalize: "user_ids",
102
- locations: ["location"]
115
+ locations: ["location", "multiple_locations"]
103
116
 
104
117
  attr_accessor :conversions, :user_ids
105
118
 
106
119
  def search_data
107
- attributes.merge conversions: conversions, user_ids: user_ids, location: [latitude, longitude]
120
+ serializable_hash.merge conversions: conversions, user_ids: user_ids, location: [latitude, longitude], multiple_locations: [[latitude, longitude], [0, 0]]
108
121
  end
109
122
  end
110
123
 
111
124
  class Animal
112
- searchkick
125
+ searchkick autocomplete: [:name], suggest: [:name]
113
126
  end
114
127
 
115
128
  Product.searchkick_index.delete if Product.searchkick_index.exists?
@@ -118,7 +131,7 @@ Product.reindex # run twice for both index paths
118
131
 
119
132
  Animal.reindex
120
133
 
121
- class MiniTest::Unit::TestCase
134
+ class Minitest::Unit::TestCase
122
135
 
123
136
  def setup
124
137
  Product.destroy_all
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchkick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-03 00:00:00.000000000 Z
11
+ date: 2013-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tire
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: minitest
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '4.7'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '4.7'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activerecord
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,8 @@ files:
122
122
  - LICENSE.txt
123
123
  - README.md
124
124
  - Rakefile
125
+ - gemfiles/mongoid3.gemfile
126
+ - gemfiles/mongoid4.gemfile
125
127
  - lib/searchkick.rb
126
128
  - lib/searchkick/logger.rb
127
129
  - lib/searchkick/model.rb
@@ -135,6 +137,7 @@ files:
135
137
  - test/autocomplete_test.rb
136
138
  - test/boost_test.rb
137
139
  - test/facets_test.rb
140
+ - test/highlight_test.rb
138
141
  - test/index_test.rb
139
142
  - test/inheritance_test.rb
140
143
  - test/match_test.rb
@@ -171,6 +174,7 @@ test_files:
171
174
  - test/autocomplete_test.rb
172
175
  - test/boost_test.rb
173
176
  - test/facets_test.rb
177
+ - test/highlight_test.rb
174
178
  - test/index_test.rb
175
179
  - test/inheritance_test.rb
176
180
  - test/match_test.rb