searchkick 1.0.0 → 1.0.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: 49cbfbcd21df174e93c80f8960ed0771182c0bd6
4
- data.tar.gz: 7f02c54a57a145744797000aae4d48c6c3fd5219
3
+ metadata.gz: a27fb3f9f9fd1773e06eec376ec0677ef60aca65
4
+ data.tar.gz: 03c0d4c6dabe39b5e9e7beda4f0365e0a3f71472
5
5
  SHA512:
6
- metadata.gz: 322e05f51de0e35bc8636f92838ae37ac482c518fbe9163e4a1c91b1f60e607e56e1c9e0fc1271ffd83ef082d77c23f316b5dd9494ca12899696fba9cd03e60b
7
- data.tar.gz: 387c81af6e19c8faeaa0fe2904d41b13f375ab970bff47b15814b1e874a149dabd0f9a48928773f6bddc94e4c21429f3cf89a1f4be5b3c3a4445702109d476f9
6
+ metadata.gz: 722dce0a1e9366ed296a9003b435deddc6f6f4c43a90771644bd0f6558d969c348b42279e4c6d04e5ef3cfa188abc75b26a483c6d3d022bd175453135e78f8d6
7
+ data.tar.gz: e59ff3b1b239b5a9d6d96f3c8482bfece495d936caef69397958292be7069c6e130c6c1bb7aec8b4fb5c0b412914eca4ad9d3af80dca5bf4b9976f9e76496de9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 1.0.1
2
+
3
+ - Added aggregations method to get raw response
4
+ - Use `execute: false` for lazy loading
5
+ - Return nil when no aggs
6
+ - Added emoji search
7
+
1
8
  ## 1.0.0
2
9
 
3
10
  - Added support for Elasticsearch 2.0
data/Gemfile CHANGED
@@ -5,3 +5,4 @@ gemspec
5
5
 
6
6
  gem "sqlite3"
7
7
  gem "activerecord", "~> 4.2.0"
8
+ gem "gemoji-parser"
data/README.md CHANGED
@@ -315,6 +315,22 @@ Or turn off misspellings with:
315
315
  Product.search "zuchini", misspellings: false # no zucchini
316
316
  ```
317
317
 
318
+ ### Emoji
319
+
320
+ Make :ice_cream::cake: match `ice cream cake`!
321
+
322
+ Add this line to your application’s Gemfile:
323
+
324
+ ```ruby
325
+ gem 'gemoji-parser'
326
+ ```
327
+
328
+ And use:
329
+
330
+ ```ruby
331
+ Product.search "[emoji go here]", emoji: true
332
+ ```
333
+
318
334
  ### Indexing
319
335
 
320
336
  Control what data is indexed with the `search_data` method. Call `Product.reindex` after changing this method.
@@ -644,7 +660,7 @@ Product.search "*", aggs: {price: {ranges: price_ranges}}
644
660
 
645
661
  ### Facets [deprecated]
646
662
 
647
- Facets have been deprecated in favor of aggregations as of Searchkick 0.9.2. See [how to upgrade](#moving-from-facets).
663
+ Facets have been deprecated in favor of aggregations as of Searchkick 1.0. See [how to upgrade](#moving-from-facets).
648
664
 
649
665
  ```ruby
650
666
  products = Product.search "chuck taylor", facets: [:product_type, :gender, :brand]
@@ -1004,6 +1020,8 @@ And use the `body` option to search:
1004
1020
  products = Product.search body: {match: {name: "milk"}}
1005
1021
  ```
1006
1022
 
1023
+ **Note:** This replaces the entire body, so other options are ignored.
1024
+
1007
1025
  View the response with:
1008
1026
 
1009
1027
  ```ruby
@@ -1135,6 +1153,13 @@ Create index without importing
1135
1153
  Product.reindex(import: false)
1136
1154
  ```
1137
1155
 
1156
+ Lazy searching
1157
+
1158
+ ```ruby
1159
+ products = Product.search("carrots", execute: false)
1160
+ products.each { ... } # search not executed until here
1161
+ ```
1162
+
1138
1163
  Make fields unsearchable but include in the source
1139
1164
 
1140
1165
  ```ruby
@@ -1,8 +1,12 @@
1
1
  module Searchkick
2
2
  class Query
3
+ extend Forwardable
4
+
3
5
  attr_reader :klass, :term, :options
4
6
  attr_accessor :body
5
7
 
8
+ def_delegators :execute, :map, :each, :any?, :empty?, :size, :length, :slice, :[], :to_ary
9
+
6
10
  def initialize(klass, term, options = {})
7
11
  if term.is_a?(Hash)
8
12
  options = term
@@ -11,6 +15,10 @@ module Searchkick
11
15
  term = term.to_s
12
16
  end
13
17
 
18
+ if options[:emoji]
19
+ term = EmojiParser.parse_unicode(term) { |e| " #{e.name} " }.strip
20
+ end
21
+
14
22
  @klass = klass
15
23
  @term = term
16
24
  @options = options
