rmla 1.0
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.
- data/.document +6 -0
- data/.rspec +1 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +139 -0
- data/LICENSE.txt +20 -0
- data/README.md +255 -0
- data/Rakefile +44 -0
- data/TODO.md +23 -0
- data/VERSION +1 -0
- data/lib/generators/mebla/install/USAGE +7 -0
- data/lib/generators/mebla/install/install_generator.rb +35 -0
- data/lib/generators/mebla/install/templates/mebla.yml +15 -0
- data/lib/mebla.rb +117 -0
- data/lib/mebla/configuration.rb +71 -0
- data/lib/mebla/context.rb +298 -0
- data/lib/mebla/errors.rb +11 -0
- data/lib/mebla/errors/mebla_configuration_exception.rb +10 -0
- data/lib/mebla/errors/mebla_error.rb +14 -0
- data/lib/mebla/errors/mebla_fatal.rb +14 -0
- data/lib/mebla/errors/mebla_index_exception.rb +10 -0
- data/lib/mebla/errors/mebla_synchronization_exception.rb +9 -0
- data/lib/mebla/log_subscriber.rb +74 -0
- data/lib/mebla/mongoid/mebla.rb +341 -0
- data/lib/mebla/railtie.rb +39 -0
- data/lib/mebla/result_set.rb +91 -0
- data/lib/mebla/search.rb +240 -0
- data/lib/mebla/tasks.rb +49 -0
- data/mebla.gemspec +113 -0
- data/spec/fixtures/models.rb +99 -0
- data/spec/fixtures/mongoid.yml +3 -0
- data/spec/mebla/indexing_spec.rb +165 -0
- data/spec/mebla/searching_spec.rb +142 -0
- data/spec/mebla/synchronizing_spec.rb +126 -0
- data/spec/mebla_helper.rb +33 -0
- data/spec/mebla_spec.rb +28 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/support/mongoid.rb +3 -0
- data/spec/support/rails.rb +13 -0
- metadata +301 -0
data/lib/mebla/errors.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
2
|
+
module Mebla
|
|
3
|
+
# Represents the parent module for all errors in Mebla
|
|
4
|
+
module Errors
|
|
5
|
+
autoload :MeblaError, 'mebla/errors/mebla_error'
|
|
6
|
+
autoload :MeblaFatal, 'mebla/errors/mebla_fatal'
|
|
7
|
+
autoload :MeblaConfigurationException, 'mebla/errors/mebla_configuration_exception'
|
|
8
|
+
autoload :MeblaIndexException, 'mebla/errors/mebla_index_exception'
|
|
9
|
+
autoload :MeblaSynchronizationException, 'mebla/errors/mebla_synchronization_exception'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
2
|
+
module Mebla
|
|
3
|
+
# Represents the parent module for all errors in Mebla
|
|
4
|
+
module Errors
|
|
5
|
+
# Thrown when configuration fails
|
|
6
|
+
# @note this is a fatal exception
|
|
7
|
+
class MeblaConfigurationException < MeblaFatal
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
2
|
+
module Mebla
|
|
3
|
+
# Represents the parent module for all errors in Mebla
|
|
4
|
+
module Errors
|
|
5
|
+
# Default parent Mebla error for all custom non-fatal errors.
|
|
6
|
+
class MeblaError < ::StandardError
|
|
7
|
+
def initialize(message)
|
|
8
|
+
super message
|
|
9
|
+
::ActiveSupport::Notifications.
|
|
10
|
+
instrument('mebla_error.mebla', :message => message)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
2
|
+
module Mebla
|
|
3
|
+
# Represents the parent module for all errors in Mebla
|
|
4
|
+
module Errors
|
|
5
|
+
# Default parent Mebla error for all custom fatal errors.
|
|
6
|
+
class MeblaFatal < ::StandardError
|
|
7
|
+
def initialize(message)
|
|
8
|
+
super message
|
|
9
|
+
::ActiveSupport::Notifications.
|
|
10
|
+
instrument('mebla_fatal.mebla', :message => message)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
2
|
+
module Mebla
|
|
3
|
+
# Represents the parent module for all errors in Mebla
|
|
4
|
+
module Errors
|
|
5
|
+
# Thrown when an index operation fails
|
|
6
|
+
# @note this is a fatal exception
|
|
7
|
+
class MeblaIndexException < MeblaFatal
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
2
|
+
module Mebla
|
|
3
|
+
# Represents the parent module for all errors in Mebla
|
|
4
|
+
module Errors
|
|
5
|
+
# Thrown when a synchronization operation fails
|
|
6
|
+
class MeblaSynchronizationException < MeblaError
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'active_support/log_subscriber'
|
|
2
|
+
|
|
3
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
4
|
+
module Mebla
|
|
5
|
+
# Handles logging
|
|
6
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
|
7
|
+
# Debug message
|
|
8
|
+
def mebla_debug(event)
|
|
9
|
+
debug_green event.payload[:message]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Error message
|
|
13
|
+
def mebla_error(event)
|
|
14
|
+
error_red event.payload[:message]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Info message
|
|
18
|
+
def mebla_info(event)
|
|
19
|
+
info_blue event.payload[:message]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Fatal message
|
|
23
|
+
def mebla_fatal(event)
|
|
24
|
+
fatal_magenta event.payload[:message]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Warning message
|
|
28
|
+
def mebla_warn(event)
|
|
29
|
+
warn_yellow event.payload[:message]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Unknown message
|
|
33
|
+
def mebla_unknown(event)
|
|
34
|
+
unknown event.payload[:message]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# --
|
|
38
|
+
# -------------------------------------------------------------
|
|
39
|
+
# Add some colors
|
|
40
|
+
# -------------------------------------------------------------
|
|
41
|
+
# ++
|
|
42
|
+
|
|
43
|
+
# Print a debug message to the log file
|
|
44
|
+
def debug_green(msg)
|
|
45
|
+
debug color(msg, LogSubscriber::GREEN)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Print an error message to the log file
|
|
49
|
+
def error_red(msg)
|
|
50
|
+
error color(msg, LogSubscriber::RED)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Print an info message to the log file
|
|
54
|
+
def info_blue(msg)
|
|
55
|
+
info color(msg, LogSubscriber::BLUE)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Print a fatal message to the log file
|
|
59
|
+
def fatal_magenta(msg)
|
|
60
|
+
fatal color(msg, LogSubscriber::MAGENTA)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Print a warn message to the log file
|
|
64
|
+
def warn_yellow(msg)
|
|
65
|
+
warn color(msg, LogSubscriber::YELLOW)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Returns the main logger for Mebla
|
|
69
|
+
# @return [Logger]
|
|
70
|
+
def self.logger
|
|
71
|
+
Mebla::Configuration.instance.logger
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# @private
|
|
2
|
+
module Mongoid
|
|
3
|
+
# A wrapper for slingshot elastic-search adapter for Mongoid
|
|
4
|
+
module Mebla
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
included do
|
|
7
|
+
# Used to properly represent data types
|
|
8
|
+
unless defined?(SLINGSHOT_TYPE_MAPPING)
|
|
9
|
+
SLINGSHOT_TYPE_MAPPING = {
|
|
10
|
+
'Date' => 'date',
|
|
11
|
+
'DateTime' => 'date',
|
|
12
|
+
'Time' => 'date',
|
|
13
|
+
'Float' => 'float',
|
|
14
|
+
'Integer' => 'integer',
|
|
15
|
+
'BigDecimal' => 'float',
|
|
16
|
+
'Boolean' => 'boolean'
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class_attribute :embedded_as
|
|
21
|
+
class_attribute :embedded_parent
|
|
22
|
+
class_attribute :embedded_parent_foreign_key
|
|
23
|
+
class_attribute :slingshot_mappings
|
|
24
|
+
class_attribute :search_fields
|
|
25
|
+
class_attribute :search_relations
|
|
26
|
+
class_attribute :whiny_indexing # set to true to raise errors if indexing fails
|
|
27
|
+
|
|
28
|
+
# make sure critical data remain read only
|
|
29
|
+
private_class_method :"search_fields=", :"slingshot_mappings=",
|
|
30
|
+
:"embedded_parent_foreign_key=", :"embedded_parent=", :"embedded_as="
|
|
31
|
+
|
|
32
|
+
# add callbacks to synchronize modifications with elasticsearch
|
|
33
|
+
after_save :add_to_index
|
|
34
|
+
before_destroy :remove_from_index
|
|
35
|
+
|
|
36
|
+
# by default if synchronizing fails no error is raised
|
|
37
|
+
self.whiny_indexing = false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Defines class methods for Mongoid::Mebla
|
|
41
|
+
module ClassMethods
|
|
42
|
+
# Defines which fields should be indexed and searched
|
|
43
|
+
# @param [*opts] fields
|
|
44
|
+
# @return [nil]
|
|
45
|
+
#
|
|
46
|
+
# Defines a search index on a normal document with custom mappings on "body"::
|
|
47
|
+
#
|
|
48
|
+
# class Document
|
|
49
|
+
# include Mongoid::Document
|
|
50
|
+
# include Mongoid::Mebla
|
|
51
|
+
# field :title
|
|
52
|
+
# field :body
|
|
53
|
+
# field :publish_date, :type => Date
|
|
54
|
+
# #...
|
|
55
|
+
# search_in :title, :publish_date, :body => { :boost => 2.0, :analyzer => 'snowball' }
|
|
56
|
+
# end
|
|
57
|
+
#
|
|
58
|
+
# Defines a search index on a normal document with an index on a field inside a relation::
|
|
59
|
+
#
|
|
60
|
+
# class Document
|
|
61
|
+
# include Mongoid::Document
|
|
62
|
+
# include Mongoid::Mebla
|
|
63
|
+
# field :title
|
|
64
|
+
# field :body
|
|
65
|
+
# field :publish_date, :type => Date
|
|
66
|
+
#
|
|
67
|
+
# referenced_in :blog
|
|
68
|
+
# #...
|
|
69
|
+
# # relations mappings are detected automatically
|
|
70
|
+
# search_in :title, :publish_date, :body => { :boost => 2.0, :analyzer => 'snowball' }, :search_relations => {
|
|
71
|
+
# :blog => [:author, :name]
|
|
72
|
+
# }
|
|
73
|
+
# end
|
|
74
|
+
#
|
|
75
|
+
# Defines a search index on a normal document with an index on method "permalink"::
|
|
76
|
+
#
|
|
77
|
+
# class Document
|
|
78
|
+
# include Mongoid::Document
|
|
79
|
+
# include Mongoid::Mebla
|
|
80
|
+
# field :title
|
|
81
|
+
# field :body
|
|
82
|
+
# field :publish_date, :type => Date
|
|
83
|
+
#
|
|
84
|
+
# def permalink
|
|
85
|
+
# self.title.gsub(/\s/, "-").downcase
|
|
86
|
+
# end
|
|
87
|
+
# #...
|
|
88
|
+
# # methods can also define custom mappings if needed
|
|
89
|
+
# search_in :title, :publish_date, :permalink, :body => { :boost => 2.0, :analyzer => 'snowball' }
|
|
90
|
+
# end
|
|
91
|
+
#
|
|
92
|
+
# Defines a search index on an embedded document with a single parent and custom mappings on "body"::
|
|
93
|
+
#
|
|
94
|
+
# class Document
|
|
95
|
+
# include Mongoid::Document
|
|
96
|
+
# include Mongoid::Mebla
|
|
97
|
+
# field :title
|
|
98
|
+
# field :body
|
|
99
|
+
# field :publish_date, :type => Date
|
|
100
|
+
# #...
|
|
101
|
+
# embedded_in :category
|
|
102
|
+
# search_in :title, :publish_date, :body => { :boost => 2.0, :analyzer => 'snowball' }, :embedded_in => :category
|
|
103
|
+
# end
|
|
104
|
+
def search_in(*opts)
|
|
105
|
+
# Extract advanced indeces
|
|
106
|
+
options = opts.extract_options!.symbolize_keys
|
|
107
|
+
# Extract simple indeces
|
|
108
|
+
attrs = opts.flatten
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# If this document is embedded check for the embedded_in option and raise an error if none is specified
|
|
112
|
+
# Example::
|
|
113
|
+
# embedded in a regular class (e.g.: using the default convention for naming the foreign key)
|
|
114
|
+
# :embedded_in => :parent
|
|
115
|
+
if self.embedded?
|
|
116
|
+
if (embedor = options.delete(:embedded_in))
|
|
117
|
+
relation = self.relations[embedor.to_s]
|
|
118
|
+
|
|
119
|
+
# Infer the attributes of the relation
|
|
120
|
+
self.embedded_parent = relation.class_name.constantize
|
|
121
|
+
self.embedded_parent_foreign_key = relation.key.to_s
|
|
122
|
+
self.embedded_as = relation[:inverse_of] || relation.inverse_setter.to_s.gsub(/=$/, '')
|
|
123
|
+
|
|
124
|
+
if self.embedded_as.blank?
|
|
125
|
+
raise ::Mebla::Errors::MeblaConfigurationException.new("Couldn't infer #{embedor.to_s} inverse relation, please set :inverse_of option on the relation.")
|
|
126
|
+
end
|
|
127
|
+
else
|
|
128
|
+
raise ::Mebla::Errors::MeblaConfigurationException.new("#{self.name} is embedded: embedded_in option should be set to the parent class if the document is embedded.")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
self.search_relations = {}
|
|
133
|
+
# Keep track of relational indecies
|
|
134
|
+
unless (relations_inedcies = options.delete(:search_relations)).nil?
|
|
135
|
+
relations_inedcies.each do |relation, index|
|
|
136
|
+
self.search_relations[relation] = index
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Keep track of searchable fields (for indexing)
|
|
141
|
+
self.search_fields = attrs + options.keys
|
|
142
|
+
|
|
143
|
+
# Generate simple indeces' mappings
|
|
144
|
+
attrs_mappings = {}
|
|
145
|
+
|
|
146
|
+
attrs.each do |attribute|
|
|
147
|
+
unless (attr_field = self.fields[attribute.to_s]).nil?
|
|
148
|
+
unless (field_type = attr_field.type.to_s) == "Array" # arrays don't need mappings
|
|
149
|
+
attrs_mappings[attribute] = {:type => SLINGSHOT_TYPE_MAPPING[field_type] || "string"}
|
|
150
|
+
end
|
|
151
|
+
else
|
|
152
|
+
attrs_mappings[attribute] = {:type => "string"}
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Generate advanced indeces' mappings
|
|
157
|
+
opts_mappings = {}
|
|
158
|
+
|
|
159
|
+
options.each do |opt, properties|
|
|
160
|
+
unless (attr_field = self.fields[opt.to_s]).nil?
|
|
161
|
+
unless (field_type = attr_field.type.to_s) == "Array"
|
|
162
|
+
opts_mappings[opt] = {:type => SLINGSHOT_TYPE_MAPPING[field_type] || "string" }.merge!(properties)
|
|
163
|
+
end
|
|
164
|
+
else
|
|
165
|
+
opts_mappings[opt] = {:type => "string"}.merge!(properties)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Merge mappings
|
|
170
|
+
self.slingshot_mappings = {}.merge!(attrs_mappings).merge!(opts_mappings)
|
|
171
|
+
|
|
172
|
+
# Keep track of indexed models (for bulk indexing)
|
|
173
|
+
::Mebla.context.add_indexed_model(self, self.slingshot_type_name.to_sym => prepare_mappings)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Searches the model using Slingshot search DSL
|
|
177
|
+
# @param [String] query a string representing the search query
|
|
178
|
+
# @return [Mebla::Search]
|
|
179
|
+
#
|
|
180
|
+
# Search for all posts with a field 'title' of value 'Testing Search'::
|
|
181
|
+
#
|
|
182
|
+
# Post.search "title: Testing Search"
|
|
183
|
+
def search(query = "")
|
|
184
|
+
::Mebla.search(query, self.slingshot_type_name)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Retrieves the type name of the model
|
|
188
|
+
# (used to populate the _type variable while indexing)
|
|
189
|
+
# @return [String]
|
|
190
|
+
def slingshot_type_name
|
|
191
|
+
"#{self.name.underscore}"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Enables the modification of records without indexing
|
|
195
|
+
# @return [nil]
|
|
196
|
+
# Example::
|
|
197
|
+
# create record without it being indexed
|
|
198
|
+
# Class.without_indexing do
|
|
199
|
+
# create :title => "This is not indexed", :body => "Nothing will be indexed within this block"
|
|
200
|
+
# end
|
|
201
|
+
# @note you can skip indexing to create, update or delete records without affecting the index
|
|
202
|
+
def without_indexing(&block)
|
|
203
|
+
skip_callback(:save, :after, :add_to_index)
|
|
204
|
+
skip_callback(:destroy, :before, :remove_from_index)
|
|
205
|
+
yield
|
|
206
|
+
set_callback(:save, :after, :add_to_index)
|
|
207
|
+
set_callback(:destroy, :before, :remove_from_index)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Checks if the class is a subclass
|
|
211
|
+
# @return [Boolean] true if class is a subclass
|
|
212
|
+
def sub_class?
|
|
213
|
+
self.superclass != Object
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
private
|
|
217
|
+
# Prepare the mappings required for this document
|
|
218
|
+
# @return [Hash]
|
|
219
|
+
def prepare_mappings
|
|
220
|
+
if self.embedded?
|
|
221
|
+
mappings = {
|
|
222
|
+
:_parent => { :type => self.embedded_parent.name.underscore },
|
|
223
|
+
:_routing => {
|
|
224
|
+
:required => true,
|
|
225
|
+
:path => self.embedded_parent_foreign_key + "_id"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else
|
|
229
|
+
mappings = {}
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
mappings.merge!({
|
|
233
|
+
:properties => self.slingshot_mappings
|
|
234
|
+
})
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
private
|
|
239
|
+
# Adds the document to the index
|
|
240
|
+
# @return [Boolean] true if the operation is successful
|
|
241
|
+
def add_to_index
|
|
242
|
+
return false unless ::Mebla.context.index_exists? # only try to index if the index exists
|
|
243
|
+
return false unless ::Mebla.context.indexed_models.include?(self.class.name)
|
|
244
|
+
|
|
245
|
+
# Prepare attributes to hash
|
|
246
|
+
to_index_hash = {:id => self.id.to_s}
|
|
247
|
+
|
|
248
|
+
# If the document is embedded set _parent to the parent's id
|
|
249
|
+
if self.embedded?
|
|
250
|
+
parent_id = self.send(self.class.embedded_parent_foreign_key.to_sym).id.to_s
|
|
251
|
+
to_index_hash.merge!({
|
|
252
|
+
(self.class.embedded_parent_foreign_key + "_id").to_sym => parent_id,
|
|
253
|
+
:_parent => parent_id
|
|
254
|
+
})
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Add indexed fields to the hash
|
|
258
|
+
self.class.search_fields.each do |sfield|
|
|
259
|
+
if self.class.fields[sfield.to_s]
|
|
260
|
+
to_index_hash[sfield] = self.attributes[sfield.to_s]
|
|
261
|
+
else
|
|
262
|
+
to_index_hash[sfield] = self.send(sfield)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Add indexed relations to the hash
|
|
267
|
+
self.class.search_relations.each do |relation, fields|
|
|
268
|
+
entries = self.send(relation.to_sym)
|
|
269
|
+
|
|
270
|
+
next if entries.nil?
|
|
271
|
+
|
|
272
|
+
if entries.is_a?(Array) || entries.is_a?(Mongoid::Relations::Targets::Enumerable)
|
|
273
|
+
next if entries.empty?
|
|
274
|
+
to_index_hash[relation] = []
|
|
275
|
+
entries.each do |entry|
|
|
276
|
+
if fields.is_a?(Array)
|
|
277
|
+
to_index_hash[relation] << entry.attributes.reject{|key, value| !fields.include?(key.to_sym)}
|
|
278
|
+
else
|
|
279
|
+
to_index_hash[relation] << { fields => entry.attributes[fields.to_s] }
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
else
|
|
283
|
+
to_index_hash[relation] = {}
|
|
284
|
+
if fields.is_a?(Array)
|
|
285
|
+
to_index_hash[relation].merge!(entries.attributes.reject{|key, value| !fields.include?(key.to_sym)})
|
|
286
|
+
else
|
|
287
|
+
to_index_hash[relation].merge!({ fields => entries.attributes[fields.to_s] })
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
::Mebla.log("Indexing #{self.class.slingshot_type_name}: #{to_index_hash.to_s}", :debug)
|
|
293
|
+
|
|
294
|
+
# Index the data under its correct type
|
|
295
|
+
response = ::Mebla.context.slingshot_index.store(self.class.slingshot_type_name.to_sym, to_index_hash)
|
|
296
|
+
|
|
297
|
+
::Mebla.log("Response for indexing #{self.class.slingshot_type_name}: #{response.to_s}", :debug)
|
|
298
|
+
|
|
299
|
+
# Refresh the index
|
|
300
|
+
::Mebla.context.refresh_index
|
|
301
|
+
return true
|
|
302
|
+
rescue => error
|
|
303
|
+
raise_synchronization_exception(error)
|
|
304
|
+
|
|
305
|
+
return false
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
# Deletes the document from the index
|
|
309
|
+
# @return [Boolean] true if the operation is successful
|
|
310
|
+
def remove_from_index
|
|
311
|
+
return false unless ::Mebla.context.index_exists? # only try to index if the index exists
|
|
312
|
+
|
|
313
|
+
::Mebla.log("Removing #{self.class.slingshot_type_name} with id: #{self.id.to_s}", :debug)
|
|
314
|
+
|
|
315
|
+
# Delete the document
|
|
316
|
+
response = Slingshot::Configuration.client.delete "#{::Mebla::Configuration.instance.url}/#{::Mebla.context.slingshot_index_name}/#{self.class.slingshot_type_name}/#{self.id.to_s}"
|
|
317
|
+
|
|
318
|
+
::Mebla.log("Response for removing #{self.class.slingshot_type_name}: #{response.to_s}", :debug)
|
|
319
|
+
|
|
320
|
+
# Refresh the index
|
|
321
|
+
::Mebla.context.refresh_index
|
|
322
|
+
return true
|
|
323
|
+
rescue => error
|
|
324
|
+
raise_synchronization_exception(error)
|
|
325
|
+
|
|
326
|
+
return false
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Raises synchronization exception in either #add_to_index or #remove_from_index
|
|
330
|
+
def raise_synchronization_exception(error)
|
|
331
|
+
exception_message = "#{self.class.slingshot_type_name} synchronization failed with the following error: #{error.message}"
|
|
332
|
+
if self.class.whiny_indexing
|
|
333
|
+
# Whine when mebla is not able to synchronize
|
|
334
|
+
raise ::Mebla::Errors::MeblaSynchronizationException.new(exception_message)
|
|
335
|
+
else
|
|
336
|
+
# Whining is not allowed, silently log the exception
|
|
337
|
+
::Mebla.log(exception_message, :warn)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|