searchkick 2.3.2 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +377 -84
  3. data/LICENSE.txt +1 -1
  4. data/README.md +859 -602
  5. data/lib/searchkick/bulk_reindex_job.rb +13 -9
  6. data/lib/searchkick/controller_runtime.rb +40 -0
  7. data/lib/searchkick/hash_wrapper.rb +12 -0
  8. data/lib/searchkick/index.rb +281 -356
  9. data/lib/searchkick/index_cache.rb +30 -0
  10. data/lib/searchkick/index_options.rb +487 -281
  11. data/lib/searchkick/indexer.rb +15 -8
  12. data/lib/searchkick/log_subscriber.rb +57 -0
  13. data/lib/searchkick/middleware.rb +9 -2
  14. data/lib/searchkick/model.rb +72 -118
  15. data/lib/searchkick/multi_search.rb +9 -10
  16. data/lib/searchkick/process_batch_job.rb +12 -15
  17. data/lib/searchkick/process_queue_job.rb +22 -13
  18. data/lib/searchkick/query.rb +458 -217
  19. data/lib/searchkick/railtie.rb +7 -0
  20. data/lib/searchkick/record_data.rb +128 -0
  21. data/lib/searchkick/record_indexer.rb +164 -0
  22. data/lib/searchkick/reindex_queue.rb +51 -9
  23. data/lib/searchkick/reindex_v2_job.rb +10 -32
  24. data/lib/searchkick/relation.rb +247 -0
  25. data/lib/searchkick/relation_indexer.rb +155 -0
  26. data/lib/searchkick/results.rb +201 -82
  27. data/lib/searchkick/version.rb +1 -1
  28. data/lib/searchkick/where.rb +11 -0
  29. data/lib/searchkick.rb +269 -97
  30. data/lib/tasks/searchkick.rake +37 -0
  31. metadata +24 -178
  32. data/.gitignore +0 -22
  33. data/.travis.yml +0 -39
  34. data/Gemfile +0 -16
  35. data/Rakefile +0 -20
  36. data/benchmark/Gemfile +0 -23
  37. data/benchmark/benchmark.rb +0 -97
  38. data/lib/searchkick/logging.rb +0 -242
  39. data/lib/searchkick/tasks.rb +0 -33
  40. data/searchkick.gemspec +0 -28
  41. data/test/aggs_test.rb +0 -197
  42. data/test/autocomplete_test.rb +0 -75
  43. data/test/boost_test.rb +0 -202
  44. data/test/callbacks_test.rb +0 -59
  45. data/test/ci/before_install.sh +0 -17
  46. data/test/errors_test.rb +0 -19
  47. data/test/gemfiles/activerecord31.gemfile +0 -7
  48. data/test/gemfiles/activerecord32.gemfile +0 -7
  49. data/test/gemfiles/activerecord40.gemfile +0 -8
  50. data/test/gemfiles/activerecord41.gemfile +0 -8
  51. data/test/gemfiles/activerecord42.gemfile +0 -7
  52. data/test/gemfiles/activerecord50.gemfile +0 -7
  53. data/test/gemfiles/apartment.gemfile +0 -8
  54. data/test/gemfiles/cequel.gemfile +0 -8
  55. data/test/gemfiles/mongoid2.gemfile +0 -7
  56. data/test/gemfiles/mongoid3.gemfile +0 -6
  57. data/test/gemfiles/mongoid4.gemfile +0 -7
  58. data/test/gemfiles/mongoid5.gemfile +0 -7
  59. data/test/gemfiles/mongoid6.gemfile +0 -12
  60. data/test/gemfiles/nobrainer.gemfile +0 -8
  61. data/test/gemfiles/parallel_tests.gemfile +0 -8
  62. data/test/geo_shape_test.rb +0 -175
  63. data/test/highlight_test.rb +0 -78
  64. data/test/index_test.rb +0 -166
  65. data/test/inheritance_test.rb +0 -83
  66. data/test/marshal_test.rb +0 -8
  67. data/test/match_test.rb +0 -276
  68. data/test/misspellings_test.rb +0 -56
  69. data/test/model_test.rb +0 -42
  70. data/test/multi_search_test.rb +0 -36
  71. data/test/multi_tenancy_test.rb +0 -22
  72. data/test/order_test.rb +0 -46
  73. data/test/pagination_test.rb +0 -70
  74. data/test/partial_reindex_test.rb +0 -58
  75. data/test/query_test.rb +0 -35
  76. data/test/records_test.rb +0 -10
  77. data/test/reindex_test.rb +0 -64
  78. data/test/reindex_v2_job_test.rb +0 -32
  79. data/test/routing_test.rb +0 -23
  80. data/test/should_index_test.rb +0 -32
  81. data/test/similar_test.rb +0 -28
  82. data/test/sql_test.rb +0 -214
  83. data/test/suggest_test.rb +0 -95
  84. data/test/support/kaminari.yml +0 -21
  85. data/test/synonyms_test.rb +0 -67
  86. data/test/test_helper.rb +0 -567
  87. data/test/where_test.rb +0 -223
