meilisearch-rails 0.11.1 → 0.12.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.
- checksums.yaml +4 -4
- data/README.md +53 -0
- data/lib/meilisearch/rails/multi_search/result.rb +84 -0
- data/lib/meilisearch/rails/multi_search.rb +49 -0
- data/lib/meilisearch/rails/utilities.rb +8 -0
- data/lib/meilisearch/rails/version.rb +1 -1
- data/lib/meilisearch-rails.rb +6 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3aebe8eb25a9272e97c71563db1dae9758c50f5423adc3909228964097116047
|
4
|
+
data.tar.gz: 18e9133418b2c512d8645ce4d1ee9a06113076c9c2af4e5b53e4e295c5d47fe7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
data/lib/meilisearch-rails.rb
CHANGED
@@ -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.
|
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-
|
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
|