meilisearch-rails 0.2.2 → 0.4.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.
@@ -2,6 +2,7 @@ require 'meilisearch'
2
2
 
3
3
  require 'meilisearch/version'
4
4
  require 'meilisearch/utilities'
5
+ require 'meilisearch/errors'
5
6
 
6
7
  if defined? Rails
7
8
  begin
@@ -19,11 +20,6 @@ end
19
20
  require 'logger'
20
21
 
21
22
  module MeiliSearch
22
-
23
- class NotConfigured < StandardError; end
24
- class BadConfiguration < StandardError; end
25
- class NoBlockGiven < StandardError; end
26
-
27
23
  autoload :Configuration, 'meilisearch/configuration'
28
24
  extend Configuration
29
25
 
@@ -42,27 +38,26 @@ module MeiliSearch
42
38
  include InstanceMethods
43
39
  end
44
40
  end
45
-
46
41
  end
47
42
 
48
43
  class IndexSettings
49
44
  DEFAULT_BATCH_SIZE = 1000
50
45
 
51
- DEFAULT_PRIMARY_KEY = 'id'
46
+ DEFAULT_PRIMARY_KEY = 'id'.freeze
52
47
 
53
48
  # MeiliSearch settings
54
- OPTIONS = [
55
- :searchableAttributes,
56
- :filterableAttributes,
57
- :displayedAttributes,
58
- :distinctAttribute,
59
- :synonyms,
60
- :stopWords,
61
- :rankingRules,
62
- :attributesToHighlight,
63
- :attributesToCrop,
64
- :cropLength,
65
- ]
49
+ OPTIONS = %i[
50
+ searchableAttributes
51
+ filterableAttributes
52
+ displayedAttributes
53
+ distinctAttribute
54
+ synonyms
55
+ stopWords
56
+ rankingRules
57
+ attributesToHighlight
58
+ attributesToCrop
59
+ cropLength
60
+ ].freeze
66
61
 
67
62
  OPTIONS.each do |option|
68
63
  define_method option do |value|
@@ -84,40 +79,42 @@ module MeiliSearch
84
79
  end
85
80
 
86
81
  def attribute(*names, &block)
87
- raise ArgumentError.new('Cannot pass multiple attribute names if block given') if block_given? and names.length > 1
82
+ raise ArgumentError, 'Cannot pass multiple attribute names if block given' if block_given? && (names.length > 1)
83
+
88
84
  @attributes ||= {}
89
85
  names.flatten.each do |name|
90
- @attributes[name.to_s] = block_given? ? Proc.new { |d| d.instance_eval(&block) } : Proc.new { |d| d.send(name) }
86
+ @attributes[name.to_s] = block_given? ? proc { |d| d.instance_eval(&block) } : proc { |d| d.send(name) }
91
87
  end
92
88
  end
93
- alias :attributes :attribute
89
+ alias attributes attribute
94
90
 
95
91
  def add_attribute(*names, &block)
96
- raise ArgumentError.new('Cannot pass multiple attribute names if block given') if block_given? and names.length > 1
92
+ raise ArgumentError, 'Cannot pass multiple attribute names if block given' if block_given? && (names.length > 1)
93
+
97
94
  @additional_attributes ||= {}
98
95
  names.each do |name|
99
- @additional_attributes[name.to_s] = block_given? ? Proc.new { |d| d.instance_eval(&block) } : Proc.new { |d| d.send(name) }
96
+ @additional_attributes[name.to_s] = block_given? ? proc { |d| d.instance_eval(&block) } : proc { |d| d.send(name) }
100
97
  end
101
98
  end
102
- alias :add_attributes :add_attribute
99
+ alias add_attributes add_attribute
103
100
 
104
- def is_mongoid?(document)
101
+ def mongoid?(document)
105
102
  defined?(::Mongoid::Document) && document.class.include?(::Mongoid::Document)
106
103
  end
107
104
 
108
- def is_sequel?(document)
105
+ def sequel?(document)
109
106
  defined?(::Sequel) && document.class < ::Sequel::Model
110
107
  end
111
108
 
112
- def is_active_record?(document)
113
- !is_mongoid?(document) && !is_sequel?(document)
109
+ def active_record?(document)
110
+ !mongoid?(document) && !sequel?(document)
114
111
  end
115
112
 
116
113
  def get_default_attributes(document)
117
- if is_mongoid?(document)
114
+ if mongoid?(document)
118
115
  # work-around mongoid 2.4's unscoped method, not accepting a block
119
116
  document.attributes
120
- elsif is_sequel?(document)
117
+ elsif sequel?(document)
121
118
  document.to_hash
122
119
  else
123
120
  document.class.unscoped do
@@ -132,7 +129,7 @@ module MeiliSearch
132
129
 
