searchkick 2.1.1 → 2.2.0
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 +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +97 -15
- data/lib/searchkick/index.rb +1 -0
- data/lib/searchkick/index_options.rb +4 -4
- data/lib/searchkick/model.rb +7 -1
- data/lib/searchkick/process_queue_job.rb +1 -1
- data/lib/searchkick/query.rb +11 -1
- data/lib/searchkick/reindex_v2_job.rb +2 -1
- data/lib/searchkick/version.rb +1 -1
- data/lib/searchkick.rb +13 -1
- data/test/aggs_test.rb +2 -2
- data/test/boost_test.rb +10 -0
- data/test/errors_test.rb +2 -2
- data/test/gemfiles/activerecord51.gemfile +7 -0
- data/test/gemfiles/cequel.gemfile +8 -0
- data/test/highlight_test.rb +5 -0
- data/test/index_test.rb +19 -2
- data/test/inheritance_test.rb +5 -0
- data/test/match_test.rb +14 -3
- data/test/model_test.rb +1 -1
- data/test/order_test.rb +2 -0
- data/test/records_test.rb +2 -0
- data/test/reindex_test.rb +2 -2
- data/test/test_helper.rb +86 -0
- data/test/where_test.rb +19 -6
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85108ff6dc90bd7075f66c5627fc06eba581657f
|
4
|
+
data.tar.gz: 062420bd6cd4c9601026425d40923cc82e649364
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 680ef536ba5e15456b0df70412eec5e47d13f43424c02e7d039921abf3c83b06fbaefa95d824fa2ae0efeecde8c6488ad56b4aabed442eb6c191a309f2204c6c
|
7
|
+
data.tar.gz: d118d331ffd37c1fbec228bba2cc043f03730510a0ca45d7bd9afe9c04aa31a8ebeeaba82b57113c070fd7af3b1c8c347f0b22bd8cff43565f9246ed408a0c77
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 2.2.0
|
2
|
+
|
3
|
+
- Fixed bug with text values longer than 256 characters and `_all` field - see [#850](https://github.com/ankane/searchkick/issues/850)
|
4
|
+
- Fixed issue with `_all` field in `searchable`
|
5
|
+
- Fixed `exclude` option with `word_start`
|
6
|
+
|
1
7
|
## 2.1.1
|
2
8
|
|
3
9
|
- Fixed duplicate notifications
|
@@ -41,6 +47,10 @@ Breaking changes
|
|
41
47
|
- Removed support for Elasticsearch 1 as it reaches [end of life](https://www.elastic.co/support/eol)
|
42
48
|
- Removed facets, legacy options, and legacy methods
|
43
49
|
- Invalid options now throw an `ArgumentError`
|
50
|
+
- The `query` and `json` options have been removed in favor of `body`
|
51
|
+
- The `include` option has been removed in favor of `includes`
|
52
|
+
- The `personalize` option has been removed in favor of `boost_where`
|
53
|
+
- The `partial` option has been removed in favor of `operator`
|
44
54
|
- Renamed `select_v2` to `select` (legacy `select` no longer available)
|
45
55
|
- The `_all` field is disabled if `searchable` option is used (for performance)
|
46
56
|
- The `partial_reindex(:method_name)` method has been replaced with `reindex(:method_name)`
|
data/README.md
CHANGED
@@ -47,9 +47,7 @@ Plus:
|
|
47
47
|
|
48
48
|
```sh
|
49
49
|
brew install elasticsearch
|
50
|
-
|
51
|
-
# start the server
|
52
|
-
elasticsearch
|
50
|
+
brew services start elasticsearch
|
53
51
|
```
|
54
52
|
|
55
53
|
Add this line to your application’s Gemfile:
|
@@ -385,6 +383,17 @@ If a user searches `butter`, they may also get results for `peanut butter`. To p
|
|
385
383
|
Product.search "butter", exclude: ["peanut butter"]
|
386
384
|
```
|
387
385
|
|
386
|
+
You can map queries and terms to exclude with:
|
387
|
+
|
388
|
+
```ruby
|
389
|
+
exclude_queries = {
|
390
|
+
"butter" => ["peanut butter"],
|
391
|
+
"cream" => ["ice cream"]
|
392
|
+
}
|
393
|
+
|
394
|
+
Product.search query, exclude: exclude_queries[query]
|
395
|
+
```
|
396
|
+
|
388
397
|
### Emoji
|
389
398
|
|
390
399
|
Search :ice_cream::cake: and get `ice cream cake`!
|
@@ -1018,7 +1027,7 @@ Product.search_index.tokens("dieg", analyzer: "searchkick_word_search")
|
|
1018
1027
|
# ["dieg"] - match!!
|
1019
1028
|
```
|
1020
1029
|
|
1021
|
-
See the [complete list of analyzers](lib/searchkick/
|
1030
|
+
See the [complete list of analyzers](https://github.com/ankane/searchkick/blob/31780ddac7a89eab1e0552a32b403f2040a37931/lib/searchkick/index_options.rb#L32).
|
1022
1031
|
|
1023
1032
|
## Deployment
|
1024
1033
|
|
@@ -1136,9 +1145,11 @@ Significantly increase performance with faster JSON generation. Add [Oj](https:/
|
|
1136
1145
|
gem 'oj'
|
1137
1146
|
```
|
1138
1147
|
|
1148
|
+
This speeds up all JSON generation and parsing in your application (automatically!)
|
1149
|
+
|
1139
1150
|
### Persistent HTTP Connections
|
1140
1151
|
|
1141
|
-
Significantly increase performance with persistent HTTP connections. Add [Typhoeus](https://github.com/typhoeus/typhoeus) to your Gemfile.
|
1152
|
+
Significantly increase performance with persistent HTTP connections. Add [Typhoeus](https://github.com/typhoeus/typhoeus) to your Gemfile and it’ll automatically be used.
|
1142
1153
|
|
1143
1154
|
```ruby
|
1144
1155
|
gem 'typhoeus'
|
@@ -1199,18 +1210,19 @@ And use:
|
|
1199
1210
|
Searchkick.reindex_status(index_name)
|
1200
1211
|
```
|
1201
1212
|
|
1202
|
-
You can use [ActiveJob::TrafficControl](https://github.com/nickelser/activejob-traffic_control) to control concurrency. Install the gem
|
1213
|
+
You can use [ActiveJob::TrafficControl](https://github.com/nickelser/activejob-traffic_control) to control concurrency. Install the gem:
|
1203
1214
|
|
1204
1215
|
```ruby
|
1205
|
-
|
1216
|
+
gem 'activejob-traffic_control', '>= 0.1.3'
|
1217
|
+
```
|
1206
1218
|
|
1207
|
-
|
1219
|
+
And create an initializer with:
|
1220
|
+
|
1221
|
+
```ruby
|
1208
1222
|
ActiveJob::TrafficControl.client = Searchkick.redis
|
1209
1223
|
|
1210
1224
|
class Searchkick::BulkReindexJob
|
1211
|
-
|
1212
|
-
|
1213
|
-
concurrency 3, drop: false
|
1225
|
+
concurrency 3
|
1214
1226
|
end
|
1215
1227
|
```
|
1216
1228
|
|
@@ -1677,21 +1689,78 @@ Product.search "ah", misspellings: {prefix_length: 2} # ah, no aha
|
|
1677
1689
|
|
1678
1690
|
## Testing
|
1679
1691
|
|
1680
|
-
|
1692
|
+
For performance, only enable Searchkick callbacks for the tests that need it.
|
1693
|
+
|
1694
|
+
### Minitest
|
1695
|
+
|
1696
|
+
Add to your `test/test_helper.rb`:
|
1697
|
+
|
1698
|
+
```ruby
|
1699
|
+
# reindex models
|
1700
|
+
Product.reindex
|
1701
|
+
|
1702
|
+
# and disable callbacks
|
1703
|
+
Searchkick.disable_callbacks
|
1704
|
+
```
|
1705
|
+
|
1706
|
+
And use:
|
1707
|
+
|
1708
|
+
```ruby
|
1709
|
+
class ProductTest < Minitest::Test
|
1710
|
+
def setup
|
1711
|
+
Searchkick.enable_callbacks
|
1712
|
+
end
|
1713
|
+
|
1714
|
+
def teardown
|
1715
|
+
Searchkick.disable_callbacks
|
1716
|
+
end
|
1717
|
+
|
1718
|
+
def test_search
|
1719
|
+
Product.create!(name: "Apple")
|
1720
|
+
Product.search_index.refresh
|
1721
|
+
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1722
|
+
end
|
1723
|
+
end
|
1724
|
+
```
|
1681
1725
|
|
1682
1726
|
### RSpec
|
1683
1727
|
|
1728
|
+
Add to your `spec/spec_helper.rb`:
|
1729
|
+
|
1684
1730
|
```ruby
|
1685
|
-
|
1686
|
-
|
1731
|
+
RSpec.configure do |config|
|
1732
|
+
config.before(:suite) do
|
1733
|
+
# reindex models
|
1687
1734
|
Product.reindex
|
1688
|
-
|
1735
|
+
|
1736
|
+
# and disable callbacks
|
1737
|
+
Searchkick.disable_callbacks
|
1738
|
+
end
|
1739
|
+
|
1740
|
+
config.around(:each, search: true) do |example|
|
1741
|
+
Searchkick.enable_callbacks
|
1742
|
+
example.run
|
1743
|
+
Searchkick.disable_callbacks
|
1744
|
+
end
|
1745
|
+
end
|
1746
|
+
```
|
1747
|
+
|
1748
|
+
And use:
|
1749
|
+
|
1750
|
+
```ruby
|
1751
|
+
describe Product, search: true do
|
1752
|
+
it "searches" do
|
1753
|
+
Product.create!(name: "Apple")
|
1754
|
+
Product.search_index.refresh
|
1755
|
+
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1689
1756
|
end
|
1690
1757
|
end
|
1691
1758
|
```
|
1692
1759
|
|
1693
1760
|
### Factory Girl
|
1694
1761
|
|
1762
|
+
Manually reindex after an instance is created.
|
1763
|
+
|
1695
1764
|
```ruby
|
1696
1765
|
product = FactoryGirl.create(:product)
|
1697
1766
|
product.reindex(refresh: true)
|
@@ -1716,6 +1785,10 @@ Important notes are listed below.
|
|
1716
1785
|
- Removed support for Elasticsearch 1 as it reaches [end of life](https://www.elastic.co/support/eol)
|
1717
1786
|
- Removed facets, legacy options, and legacy methods
|
1718
1787
|
- Invalid options now throw an `ArgumentError`
|
1788
|
+
- The `query` and `json` options have been removed in favor of `body`
|
1789
|
+
- The `include` option has been removed in favor of `includes`
|
1790
|
+
- The `personalize` option has been removed in favor of `boost_where`
|
1791
|
+
- The `partial` option has been removed in favor of `operator`
|
1719
1792
|
- Renamed `select_v2` to `select` (legacy `select` no longer available)
|
1720
1793
|
- The `_all` field is disabled if `searchable` option is used (for performance)
|
1721
1794
|
- The `partial_reindex(:method_name)` method has been replaced with `reindex(:method_name)`
|
@@ -1754,6 +1827,15 @@ Before `0.3.0`, locations were indexed incorrectly. When upgrading, be sure to r
|
|
1754
1827
|
|
1755
1828
|
## Elasticsearch Gotchas
|
1756
1829
|
|
1830
|
+
### Consistency
|
1831
|
+
|
1832
|
+
Elasticsearch is eventually consistent, meaning it can take up to a second for a change to reflect in search. You can use the `refresh` method to have it show up immediately.
|
1833
|
+
|
1834
|
+
```ruby
|
1835
|
+
product.save!
|
1836
|
+
Product.search_index.refresh
|
1837
|
+
```
|
1838
|
+
|
1757
1839
|
### Inconsistent Scores
|
1758
1840
|
|
1759
1841
|
Due to the distributed nature of Elasticsearch, you can get incorrect results when the number of documents in the index is low. You can [read more about it here](https://www.elastic.co/blog/understanding-query-then-fetch-vs-dfs-query-then-fetch). To fix this, do:
|
data/lib/searchkick/index.rb
CHANGED
@@ -25,7 +25,7 @@ module Searchkick
|
|
25
25
|
}
|
26
26
|
end
|
27
27
|
|
28
|
-
keyword_mapping[:ignore_above] = (options[:ignore_above] ||
|
28
|
+
keyword_mapping[:ignore_above] = (options[:ignore_above] || 30000) unless below22
|
29
29
|
|
30
30
|
settings = {
|
31
31
|
analysis: {
|
@@ -227,6 +227,8 @@ module Searchkick
|
|
227
227
|
|
228
228
|
word = options[:word] != false && (!options[:match] || options[:match] == :word)
|
229
229
|
|
230
|
+
mapping_options[:searchable].delete("_all")
|
231
|
+
|
230
232
|
mapping_options.values.flatten.uniq.each do |field|
|
231
233
|
fields = {}
|
232
234
|
|
@@ -286,8 +288,6 @@ module Searchkick
|
|
286
288
|
dynamic_fields["{name}"] = {type: default_type, index: "no"}
|
287
289
|
end
|
288
290
|
|
289
|
-
dynamic_fields["{name}"][:ignore_above] = (options[:ignore_above] || 256) unless below22
|
290
|
-
|
291
291
|
unless options[:searchable]
|
292
292
|
if options[:match] && options[:match] != :word
|
293
293
|
dynamic_fields[options[:match]] = {type: default_type, index: "analyzed", analyzer: "searchkick_#{options[:match]}_index"}
|
@@ -301,7 +301,7 @@ module Searchkick
|
|
301
301
|
# http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/
|
302
302
|
multi_field = dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}"))
|
303
303
|
|
304
|
-
all_enabled = !options[:searchable] || options[:searchable].to_a.include?("_all")
|
304
|
+
all_enabled = !options[:searchable] || options[:searchable].to_a.map(&:to_s).include?("_all")
|
305
305
|
|
306
306
|
mappings = {
|
307
307
|
_default_: {
|
data/lib/searchkick/model.rb
CHANGED
@@ -26,7 +26,7 @@ module Searchkick
|
|
26
26
|
|
27
27
|
class << self
|
28
28
|
def searchkick_search(term = "*", **options, &block)
|
29
|
-
|
29
|
+
Searchkick.search(term, {model: self}.merge(options), &block)
|
30
30
|
end
|
31
31
|
alias_method Searchkick.search_method_name, :searchkick_search if Searchkick.search_method_name
|
32
32
|
|
@@ -144,6 +144,12 @@ module Searchkick
|
|
144
144
|
def should_index?
|
145
145
|
true
|
146
146
|
end unless method_defined?(:should_index?)
|
147
|
+
|
148
|
+
if defined?(Cequel) && self < Cequel::Record && !method_defined?(:destroyed?)
|
149
|
+
def destroyed?
|
150
|
+
transient?
|
151
|
+
end
|
152
|
+
end
|
147
153
|
end
|
148
154
|
end
|
149
155
|
end
|
@@ -6,7 +6,7 @@ module Searchkick
|
|
6
6
|
model = class_name.constantize
|
7
7
|
|
8
8
|
limit = model.searchkick_index.options[:batch_size] || 1000
|
9
|
-
record_ids =
|
9
|
+
record_ids = model.searchkick_index.reindex_queue.reserve(limit: limit)
|
10
10
|
if record_ids.any?
|
11
11
|
Searchkick::ProcessBatchJob.perform_later(
|
12
12
|
class_name: model.name,
|
data/lib/searchkick/query.rb
CHANGED
@@ -283,18 +283,25 @@ module Searchkick
|
|
283
283
|
|
284
284
|
shared_options[:operator] = operator if match_type == :match
|
285
285
|
|
286
|
+
exclude_analyzer = nil
|
287
|
+
exclude_field = field
|
288
|
+
|
286
289
|
if field == "_all" || field.end_with?(".analyzed")
|
287
290
|
shared_options[:cutoff_frequency] = 0.001 unless operator == "and" || misspellings == false
|
288
291
|
qs.concat [
|
289
292
|
shared_options.merge(analyzer: "searchkick_search"),
|
290
293
|
shared_options.merge(analyzer: "searchkick_search2")
|
291
294
|
]
|
295
|
+
exclude_analyzer = "searchkick_search2"
|
292
296
|
elsif field.end_with?(".exact")
|
293
297
|
f = field.split(".")[0..-2].join(".")
|
294
298
|
queries_to_add << {match: {f => shared_options.merge(analyzer: "keyword")}}
|
299
|
+
exclude_field = f
|
300
|
+
exclude_analyzer = "keyword"
|
295
301
|
else
|
296
302
|
analyzer = field =~ /\.word_(start|middle|end)\z/ ? "searchkick_word_search" : "searchkick_autocomplete_search"
|
297
303
|
qs << shared_options.merge(analyzer: analyzer)
|
304
|
+
exclude_analyzer = analyzer
|
298
305
|
end
|
299
306
|
|
300
307
|
if misspellings != false && match_type == :match
|
@@ -324,7 +331,10 @@ module Searchkick
|
|
324
331
|
options[:exclude].map do |phrase|
|
325
332
|
{
|
326
333
|
match_phrase: {
|
327
|
-
|
334
|
+
exclude_field => {
|
335
|
+
query: phrase,
|
336
|
+
analyzer: exclude_analyzer
|
337
|
+
}
|
328
338
|
}
|
329
339
|
}
|
330
340
|
end
|
data/lib/searchkick/version.rb
CHANGED
data/lib/searchkick.rb
CHANGED
@@ -81,7 +81,17 @@ module Searchkick
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def self.search(term = "*", **options, &block)
|
84
|
-
|
84
|
+
klass = options[:model]
|
85
|
+
|
86
|
+
# TODO add in next major version
|
87
|
+
# if !klass
|
88
|
+
# index_name = Array(options[:index_name])
|
89
|
+
# if index_name.size == 1 && index_name.first.respond_to?(:searchkick_index)
|
90
|
+
# klass = index_name.first
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
|
94
|
+
query = Searchkick::Query.new(klass, term, options.except(:model))
|
85
95
|
block.call(query.body) if block
|
86
96
|
if options[:execute] == false
|
87
97
|
query
|
@@ -169,6 +179,8 @@ module Searchkick
|
|
169
179
|
elsif records.respond_to?(:unscoped) && :id.respond_to?(:in)
|
170
180
|
# Nobrainer
|
171
181
|
records.unscoped.where(:id.in => ids)
|
182
|
+
elsif records.respond_to?(:key_column_names)
|
183
|
+
records.where(records.key_column_names.first => ids)
|
172
184
|
end
|
173
185
|
|
174
186
|
raise Searchkick::Error, "Not sure how to load records" if !records
|
data/test/aggs_test.rb
CHANGED
@@ -6,8 +6,8 @@ class AggsTest < Minitest::Test
|
|
6
6
|
store [
|
7
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
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},
|
10
|
-
{name: "Foo", latitude: 43.9333, longitude: 12.4667, store_id: 3, in_stock: false, color: "yellow", price: 15}
|
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
11
|
]
|
12
12
|
end
|
13
13
|
|
data/test/boost_test.rb
CHANGED
@@ -86,6 +86,14 @@ class BoostTest < Minitest::Test
|
|
86
86
|
assert_order "red", ["Red", "White"], fields: [{"name^10" => :word_start}, "color"]
|
87
87
|
end
|
88
88
|
|
89
|
+
# for issue #855
|
90
|
+
def test_apostrophes
|
91
|
+
store_names ["Valentine's Day Special"]
|
92
|
+
assert_search "Valentines", ["Valentine's Day Special"], fields: ["name^5"]
|
93
|
+
assert_search "Valentine's", ["Valentine's Day Special"], fields: ["name^5"]
|
94
|
+
assert_search "Valentine", ["Valentine's Day Special"], fields: ["name^5"]
|
95
|
+
end
|
96
|
+
|
89
97
|
def test_boost_by
|
90
98
|
store [
|
91
99
|
{name: "Tomato A"},
|
@@ -157,6 +165,8 @@ class BoostTest < Minitest::Test
|
|
157
165
|
end
|
158
166
|
|
159
167
|
def test_boost_by_indices
|
168
|
+
skip if cequel?
|
169
|
+
|
160
170
|
store_names ["Rex"], Animal
|
161
171
|
store_names ["Rexx"], Product
|
162
172
|
|
data/test/errors_test.rb
CHANGED
@@ -2,8 +2,8 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
class ErrorsTest < Minitest::Test
|
4
4
|
def test_bulk_import_raises_error
|
5
|
-
valid_dog =
|
6
|
-
invalid_dog =
|
5
|
+
valid_dog = Product.new(name: "2016-01-02")
|
6
|
+
invalid_dog = Product.new(name: "Ol' One-Leg")
|
7
7
|
index = Searchkick::Index.new "dogs", mappings: {
|
8
8
|
dog: {
|
9
9
|
properties: {
|
data/test/highlight_test.rb
CHANGED
@@ -46,6 +46,11 @@ class HighlightTest < Minitest::Test
|
|
46
46
|
assert_equal "<b><em>Hello</em></b>", Product.search("hello", fields: [:name], highlight: {encoder: "html"}, misspellings: false).first.search_highlights[:name]
|
47
47
|
end
|
48
48
|
|
49
|
+
def test_word_middle
|
50
|
+
store_names ["Two Door Cinema Club"]
|
51
|
+
assert_equal "Two Door <em>Cinema</em> Club", Product.search("ine", fields: [:name], match: :word_middle, highlight: true).first.search_highlights[:name]
|
52
|
+
end
|
53
|
+
|
49
54
|
def test_body
|
50
55
|
skip if ENV["MATCH"] == "word_start"
|
51
56
|
store_names ["Two Door Cinema Club"]
|
data/test/index_test.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require_relative "test_helper"
|
2
2
|
|
3
3
|
class IndexTest < Minitest::Test
|
4
|
+
def setup
|
5
|
+
super
|
6
|
+
Region.destroy_all
|
7
|
+
end
|
8
|
+
|
4
9
|
def test_clean_indices
|
5
10
|
old_index = Searchkick::Index.new("products_test_20130801000000000")
|
6
11
|
different_index = Searchkick::Index.new("items_test_20130801000000000")
|
@@ -127,8 +132,20 @@ class IndexTest < Minitest::Test
|
|
127
132
|
|
128
133
|
def test_large_value
|
129
134
|
skip if nobrainer?
|
135
|
+
large_value = 1000.times.map { "hello" }.join(" ")
|
136
|
+
store [{name: "Product A", text: large_value}], Region
|
137
|
+
assert_search "product", ["Product A"], {}, Region
|
138
|
+
assert_search "hello", ["Product A"], {fields: [:name, :text]}, Region
|
139
|
+
assert_search "hello", ["Product A"], {}, Region
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_very_large_value
|
143
|
+
skip if nobrainer? || elasticsearch_below22?
|
130
144
|
large_value = 10000.times.map { "hello" }.join(" ")
|
131
|
-
store [{name: "Product A",
|
132
|
-
assert_search "product", ["Product A"]
|
145
|
+
store [{name: "Product A", text: large_value}], Region
|
146
|
+
assert_search "product", ["Product A"], {}, Region
|
147
|
+
assert_search "hello", ["Product A"], {fields: [:name, :text]}, Region
|
148
|
+
# values that exceed ignore_above are not included in _all field :(
|
149
|
+
# assert_search "hello", ["Product A"], {}, Region
|
133
150
|
end
|
134
151
|
end
|
data/test/inheritance_test.rb
CHANGED
data/test/match_test.rb
CHANGED
@@ -161,21 +161,31 @@ class MatchTest < Minitest::Test
|
|
161
161
|
|
162
162
|
# butter
|
163
163
|
|
164
|
-
def
|
164
|
+
def test_exclude_butter
|
165
165
|
store_names ["Butter Tub", "Peanut Butter Tub"]
|
166
166
|
assert_search "butter", ["Butter Tub"], exclude: ["peanut butter"]
|
167
167
|
end
|
168
168
|
|
169
|
-
def
|
169
|
+
def test_exclude_butter_word_start
|
170
170
|
store_names ["Butter Tub", "Peanut Butter Tub"]
|
171
171
|
assert_search "butter", ["Butter Tub"], exclude: ["peanut butter"], match: :word_start
|
172
172
|
end
|
173
173
|
|
174
|
-
def
|
174
|
+
def test_exclude_butter_exact
|
175
175
|
store_names ["Butter Tub", "Peanut Butter Tub"]
|
176
176
|
assert_search "butter", [], exclude: ["peanut butter"], match: :exact
|
177
177
|
end
|
178
178
|
|
179
|
+
def test_exclude_same_exact
|
180
|
+
store_names ["Butter Tub", "Peanut Butter Tub"]
|
181
|
+
assert_search "Butter Tub", [], exclude: ["Butter Tub"], match: :exact
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_exclude_egg_word_start
|
185
|
+
store_names ["eggs", "eggplant"]
|
186
|
+
assert_search "egg", ["eggs"], exclude: ["eggplant"], match: :word_start
|
187
|
+
end
|
188
|
+
|
179
189
|
# other
|
180
190
|
|
181
191
|
def test_all
|
@@ -184,6 +194,7 @@ class MatchTest < Minitest::Test
|
|
184
194
|
end
|
185
195
|
|
186
196
|
def test_no_arguments
|
197
|
+
store_names []
|
187
198
|
assert_equal [], Product.search.to_a
|
188
199
|
end
|
189
200
|
|
data/test/model_test.rb
CHANGED
@@ -37,6 +37,6 @@ class ModelTest < Minitest::Test
|
|
37
37
|
def test_multiple_models
|
38
38
|
store_names ["Product A"]
|
39
39
|
store_names ["Product B"], Speaker
|
40
|
-
assert_equal Product.all + Speaker.all, Searchkick.search("product", index_name: [Product, Speaker], fields: [:name], order: "name").to_a
|
40
|
+
assert_equal Product.all.to_a + Speaker.all.to_a, Searchkick.search("product", index_name: [Product, Speaker], fields: [:name], order: "name").to_a
|
41
41
|
end
|
42
42
|
end
|
data/test/order_test.rb
CHANGED
data/test/records_test.rb
CHANGED
data/test/reindex_test.rb
CHANGED
@@ -2,7 +2,7 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
class ReindexTest < Minitest::Test
|
4
4
|
def test_scoped
|
5
|
-
skip if nobrainer?
|
5
|
+
skip if nobrainer? || cequel?
|
6
6
|
|
7
7
|
store_names ["Product A"]
|
8
8
|
Searchkick.callbacks(false) do
|
@@ -13,7 +13,7 @@ class ReindexTest < Minitest::Test
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_associations
|
16
|
-
skip if nobrainer?
|
16
|
+
skip if nobrainer? || cequel?
|
17
17
|
|
18
18
|
store_names ["Product A"]
|
19
19
|
store = Store.create!(name: "Test")
|
data/test/test_helper.rb
CHANGED
@@ -45,6 +45,10 @@ def nobrainer?
|
|
45
45
|
defined?(NoBrainer)
|
46
46
|
end
|
47
47
|
|
48
|
+
def cequel?
|
49
|
+
defined?(Cequel)
|
50
|
+
end
|
51
|
+
|
48
52
|
if defined?(Mongoid)
|
49
53
|
Mongoid.logger.level = Logger::INFO
|
50
54
|
Mongo::Logger.logger.level = Logger::INFO if defined?(Mongo::Logger)
|
@@ -162,6 +166,88 @@ elsif defined?(NoBrainer)
|
|
162
166
|
|
163
167
|
class Cat < Animal
|
164
168
|
end
|
169
|
+
elsif defined?(Cequel)
|
170
|
+
cequel =
|
171
|
+
Cequel.connect(
|
172
|
+
host: "127.0.0.1",
|
173
|
+
port: 9042,
|
174
|
+
keyspace: "searchkick_test",
|
175
|
+
default_consistency: :all
|
176
|
+
)
|
177
|
+
# cequel.logger = ActiveSupport::Logger.new(STDOUT)
|
178
|
+
cequel.schema.drop! if cequel.schema.exists?
|
179
|
+
cequel.schema.create!
|
180
|
+
Cequel::Record.connection = cequel
|
181
|
+
|
182
|
+
class Product
|
183
|
+
include Cequel::Record
|
184
|
+
|
185
|
+
key :id, :uuid, auto: true
|
186
|
+
column :name, :text, index: true
|
187
|
+
column :store_id, :int
|
188
|
+
column :in_stock, :boolean
|
189
|
+
column :backordered, :boolean
|
190
|
+
column :orders_count, :int
|
191
|
+
column :found_rate, :decimal
|
192
|
+
column :price, :int
|
193
|
+
column :color, :text
|
194
|
+
column :latitude, :decimal
|
195
|
+
column :longitude, :decimal
|
196
|
+
column :description, :text
|
197
|
+
column :alt_description, :text
|
198
|
+
column :created_at, :timestamp
|
199
|
+
end
|
200
|
+
|
201
|
+
class Store
|
202
|
+
include Cequel::Record
|
203
|
+
|
204
|
+
key :id, :timeuuid, auto: true
|
205
|
+
column :name, :text
|
206
|
+
|
207
|
+
# has issue with id serialization
|
208
|
+
def search_data
|
209
|
+
{
|
210
|
+
name: name
|
211
|
+
}
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
class Region
|
216
|
+
include Cequel::Record
|
217
|
+
|
218
|
+
key :id, :timeuuid, auto: true
|
219
|
+
column :name, :text
|
220
|
+
column :text, :text
|
221
|
+
end
|
222
|
+
|
223
|
+
class Speaker
|
224
|
+
include Cequel::Record
|
225
|
+
|
226
|
+
key :id, :timeuuid, auto: true
|
227
|
+
column :name, :text
|
228
|
+
end
|
229
|
+
|
230
|
+
class Animal
|
231
|
+
include Cequel::Record
|
232
|
+
|
233
|
+
key :id, :timeuuid, auto: true
|
234
|
+
column :name, :text
|
235
|
+
|
236
|
+
# has issue with id serialization
|
237
|
+
def search_data
|
238
|
+
{
|
239
|
+
name: name
|
240
|
+
}
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
class Dog < Animal
|
245
|
+
end
|
246
|
+
|
247
|
+
class Cat < Animal
|
248
|
+
end
|
249
|
+
|
250
|
+
[Product, Store, Region, Speaker, Animal].each(&:synchronize_schema)
|
165
251
|
else
|
166
252
|
require "active_record"
|
167
253
|
|
data/test/where_test.rb
CHANGED
@@ -10,16 +10,22 @@ class WhereTest < Minitest::Test
|
|
10
10
|
{name: "Product D", store_id: 4, in_stock: false, backordered: false, created_at: now - 3, orders_count: 1}
|
11
11
|
]
|
12
12
|
assert_search "product", ["Product A", "Product B"], where: {in_stock: true}
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
|
14
|
+
# due to precision
|
15
|
+
unless cequel?
|
16
|
+
# date
|
17
|
+
assert_search "product", ["Product A"], where: {created_at: {gt: now - 1}}
|
18
|
+
assert_search "product", ["Product A", "Product B"], where: {created_at: {gte: now - 1}}
|
19
|
+
assert_search "product", ["Product D"], where: {created_at: {lt: now - 2}}
|
20
|
+
assert_search "product", ["Product C", "Product D"], where: {created_at: {lte: now - 2}}
|
21
|
+
end
|
22
|
+
|
18
23
|
# integer
|
19
24
|
assert_search "product", ["Product A"], where: {store_id: {lt: 2}}
|
20
25
|
assert_search "product", ["Product A", "Product B"], where: {store_id: {lte: 2}}
|
21
26
|
assert_search "product", ["Product D"], where: {store_id: {gt: 3}}
|
22
27
|
assert_search "product", ["Product C", "Product D"], where: {store_id: {gte: 3}}
|
28
|
+
|
23
29
|
# range
|
24
30
|
assert_search "product", ["Product A", "Product B"], where: {store_id: 1..2}
|
25
31
|
assert_search "product", ["Product A"], where: {store_id: 1...2}
|
@@ -27,23 +33,30 @@ class WhereTest < Minitest::Test
|
|
27
33
|
assert_search "product", ["Product B", "Product C", "Product D"], where: {store_id: {not: 1}}
|
28
34
|
assert_search "product", ["Product C", "Product D"], where: {store_id: {not: [1, 2]}}
|
29
35
|
assert_search "product", ["Product A"], where: {user_ids: {lte: 2, gte: 2}}
|
36
|
+
|
30
37
|
# or
|
31
38
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{in_stock: true}, {store_id: 3}]]}
|
32
39
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{orders_count: [2, 4]}, {store_id: [1, 2]}]]}
|
33
40
|
assert_search "product", ["Product A", "Product D"], where: {or: [[{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]]}
|
41
|
+
|
34
42
|
# _or
|
35
43
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {_or: [{in_stock: true}, {store_id: 3}]}
|
36
44
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {_or: [{orders_count: [2, 4]}, {store_id: [1, 2]}]}
|
37
45
|
assert_search "product", ["Product A", "Product D"], where: {_or: [{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]}
|
46
|
+
|
38
47
|
# _and
|
39
48
|
assert_search "product", ["Product A"], where: {_and: [{in_stock: true}, {backordered: true}]}
|
49
|
+
|
40
50
|
# _not
|
41
51
|
assert_search "product", ["Product B", "Product C"], where: {_not: {_or: [{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]}}
|
52
|
+
|
42
53
|
# all
|
43
54
|
assert_search "product", ["Product A", "Product C"], where: {user_ids: {all: [1, 3]}}
|
44
55
|
assert_search "product", [], where: {user_ids: {all: [1, 2, 3, 4]}}
|
56
|
+
|
45
57
|
# any / nested terms
|
46
58
|
assert_search "product", ["Product B", "Product C"], where: {user_ids: {not: [2], in: [1, 3]}}
|
59
|
+
|
47
60
|
# not / exists
|
48
61
|
assert_search "product", ["Product D"], where: {user_ids: nil}
|
49
62
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {user_ids: {not: nil}}
|
@@ -78,7 +91,7 @@ class WhereTest < Minitest::Test
|
|
78
91
|
|
79
92
|
def test_where_id
|
80
93
|
store_names ["Product A"]
|
81
|
-
product = Product.
|
94
|
+
product = Product.first
|
82
95
|
assert_search "product", ["Product A"], where: {id: product.id.to_s}
|
83
96
|
end
|
84
97
|
|
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: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -138,7 +138,9 @@ files:
|
|
138
138
|
- test/gemfiles/activerecord40.gemfile
|
139
139
|
- test/gemfiles/activerecord41.gemfile
|
140
140
|
- test/gemfiles/activerecord42.gemfile
|
141
|
+
- test/gemfiles/activerecord51.gemfile
|
141
142
|
- test/gemfiles/apartment.gemfile
|
143
|
+
- test/gemfiles/cequel.gemfile
|
142
144
|
- test/gemfiles/mongoid2.gemfile
|
143
145
|
- test/gemfiles/mongoid3.gemfile
|
144
146
|
- test/gemfiles/mongoid4.gemfile
|
@@ -209,7 +211,9 @@ test_files:
|
|
209
211
|
- test/gemfiles/activerecord40.gemfile
|
210
212
|
- test/gemfiles/activerecord41.gemfile
|
211
213
|
- test/gemfiles/activerecord42.gemfile
|
214
|
+
- test/gemfiles/activerecord51.gemfile
|
212
215
|
- test/gemfiles/apartment.gemfile
|
216
|
+
- test/gemfiles/cequel.gemfile
|
213
217
|
- test/gemfiles/mongoid2.gemfile
|
214
218
|
- test/gemfiles/mongoid3.gemfile
|
215
219
|
- test/gemfiles/mongoid4.gemfile
|