searchkick 2.3.2 → 5.2.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.
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