@@ -480,49 +488,62 @@ module Searchkick
480
488
  end
481
489
 
482
490
  def execute
483
- begin
484
- response = Searchkick.client.search(params)
485
- rescue => e # TODO rescue type
486
- status_code = e.message[1..3].to_i
487
- if status_code == 404
488
- raise MissingIndexError, "Index missing - run #{searchkick_klass.name}.reindex"
489
- elsif status_code == 500 && (
490
- e.message.include?("IllegalArgumentException[minimumSimilarity >= 1]") ||
491
- e.message.include?("No query registered for [multi_match]") ||
492
- e.message.include?("[match] query does not support [cutoff_frequency]]") ||
493
- e.message.include?("No query registered for [function_score]]")
494
- )
495
-
496
- raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 1.0 or greater"
497
- elsif status_code == 400
498
- if e.message.include?("[multi_match] analyzer [searchkick_search] not found")
499
- raise InvalidQueryError, "Bad mapping - run #{searchkick_klass.name}.reindex"
491
+ @execute ||= begin
492
+ begin
493
+ response = Searchkick.client.search(params)
494
+ rescue => e # TODO rescue type
495
+ status_code = e.message[1..3].to_i
496
+ if status_code == 404
497
+ raise MissingIndexError, "Index missing - run #{searchkick_klass.name}.reindex"
498
+ elsif status_code == 500 && (
499
+ e.message.include?("IllegalArgumentException[minimumSimilarity >= 1]") ||
500
+ e.message.include?("No query registered for [multi_match]") ||
501
+ e.message.include?("[match] query does not support [cutoff_frequency]]") ||
502
+ e.message.include?("No query registered for [function_score]]")
503
+ )
504
+
505
+ raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 1.0 or greater"
506
+ elsif status_code == 400
507
+ if e.message.include?("[multi_match] analyzer [searchkick_search] not found")
508
+ raise InvalidQueryError, "Bad mapping - run #{searchkick_klass.name}.reindex"
509
+ else
510
+ raise InvalidQueryError, e.message
511
+ end
500
512
  else
501
- raise InvalidQueryError, e.message
513
+ raise e
502
514
  end
503
- else
504
- raise e
505
515
  end
506
- end
507
516
 
508
- # apply facet limit in client due to
509
- # https://github.com/elasticsearch/elasticsearch/issues/1305
510
- @facet_limits.each do |field, limit|
511
- field = field.to_s
512
- facet = response["facets"][field]
513
- response["facets"][field]["terms"] = facet["terms"].first(limit)
514
- response["facets"][field]["other"] = facet["total"] - facet["terms"].sum { |term| term["count"] }
517
+ # apply facet limit in client due to
518
+ # https://github.com/elasticsearch/elasticsearch/issues/1305
519
+ @facet_limits.each do |field, limit|
520
+ field = field.to_s
521
+ facet = response["facets"][field]
522
+ response["facets"][field]["terms"] = facet["terms"].first(limit)
523
+ response["facets"][field]["other"] = facet["total"] - facet["terms"].sum { |term| term["count"] }
524
+ end
525
+
526
+ opts = {
527
+ page: @page,
528
+ per_page: @per_page,
529
+ padding: @padding,
530
+ load: @load,
531
+ includes: options[:include] || options[:includes],
532
+ json: !options[:json].nil?
533
+ }
534
+ Searchkick::Results.new(searchkick_klass, response, opts)
515
535
  end
536
+ end
516
537
 
517
- opts = {
518
- page: @page,
519
- per_page: @per_page,
520
- padding: @padding,
521
- load: @load,
522
- includes: options[:include] || options[:includes],
523
- json: !options[:json].nil?
524
- }
525
- Searchkick::Results.new(searchkick_klass, response, opts)
538
+ def to_curl
539
+ query = params
540
+ type = query[:type]
541
+ index = query[:index].is_a?(Array) ? query[:index].join(",") : query[:index]
542
+
543
+ # no easy way to tell which host the client will use
544
+ host = Searchkick.client.transport.hosts.first
545
+ credentials = (host[:user] || host[:password]) ? "#{host[:user]}:#{host[:password]}@" : nil
546
+ "curl #{host[:protocol]}://#{credentials}#{host[:host]}:#{host[:port]}/#{CGI.escape(index)}#{type ? "/#{type.map { |t| CGI.escape(t) }.join(',')}" : ''}/_search?pretty -d '#{query[:body].to_json}'"
526
547
  end
527
548
 
528
549
  private
@@ -75,14 +75,20 @@ module Searchkick
75
75
  response["facets"]
76
76
  end
77
77
 
78
+ def aggregations
79
+ response["aggregations"]
80
+ end
81
+
78
82
  def aggs
79
83
  @aggs ||= begin