133
130
  def attributes_to_hash(attributes, document)
134
131
  if attributes
135
- Hash[attributes.map { |name, value| [name.to_s, value.call(document) ] }]
132
+ attributes.to_h { |name, value| [name.to_s, value.call(document)] }
136
133
  else
137
134
  {}
138
135
  end
@@ -141,22 +138,18 @@ module MeiliSearch
141
138
  def get_attributes(document)
142
139
  # If a serializer is set, we ignore attributes
143
140
  # everything should be done via the serializer
144
- if not @serializer.nil?
141
+ if !@serializer.nil?
145
142
  attributes = @serializer.new(document).attributes
146
- else
147
- if @attributes.nil? || @attributes.length == 0
143
+ elsif @attributes.blank?
144
+ attributes = get_default_attributes(document)
148
145
  # no `attribute ...` have been configured, use the default attributes of the model
149
- attributes = get_default_attributes(document)
150
- else
146
+ elsif active_record?(document)
151
147
  # at least 1 `attribute ...` has been configured, therefore use ONLY the one configured
152
- if is_active_record?(document)
153
- document.class.unscoped do
154
- attributes = attributes_to_hash(@attributes, document)
155
- end
156
- else
148
+ document.class.unscoped do
157
149
  attributes = attributes_to_hash(@attributes, document)
158
150
  end
159
- end
151
+ else
152
+ attributes = attributes_to_hash(@attributes, document)
160
153
  end
161
154
 
162
155
  attributes.merge!(attributes_to_hash(@additional_attributes, document)) if @additional_attributes
@@ -171,36 +164,34 @@ module MeiliSearch
171
164
  attributes = sanitize_attributes(attributes, sanitizer)
172
165
  end
173
166
 
174
- if @options[:force_utf8_encoding]
175
- attributes = encode_attributes(attributes)
176
- end
167
+ attributes = encode_attributes(attributes) if @options[:force_utf8_encoding]
177
168
 
178
169
  attributes
179
170
  end
180
171
 
181
- def sanitize_attributes(v, sanitizer)
182
- case v
172
+ def sanitize_attributes(value, sanitizer)
173
+ case value
183
174
  when String
184
- sanitizer.sanitize(v)
175
+ sanitizer.sanitize(value)
185
176
  when Hash
186
- v.each { |key, value| v[key] = sanitize_attributes(value, sanitizer) }
177
+ value.each { |key, val| value[key] = sanitize_attributes(val, sanitizer) }
187
178
  when Array
188
- v.map { |x| sanitize_attributes(x, sanitizer) }
179
+ value.map { |item| sanitize_attributes(item, sanitizer) }
189
180
  else
190
- v
181
+ value
191
182
  end
192
183
  end
193
184
 
194
- def encode_attributes(v)
195
- case v
185
+ def encode_attributes(value)
186
+ case value
196
187
  when String
197
- v.force_encoding('utf-8')
188
+ value.force_encoding('utf-8')
198
189
  when Hash
199
- v.each { |key, value| v[key] = encode_attributes(value) }
190
+ value.each { |key, val| value[key] = encode_attributes(val) }
200
191
  when Array
201
- v.map { |x| encode_attributes(x) }
192
+ value.map { |x| encode_attributes(x) }
202
193
  else
203
- v
194
+ value
204
195
  end
205
196
  end
206
197
 
@@ -212,14 +203,17 @@ module MeiliSearch
212
203
  settings = {}
213
204
  OPTIONS.each do |k|
214
205
  v = get_setting(k)
215
- settings[k] = v if !v.nil?
206
+ settings[k] = v unless v.nil?
216
207
  end
217
208
  settings
218
209
  end
219
210
 
220
211
  def add_index(index_uid, options = {}, &block)
221
- raise ArgumentError.new('No block given') if !block_given?
222
- raise ArgumentError.new('Options auto_index and auto_remove cannot be set on nested indexes') if options[:auto_index] || options[:auto_remove]
212
+ raise ArgumentError, 'No block given' unless block_given?
213
+ if options[:auto_index] || options[:auto_remove]
214
+ raise ArgumentError, 'Options auto_index and auto_remove cannot be set on nested indexes'
215
+ end
216
+
223
217
  @additional_indexes ||= {}
224
218
  options[:index_uid] = index_uid
225
219
  @additional_indexes[options] = IndexSettings.new(options, &block)
@@ -242,70 +236,68 @@ module MeiliSearch
242
236
  class SafeIndex
243
237
  def initialize(index_uid, raise_on_failure, options)
244
238
  client = MeiliSearch.client