data/test/model_test.rb DELETED
@@ -1,42 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class ModelTest < Minitest::Test
4
- def test_disable_callbacks_model
5
- store_names ["product a"]
6
-
7
- Product.disable_search_callbacks
8
- assert !Product.search_callbacks?
9
-
10
- store_names ["product b"]
11
- assert_search "product", ["product a"]
12
-
13
- Product.enable_search_callbacks
14
- Product.reindex
15
-
16
- assert_search "product", ["product a", "product b"]
17
- end
18
-
19
- def test_disable_callbacks_global
20
- # make sure callbacks default to on
21
- assert Searchkick.callbacks?
22
-
23
- store_names ["product a"]
24
-
25
- Searchkick.disable_callbacks
26
- assert !Searchkick.callbacks?
27
-
28
- store_names ["product b"]
29
- assert_search "product", ["product a"]
30
-
31
- Searchkick.enable_callbacks
32
- Product.reindex
33
-
34
- assert_search "product", ["product a", "product b"]
35
- end
36
-
37
- def test_multiple_models
38
- store_names ["Product A"]
39
- store_names ["Product B"], Speaker
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
- end
42
- end
@@ -1,36 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class MultiSearchTest < Minitest::Test
4
- def test_basic
5
- store_names ["Product A"]
6
- store_names ["Store A"], Store
7
- products = Product.search("*", execute: false)
8
- stores = Store.search("*", execute: false)
9
- Searchkick.multi_search([products, stores])
10
- assert_equal ["Product A"], products.map(&:name)
11
- assert_equal ["Store A"], stores.map(&:name)
12
- end
13
-
14
- def test_error
15
- store_names ["Product A"]
16
- products = Product.search("*", execute: false)
17
- stores = Store.search("*", order: [:bad_field], execute: false)
18
- Searchkick.multi_search([products, stores])
19
- assert !products.error
20
- assert stores.error
21
- end
22
-
23
- def test_misspellings_below_unmet
24
- store_names ["abc", "abd", "aee"]
25
- products = Product.search("abc", misspellings: {below: 2}, execute: false)
26
- Searchkick.multi_search([products])
27
- assert_equal ["abc"], products.map(&:name)
28
- end
29
-
30
- def test_misspellings_below_unmet_retry
31
- store_names ["abc", "abd", "aee"]
32
- products = Product.search("abc", misspellings: {below: 2}, execute: false)
33
- Searchkick.multi_search([products], retry_misspellings: true)
34
- assert_equal ["abc", "abd"], products.map(&:name)
35
- end
36
- end
@@ -1,22 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class MultiTenancyTest < Minitest::Test
4
- def setup
5
- skip unless defined?(Apartment)
6
- end
7
-
8
- def test_basic
9
- Apartment::Tenant.switch!("tenant1")
10
- store_names ["Product A"], Tenant
11
- Apartment::Tenant.switch!("tenant2")
12
- store_names ["Product B"], Tenant
13
- Apartment::Tenant.switch!("tenant1")
14
- assert_search "product", ["Product A"], {load: false}, Tenant
15
- Apartment::Tenant.switch!("tenant2")
16
- assert_search "product", ["Product B"], {load: false}, Tenant
17
- end
18
-
19
- def teardown
20
- Apartment::Tenant.reset if defined?(Apartment)
21
- end
22
- end
data/test/order_test.rb DELETED
@@ -1,46 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class OrderTest < Minitest::Test
4
- def test_order_hash
5
- store_names ["Product A", "Product B", "Product C", "Product D"]
6
- assert_order "product", ["Product D", "Product C", "Product B", "Product A"], order: {name: :desc}
7
- end
8
-
9
- def test_order_string
10
- store_names ["Product A", "Product B", "Product C", "Product D"]
11
- assert_order "product", ["Product A", "Product B", "Product C", "Product D"], order: "name"
12
- end
13
-
14
- def test_order_id
15
- skip if cequel?
16
-
17
- store_names ["Product A", "Product B"]
18
- product_a = Product.where(name: "Product A").first
19
- product_b = Product.where(name: "Product B").first
20
- assert_order "product", [product_a, product_b].sort_by(&:id).map(&:name), order: {id: :asc}
21
- end
22
-
23
- def test_order_multiple
24
- store [
25
- {name: "Product A", color: "blue", store_id: 1},
26
- {name: "Product B", color: "red", store_id: 3},
27
- {name: "Product C", color: "red", store_id: 2}
28
- ]
29
- assert_order "product", ["Product A", "Product B", "Product C"], order: {color: :asc, store_id: :desc}
30
- end
31
-
32
- def test_order_ignore_unmapped
33
- skip unless elasticsearch_below50?
34
- assert_order "product", [], order: {not_mapped: {ignore_unmapped: true}}, conversions: false
35
- end
36
-
37
- def test_order_unmapped_type
38
- skip if elasticsearch_below50?
39
- assert_order "product", [], order: {not_mapped: {unmapped_type: "long"}}, conversions: false
40
- end
41
-
42
- def test_order_array
43
- store [{name: "San Francisco", latitude: 37.7833, longitude: -122.4167}]
44
- assert_order "francisco", ["San Francisco"], order: [{_geo_distance: {location: "0,0"}}]
45
- end
46
- end
@@ -1,70 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class PaginationTest < Minitest::Test
4
- def test_limit
5
- store_names ["Product A", "Product B", "Product C", "Product D"]
6
- assert_order "product", ["Product A", "Product B"], order: {name: :asc}, limit: 2
7
- end
8
-
9
- def test_no_limit
10
- names = 20.times.map { |i| "Product #{i}" }
11
- store_names names
12
- assert_search "product", names
13
- end
14
-
15
- def test_offset
16
- store_names ["Product A", "Product B", "Product C", "Product D"]
17
- assert_order "product", ["Product C", "Product D"], order: {name: :asc}, offset: 2
18
- end
19
-
20
- def test_pagination
21
- store_names ["Product A", "Product B", "Product C", "Product D", "Product E", "Product F"]
22
- products = Product.search("product", order: {name: :asc}, page: 2, per_page: 2, padding: 1)
23
- assert_equal ["Product D", "Product E"], products.map(&:name)
24
- assert_equal "product", products.entry_name
25
- assert_equal 2, products.current_page
26
- assert_equal 1, products.padding
27
- assert_equal 2, products.per_page
28
- assert_equal 2, products.size
29
- assert_equal 2, products.length
30
- assert_equal 3, products.total_pages
31
- assert_equal 6, products.total_count
32
- assert_equal 6, products.total_entries
33
- assert_equal 2, products.limit_value
34
- assert_equal 3, products.offset_value
35
- assert_equal 3, products.offset
36
- assert_equal 3, products.next_page
37
- assert_equal 1, products.previous_page
38
- assert_equal 1, products.prev_page
39
- assert !products.first_page?
40
- assert !products.last_page?
41
- assert !products.empty?
42
- assert !products.out_of_range?
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_kaminari
55
- skip unless defined?(Kaminari)
56
-
57
- require "action_view"
58
-
59
- I18n.load_path = Dir["test/support/kaminari.yml"]
60
- I18n.backend.load_translations
61
-
62
- view = ActionView::Base.new
63
-
64
- store_names ["Product A"]
65
- assert_equal "Displaying <b>1</b> product", view.page_entries_info(Product.search("product"))
66
-
67
- store_names ["Product B"]
68
- assert_equal "Displaying <b>all 2</b> products", view.page_entries_info(Product.search("product"))
69
- end
70
- end
@@ -1,58 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class PartialReindexTest < Minitest::Test
4
- def test_class_method
5
- store [{name: "Hi", color: "Blue"}]
6
-
7
- # normal search
8
- assert_search "hi", ["Hi"], fields: [:name], load: false
9
- assert_search "blue", ["Hi"], fields: [:color], load: false
10
-
11
- # update
12
- product = Product.first
13
- product.name = "Bye"
14
- product.color = "Red"
15
- Searchkick.callbacks(false) do
16
- product.save!
17
- end
18
- Product.searchkick_index.refresh
19
-
20
- # index not updated
21
- assert_search "hi", ["Hi"], fields: [:name], load: false
22
- assert_search "blue", ["Hi"], fields: [:color], load: false
23
-
24
- # partial reindex
25
- Product.reindex(:search_name)
26
-
27
- # name updated, but not color
28
- assert_search "bye", ["Bye"], fields: [:name], load: false
29
- assert_search "blue", ["Bye"], fields: [:color], load: false
30
- end
31
-
32
- def test_instance_method
33
- store [{name: "Hi", color: "Blue"}]
34
-
35
- # normal search
36
- assert_search "hi", ["Hi"], fields: [:name], load: false
37
- assert_search "blue", ["Hi"], fields: [:color], load: false
38
-
39
- # update
40
- product = Product.first
41
- product.name = "Bye"
42
- product.color = "Red"
43
- Searchkick.callbacks(false) do
44
- product.save!
45
- end
46
- Product.searchkick_index.refresh
47
-
48
- # index not updated
49
- assert_search "hi", ["Hi"], fields: [:name], load: false
50
- assert_search "blue", ["Hi"], fields: [:color], load: false
51
-
52
- product.reindex(:search_name, refresh: true)
53
-
54
- # name updated, but not color
55
- assert_search "bye", ["Bye"], fields: [:name], load: false
56
- assert_search "blue", ["Bye"], fields: [:color], load: false
57
- end
58
- end
data/test/query_test.rb DELETED
@@ -1,35 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class QueryTest < Minitest::Test
4
- def test_basic
5
- store_names ["Milk", "Apple"]
6
- query = Product.search("milk", execute: false)
7
- # query.body = {query: {match_all: {}}}
8
- # query.body = {query: {match: {name: "Apple"}}}
9
- query.body[:query] = {match_all: {}}
10
- assert_equal ["Apple", "Milk"], query.map(&:name).sort
11
- assert_equal ["Apple", "Milk"], query.execute.map(&:name).sort
12
- end
13
-
14
- def test_with_effective_min_score
15
- store_names ["Milk", "Milk2"]
16
- assert_search "milk", ["Milk"], body_options: {min_score: 1}
17
- end
18
-
19
- def test_with_uneffective_min_score
20
- store_names ["Milk", "Milk2"]
21
- assert_search "milk", ["Milk", "Milk2"], body_options: {min_score: 0.0001}
22
- end
23
-
24
- def test_default_timeout
25
- assert_equal "6s", Product.search("*", execute: false).body[:timeout]
26
- end
27
-
28
- def test_timeout_override
29
- assert_equal "1s", Product.search("*", body_options: {timeout: "1s"}, execute: false).body[:timeout]
30
- end
31
-
32
- def test_request_params
33
- assert_equal "dfs_query_then_fetch", Product.search("*", request_params: {search_type: "dfs_query_then_fetch"}, execute: false).params[:search_type]
34
- end
35
- end
data/test/records_test.rb DELETED
@@ -1,10 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class RecordsTest < Minitest::Test
4
- def test_records
5
- skip if cequel?
6
-
7
- store_names ["Milk", "Apple"]
8
- assert_equal Product.search("milk").records.where(name: "Milk").count, 1
9
- end
10
- end
data/test/reindex_test.rb DELETED
@@ -1,64 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class ReindexTest < Minitest::Test
4
- def test_scoped
5
- skip if nobrainer? || cequel?
6
-
7
- store_names ["Product A"]
8
- Searchkick.callbacks(false) do
9
- store_names ["Product B", "Product C"]
10
- end
11
- Product.where(name: "Product B").reindex(refresh: true)
12
- assert_search "product", ["Product A", "Product B"]
13
- end
14
-
15
- def test_associations
16
- skip if nobrainer? || cequel?
17
-
18
- store_names ["Product A"]
19
- store = Store.create!(name: "Test")
20
- Product.create!(name: "Product B", store_id: store.id)
21
- store.products.reindex(refresh: true)
22
- assert_search "product", ["Product A", "Product B"]
23
- end
24
-
25
- def test_async
26
- skip if !defined?(ActiveJob)
27
-
28
- Searchkick.callbacks(false) do
29
- store_names ["Product A"]
30
- end
31
- reindex = Product.reindex(async: true)
32
- assert_search "product", [], conversions: false
33
-
34
- index = Searchkick::Index.new(reindex[:index_name])
35
- index.refresh
36
- assert_equal 1, index.total_docs
37
-
38
- Product.searchkick_index.promote(reindex[:index_name])
39
- assert_search "product", ["Product A"]
40
- end
41
-
42
- def test_async_non_integer_pk
43
- skip if !defined?(ActiveJob)
44
-
45
- Sku.create(id: SecureRandom.hex, name: "Test")
46
- reindex = Sku.reindex(async: true)
47
- assert_search "sku", [], conversions: false
48
-
49
- index = Searchkick::Index.new(reindex[:index_name])
50
- index.refresh
51
- assert_equal 1, index.total_docs
52
- end
53
-
54
- def test_refresh_interval
55
- reindex = Product.reindex(refresh_interval: "30s", async: true, import: false)
56
- index = Searchkick::Index.new(reindex[:index_name])
57
- assert_nil Product.search_index.refresh_interval
58
- assert_equal "30s", index.refresh_interval
59
-
60
- Product.search_index.promote(index.name, update_refresh_interval: true)
61
- assert_equal "1s", index.refresh_interval
62
- assert_equal "1s", Product.search_index.refresh_interval
63
- end
64
- end
@@ -1,32 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class ReindexV2JobTest < Minitest::Test
4
- def setup
5
- skip unless defined?(ActiveJob)
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::ReindexV2Job.perform_later("Product", product.id.to_s)
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::ReindexV2Job.perform_later("Product", product.id.to_s)
29
- Product.searchkick_index.refresh
30
- assert_search "*", []
31
- end
32
- end
data/test/routing_test.rb DELETED
@@ -1,23 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class RoutingTest < Minitest::Test
4
- def test_routing_query
5
- query = Store.search("Dollar Tree", routing: "Dollar Tree", execute: false)
6
- assert_equal query.params[:routing], "Dollar Tree"
7
- end
8
-
9
- def test_routing_mappings
10
- index_options = Store.searchkick_index.index_options
11
- assert_equal index_options[:mappings][:_default_][:_routing], required: true
12
- end
13
-
14
- def test_routing_correct_node
15
- store_names ["Dollar Tree"], Store
16
- assert_search "*", ["Dollar Tree"], {routing: "Dollar Tree"}, Store
17
- end
18
-
19
- def test_routing_incorrect_node
20
- store_names ["Dollar Tree"], Store
21
- assert_search "*", ["Dollar Tree"], {routing: "Boom"}, Store
22
- end
23
- end
@@ -1,32 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class ShouldIndexTest < Minitest::Test
4
- def test_basic
5
- store_names ["INDEX", "DO NOT INDEX"]
6
- assert_search "index", ["INDEX"]
7
- end
8
-
9
- def test_default_true
10
- assert Animal.new.should_index?
11
- end
12
-
13
- def test_change_to_true
14
- store_names ["DO NOT INDEX"]
15
- assert_search "index", []
16
- product = Product.first
17
- product.name = "INDEX"
18
- product.save!
19
- Product.searchkick_index.refresh
20
- assert_search "index", ["INDEX"]
21
- end
22
-
23
- def test_change_to_false
24
- store_names ["INDEX"]
25
- assert_search "index", ["INDEX"]
26
- product = Product.first
27
- product.name = "DO NOT INDEX"
28
- product.save!
29
- Product.searchkick_index.refresh
30
- assert_search "index", []
31
- end
32
- end
data/test/similar_test.rb DELETED
@@ -1,28 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class SimilarTest < Minitest::Test
4
- def test_similar
5
- store_names ["Annie's Naturals Organic Shiitake & Sesame Dressing"]
6
- assert_search "Annie's Naturals Shiitake & Sesame Vinaigrette", ["Annie's Naturals Organic Shiitake & Sesame Dressing"], similar: true
7
- end
8
-
9
- def test_fields
10
- store_names ["1% Organic Milk", "2% Organic Milk", "Popcorn"]
11
- assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"]).map(&:name)
12
- end
13
-
14
- def test_order
15
- store_names ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"]
16
- assert_order "Lucerne Fat Free Chocolate Milk", ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"], similar: true
17
- end
18
-
19
- def test_limit
20
- store_names ["1% Organic Milk", "2% Organic Milk", "Fat Free Organic Milk", "Popcorn"]
21
- assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"], order: ["name"], limit: 1).map(&:name)
22
- end
23
-
24
- def test_per_page
25
- store_names ["1% Organic Milk", "2% Organic Milk", "Fat Free Organic Milk", "Popcorn"]
26
- assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"], order: ["name"], per_page: 1).map(&:name)
27
- end
28
- end