searchkick-hooopo 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.travis.yml +35 -0
  4. data/CHANGELOG.md +491 -0
  5. data/Gemfile +12 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +1908 -0
  8. data/Rakefile +20 -0
  9. data/benchmark/Gemfile +23 -0
  10. data/benchmark/benchmark.rb +97 -0
  11. data/lib/searchkick/bulk_reindex_job.rb +17 -0
  12. data/lib/searchkick/index.rb +500 -0
  13. data/lib/searchkick/index_options.rb +333 -0
  14. data/lib/searchkick/indexer.rb +28 -0
  15. data/lib/searchkick/logging.rb +242 -0
  16. data/lib/searchkick/middleware.rb +12 -0
  17. data/lib/searchkick/model.rb +156 -0
  18. data/lib/searchkick/process_batch_job.rb +23 -0
  19. data/lib/searchkick/process_queue_job.rb +23 -0
  20. data/lib/searchkick/query.rb +901 -0
  21. data/lib/searchkick/reindex_queue.rb +38 -0
  22. data/lib/searchkick/reindex_v2_job.rb +39 -0
  23. data/lib/searchkick/results.rb +216 -0
  24. data/lib/searchkick/tasks.rb +33 -0
  25. data/lib/searchkick/version.rb +3 -0
  26. data/lib/searchkick.rb +215 -0
  27. data/searchkick.gemspec +28 -0
  28. data/test/aggs_test.rb +197 -0
  29. data/test/autocomplete_test.rb +75 -0
  30. data/test/boost_test.rb +175 -0
  31. data/test/callbacks_test.rb +59 -0
  32. data/test/ci/before_install.sh +17 -0
  33. data/test/errors_test.rb +19 -0
  34. data/test/gemfiles/activerecord31.gemfile +7 -0
  35. data/test/gemfiles/activerecord32.gemfile +7 -0
  36. data/test/gemfiles/activerecord40.gemfile +8 -0
  37. data/test/gemfiles/activerecord41.gemfile +8 -0
  38. data/test/gemfiles/activerecord42.gemfile +7 -0
  39. data/test/gemfiles/activerecord50.gemfile +7 -0
  40. data/test/gemfiles/apartment.gemfile +8 -0
  41. data/test/gemfiles/cequel.gemfile +8 -0
  42. data/test/gemfiles/mongoid2.gemfile +7 -0
  43. data/test/gemfiles/mongoid3.gemfile +6 -0
  44. data/test/gemfiles/mongoid4.gemfile +7 -0
  45. data/test/gemfiles/mongoid5.gemfile +7 -0
  46. data/test/gemfiles/mongoid6.gemfile +8 -0
  47. data/test/gemfiles/nobrainer.gemfile +8 -0
  48. data/test/gemfiles/parallel_tests.gemfile +8 -0
  49. data/test/geo_shape_test.rb +172 -0
  50. data/test/highlight_test.rb +78 -0
  51. data/test/index_test.rb +153 -0
  52. data/test/inheritance_test.rb +83 -0
  53. data/test/marshal_test.rb +8 -0
  54. data/test/match_test.rb +276 -0
  55. data/test/misspellings_test.rb +56 -0
  56. data/test/model_test.rb +42 -0
  57. data/test/multi_search_test.rb +22 -0
  58. data/test/multi_tenancy_test.rb +22 -0
  59. data/test/order_test.rb +46 -0
  60. data/test/pagination_test.rb +53 -0
  61. data/test/partial_reindex_test.rb +58 -0
  62. data/test/query_test.rb +35 -0
  63. data/test/records_test.rb +10 -0
  64. data/test/reindex_test.rb +52 -0
  65. data/test/reindex_v2_job_test.rb +32 -0
  66. data/test/routing_test.rb +23 -0
  67. data/test/should_index_test.rb +32 -0
  68. data/test/similar_test.rb +28 -0
  69. data/test/sql_test.rb +198 -0
  70. data/test/suggest_test.rb +85 -0
  71. data/test/synonyms_test.rb +67 -0
  72. data/test/test_helper.rb +527 -0
  73. data/test/where_test.rb +223 -0
  74. metadata +250 -0