245
- primary_key = options[:primary_key] || MeiliSearch::IndexSettings::DEFAULT_PRIMARY_KEY
246
- @index = client.get_or_create_index(index_uid, { primaryKey: primary_key })
239
+ primary_key = options[:primary_key] || MeiliSearch::IndexSettings::DEFAULT_PRIMARY_KEY
240
+ client.create_index(index_uid, { primaryKey: primary_key })
241
+ @index = client.index(index_uid)
247
242
  @raise_on_failure = raise_on_failure.nil? || raise_on_failure
248
243
  end
249
244
 
250
245
  ::MeiliSearch::Index.instance_methods(false).each do |m|
251
- define_method(m) do |*args, &block|
252
- if (m == :update_settings)
253
- args[0].delete(:attributesToHighlight) if args[0][:attributesToHighlight]
254
- args[0].delete(:attributesToCrop) if args[0][:attributesToCrop]
255
- args[0].delete(:cropLength) if args[0][:cropLength]
256
- end
257
- SafeIndex.log_or_throw(m, @raise_on_failure) do
258
- @index.send(m, *args, &block)
259
- end
246
+ define_method(m) do |*args, &block|
247
+ if m == :update_settings
248
+ args[0].delete(:attributesToHighlight) if args[0][:attributesToHighlight]
249
+ args[0].delete(:attributesToCrop) if args[0][:attributesToCrop]
250
+ args[0].delete(:cropLength) if args[0][:cropLength]
251
+ end
252
+ SafeIndex.log_or_throw(m, @raise_on_failure) do
253
+ @index.send(m, *args, &block)
260
254
  end
255
+ end
261
256
  end
262
257
 
263
- # special handling of wait_for_pending_update to handle null task_id
264
- def wait_for_pending_update(update_id)
265
- return if update_id.nil? && !@raise_on_failure # ok
266
- SafeIndex.log_or_throw(:wait_for_pending_update, @raise_on_failure) do
267
- @index.wait_for_pending_update(update_id)
258
+ # special handling of wait_for_task to handle null task_id
259
+ def wait_for_task(task_uid)
260
+ return if task_uid.nil? && !@raise_on_failure # ok
261
+
262
+ SafeIndex.log_or_throw(:wait_for_task, @raise_on_failure) do
263
+ @index.wait_for_task(task_uid)
268
264
  end
269
265
  end
270
266
 
271
267
  # special handling of settings to avoid raising errors on 404
272
268
  def settings(*args)
273
269
  SafeIndex.log_or_throw(:settings, @raise_on_failure) do
274
- begin
275
- @index.settings(*args)
276
- rescue ::MeiliSearch::ApiError => e
277
- return {} if e.code == 404 # not fatal
278
- raise e
279
- end
270
+ @index.settings(*args)
271
+ rescue ::MeiliSearch::ApiError => e
272
+ return {} if e.code == 404 # not fatal
273
+
274
+ raise e
280
275
  end
281
276
  end
282
277
 
283
- private
284
278
  def self.log_or_throw(method, raise_on_failure, &block)
285
- begin
286
- yield
287
- rescue ::MeiliSearch::ApiError => e
288
- raise e if raise_on_failure
289
- # log the error
290
- (Rails.logger || Logger.new(STDOUT)).error("[meilisearch-rails] #{e.message}")
291
- # return something
292
- case method.to_s
293
- when 'search'
294
- # some attributes are required
295
- { 'hits' => [], 'hitsPerPage' => 0, 'page' => 0, 'facetsDistribution' => {}, 'error' => e }
296
- else
297
- # empty answer
298
- { 'error' => e }
299
- end
279
+ yield
280
+ rescue ::MeiliSearch::ApiError => e
281
+ raise e if raise_on_failure
282
+
283
+ # log the error
284
+ (Rails.logger || Logger.new($stdout)).error("[meilisearch-rails] #{e.message}")
285
+ # return something
286
+ case method.to_s
287
+ when 'search'
288
+ # some attributes are required
289
+ { 'hits' => [], 'hitsPerPage' => 0, 'page' => 0, 'facetsDistribution' => {}, 'error' => e }
290
+ else
291
+ # empty answer
292
+ { 'error' => e }
300
293
  end
301
294
  end
302
295
  end
303
296
 
304
297
  # these are the class methods added when MeiliSearch is included
305
298
  module ClassMethods
306
-
307
299
  def self.extended(base)
308
- class <<base
300
+ class << base
309
301
  alias_method :without_auto_index, :ms_without_auto_index unless method_defined? :without_auto_index
310
302
  alias_method :reindex!, :ms_reindex! unless method_defined? :reindex!
311
303
  alias_method :index_documents, :ms_index_documents unless method_defined? :index_documents
@@ -324,7 +316,10 @@ module MeiliSearch
324
316
 
325
317
  def meilisearch(options = {}, &block)
