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 +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
|