meilisearch-rails 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)