meilisearch-rails 0.2.3 → 0.3.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.
@@ -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.map { |name, value| [name.to_s, value.call(document)] }.to_h
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,27 +236,28 @@ 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
239
+ primary_key = options[:primary_key] || MeiliSearch::IndexSettings::DEFAULT_PRIMARY_KEY
246
240
  @index = client.get_or_create_index(index_uid, { primaryKey: primary_key })
247
241
  @raise_on_failure = raise_on_failure.nil? || raise_on_failure
248
242
  end
249
243
 
250
244
  ::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
245
+ define_method(m) do |*args, &block|
246
+ if m == :update_settings
247
+ args[0].delete(:attributesToHighlight) if args[0][:attributesToHighlight]
248
+ args[0].delete(:attributesToCrop) if args[0][:attributesToCrop]
249
+ args[0].delete(:cropLength) if args[0][:cropLength]
260
250
  end
251
+ SafeIndex.log_or_throw(m, @raise_on_failure) do
252
+ @index.send(m, *args, &block)
253
+ end
254
+ end
261
255
  end
262
256
 
263
257
  # special handling of wait_for_pending_update to handle null task_id
264
258
  def wait_for_pending_update(update_id)
265
259
  return if update_id.nil? && !@raise_on_failure # ok
260
+
266
261
  SafeIndex.log_or_throw(:wait_for_pending_update, @raise_on_failure) do
267
262
  @index.wait_for_pending_update(update_id)
268
263
  end
@@ -271,41 +266,37 @@ module MeiliSearch
271
266
  # special handling of settings to avoid raising errors on 404
272
267
  def settings(*args)
273
268
  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
269
+ @index.settings(*args)
270
+ rescue ::MeiliSearch::ApiError => e
271
+ return {} if e.code == 404 # not fatal
272
+
273
+ raise e
280
274
  end
281
275
  end
282
276
 
283
- private
284
277
  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
278
+ yield
279
+ rescue ::MeiliSearch::ApiError => e
280
+ raise e if raise_on_failure
281
+
282
+ # log the error
283
+ (Rails.logger || Logger.new($stdout)).error("[meilisearch-rails] #{e.message}")
284
+ # return something
285
+ case method.to_s
286
+ when 'search'
287
+ # some attributes are required
288
+ { 'hits' => [], 'hitsPerPage' => 0, 'page' => 0, 'facetsDistribution' => {}, 'error' => e }
289
+ else
290
+ # empty answer
291
+ { 'error' => e }
300
292
  end
301
293
  end
302
294
  end
303
295
 
304
296
  # these are the class methods added when MeiliSearch is included
305
297
  module ClassMethods
306
-
307
298
  def self.extended(base)
308
- class <<base
299
+ class << base
309
300
  alias_method :without_auto_index, :ms_without_auto_index unless method_defined? :without_auto_index
310
301
  alias_method :reindex!, :ms_reindex! unless method_defined? :reindex!
311
302
  alias_method :index_documents, :ms_index_documents unless method_defined? :index_documents
@@ -324,7 +315,10 @@ module MeiliSearch
324
315
 
325
316
  def meilisearch(options = {}, &block)
326
317
  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)
318
+ self.meilisearch_options = {
319
+ type: ms_full_const_get(model_name.to_s),
320
+ per_page: meilisearch_settings.get_setting(:hitsPerPage) || 20, page: 1
321
+ }.merge(options)
328
322
 
329
323
  attr_accessor :formatted
330
324
 
@@ -338,24 +332,25 @@ module MeiliSearch
338
332
  ms_mark_synchronous
339
333
  end
340
334
  end
341
- else
342
- after_validation :ms_mark_synchronous if respond_to?(:after_validation)
335
+ elsif respond_to?(:after_validation)
336
+ after_validation :ms_mark_synchronous
343
337
  end
344
338
  end
345
339
  if options[:enqueue]
346
- raise ArgumentError.new("Cannot use a enqueue if the `synchronous` option if set") if options[:synchronous]
340
+ raise ArgumentError, 'Cannot use a enqueue if the `synchronous` option if set' if options[:synchronous]
341
+
347
342
  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|
343
+ proc do |record, remove|
344
+ MSJob.perform_later(record, remove ? 'ms_remove_from_index!' : 'ms_index!')
345
+ end
346
+ elsif options[:enqueue].respond_to?(:call)
347
+ options[:enqueue]
348
+ elsif options[:enqueue].is_a?(Symbol)
349
+ proc { |record, remove| send(options[:enqueue], record, remove) }
350
+ else
351
+ raise ArgumentError, "Invalid `enqueue` option: #{options[:enqueue]}"
352
+ end
353
+ meilisearch_options[:enqueue] = proc do |record, remove|
359
354
  proc.call(record, remove) unless ms_without_auto_index_scope