326
318
  self.meilisearch_settings = IndexSettings.new(options, &block)
327
- self.meilisearch_options = { type: ms_full_const_get(model_name.to_s), per_page: meilisearch_settings.get_setting(:hitsPerPage) || 20, page: 1 }.merge(options)
319
+ self.meilisearch_options = {
320
+ type: model_name.to_s.constantize,
321
+ per_page: meilisearch_settings.get_setting(:hitsPerPage) || 20, page: 1
322
+ }.merge(options)
328
323
 
329
324
  attr_accessor :formatted
330
325
 
@@ -338,24 +333,25 @@ module MeiliSearch
338
333
  ms_mark_synchronous
339
334
  end
340
335
  end
341
- else
342
- after_validation :ms_mark_synchronous if respond_to?(:after_validation)
336
+ elsif respond_to?(:after_validation)
337
+ after_validation :ms_mark_synchronous
343
338
  end
344
339
  end
345
340
  if options[:enqueue]
346
- raise ArgumentError.new("Cannot use a enqueue if the `synchronous` option if set") if options[:synchronous]
341
+ raise ArgumentError, 'Cannot use a enqueue if the `synchronous` option if set' if options[:synchronous]
342
+
347
343
  proc = if options[:enqueue] == true
348
- Proc.new do |record, remove|
349
- MSJob.perform_later(record, remove ? 'ms_remove_from_index!' : 'ms_index!')
350
- end
351
- elsif options[:enqueue].respond_to?(:call)
352
- options[:enqueue]
353
- elsif options[:enqueue].is_a?(Symbol)
354
- Proc.new { |record, remove| self.send(options[:enqueue], record, remove) }
355
- else
356
- raise ArgumentError.new("Invalid `enqueue` option: #{options[:enqueue]}")
357
- end
358
- meilisearch_options[:enqueue] = Proc.new do |record, remove|
344
+ proc do |record, remove|
345
+ MSJob.perform_later(record, remove ? 'ms_remove_from_index!' : 'ms_index!')
346
+ end
347
+ elsif options[:enqueue].respond_to?(:call)
348
+ options[:enqueue]
349
+ elsif options[:enqueue].is_a?(Symbol)
350
+ proc { |record, remove| send(options[:enqueue], record, remove) }
351
+ else
352
+ raise ArgumentError, "Invalid `enqueue` option: #{options[:enqueue]}"
353
+ end
354
+ meilisearch_options[:enqueue] = proc do |record, remove|
359
355
  proc.call(record, remove) unless ms_without_auto_index_scope
360
356
  end
361
357
  end
@@ -390,7 +386,7 @@ module MeiliSearch
390
386
  define_method(:after_save) do |*args|
391
387
  super(*args)
392
388
  copy_after_save.bind(self).call
393
- self.db.after_commit do
389
+ db.after_commit do
394
390
  ms_perform_index_tasks
395
391
  end
396
392
  end
@@ -417,8 +413,8 @@ module MeiliSearch
417
413
  super(*args)
418
414
  end
419
415
  end
420
- else
421
- after_destroy { |searchable| searchable.ms_enqueue_remove_from_index!(ms_synchronous?) } if respond_to?(:after_destroy)
416
+ elsif respond_to?(:after_destroy)
417
+ after_destroy { |searchable| searchable.ms_enqueue_remove_from_index!(ms_synchronous?) }
422
418
  end
423
419
  end
424
420
  end
@@ -433,38 +429,38 @@ module MeiliSearch
433
429
  end
434
430
 
435
431
  def ms_without_auto_index_scope=(value)
436
- Thread.current["ms_without_auto_index_scope_for_#{self.model_name}"] = value
432
+ Thread.current["ms_without_auto_index_scope_for_#{model_name}"] = value
437
433
  end
438
434
 
439
435
  def ms_without_auto_index_scope
440
- Thread.current["ms_without_auto_index_scope_for_#{self.model_name}"]
436
+ Thread.current["ms_without_auto_index_scope_for_#{model_name}"]
441
437
  end
442
438
 
443
439
  def ms_reindex!(batch_size = MeiliSearch::IndexSettings::DEFAULT_BATCH_SIZE, synchronous = false)
444
440
  return if ms_without_auto_index_scope
441
+
445
442
  ms_configurations.each do |options, settings|
446
443
  next if ms_indexing_disabled?(options)
444
+
447
445
  index = ms_ensure_init(options, settings)
448
- last_update = nil
446
+ last_task = nil
449
447
 
450
448
  ms_find_in_batches(batch_size) do |group|
451
449
  if ms_conditional_index?(options)
452
450
  # delete non-indexable documents
453
451
  ids = group.select { |d| !ms_indexable?(d, options) }.map { |d| ms_primary_key_of(d, options) }
