searchkick_evichat 0.0.2
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 +7 -0
- data/.github/ISSUE_TEMPLATE.md +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +33 -0
- data/CHANGELOG.md +571 -0
- data/CONTRIBUTING.md +51 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +22 -0
- data/README.md +1895 -0
- data/Rakefile +16 -0
- data/benchmark/Gemfile +24 -0
- data/benchmark/index.rb +99 -0
- data/benchmark/search.rb +48 -0
- data/docs/Searchkick-3-Upgrade.md +57 -0
- data/lib/searchkick.rb +255 -0
- data/lib/searchkick/bulk_indexer.rb +171 -0
- data/lib/searchkick/bulk_reindex_job.rb +27 -0
- data/lib/searchkick/hash_wrapper.rb +12 -0
- data/lib/searchkick/index.rb +331 -0
- data/lib/searchkick/index_options.rb +414 -0
- data/lib/searchkick/indexer.rb +28 -0
- data/lib/searchkick/logging.rb +243 -0
- data/lib/searchkick/middleware.rb +12 -0
- data/lib/searchkick/model.rb +105 -0
- data/lib/searchkick/multi_search.rb +41 -0
- data/lib/searchkick/process_batch_job.rb +23 -0
- data/lib/searchkick/process_queue_job.rb +23 -0
- data/lib/searchkick/query.rb +978 -0
- data/lib/searchkick/record_data.rb +128 -0
- data/lib/searchkick/record_indexer.rb +59 -0
- data/lib/searchkick/reindex_queue.rb +38 -0
- data/lib/searchkick/reindex_v2_job.rb +36 -0
- data/lib/searchkick/results.rb +235 -0
- data/lib/searchkick/tasks.rb +29 -0
- data/lib/searchkick/version.rb +3 -0
- data/searchkick.gemspec +30 -0
- data/test/aggs_test.rb +217 -0
- data/test/autocomplete_test.rb +81 -0
- data/test/boost_test.rb +207 -0
- data/test/callbacks_test.rb +59 -0
- data/test/ci/before_install.sh +17 -0
- data/test/errors_test.rb +19 -0
- data/test/gemfiles/activerecord42.gemfile +7 -0
- data/test/gemfiles/activerecord50.gemfile +7 -0
- data/test/gemfiles/activerecord51.gemfile +7 -0
- data/test/gemfiles/apartment.gemfile +8 -0
- data/test/gemfiles/cequel.gemfile +8 -0
- data/test/gemfiles/mongoid5.gemfile +7 -0
- data/test/gemfiles/mongoid6.gemfile +12 -0
- data/test/gemfiles/nobrainer.gemfile +8 -0
- data/test/gemfiles/parallel_tests.gemfile +8 -0
- data/test/geo_shape_test.rb +171 -0
- data/test/highlight_test.rb +94 -0
- data/test/index_test.rb +165 -0
- data/test/inheritance_test.rb +82 -0
- data/test/language_test.rb +79 -0
- data/test/marshal_test.rb +13 -0
- data/test/match_test.rb +293 -0
- data/test/misspellings_test.rb +56 -0
- data/test/model_test.rb +40 -0
- data/test/multi_search_test.rb +37 -0
- data/test/multi_tenancy_test.rb +22 -0
- data/test/order_test.rb +40 -0
- data/test/pagination_test.rb +96 -0
- data/test/partial_reindex_test.rb +65 -0
- data/test/query_test.rb +43 -0
- data/test/reindex_test.rb +87 -0
- data/test/reindex_v2_job_test.rb +27 -0
- data/test/routing_test.rb +23 -0
- data/test/should_index_test.rb +32 -0
- data/test/similar_test.rb +28 -0
- data/test/sql_test.rb +190 -0
- data/test/suggest_test.rb +100 -0
- data/test/support/kaminari.yml +21 -0
- data/test/synonyms_test.rb +69 -0
- data/test/test_helper.rb +593 -0
- data/test/where_test.rb +249 -0
- metadata +250 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
class RecordData
|
|
3
|
+
TYPE_KEYS = ["type", :type]
|
|
4
|
+
|
|
5
|
+
attr_reader :index, :record
|
|
6
|
+
|
|
7
|
+
def initialize(index, record)
|
|
8
|
+
@index = index
|
|
9
|
+
@record = record
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def index_data
|
|
13
|
+
data = record_data
|
|
14
|
+
data[:data] = search_data
|
|
15
|
+
{index: data}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update_data(method_name)
|
|
19
|
+
data = record_data
|
|
20
|
+
data[:data] = {doc: search_data(method_name)}
|
|
21
|
+
{update: data}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delete_data
|
|
25
|
+
{delete: record_data}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def search_id
|
|
29
|
+
id = record.respond_to?(:search_document_id) ? record.search_document_id : record.id
|
|
30
|
+
id.is_a?(Numeric) ? id : id.to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def document_type(ignore_type = false)
|
|
34
|
+
index.klass_document_type(record.class, ignore_type)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def record_data
|
|
40
|
+
data = {
|
|
41
|
+
_index: index.name,
|
|
42
|
+
_id: search_id,
|
|
43
|
+
_type: document_type
|
|
44
|
+
}
|
|
45
|
+
data[:_routing] = record.search_routing if record.respond_to?(:search_routing)
|
|
46
|
+
data
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def search_data(method_name = nil)
|
|
50
|
+
partial_reindex = !method_name.nil?
|
|
51
|
+
|
|
52
|
+
source = record.send(method_name || :search_data)
|
|
53
|
+
|
|
54
|
+
# conversions
|
|
55
|
+
index.conversions_fields.each do |conversions_field|
|
|
56
|
+
if source[conversions_field]
|
|
57
|
+
source[conversions_field] = source[conversions_field].map { |k, v| {query: k, count: v} }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# hack to prevent generator field doesn't exist error
|
|
62
|
+
if !partial_reindex
|
|
63
|
+
index.suggest_fields.each do |field|
|
|
64
|
+
if !source[field] && !source[field.to_sym]
|
|
65
|
+
source[field] = nil
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# locations
|
|
71
|
+
index.locations_fields.each do |field|
|
|
72
|
+
if source[field]
|
|
73
|
+
if !source[field].is_a?(Hash) && (source[field].first.is_a?(Array) || source[field].first.is_a?(Hash))
|
|
74
|
+
# multiple locations
|
|
75
|
+
source[field] = source[field].map { |a| location_value(a) }
|
|
76
|
+
else
|
|
77
|
+
source[field] = location_value(source[field])
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
if index.options[:inheritance]
|
|
83
|
+
if !TYPE_KEYS.any? { |tk| source.key?(tk) }
|
|
84
|
+
source[:type] = document_type(true)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
cast_big_decimal(source)
|
|
89
|
+
|
|
90
|
+
source
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def location_value(value)
|
|
94
|
+
if value.is_a?(Array)
|
|
95
|
+
value.map(&:to_f).reverse
|
|
96
|
+
elsif value.is_a?(Hash)
|
|
97
|
+
{lat: value[:lat].to_f, lon: value[:lon].to_f}
|
|
98
|
+
else
|
|
99
|
+
value
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# change all BigDecimal values to floats due to
|
|
104
|
+
# https://github.com/rails/rails/issues/6033
|
|
105
|
+
# possible loss of precision :/
|
|
106
|
+
def cast_big_decimal(obj)
|
|
107
|
+
case obj
|
|
108
|
+
when BigDecimal
|
|
109
|
+
obj.to_f
|
|
110
|
+
when Hash
|
|
111
|
+
obj.each do |k, v|
|
|
112
|
+
# performance
|
|
113
|
+
if v.is_a?(BigDecimal)
|
|
114
|
+
obj[k] = v.to_f
|
|
115
|
+
elsif v.is_a?(Enumerable) ||
|
|
116
|
+
obj[k] = cast_big_decimal(v)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
when Enumerable
|
|
120
|
+
obj.map do |v|
|
|
121
|
+
cast_big_decimal(v)
|
|
122
|
+
end
|
|
123
|
+
else
|
|
124
|
+
obj
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
class RecordIndexer
|
|
3
|
+
attr_reader :record, :index
|
|
4
|
+
|
|
5
|
+
def initialize(record)
|
|
6
|
+
@record = record
|
|
7
|
+
@index = record.class.searchkick_index
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def reindex(method_name = nil, refresh: false, mode: nil)
|
|
11
|
+
unless [true, nil, :async, :queue].include?(mode)
|
|
12
|
+
raise ArgumentError, "Invalid value for mode"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
mode ||= Searchkick.callbacks_value || index.options[:callbacks] || true
|
|
16
|
+
|
|
17
|
+
case mode
|
|
18
|
+
when :queue
|
|
19
|
+
if method_name
|
|
20
|
+
raise Searchkick::Error, "Partial reindex not supported with queue option"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
index.reindex_queue.push(record.id.to_s)
|
|
24
|
+
when :async
|
|
25
|
+
unless defined?(ActiveJob)
|
|
26
|
+
raise Searchkick::Error, "Active Job not found"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Searchkick::ReindexV2Job.perform_later(
|
|
30
|
+
record.class.name,
|
|
31
|
+
record.id.to_s,
|
|
32
|
+
method_name ? method_name.to_s : nil
|
|
33
|
+
)
|
|
34
|
+
else # bulk, true
|
|
35
|
+
reindex_record(method_name)
|
|
36
|
+
|
|
37
|
+
index.refresh if refresh
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def reindex_record(method_name)
|
|
44
|
+
if record.destroyed? || !record.persisted? || !record.should_index?
|
|
45
|
+
begin
|
|
46
|
+
index.remove(record)
|
|
47
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
|
48
|
+
# do nothing
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
if method_name
|
|
52
|
+
index.update_record(record, method_name)
|
|
53
|
+
else
|
|
54
|
+
index.store(record)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
class ReindexQueue
|
|
3
|
+
attr_reader :name
|
|
4
|
+
|
|
5
|
+
def initialize(name)
|
|
6
|
+
@name = name
|
|
7
|
+
|
|
8
|
+
raise Searchkick::Error, "Searchkick.redis not set" unless Searchkick.redis
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def push(record_id)
|
|
12
|
+
Searchkick.with_redis { |r| r.lpush(redis_key, record_id) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# TODO use reliable queuing
|
|
16
|
+
def reserve(limit: 1000)
|
|
17
|
+
record_ids = Set.new
|
|
18
|
+
while record_ids.size < limit && (record_id = Searchkick.with_redis { |r| r.rpop(redis_key) })
|
|
19
|
+
record_ids << record_id
|
|
20
|
+
end
|
|
21
|
+
record_ids.to_a
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def clear
|
|
25
|
+
Searchkick.with_redis { |r| r.del(redis_key) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def length
|
|
29
|
+
Searchkick.with_redis { |r| r.llen(redis_key) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def redis_key
|
|
35
|
+
"searchkick:reindex_queue:#{name}"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Searchkick
|
|
2
|
+
class ReindexV2Job < ActiveJob::Base
|
|
3
|
+
RECORD_NOT_FOUND_CLASSES = [
|
|
4
|
+
"ActiveRecord::RecordNotFound",
|
|
5
|
+
"Mongoid::Errors::DocumentNotFound",
|
|
6
|
+
"NoBrainer::Error::DocumentNotFound",
|
|
7
|
+
"Cequel::Record::RecordNotFound"
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
queue_as { Searchkick.queue_name }
|
|
11
|
+
|
|
12
|
+
def perform(klass, id, method_name = nil)
|
|
13
|
+
model = klass.constantize
|
|
14
|
+
record =
|
|
15
|
+
begin
|
|
16
|
+
if model.respond_to?(:unscoped)
|
|
17
|
+
model.unscoped.find(id)
|
|
18
|
+
else
|
|
19
|
+
model.find(id)
|
|
20
|
+
end
|
|
21
|
+
rescue => e
|
|
22
|
+
# check by name rather than rescue directly so we don't need
|
|
23
|
+
# to determine which classes are defined
|
|
24
|
+
raise e unless RECORD_NOT_FOUND_CLASSES.include?(e.class.name)
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
unless record
|
|
29
|
+
record = model.new
|
|
30
|
+
record.id = id
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
RecordIndexer.new(record).reindex(method_name, mode: true)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
require "forwardable"
|
|
2
|
+
|
|
3
|
+
module Searchkick
|
|
4
|
+
class Results
|
|
5
|
+
include Enumerable
|
|
6
|
+
extend Forwardable
|
|
7
|
+
|
|
8
|
+
attr_reader :klass, :response, :options
|
|
9
|
+
|
|
10
|
+
def_delegators :results, :each, :any?, :empty?, :size, :length, :slice, :[], :to_ary
|
|
11
|
+
|
|
12
|
+
def initialize(klass, response, options = {})
|
|
13
|
+
@klass = klass
|
|
14
|
+
@response = response
|
|
15
|
+
@options = options
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def results
|
|
19
|
+
@results ||= begin
|
|
20
|
+
if options[:load]
|
|
21
|
+
# results can have different types
|
|
22
|
+
results = {}
|
|
23
|
+
|
|
24
|
+
hits.group_by { |hit, _| hit["_type"] }.each do |type, grouped_hits|
|
|
25
|
+
klass = (!options[:index_name] && @klass) || type.camelize.constantize
|
|
26
|
+
results[type] = results_query(klass, grouped_hits).to_a.index_by { |r| r.id.to_s }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# sort
|
|
30
|
+
hits.map do |hit|
|
|
31
|
+
result = results[hit["_type"]][hit["_id"].to_s]
|
|
32
|
+
if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable])
|
|
33
|
+
if hit["highlight"] && !result.respond_to?(:search_highlights)
|
|
34
|
+
highlights = Hash[hit["highlight"].map { |k, v| [(options[:json] ? k : k.sub(/\.#{@options[:match_suffix]}\z/, "")).to_sym, v.first] }]
|
|
35
|
+
result.define_singleton_method(:search_highlights) do
|
|
36
|
+
highlights
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
result
|
|
41
|
+
end.compact
|
|
42
|
+
else
|
|
43
|
+
hits.map do |hit|
|
|
44
|
+
result =
|
|
45
|
+
if hit["_source"]
|
|
46
|
+
hit.except("_source").merge(hit["_source"])
|
|
47
|
+
elsif hit["fields"]
|
|
48
|
+
hit.except("fields").merge(hit["fields"])
|
|
49
|
+
else
|
|
50
|
+
hit
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if hit["highlight"]
|
|
54
|
+
highlight = Hash[hit["highlight"].map { |k, v| [base_field(k), v.first] }]
|
|
55
|
+
options[:highlighted_fields].map { |k| base_field(k) }.each do |k|
|
|
56
|
+
result["highlighted_#{k}"] ||= (highlight[k] || result[k])
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
result["id"] ||= result["_id"] # needed for legacy reasons
|
|
61
|
+
HashWrapper.new(result)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def suggestions
|
|
68
|
+
if response["suggest"]
|
|
69
|
+
response["suggest"].values.flat_map { |v| v.first["options"] }.sort_by { |o| -o["score"] }.map { |o| o["text"] }.uniq
|
|
70
|
+
elsif options[:term] == "*"
|
|
71
|
+
[]
|
|
72
|
+
else
|
|
73
|
+
raise "Pass `suggest: true` to the search method for suggestions"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def aggregations
|
|
78
|
+
response["aggregations"]
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def aggs
|
|
82
|
+
@aggs ||= begin
|
|
83
|
+
if aggregations
|
|
84
|
+
aggregations.dup.each do |field, filtered_agg|
|
|
85
|
+
buckets = filtered_agg[field]
|
|
86
|
+
# move the buckets one level above into the field hash
|
|
87
|
+
if buckets
|
|
88
|
+
filtered_agg.delete(field)
|
|
89
|
+
filtered_agg.merge!(buckets)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def took
|
|
97
|
+
response["took"]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def error
|
|
101
|
+
response["error"]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def model_name
|
|
105
|
+
klass.model_name
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def entry_name(options = {})
|
|
109
|
+
if options.empty?
|
|
110
|
+
# backward compatibility
|
|
111
|
+
model_name.human.downcase
|
|
112
|
+
else
|
|
113
|
+
default = options[:count] == 1 ? model_name.human : model_name.human.pluralize
|
|
114
|
+
model_name.human(options.reverse_merge(default: default))
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def total_count
|
|
119
|
+
response["hits"]["total"]
|
|
120
|
+
end
|
|
121
|
+
alias_method :total_entries, :total_count
|
|
122
|
+
|
|
123
|
+
def current_page
|
|
124
|
+
options[:page]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def per_page
|
|
128
|
+
options[:per_page]
|
|
129
|
+
end
|
|
130
|
+
alias_method :limit_value, :per_page
|
|
131
|
+
|
|
132
|
+
def padding
|
|
133
|
+
options[:padding]
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def total_pages
|
|
137
|
+
(total_count / per_page.to_f).ceil
|
|
138
|
+
end
|
|
139
|
+
alias_method :num_pages, :total_pages
|
|
140
|
+
|
|
141
|
+
def offset_value
|
|
142
|
+
(current_page - 1) * per_page + padding
|
|
143
|
+
end
|
|
144
|
+
alias_method :offset, :offset_value
|
|
145
|
+
|
|
146
|
+
def previous_page
|
|
147
|
+
current_page > 1 ? (current_page - 1) : nil
|
|
148
|
+
end
|
|
149
|
+
alias_method :prev_page, :previous_page
|
|
150
|
+
|
|
151
|
+
def next_page
|
|
152
|
+
current_page < total_pages ? (current_page + 1) : nil
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def first_page?
|
|
156
|
+
previous_page.nil?
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def last_page?
|
|
160
|
+
next_page.nil?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def out_of_range?
|
|
164
|
+
current_page > total_pages
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def hits
|
|
168
|
+
if error
|
|
169
|
+
raise Searchkick::Error, "Query error - use the error method to view it"
|
|
170
|
+
else
|
|
171
|
+
@response["hits"]["hits"]
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def with_hit
|
|
176
|
+
results.zip(hits)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def highlights(multiple: false)
|
|
180
|
+
hits.map do |hit|
|
|
181
|
+
Hash[hit["highlight"].map { |k, v| [(options[:json] ? k : k.sub(/\.#{@options[:match_suffix]}\z/, "")).to_sym, multiple ? v : v.first] }]
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def with_highlights(multiple: false)
|
|
186
|
+
results.zip(highlights(multiple: multiple))
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def misspellings?
|
|
190
|
+
@options[:misspellings]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
private
|
|
194
|
+
|
|
195
|
+
def results_query(records, hits)
|
|
196
|
+
ids = hits.map { |hit| hit["_id"] }
|
|
197
|
+
if options[:includes] || options[:model_includes]
|
|
198
|
+
included_relations = []
|
|
199
|
+
combine_includes(included_relations, options[:includes])
|
|
200
|
+
combine_includes(included_relations, options[:model_includes][records]) if options[:model_includes]
|
|
201
|
+
|
|
202
|
+
records =
|
|
203
|
+
if defined?(NoBrainer::Document) && records < NoBrainer::Document
|
|
204
|
+
if Gem.loaded_specs["nobrainer"].version >= Gem::Version.new("0.21")
|
|
205
|
+
records.eager_load(included_relations)
|
|
206
|
+
else
|
|
207
|
+
records.preload(included_relations)
|
|
208
|
+
end
|
|
209
|
+
else
|
|
210
|
+
records.includes(included_relations)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
if options[:scope_results]
|
|
215
|
+
records = options[:scope_results].call(records)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
Searchkick.load_records(records, ids)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def combine_includes(result, inc)
|
|
222
|
+
if inc
|
|
223
|
+
if inc.is_a?(Array)
|
|
224
|
+
result.concat(inc)
|
|
225
|
+
else
|
|
226
|
+
result << inc
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def base_field(k)
|
|
232
|
+
k.sub(/\.(analyzed|word_start|word_middle|word_end|text_start|text_middle|text_end|exact)\z/, "")
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|