360
355
  end
361
356
  end
@@ -390,7 +385,7 @@ module MeiliSearch
390
385
  define_method(:after_save) do |*args|
391
386
  super(*args)
392
387
  copy_after_save.bind(self).call
393
- self.db.after_commit do
388
+ db.after_commit do
394
389
  ms_perform_index_tasks
395
390
  end
396
391
  end
@@ -417,8 +412,8 @@ module MeiliSearch
417
412
  super(*args)
418
413
  end
419
414
  end
420
- else
421
- after_destroy { |searchable| searchable.ms_enqueue_remove_from_index!(ms_synchronous?) } if respond_to?(:after_destroy)
415
+ elsif respond_to?(:after_destroy)
416
+ after_destroy { |searchable| searchable.ms_enqueue_remove_from_index!(ms_synchronous?) }
422
417
  end
423
418
  end
424
419
  end
@@ -433,17 +428,19 @@ module MeiliSearch
433
428
  end
434
429
 
435
430
  def ms_without_auto_index_scope=(value)
436
- Thread.current["ms_without_auto_index_scope_for_#{self.model_name}"] = value
431
+ Thread.current["ms_without_auto_index_scope_for_#{model_name}"] = value
437
432
  end
438
433
 
439
434
  def ms_without_auto_index_scope
440
- Thread.current["ms_without_auto_index_scope_for_#{self.model_name}"]
435
+ Thread.current["ms_without_auto_index_scope_for_#{model_name}"]
441
436
  end
442
437
 
443
438
  def ms_reindex!(batch_size = MeiliSearch::IndexSettings::DEFAULT_BATCH_SIZE, synchronous = false)
444
439
  return if ms_without_auto_index_scope
440
+
445
441
  ms_configurations.each do |options, settings|
446
442
  next if ms_indexing_disabled?(options)
443
+
447
444
  index = ms_ensure_init(options, settings)
448
445
  last_update = nil
449
446
 
@@ -451,20 +448,18 @@ module MeiliSearch
451
448
  if ms_conditional_index?(options)
452
449
  # delete non-indexable documents
453
450
  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? })
451
+ index.delete_documents(ids.select(&:present?))
455
452
  # select only indexable documents
456
453
  group = group.select { |d| ms_indexable?(d, options) }
457
454
  end
458
455
  documents = group.map do |d|
459
456
  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)
457
+ attributes = attributes.to_hash unless attributes.instance_of?(Hash)
458
+ attributes.merge ms_pk(options) => ms_primary_key_of(d, options)
464
459
  end
465
460
  last_update= index.add_documents(documents)
466
461
  end
467
- index.wait_for_pending_update(last_update["updateId"]) if last_update and (synchronous || options[:synchronous])
462
+ index.wait_for_pending_update(last_update['updateId']) if last_update && (synchronous || options[:synchronous])
468
463
  end
469
464
  nil
470
465
  end
@@ -480,37 +475,40 @@ module MeiliSearch
480
475
 
481
476
  index = SafeIndex.new(ms_index_uid(options), true, options)
482
477
  update = index.update_settings(final_settings)
483
- index.wait_for_pending_update(update["updateId"]) if synchronous
478
+ index.wait_for_pending_update(update['updateId']) if synchronous
484
479
  end
485
480
  end
486
481
 
487
482
  def ms_index_documents(documents, synchronous = false)
488
483
  ms_configurations.each do |options, settings|
489
484
  next if ms_indexing_disabled?(options)
485
+
490
486
  index = ms_ensure_init(options, settings)
491
487
  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
+ index.wait_for_pending_update(update['updateId']) if synchronous || options[:synchronous]
493
489
  end
494
490
  end
495
491
 
496
492
  def ms_index!(document, synchronous = false)
497
493
  return if ms_without_auto_index_scope
494
+
498
495
  ms_configurations.each do |options, settings|
499
496
  next if ms_indexing_disabled?(options)
497
+
500
498
  primary_key = ms_primary_key_of(document, options)
501
499
  index = ms_ensure_init(options, settings)
502
500
  if ms_indexable?(document, options)
503
- raise ArgumentError.new("Cannot index a record without a primary key") if primary_key.blank?
501
+ raise ArgumentError, 'Cannot index a record without a primary key' if primary_key.blank?
502
+
503
+ doc = settings.get_attributes(document)
504
+ doc = doc.merge ms_pk(options) => primary_key
505
+
504
506
  if synchronous || options[:synchronous]
505
- doc = settings.get_attributes(document)
506
- doc = doc.merge ms_pk(options) => primary_key
507
507
  index.add_documents!(doc)
508
508
  else
509
- doc = settings.get_attributes(document)
510
- doc = doc.merge ms_pk(options) => primary_key
511
509
  index.add_documents(doc)
512
510
  end
513
- elsif ms_conditional_index?(options) && !primary_key.blank?
511
+ elsif ms_conditional_index?(options) && primary_key.present?
514
512
  # remove non-indexable documents
515
513
  if synchronous || options[:synchronous]
516
514
  index.delete_document!(primary_key)
@@ -524,10 +522,13 @@ module MeiliSearch
524
522
 
525
523
  def ms_remove_from_index!(document, synchronous = false)
526
524
  return if ms_without_auto_index_scope
525
+
527
526
  primary_key = ms_primary_key_of(document)
528
- raise ArgumentError.new("Cannot index a record without a primary key") if primary_key.blank?
527
+ raise ArgumentError, 'Cannot index a record without a primary key' if primary_key.blank?
528
+
529
529
  ms_configurations.each do |options, settings|
530
530
  next if ms_indexing_disabled?(options)
531
+
531
532
  index = ms_ensure_init(options, settings)
532
533
  if synchronous || options[:synchronous]
533
534
  index.delete_document!(primary_key)
@@ -541,6 +542,7 @@ module MeiliSearch
541
542
  def ms_clear_index!(synchronous = false)
542
543
  ms_configurations.each do |options, settings|
543
544
  next if ms_indexing_disabled?(options)
545
+
544
546
  index = ms_ensure_init(options, settings)
545
547
  synchronous || options[:synchronous] ? index.delete_all_documents! : index.delete_all_documents
546
548
  @ms_indexes[settings] = nil
@@ -549,24 +551,27 @@ module MeiliSearch
549
551
  end
550
552
 
551
553
  def ms_raw_search(q, params = {})
552
- index_uid = params.delete(:index) ||
553
- params.delete('index')
554
+ index_uid = params.delete(:index) || params.delete('index')
554
555
 
555
- if !meilisearch_settings.get_setting(:attributesToHighlight).nil?
556
+ unless meilisearch_settings.get_setting(:attributesToHighlight).nil?
556
557
  params[:attributesToHighlight] = meilisearch_settings.get_setting(:attributesToHighlight)
557
558
  end
558
559
 
559
- if !meilisearch_settings.get_setting(:attributesToCrop).nil?
560
+ unless meilisearch_settings.get_setting(:attributesToCrop).nil?
560
561
  params[:attributesToCrop] = meilisearch_settings.get_setting(:attributesToCrop)
561
- params[:cropLength] = meilisearch_settings.get_setting(:cropLength) if !meilisearch_settings.get_setting(:cropLength).nil?
562
+
563
+ unless meilisearch_settings.get_setting(:cropLength).nil?
564
+ params[:cropLength] = meilisearch_settings.get_setting(:cropLength)
565
+ end
562
566
  end
567
+
563
568
  index = ms_index(index_uid)
564
- index.search(q, Hash[params.map { |k,v| [k, v] }])
569
+ index.search(q, params.map { |k, v| [k, v] }.to_h)
565
570
  end
566
571
 
567
572
  module AdditionalMethods
568
573
  def self.extended(base)
569
- class <<base
574
+ class << base
570
575
  alias_method :raw_answer, :ms_raw_answer unless method_defined? :raw_answer
571
576
  alias_method :facets_distribution, :ms_facets_distribution unless method_defined? :facets_distribution
572
577
  end
@@ -581,12 +586,13 @@ module MeiliSearch
581
586
  end
582
587
 
583
588
  private
589
+
584
590
  def ms_init_raw_answer(json)
585
591
  @ms_json = json
586
592
  end
587
593
  end
588
594
 
589
- def ms_search(q, params = {})
595
+ def ms_search(query, params = {})
590
596
  if MeiliSearch.configuration[:pagination_backend]
591
597
 
592
598
  page = params[:page].nil? ? params[:page] : params[:page].to_i
@@ -598,28 +604,29 @@ module MeiliSearch
598
604
  end
599
605
 
600
606
  # 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)
607
+ # {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "nbHits"=>1,
608
+ # "exhaustiveNbHits"=>false, "processingTimeMs"=>0, "query"=>"iphone"}
609
+ json = ms_raw_search(query, params)
603
610
 
604
611
  # Returns the ids of the hits: 13
605
612
  hit_ids = json['hits'].map { |hit| hit[ms_pk(meilisearch_options).to_s] }
606
613
 
607
614
  # 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
615
+ condition_key = if defined?(::Mongoid::Document) && include?(::Mongoid::Document)
616
+ ms_primary_key_method.in
617
+ else
618
+ ms_primary_key_method
619
+ end
613
620
 
614
621
  # 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>}
622
+ # results_by_id creates a hash with the primaryKey of the document (id) as the key and doc itself as the value
623
+ # {"13"=>#<Product id: 13, name: "iphone", href: "apple", tags: nil, type: nil,
624
+ # description: "Puts even more features at your fingertips", release_date: nil>}
617
625
  results_by_id = meilisearch_options[:type].where(condition_key => hit_ids).index_by do |hit|
618
626
  ms_primary_key_of(hit)
619
627
  end
620
628
 
621
629
  results = json['hits'].map do |hit|
622
-
623
630
  o = results_by_id[hit[ms_pk(meilisearch_options).to_s].to_s]
624
631
  if o
625
632
  o.formatted = hit['_formatted']
@@ -631,7 +638,7 @@ module MeiliSearch
631
638
  hits_per_page ||= 20
632
639
  page ||= 1
633
640
 
634
- res = MeiliSearch::Pagination.create(results, total_hits, meilisearch_options.merge({ page: page , per_page: hits_per_page }))
641
+ res = MeiliSearch::Pagination.create(results, total_hits, meilisearch_options.merge(page: page, per_page: hits_per_page))
635
642
  res.extend(AdditionalMethods)
636
643
  res.send(:ms_init_raw_answer, json)
637
644
  res
@@ -642,7 +649,7 @@ module MeiliSearch
642
649
  ms_configurations.each do |o, s|
643
650
  return ms_ensure_init(o, s) if o[:index_uid].to_s == name.to_s
644
651
  end
645
- raise ArgumentError.new("Invalid index name: #{name}")
652
+ raise ArgumentError, "Invalid index name: #{name}"
646
653
  end
647
654
  ms_ensure_init
648
655
  end
@@ -650,17 +657,19 @@ module MeiliSearch
650
657
  def ms_index_uid(options = nil)
651
658
  options ||= meilisearch_options
652
659
  name = options[:index_uid] || model_name.to_s.gsub('::', '_')
653
- name = "#{name}_#{Rails.env.to_s}" if options[:per_environment]
660
+ name = "#{name}_#{Rails.env}" if options[:per_environment]
654
661
  name
655
662
  end
656
663
 
657
664
  def ms_must_reindex?(document)
658
665
  # use +ms_dirty?+ method if implemented
659
- return document.send(:ms_dirty?) if (document.respond_to?(:ms_dirty?))
666
+ return document.send(:ms_dirty?) if document.respond_to?(:ms_dirty?)
667
+
660
668
  # Loop over each index to see if a attribute used in records has changed
661
669
  ms_configurations.each do |options, settings|
662
670
  next if ms_indexing_disabled?(options)
663
671
  return true if ms_primary_key_changed?(document, options)
672
+
664
673
  settings.get_attribute_names(document).each do |k|
665
674
  return true if ms_attribute_changed?(document, k)
666
675
  # return true if !document.respond_to?(changed_method) || document.send(changed_method)
@@ -678,14 +687,15 @@ module MeiliSearch
678
687
  end
679
688
  end
680
689
  end
690
+
681
691
  # By default, we don't reindex
682
- return false
692
+ false
683
693
  end
684
694
 
685
695
  protected
686
696
 
687
697
  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?
698
+ raise ArgumentError, 'No `meilisearch` block found in your model.' if meilisearch_settings.nil?
689
699
 
690
700
  @ms_indexes ||= {}
691
701
 
@@ -696,7 +706,7 @@ module MeiliSearch
696
706
 
697
707
  @ms_indexes[settings] = SafeIndex.new(ms_index_uid(options), meilisearch_options[:raise_on_failure], meilisearch_options)
698
708
 
699
- current_settings = @ms_indexes[settings].settings(:getVersion => 1) rescue nil # if the index doesn't exist
709
+ current_settings = @ms_indexes[settings].settings(getVersion: 1) rescue nil # if the index doesn't exist
700
710
 
701
711
  index_settings ||= settings.to_settings
702
712
  index_settings = options[:primary_settings].to_settings.merge(index_settings) if options[:inherit]
@@ -713,17 +723,18 @@ module MeiliSearch
713
723
  private
714
724
 
715
725
  def ms_configurations