454
- index.delete_documents(ids.select { |id| !id.blank? })
452
+ index.delete_documents(ids.select(&:present?))
455
453
  # select only indexable documents
456
454
  group = group.select { |d| ms_indexable?(d, options) }
457
455
  end
458
456
  documents = group.map do |d|
459
457
  attributes = settings.get_attributes(d)
460
- unless attributes.class == Hash
461
- attributes = attributes.to_hash
462
- end
463
- attributes.merge ms_pk(options) => ms_primary_key_of(d, options)
458
+ attributes = attributes.to_hash unless attributes.instance_of?(Hash)
459
+ attributes.merge ms_pk(options) => ms_primary_key_of(d, options)
464
460
  end
465
- last_update= index.add_documents(documents)
461
+ last_task = index.add_documents(documents)
466
462
  end
467
- index.wait_for_pending_update(last_update["updateId"]) if last_update and (synchronous || options[:synchronous])
463
+ index.wait_for_task(last_task['uid']) if last_task && (synchronous || options[:synchronous])
468
464
  end
469
465
  nil
470
466
  end
@@ -479,38 +475,41 @@ module MeiliSearch
479
475
  end
480
476
 
481
477
  index = SafeIndex.new(ms_index_uid(options), true, options)
482
- update = index.update_settings(final_settings)
483
- index.wait_for_pending_update(update["updateId"]) if synchronous
478
+ task = index.update_settings(final_settings)
479
+ index.wait_for_task(task['uid']) if synchronous
484
480
  end
485
481
  end
486
482
 
487
483
  def ms_index_documents(documents, synchronous = false)
488
484
  ms_configurations.each do |options, settings|
489
485
  next if ms_indexing_disabled?(options)
486
+
490
487
  index = ms_ensure_init(options, settings)
491
- update = index.add_documents(documents.map { |d| settings.get_attributes(d).merge ms_pk(options) => ms_primary_key_of(d, options) })
492
- index.wait_for_pending_update(update["updateId"]) if synchronous || options[:synchronous]
488
+ task = index.add_documents(documents.map { |d| settings.get_attributes(d).merge ms_pk(options) => ms_primary_key_of(d, options) })
489
+ index.wait_for_task(task['uid']) if synchronous || options[:synchronous]
493
490
  end
494
491
  end
495
492
 
496
493
  def ms_index!(document, synchronous = false)
497
494
  return if ms_without_auto_index_scope
495
+
498
496
  ms_configurations.each do |options, settings|
499
497
  next if ms_indexing_disabled?(options)
498
+
500
499
  primary_key = ms_primary_key_of(document, options)
501
500
  index = ms_ensure_init(options, settings)
502
501
  if ms_indexable?(document, options)
503
- raise ArgumentError.new("Cannot index a record without a primary key") if primary_key.blank?
502
+ raise ArgumentError, 'Cannot index a record without a primary key' if primary_key.blank?
503
+
504
+ doc = settings.get_attributes(document)
505
+ doc = doc.merge ms_pk(options) => primary_key
506
+
504
507
  if synchronous || options[:synchronous]
505
- doc = settings.get_attributes(document)
506
- doc = doc.merge ms_pk(options) => primary_key
507
508
  index.add_documents!(doc)
508
509
  else
509
- doc = settings.get_attributes(document)
510
- doc = doc.merge ms_pk(options) => primary_key
511
510
  index.add_documents(doc)
512
511
  end
513
- elsif ms_conditional_index?(options) && !primary_key.blank?
512
+ elsif ms_conditional_index?(options) && primary_key.present?
514
513
  # remove non-indexable documents
515
514
  if synchronous || options[:synchronous]
516
515
  index.delete_document!(primary_key)
@@ -524,10 +523,13 @@ module MeiliSearch
524
523
 
525
524
  def ms_remove_from_index!(document, synchronous = false)
526
525
  return if ms_without_auto_index_scope
526
+
527
527
  primary_key = ms_primary_key_of(document)
528
- raise ArgumentError.new("Cannot index a record without a primary key") if primary_key.blank?
528
+ raise ArgumentError, 'Cannot index a record without a primary key' if primary_key.blank?
529
+
529
530
  ms_configurations.each do |options, settings|
530
531
  next if ms_indexing_disabled?(options)
532
+
531
533
  index = ms_ensure_init(options, settings)
532
534
  if synchronous || options[:synchronous]
533
535
  index.delete_document!(primary_key)
@@ -541,6 +543,7 @@ module MeiliSearch
541
543
  def ms_clear_index!(synchronous = false)
542
544
  ms_configurations.each do |options, settings|
543
545
  next if ms_indexing_disabled?(options)