80
- response["aggregations"].dup.each do |field, filtered_agg|
81
- buckets = filtered_agg[field]
82
- # move the buckets one level above into the field hash
83
- if buckets
84
- filtered_agg.delete(field)
85
- filtered_agg.merge!(buckets)
84
+ if aggregations
85
+ aggregations.dup.each do |field, filtered_agg|
86
+ buckets = filtered_agg[field]
87
+ # move the buckets one level above into the field hash
88
+ if buckets
89
+ filtered_agg.delete(field)
90
+ filtered_agg.merge!(buckets)
91
+ end
86
92
  end
87
93
  end
88
94
  end
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
data/test/aggs_test.rb CHANGED
@@ -25,6 +25,10 @@ class AggsTest < Minitest::Test
25
25
  assert_equal ({1 => 1, 2 => 2}), store_agg({aggs: {store_id_new: {field: "store_id"}}}, "store_id_new")
26
26
  end
27
27
 
28
+ def test_no_aggs
29
+ assert_nil Product.search("*").aggs
30
+ end
31
+
28
32
  def test_limit
29
33
  agg = Product.search("Product", aggs: {store_id: {limit: 1}}).aggs["store_id"]
30
34
  assert_equal 1, agg["buckets"].size
data/test/index_test.rb CHANGED
@@ -107,6 +107,11 @@ class IndexTest < Minitest::Test
107
107
  assert_raises(Searchkick::DangerousOperation) { Product.where(id: [1, 2, 3]).reindex }
108
108
  end
109
109
 
110
+ def test_dangerous_index_associations
111
+ Store.create!(name: "Test")
112
+ assert_raises(Searchkick::DangerousOperation) { Store.first.products.reindex }
113
+ end
114
+
110
115
  def test_dangerous_reindex_accepted
111
116
  store_names ["Product A", "Product B"]
112
117
  Product.where(name: "Product A").reindex(accept_danger: true)
@@ -124,7 +129,7 @@ class IndexTest < Minitest::Test
124
129
  store_names ["Product A"]
125
130
  raise ActiveRecord::Rollback
126
131
  end
127
- assert_search "product", [], conversions: false
132
+ assert_search "product", []
128
133
  end
129
134
  end
130
135
  end
data/test/match_test.rb CHANGED
@@ -197,4 +197,16 @@ class MatchTest < Minitest::Test
197
197
  ]
198
198
  assert_search "almond", []
199
199
  end
200
+
201
+ def test_emoji
202
+ skip unless defined?(EmojiParser)
203
+ store_names ["Banana"]
204
+ assert_search "🍌", ["Banana"], emoji: true
205
+ end
206
+
207
+ def test_emoji_multiple
208
+ skip unless defined?(EmojiParser)
209
+ store_names ["Ice Cream Cake"]
210
+ assert_search "🍨🍰", ["Ice Cream Cake"], emoji: true
211
+ end
200
212
  end
data/test/query_test.rb CHANGED
@@ -7,6 +7,7 @@ class QueryTest < Minitest::Test
7
7
  # query.body = {query: {match_all: {}}}
8
8
  # query.body = {query: {match: {name: "Apple"}}}
9
9
  query.body[:query] = {match_all: {}}
10
+ assert_equal ["Apple", "Milk"], query.map(&:name).sort
10
11
  assert_equal ["Apple", "Milk"], query.execute.map(&:name).sort
11
12
  end
12
13
  end
data/test/sql_test.rb CHANGED
@@ -213,12 +213,12 @@ class SqlTest < Minitest::Test
213
213
  end
214
214
 
215
215
  def test_order_ignore_unmapped
216
- assert_order "product", [], order: {not_mapped: {ignore_unmapped: true}}, conversions: false
216
+ assert_order "product", [], order: {not_mapped: {ignore_unmapped: true}}
217
217
  end
218
218
 
219
219
  def test_order_array
220
220
  store [{name: "San Francisco", latitude: 37.7833, longitude: -122.4167}]
221
- assert_order "francisco", ["San Francisco"], order: [{_geo_distance: {location: "0,0"}}], conversions: false
221
+ assert_order "francisco", ["San Francisco"], order: [{_geo_distance: {location: "0,0"}}]
222
222
  end
223
223
 
224
224
  def test_partial
data/test/test_helper.rb CHANGED
@@ -76,6 +76,7 @@ if defined?(Mongoid)
76
76
 
77
77
  class Store
78
78
  include Mongoid::Document
79
+ has_many :products
79
80
 
80
81
  field :name
81
82
  end
@@ -178,6 +179,7 @@ else
178
179
  end
179
180
 
180
181
  class Store < ActiveRecord::Base
182
+ has_many :products
181
183
  end
182
184
 
183
185
  class Animal < ActiveRecord::Base
@@ -257,6 +259,7 @@ end
257
259
  Product.searchkick_index.delete if Product.searchkick_index.exists?
258
260
  Product.reindex
259
261
  Product.reindex # run twice for both index paths
262
+ Product.create!(name: "Set mapping")
260
263
 
261
264
  Store.reindex
262
265
  Animal.reindex
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: 1.0.0
4
+ version: 1.0.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: 2015-10-30 00:00:00.000000000 Z
11
+ date: 2015-11-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel