meilisearch-rails 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 215428bdb5e437c3a906e1246444dc7e2afce9d2b52646790de1d55d0490783f
4
- data.tar.gz: 412f8d56c952a330a9b3473602aca9ac0fee6789a3a3632f65340c7c85524637
3
+ metadata.gz: 3aebe8eb25a9272e97c71563db1dae9758c50f5423adc3909228964097116047
4
+ data.tar.gz: 18e9133418b2c512d8645ce4d1ee9a06113076c9c2af4e5b53e4e295c5d47fe7
5
5
  SHA512:
6
- metadata.gz: ad8f9e4489c11dd3b2a522b134921232fbe2b66946f57ebf6be0c18ccd0643490379fb483d0a2ecf3371a427ff442809801130308e8f11fdedc7d6869a8d14c5
7
- data.tar.gz: 5473ca9c267a3dfada14258db095d86c2e3618d356afc29ecf60c6975b067078cac91d8cc84c3e0b0bf8b5f227496d95830d77ed41923d0deeb313165b0b37df
6
+ metadata.gz: 7730a5763da77d4dfb383ee223e11c29db59e91fbfb7d16eb93e54c901b6b4c2d8472da909efcf2541745ac343a75676196d82a5be7754729b30c6ecd4096ed3
7
+ data.tar.gz: 68ea1f648aa284a1a1c5e63715109fd545c7ec53b5e784188abee97ed30dada6ba06d8e0799500a99401161fe2351fd43871ca04464b06f7ae40313d0b462f2e
data/README.md CHANGED
@@ -38,6 +38,7 @@
38
38
  - [Compatibility](#-compatibility)
39
39
  - [⚙️ Settings](#️-settings)
40
40
  - [🔍 Custom search](#-custom-search)
41
+ - [🔍🔍 Multi search](#-multi-search)
41
42
  - [🪛 Options](#-options)
42
43
  - [Meilisearch configuration & environment](#meilisearch-configuration--environment)
43
44
  - [Pagination with `kaminari` or `will_paginate`](#backend-pagination-with-kaminari-or-will_paginate-)
@@ -240,6 +241,58 @@ Book.search('*', sort: ['title:asc'])
240
241
 
241
242
  👉 Don't forget to set up the `sortable_attributes` option in the `meilisearch` block of your model.
242
243
 
244
+ ## 🔍🔍 Multi search
245
+
246
+ Meilisearch supports searching multiple models at the same time (see [🔍 Custom search](#-custom-search) for search options):
247
+
248
+ ```ruby
249
+ multi_search_results = MeiliSearch::Rails.multi_search(
250
+ Book => { q: 'Harry' },
251
+ Manga => { q: 'Attack' }
252
+ )
253
+ ```
254
+
255
+ You can iterate through the results with `.each` or `.each_result`:
256
+
257
+ ```erb
258
+ <% multi_search_results.each do |record| %>
259
+ <p><%= record.title %></p>
260
+ <p><%= record.author %></p>
261
+ <% end %>
262
+
263
+ <p>Harry Potter and the Philosopher's Stone</p>
264
+ <p>J. K. Rowling</p>
265
+ <p>Harry Potter and the Chamber of Secrets</p>
266
+ <p>J. K. Rowling</p>
267
+ <p>Attack on Titan</p>
268
+ <p>Iseyama</p>
269
+ ```
270
+
271
+ ```erb
272
+ <% multi_search_results.each_result do |klass, results| %>
273
+ <p><%= klass.name.pluralize %></p>
274
+
275
+ <ul>
276
+ <% results.each do |record| %>
277
+ <li><%= record.title %></li>
278
+ <% end %>
279
+ </ul>
280
+ <% end %>
281
+
282
+
283
+ <p>Books</p>
284
+ <ul>
285
+ <li>Harry Potter and the Philosopher's Stone</li>
286
+ <li>Harry Potter and the Chamber of Secrets</li>
287
+ </ul>
288
+ <p>Mangas</p>
289
+ <ul>
290
+ <li>Attack on Titan</li>
291
+ </ul>
292
+ ```
293
+
294
+ See the [official multi search documentation](https://www.meilisearch.com/docs/reference/api/multi_search).
295
+
243
296
  ## 🪛 Options
244
297
 
245
298
  ### Meilisearch configuration & environment
@@ -0,0 +1,84 @@
1
+ module MeiliSearch
2
+ module Rails
3
+ class MultiSearchResult
4
+ attr_reader :metadata
5
+
6
+ def initialize(searches, raw_results)
7
+ @results = {}
8
+ @metadata = {}
9
+
10
+ searches.zip(raw_results['results']).each do |(index_target, search_options), result|
11
+ index_target = search_options[:class_name].constantize if search_options[:class_name]
12
+
13
+ @results[index_target] = case index_target
14
+ when String, Symbol
15
+ result['hits']
16
+ else
17
+ load_results(index_target, result)
18
+ end
19
+
20
+ @metadata[index_target] = result.except('hits')
21
+ end
22
+ end
23
+
24
+ include Enumerable
25
+
26
+ def each_hit(&block)
27
+ @results.each do |_index_target, results|
28
+ results.each(&block)
29
+ end
30
+ end
31
+ alias each each_hit
32
+
33
+ def each_result
34
+ @results.each
35
+ end
36
+
37
+ def to_a
38
+ @results.values.flatten(1)
39
+ end
40
+ alias to_ary to_a
41
+
42
+ def to_h
43
+ @results
44
+ end
45
+ alias to_hash to_h
46
+
47
+ private
48
+
49
+ def load_results(klass, result)
50
+ pk_method = klass.ms_primary_key_method
51
+ pk_method = pk_method.in if Utilities.mongo_model?(klass)
52
+
53
+ condition_key = pk_is_virtual?(klass, pk_method) ? klass.primary_key : pk_method
54
+
55
+ hits_by_id =
56
+ result['hits'].index_by { |hit| hit[condition_key.to_s] }
57
+
58
+ records = klass.where(condition_key => hits_by_id.keys)
59
+
60
+ if records.respond_to? :in_order_of
61
+ records.in_order_of(condition_key, hits_by_id.keys).each do |record|
62
+ record.formatted = hits_by_id[record.send(condition_key).to_s]['_formatted']
63
+ end
64
+ else
65
+ results_by_id = records.index_by do |hit|
66
+ hit.send(condition_key).to_s
67
+ end
68
+
69
+ result['hits'].filter_map do |hit|
70
+ record = results_by_id[hit[condition_key.to_s].to_s]
71
+ record&.formatted = hit['_formatted']
72
+ record
73
+ end
74
+ end
75
+ end
76
+
77
+ def pk_is_virtual?(model_class, pk_method)
78
+ model_class.columns
79
+ .map(&(Utilities.sequel_model?(model_class) ? :to_s : :name))
80
+ .exclude?(pk_method.to_s)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,49 @@
1
+ require_relative 'multi_search/result'
2
+
3
+ module MeiliSearch
4
+ module Rails
5
+ class << self
6
+ def multi_search(searches)
7
+ search_parameters = searches.map do |(index_target, options)|
8
+ paginate(options) if pagination_enabled?
9
+ normalize(options, index_target)
10
+ end
11
+
12
+ MultiSearchResult.new(searches, client.multi_search(search_parameters))
13
+ end
14
+
15
+ private
16
+
17
+ def normalize(options, index_target)
18
+ options
19
+ .except(:class_name)
20
+ .merge!(index_uid: index_uid_from_target(index_target))
21
+ end
22
+
23
+ def index_uid_from_target(index_target)
24
+ case index_target
25
+ when String, Symbol
26
+ index_target
27
+ else
28
+ index_target.index.uid
29
+ end
30
+ end
31
+
32
+ def paginate(options)
33
+ %w[page hitsPerPage hits_per_page].each do |key|
34
+ # Deletes hitsPerPage to avoid passing along a meilisearch-ruby warning/exception
35
+ value = options.delete(key) || options.delete(key.to_sym)
36
+ options[key.underscore.to_sym] = value.to_i if value
37
+ end
38
+
39
+ # It is required to activate the finite pagination in Meilisearch v0.30 (or newer),
40
+ # to have at least `hits_per_page` defined or `page` in the search request.
41
+ options[:page] ||= 1
42
+ end
43
+
44
+ def pagination_enabled?
45
+ MeiliSearch::Rails.configuration[:pagination_backend]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -48,6 +48,14 @@ module MeiliSearch
48
48
  true
49
49
  end
50
50
 
51
+ def mongo_model?(model_class)
52
+ defined?(::Mongoid::Document) && model_class.include?(::Mongoid::Document)
53
+ end
54
+
55
+ def sequel_model?(model_class)
56
+ defined?(::Sequel::Model) && model_class < Sequel::Model
57
+ end
58
+
51
59
  private
52
60
 
53
61
  def constraint_passes?(record, constraint)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module MeiliSearch
4
4
  module Rails
5
- VERSION = '0.11.0'
5
+ VERSION = '0.12.0'
6
6
 
7
7
  def self.qualified_version
8
8
  "Meilisearch Rails (v#{VERSION})"
@@ -3,6 +3,7 @@ require 'meilisearch/rails/null_object'
3
3
  require 'meilisearch/rails/version'
4
4
  require 'meilisearch/rails/utilities'
5
5
  require 'meilisearch/rails/errors'
6
+ require 'meilisearch/rails/multi_search'
6
7
 
7
8
  if defined? Rails
8
9
  begin
@@ -261,7 +262,7 @@ module MeiliSearch
261
262
  @raise_on_failure = raise_on_failure.nil? || raise_on_failure
262
263
 
263
264
  SafeIndex.log_or_throw(nil, @raise_on_failure) do
264
- client.create_index!(index_uid, { primary_key: primary_key })
265
+ client.create_index(index_uid, { primary_key: primary_key })
265
266
  end
266
267
 
267
268
  @index = client.index(index_uid)
@@ -306,7 +307,7 @@ module MeiliSearch
306
307
  SafeIndex.log_or_throw(:settings, @raise_on_failure) do
307
308
  @index.settings(*args)
308
309
  rescue ::MeiliSearch::ApiError => e
309
- return {} if e.code == 404 # not fatal
310
+ return {} if e.code == 'index_not_found' # not fatal
310
311
 
311
312
  raise e
312
313
  end
@@ -760,6 +761,11 @@ module MeiliSearch
760
761
  false
761
762
  end
762
763
 
764
+ def ms_primary_key_method(options = nil)
765
+ options ||= meilisearch_options
766
+ options[:primary_key] || options[:id] || :id
767
+ end
768
+
763
769
  protected
764
770
 
765
771
  def ms_ensure_init(options = meilisearch_options, settings = meilisearch_settings, user_configuration = settings.to_settings)
@@ -814,11 +820,6 @@ module MeiliSearch
814
820
  @configurations
815
821
  end
816
822
 
817
- def ms_primary_key_method(options = nil)
818
- options ||= meilisearch_options
819
- options[:primary_key] || options[:id] || :id
820
- end
821
-
822
823
  def ms_primary_key_of(doc, options = nil)
823
824
  doc.send(ms_primary_key_method(options)).to_s
824
825
  end
@@ -843,7 +844,7 @@ module MeiliSearch
843
844
  if user.is_a?(Hash) && server.is_a?(Hash)
844
845
  meilisearch_settings_changed?(server, user)
845
846
  elsif user.is_a?(Array) && server.is_a?(Array)
846
- user.map(&:to_s) != server.map(&:to_s)
847
+ user.map(&:to_s).sort! != server.map(&:to_s).sort!
847
848
  else
848
849
  user.to_s != server.to_s
849
850
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meilisearch-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Meili
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-12 00:00:00.000000000 Z
11
+ date: 2024-02-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: meilisearch
@@ -42,6 +42,8 @@ files:
42
42
  - lib/meilisearch/rails/errors.rb
43
43
  - lib/meilisearch/rails/ms_clean_up_job.rb
44
44
  - lib/meilisearch/rails/ms_job.rb
45
+ - lib/meilisearch/rails/multi_search.rb
46
+ - lib/meilisearch/rails/multi_search/result.rb
45
47
  - lib/meilisearch/rails/null_object.rb
46
48
  - lib/meilisearch/rails/pagination.rb
47
49
  - lib/meilisearch/rails/pagination/kaminari.rb