record_indexer.rb
3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
module Searchkick
class RecordIndexer
EXCLUDED_ATTRIBUTES = ["_id", "_type"]
attr_reader :index, :record
def initialize(index, record)
@index = index
@record = record
end
def index_data
data = record_data
data[:data] = search_data
{index: data}
end
def update_data(method_name)
data = record_data
data[:data] = {doc: search_data(method_name)}
{update: data}
end
def delete_data
{delete: record_data}
end
def document_type(ignore_type = false)
index.klass_document_type(record.class, ignore_type)
end
def search_id
id = record.respond_to?(:search_document_id) ? record.search_document_id : record.id
id.is_a?(Numeric) ? id : id.to_s
end
private
def record_data
data = {
_index: index.name,
_id: search_id,
_type: document_type
}
data[:_routing] = record.search_routing if record.respond_to?(:search_routing)
data
end
def search_data(method_name = nil)
partial_reindex = !method_name.nil?
options = record.class.searchkick_options
# remove _id since search_id is used instead
source = record.send(method_name || :search_data).each_with_object({}) { |(k, v), memo| memo[k.to_s] = v; memo }.except(*EXCLUDED_ATTRIBUTES)
# conversions
if options[:conversions]
Array(options[:conversions]).map(&:to_s).each do |conversions_field|
if source[conversions_field]
source[conversions_field] = source[conversions_field].map { |k, v| {query: k, count: v} }
end
end
end
# hack to prevent generator field doesn't exist error
if options[:suggest]
options[:suggest].map(&:to_s).each do |field|
source[field] = nil if !source[field] && !partial_reindex
end
end
# locations
if options[:locations]
options[:locations].map(&:to_s).each do |field|
if source[field]
if !source[field].is_a?(Hash) && (source[field].first.is_a?(Array) || source[field].first.is_a?(Hash))
# multiple locations
source[field] = source[field].map { |a| location_value(a) }
else
source[field] = location_value(source[field])
end
end
end
end
if !source.key?("type") && record.class.searchkick_klass.searchkick_options[:inheritance]
source["type"] = document_type(true)
end
cast_big_decimal(source)
source
end
def location_value(value)
if value.is_a?(Array)
value.map(&:to_f).reverse
elsif value.is_a?(Hash)
{lat: value[:lat].to_f, lon: value[:lon].to_f}
else
value
end
end
# change all BigDecimal values to floats due to
# https://github.com/rails/rails/issues/6033
# possible loss of precision :/
def cast_big_decimal(obj)
case obj
when BigDecimal
obj.to_f
when Hash
obj.each do |k, v|
obj[k] = cast_big_decimal(v)
end
when Enumerable
obj.map do |v|
cast_big_decimal(v)
end
else
obj
end
end
end
end