716
- raise ArgumentError.new('No `meilisearch` block found in your model.') if meilisearch_settings.nil?
726
+ raise ArgumentError, 'No `meilisearch` block found in your model.' if meilisearch_settings.nil?
727
+
717
728
  if @configurations.nil?
718
729
  @configurations = {}
719
730
  @configurations[meilisearch_options] = meilisearch_settings
720
- meilisearch_settings.additional_indexes.each do |k,v|
731
+ meilisearch_settings.additional_indexes.each do |k, v|
721
732
  @configurations[k] = v
722
733
 
723
- if v.additional_indexes.any?
724
- v.additional_indexes.each do |options, index|
725
- @configurations[options] = index
726
- end
734
+ next unless v.additional_indexes.any?
735
+
736
+ v.additional_indexes.each do |options, index|
737
+ @configurations[options] = index
727
738
  end
728
739
  end
729
740
  end
@@ -750,13 +761,14 @@ module MeiliSearch
750
761
 
751
762
  def meilisearch_settings_changed?(prev, current)
752
763
  return true if prev.nil?
764
+
753
765
  current.each do |k, v|
754
766
  prev_v = prev[k.to_s]
755
- if v.is_a?(Array) and prev_v.is_a?(Array)
767
+ if v.is_a?(Array) && prev_v.is_a?(Array)
756
768
  # 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
769
+ return true if v.map(&:to_s) != prev_v.map(&:to_s)
770
+ elsif prev_v != v
771
+ return true
760
772
  end
761
773
  end
762
774
  false
@@ -796,11 +808,11 @@ module MeiliSearch
796
808
  # All constraints must pass
797
809
  constraint.all? { |inner_constraint| ms_constraint_passes?(document, inner_constraint) }
798
810
  else
799
- if constraint.respond_to?(:call) # Proc
800
- constraint.call(document)
801
- else
811
+ unless constraint.respond_to?(:call)
802
812
  raise ArgumentError, "Unknown constraint type: #{constraint} (#{constraint.class})"
803
813
  end
814
+
815
+ constraint.call(document)
804
816
  end
805
817
  end
806
818
 
@@ -830,7 +842,7 @@ module MeiliSearch
830
842
  items = []
831
843
  all.each do |item|
832
844
  items << item
833
- if items.length % batch_size == 0
845
+ if (items.length % batch_size).zero?
834
846
  yield items
835
847
  items = []
836
848
  end
@@ -869,7 +881,9 @@ module MeiliSearch
869
881
 
870
882
  def ms_enqueue_remove_from_index!(synchronous)
871
883
  if meilisearch_options[:enqueue]
872
- meilisearch_options[:enqueue].call(self, true) unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
884
+ unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
885
+ meilisearch_options[:enqueue].call(self, true)
886
+ end
873
887
  else
874
888
  ms_remove_from_index!(synchronous || ms_synchronous?)
875
889
  end
@@ -877,18 +891,20 @@ module MeiliSearch
877
891
 
878
892
  def ms_enqueue_index!(synchronous)
879
893
  if meilisearch_options[:enqueue]
880
- meilisearch_options[:enqueue].call(self, false) unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
894
+ unless self.class.send(:ms_indexing_disabled?, meilisearch_options)
895
+ meilisearch_options[:enqueue].call(self, false)
896
+ end
881
897
  else
882
898
  ms_index!(synchronous)
883
899
  end
884
900
  end
885
901
 
886
- private
887
-
888
902
  def ms_synchronous?
889
- @ms_synchronous == true
903
+ @ms_synchronous
890
904
  end
891
905
 
906
+ private
907
+
892
908
  def ms_mark_synchronous
893
909
  @ms_synchronous = true
894
910
  end
@@ -899,18 +915,19 @@ module MeiliSearch
899
915
 
900
916
  def ms_mark_must_reindex
901
917
  # 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
918
+ # a transaction, keep flag set until it is explicitly unset
903
919
  @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
920
+ if defined?(::Sequel) && is_a?(Sequel::Model)
921
+ new? || self.class.ms_must_reindex?(self)
922
+ else
923
+ new_record? || self.class.ms_must_reindex?(self)
924
+ end
909
925
  true
910
926
  end
911
927
 
912
928
  def ms_perform_index_tasks
913
929
  return if !@ms_auto_indexing || @ms_must_reindex == false
930
+
914
931
  ms_enqueue_index!(ms_synchronous?)
915
932
  remove_instance_variable(:@ms_auto_indexing) if instance_variable_defined?(:@ms_auto_indexing)
916
933
  remove_instance_variable(:@ms_synchronous) if instance_variable_defined?(:@ms_synchronous)