searchkick 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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