546
+
544
547
  index = ms_ensure_init(options, settings)
545
548
  synchronous || options[:synchronous] ? index.delete_all_documents! : index.delete_all_documents
546
549
  @ms_indexes[settings] = nil
@@ -549,24 +552,27 @@ module MeiliSearch
549
552
  end
550
553
 
551
554
  def ms_raw_search(q, params = {})
552
- index_uid = params.delete(:index) ||
553
- params.delete('index')
555
+ index_uid = params.delete(:index) || params.delete('index')
554
556
 
555
- if !meilisearch_settings.get_setting(:attributesToHighlight).nil?
557
+ unless meilisearch_settings.get_setting(:attributesToHighlight).nil?
556
558
  params[:attributesToHighlight] = meilisearch_settings.get_setting(:attributesToHighlight)
557
559
  end
558
560
 
559
- if !meilisearch_settings.get_setting(:attributesToCrop).nil?
561
+ unless meilisearch_settings.get_setting(:attributesToCrop).nil?
560
562
  params[:attributesToCrop] = meilisearch_settings.get_setting(:attributesToCrop)
561
- params[:cropLength] = meilisearch_settings.get_setting(:cropLength) if !meilisearch_settings.get_setting(:cropLength).nil?
563
+
564
+ unless meilisearch_settings.get_setting(:cropLength).nil?
565
+ params[:cropLength] = meilisearch_settings.get_setting(:cropLength)
566
+ end
562
567
  end
568
+
563
569
  index = ms_index(index_uid)
564
- index.search(q, Hash[params.map { |k,v| [k, v] }])
570
+ index.search(q, params.to_h { |k, v| [k, v] })
565
571
  end
566
572
 
567
573
  module AdditionalMethods
568
574
  def self.extended(base)
569
- class <<base
575
+ class << base
570
576
  alias_method :raw_answer, :ms_raw_answer unless method_defined? :raw_answer
571
577
  alias_method :facets_distribution, :ms_facets_distribution unless method_defined? :facets_distribution
572
578
  end
@@ -581,12 +587,13 @@ module MeiliSearch
581
587
  end
582
588
 
583
589
  private
590
+
584
591
  def ms_init_raw_answer(json)
585
592
  @ms_json = json
586
593
  end
587
594
  end
588
595
 
589
- def ms_search(q, params = {})
596
+ def ms_search(query, params = {})
590
597
  if MeiliSearch.configuration[:pagination_backend]
591
598
 
592
599
  page = params[:page].nil? ? params[:page] : params[:page].to_i
@@ -598,28 +605,29 @@ module MeiliSearch
598
605
  end
599
606
 
600
607
  # Returns raw json hits as follows:
601
- # {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "nbHits"=>1, "exhaustiveNbHits"=>false, "processingTimeMs"=>0, "query"=>"iphone"}
602
- json = ms_raw_search(q, params)
608
+ # {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "nbHits"=>1,
609
+ # "exhaustiveNbHits"=>false, "processingTimeMs"=>0, "query"=>"iphone"}
610
+ json = ms_raw_search(query, params)
603
611
 
604
612
  # Returns the ids of the hits: 13
605
613
  hit_ids = json['hits'].map { |hit| hit[ms_pk(meilisearch_options).to_s] }
606
614
 
607
615
  # condition_key gets the primary key of the document; looks for "id" on the options
608
- if defined?(::Mongoid::Document) && self.include?(::Mongoid::Document)
609
- condition_key = ms_primary_key_method.in
610
- else
611
- condition_key = ms_primary_key_method
612
- end
616
+ condition_key = if defined?(::Mongoid::Document) && include?(::Mongoid::Document)
617
+ ms_primary_key_method.in
618
+ else
619
+ ms_primary_key_method
620
+ end
613
621
 
614
622
  # meilisearch_options[:type] refers to the Model name (e.g. Product)
615
- # results_by_id creates a hash with the primaryKey of the document (id) as the key and the document itself as the value
616
- # {"13"=>#<Product id: 13, name: "iphone", href: "apple", tags: nil, type: nil, description: "Puts even more features at your fingertips", release_date: nil>}
623
+ # results_by_id creates a hash with the primaryKey of the document (id) as the key and doc itself as the value
624
+ # {"13"=>#<Product id: 13, name: "iphone", href: "apple", tags: nil, type: nil,
625
+ # description: "Puts even more features at your fingertips", release_date: nil>}
617
626
  results_by_id = meilisearch_options[:type].where(condition_key => hit_ids).index_by do |hit|
618
627
  ms_primary_key_of(hit)
619
628
  end
620
629
 
621
630
  results = json['hits'].map do |hit|
622
-
623
631
  o = results_by_id[hit[ms_pk(meilisearch_options).to_s].to_s]
