meilisearch-rails 0.11.1 → 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: 75f8a8a3ebfe381cbb7c9b40072dcf859882ccf9bf78bc5bb8ab0b94c05231d9
4
- data.tar.gz: b3b5ec98f2524a08c738847a6b70671201f27cf466a62730f1aabbb0e177e08e
3
+ metadata.gz: 3aebe8eb25a9272e97c71563db1dae9758c50f5423adc3909228964097116047
4
+ data.tar.gz: 18e9133418b2c512d8645ce4d1ee9a06113076c9c2af4e5b53e4e295c5d47fe7
5
5
  SHA512:
6
- metadata.gz: 5602abb0df9c02912553d45b6afbef167b735e1a585e5f19484b2bc0a38f366b34d2081130cd0e6257b3228023798e4e36ea5bbea85e5e9a1beed60370f7f0e4
7
- data.tar.gz: d40ba9defa8b7eeb754a8aff10ad9dfccdef04911c867a89c8a7d236c183582e60100573a1305e76e52da4d871d7a59d3413f0c8e0cdfe50405bb8f43072fdac
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.1'
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
@@ -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
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.1
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-26 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