@@ -0,0 +1,156 @@
1
+ module Searchkick
2
+ module Model
3
+ def searchkick(**options)
4
+ unknown_keywords = options.keys - [:batch_size, :callbacks, :conversions,
5
+ :filterable, :geo_shape, :highlight, :ignore_above, :index_name, :index_prefix, :language,
6
+ :locations, :mappings, :match, :merge_mappings, :routing, :searchable, :settings, :similarity,
7
+ :special_characters, :stem_conversions, :suggest, :synonyms, :text_end,
8
+ :text_middle, :text_start, :word, :wordnet, :word_end, :word_middle, :word_start]
9
+ raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any?
10
+
11
+ raise "Only call searchkick once per model" if respond_to?(:searchkick_index)
12
+
13
+ Searchkick.models << self
14
+
15
+ class_eval do
16
+ cattr_reader :searchkick_options, :searchkick_klass
17
+
18
+ callbacks = options.key?(:callbacks) ? options[:callbacks] : true
19
+
20
+ class_variable_set :@@searchkick_options, options.dup
21
+ class_variable_set :@@searchkick_klass, self
22
+ class_variable_set :@@searchkick_callbacks, callbacks
23
+ class_variable_set :@@searchkick_index, options[:index_name] ||
24
+ (options[:index_prefix].respond_to?(:call) && proc { [options[:index_prefix].call, model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_") }) ||
25
+ [options[:index_prefix], model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_")
26
+
27
+ class << self
28
+ def searchkick_search(term = "*", **options, &block)
29
+ Searchkick.search(term, {model: self}.merge(options), &block)
30
+ end
31
+ alias_method Searchkick.search_method_name, :searchkick_search if Searchkick.search_method_name
32
+
33
+ def searchkick_index
34
+ index = class_variable_get :@@searchkick_index
35
+ index = index.call if index.respond_to? :call
36
+ Searchkick::Index.new(index, searchkick_options)
37
+ end
38
+ alias_method :search_index, :searchkick_index unless method_defined?(:search_index)
39
+
40
+ def enable_search_callbacks
41
+ class_variable_set :@@searchkick_callbacks, true
42
+ end
43
+
44
+ def disable_search_callbacks
45
+ class_variable_set :@@searchkick_callbacks, false
46
+ end
47
+
48
+ def search_callbacks?
49
+ class_variable_get(:@@searchkick_callbacks) && Searchkick.callbacks?
50
+ end
51
+
52
+ def searchkick_reindex(method_name = nil, full: false, **options)
53
+ scoped = (respond_to?(:current_scope) && respond_to?(:default_scoped) && current_scope && current_scope.to_sql != default_scoped.to_sql) ||
54
+ (respond_to?(:queryable) && queryable != unscoped.with_default_scope)
55
+
56
+ refresh = options.fetch(:refresh, !scoped)
57
+
58
+ if method_name
59
+ # update
60
+ searchkick_index.import_scope(searchkick_klass, method_name: method_name)
61
+ searchkick_index.refresh if refresh
62
+ true
63
+ elsif scoped && !full
64
+ # reindex association
65
+ searchkick_index.import_scope(searchkick_klass)
66
+ searchkick_index.refresh if refresh
67
+ true
68
+ else
69
+ # full reindex
70
+ searchkick_index.reindex_scope(searchkick_klass, options)
71
+ end
72
+ end
73
+ alias_method :reindex, :searchkick_reindex unless method_defined?(:reindex)
74
+
75
+ def searchkick_index_options
76
+ searchkick_index.index_options
77
+ end
78
+ end
79
+
80
+ callback_name = callbacks == :async ? :reindex_async : :reindex
81
+ if respond_to?(:after_commit)
82
+ after_commit callback_name, if: proc { self.class.search_callbacks? }
83
+ elsif respond_to?(:after_save)
84
+ after_save callback_name, if: proc { self.class.search_callbacks? }
85
+ after_destroy callback_name, if: proc { self.class.search_callbacks? }
86
+ end
87
+
88
+ def reindex(method_name = nil, refresh: false, async: false, mode: nil)
89
+ klass_options = self.class.searchkick_index.options
90
+
91
+ if mode.nil?
92
+ mode =
93
+ if async
94
+ :async
95
+ elsif Searchkick.callbacks_value
96
+ Searchkick.callbacks_value
97
+ elsif klass_options.key?(:callbacks) && klass_options[:callbacks] != :async
98
+ # TODO remove 2nd condition in next major version
99
+ klass_options[:callbacks]
100
+ end
101
+ end
102
+
103
+ case mode
104
+ when :queue
105
+ if method_name
106
+ raise Searchkick::Error, "Partial reindex not supported with queue option"
107
+ else
108
+ self.class.searchkick_index.reindex_queue.push(id.to_s)
109
+ end
110
+ when :async
111
+ if method_name
112
+ # TODO support Mongoid and NoBrainer and non-id primary keys
113
+ Searchkick::BulkReindexJob.perform_later(
114
+ class_name: self.class.name,
115
+ record_ids: [id.to_s],
116
+ method_name: method_name ? method_name.to_s : nil
117
+ )
118
+ else
119
+ self.class.searchkick_index.reindex_record_async(self)
120
+ end
121
+ else
122
+ if method_name
123
+ self.class.searchkick_index.update_record(self, method_name)
124
+ else
125
+ self.class.searchkick_index.reindex_record(self)
126
+ end
127
+ self.class.searchkick_index.refresh if refresh
128
+ end
129
+ end unless method_defined?(:reindex)
130
+
131
+ # TODO remove this method in next major version
132
+ def reindex_async
133
+ reindex(async: true)
134
+ end unless method_defined?(:reindex_async)
135
+
136
+ def similar(options = {})
137
+ self.class.searchkick_index.similar_record(self, options)
138
+ end unless method_defined?(:similar)
139
+
140
+ def search_data
141
+ respond_to?(:to_hash) ? to_hash : serializable_hash
142
+ end unless method_defined?(:search_data)
143
+
144
+ def should_index?
145
+ true
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
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,23 @@
1
+ module Searchkick
2
+ class ProcessBatchJob < ActiveJob::Base
3
+ queue_as :searchkick
4
+
5
+ def perform(class_name:, record_ids:)
6
+ klass = class_name.constantize
7
+ scope = Searchkick.load_records(klass, record_ids)
8
+ scope = scope.search_import if scope.respond_to?(:search_import)
9
+ records = scope.select(&:should_index?)
10
+
11
+ # determine which records to delete
12
+ delete_ids = record_ids - records.map { |r| r.id.to_s }
13
+ delete_records = delete_ids.map { |id| m = klass.new; m.id = id; m }
14
+
15
+ # bulk reindex
16
+ index = klass.searchkick_index
17
+ Searchkick.callbacks(:bulk) do
18
+ index.bulk_index(records) if records.any?
19
+ index.bulk_delete(delete_records) if delete_records.any?
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module Searchkick
2
+ class ProcessQueueJob < ActiveJob::Base
3
+ queue_as :searchkick
4
+
5
+ def perform(class_name:)
6
+ model = class_name.constantize
7
+
8
+ limit = model.searchkick_index.options[:batch_size] || 1000
9
+ record_ids = model.searchkick_index.reindex_queue.reserve(limit: limit)
10
+ if record_ids.any?
11
+ Searchkick::ProcessBatchJob.perform_later(
12
+ class_name: model.name,
13
+ record_ids: record_ids
14
+ )
15
+ # TODO when moving to reliable queuing, mark as complete
16
+
17
+ if record_ids.size == limit
18
+ Searchkick::ProcessQueueJob.perform_later(class_name: class_name)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end