624
632
  if o
625
633
  o.formatted = hit['_formatted']
@@ -631,7 +639,7 @@ module MeiliSearch
631
639
  hits_per_page ||= 20
632
640
  page ||= 1
633
641
 
634
- res = MeiliSearch::Pagination.create(results, total_hits, meilisearch_options.merge({ page: page , per_page: hits_per_page }))
642
+ res = MeiliSearch::Pagination.create(results, total_hits, meilisearch_options.merge(page: page, per_page: hits_per_page))
635
643
  res.extend(AdditionalMethods)
636
644
  res.send(:ms_init_raw_answer, json)
637
645
  res
@@ -642,7 +650,7 @@ module MeiliSearch
642
650
  ms_configurations.each do |o, s|
643
651
  return ms_ensure_init(o, s) if o[:index_uid].to_s == name.to_s
644
652
  end
645
- raise ArgumentError.new("Invalid index name: #{name}")
653
+ raise ArgumentError, "Invalid index name: #{name}"
646
654
  end
647
655
  ms_ensure_init
648
656
  end
@@ -650,17 +658,19 @@ module MeiliSearch
650
658
  def ms_index_uid(options = nil)
651
659
  options ||= meilisearch_options
652
660
  name = options[:index_uid] || model_name.to_s.gsub('::', '_')
653
- name = "#{name}_#{Rails.env.to_s}" if options[:per_environment]
661
+ name = "#{name}_#{Rails.env}" if options[:per_environment]
654
662
  name
655
663
  end
656
664
 
657
665
  def ms_must_reindex?(document)
658
666
  # use +ms_dirty?+ method if implemented
659
- return document.send(:ms_dirty?) if (document.respond_to?(:ms_dirty?))
667
+ return document.send(:ms_dirty?) if document.respond_to?(:ms_dirty?)
668
+
660
669
  # Loop over each index to see if a attribute used in records has changed
661
670
  ms_configurations.each do |options, settings|
662
671
  next if ms_indexing_disabled?(options)
663
672
  return true if ms_primary_key_changed?(document, options)
673
+
664
674
  settings.get_attribute_names(document).each do |k|
665
675
  return true if ms_attribute_changed?(document, k)
666
676
  # return true if !document.respond_to?(changed_method) || document.send(changed_method)
@@ -678,14 +688,15 @@ module MeiliSearch
678
688
  end
679
689
  end
680
690
  end
691
+
681
692
  # By default, we don't reindex
682
- return false
693
+ false
683
694
  end
684
695
 
685
696
  protected
686
697
 
687
698
  def ms_ensure_init(options = nil, settings = nil, index_settings = nil)
688
- raise ArgumentError.new('No `meilisearch` block found in your model.') if meilisearch_settings.nil?
699
+ raise ArgumentError, 'No `meilisearch` block found in your model.' if meilisearch_settings.nil?
689
700
 
690
701
  @ms_indexes ||= {}
691
702
 
@@ -696,7 +707,7 @@ module MeiliSearch
696
707
 
697
708
  @ms_indexes[settings] = SafeIndex.new(ms_index_uid(options), meilisearch_options[:raise_on_failure], meilisearch_options)
698
709
 
699
- current_settings = @ms_indexes[settings].settings(:getVersion => 1) rescue nil # if the index doesn't exist
710
+ current_settings = @ms_indexes[settings].settings(getVersion: 1) rescue nil # if the index doesn't exist
700
711
 
701
712
  index_settings ||= settings.to_settings
702
713
  index_settings = options[:primary_settings].to_settings.merge(index_settings) if options[:inherit]
@@ -713,17 +724,18 @@ module MeiliSearch
713
724
  private
714
725
 
715
726
  def ms_configurations
716
- raise ArgumentError.new('No `meilisearch` block found in your model.') if meilisearch_settings.nil?
727
+ raise ArgumentError, 'No `meilisearch` block found in your model.' if meilisearch_settings.nil?
728
+
717
729
  if @configurations.nil?
718
730
  @configurations = {}
719
731
  @configurations[meilisearch_options] = meilisearch_settings
720
- meilisearch_settings.additional_indexes.each do |k,v|
732
+ meilisearch_settings.additional_indexes.each do |k, v|
721
733
  @configurations[k] = v
722
734
 
723
- if v.additional_indexes.any?
724
- v.additional_indexes.each do |options, index|
725
- @configurations[options] = index
726
- end
735
+ next unless v.additional_indexes.any?
736
+
737
+ v.additional_indexes.each do |options, index|
738
+ @configurations[options] = index
727
739
  end
728
740
  end
729
741
  end
@@ -750,30 +762,19 @@ module MeiliSearch
750
762
 
751
763
  def meilisearch_settings_changed?(prev, current)
752
764
  return true if prev.nil?
765
+
753
766
  current.each do |k, v|
754
767
  prev_v = prev[k.to_s]
755
- if v.is_a?(Array) and prev_v.is_a?(Array)
768
+ if v.is_a?(Array) && prev_v.is_a?(Array)
756
769
  # compare array of strings, avoiding symbols VS strings comparison
757
- return true if v.map { |x| x.to_s } != prev_v.map { |x| x.to_s }
758
- else
759
- return true if prev_v != v
770
+ return true if v.map(&:to_s) != prev_v.map(&:to_s)
771
+ elsif prev_v != v
772
+ return true
760
773
  end
761
774
  end
762
775
  false
763
776
  end
764
777
 
765
- def ms_full_const_get(name)
766
- list = name.split('::')
767
- list.shift if list.first.blank?
768
- obj = self
769
- list.each do |x|
770
- # This is required because const_get tries to look for constants in the
771
- # ancestor chain, but we only want constants that are HERE
772
- obj = obj.const_defined?(x) ? obj.const_get(x) : obj.const_missing(x)
773
- end
774
- obj
775
- end
776
-
777
778
  def ms_conditional_index?(options = nil)
778
779
  options ||= meilisearch_options
779
780
  options[:if].present? || options[:unless].present?
@@ -796,11 +797,11 @@ module MeiliSearch
796
797
  # All constraints must pass
797
798
  constraint.all? { |inner_constraint| ms_constraint_passes?(document, inner_constraint) }
798
799
  else
799
- if constraint.respond_to?(:call) # Proc
800
- constraint.call(document)
801
- else
800
+ unless constraint.respond_to?(:call)
802
801
  raise ArgumentError, "Unknown constraint type: #{constraint} (#{constraint.class})"
803
802
  end
803
+
804
+ constraint.call(document)
804
805
  end
805
806
  end
806
807
 
@@ -830,7 +831,7 @@ module MeiliSearch
830
831
  items = []
831
832
  all.each do |item|
832
833
  items << item
833
- if items.length % batch_size == 0
834
+ if (items.length % batch_size).zero?
834
835
  yield items
835
836
  items = []
836
837
  end
@@ -869,7 +870,9 @@ module MeiliSearch
869
870
 
870
871
  def ms_enqueue_remove_from_index!(synchronous)
871
872
  if meilisearch_options[:enqueue]
872
- meilisearch_options[:enqueue].call(self, true) unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
873
+ unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
874
+ meilisearch_options[:enqueue].call(self, true)
875
+ end
873
876
  else
874
877
  ms_remove_from_index!(synchronous || ms_synchronous?)
875
878
  end
@@ -877,18 +880,20 @@ module MeiliSearch
877
880
 
878
881
  def ms_enqueue_index!(synchronous)
879
882
  if meilisearch_options[:enqueue]
880
- meilisearch_options[:enqueue].call(self, false) unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
883
+ unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
884
+ meilisearch_options[:enqueue].call(self, false)
885
+ end
881
886
  else
882
887
  ms_index!(synchronous)
883
888
  end
884
889
  end
885
890
 
886
- private
887
-
888
891
  def ms_synchronous?
889
- @ms_synchronous == true
892
+ @ms_synchronous
890
893
  end
891
894
 
895
+ private
896
+
892
897
  def ms_mark_synchronous
893
898
  @ms_synchronous = true
894
899
  end
@@ -899,18 +904,19 @@ module MeiliSearch
899
904
 
900
905
  def ms_mark_must_reindex
901
906
  # ms_must_reindex flag is reset after every commit as part. If we must reindex at any point in
902
- # a stransaction, keep flag set until it is explicitly unset
907
+ # a transaction, keep flag set until it is explicitly unset
903
908
  @ms_must_reindex ||=
904
- if defined?(::Sequel) && is_a?(Sequel::Model)
905
- new? || self.class.ms_must_reindex?(self)
906
- else
907
- new_record? || self.class.ms_must_reindex?(self)
908
- end
909
+ if defined?(::Sequel) && is_a?(Sequel::Model)
910
+ new? || self.class.ms_must_reindex?(self)
911
+ else
912
+ new_record? || self.class.ms_must_reindex?(self)
913
+ end
909
914
  true
910
915
  end
911
916
 
912
917
  def ms_perform_index_tasks
913
918
  return if !@ms_auto_indexing || @ms_must_reindex == false
919
+
914
920
  ms_enqueue_index!(ms_synchronous?)
915
921
  remove_instance_variable(:@ms_auto_indexing) if instance_variable_defined?(:@ms_auto_indexing)
916
922
  remove_instance_variable(:@ms_synchronous) if instance_variable_defined?(:@ms_synchronous)