meilisearch-rails 0.11.1 → 0.13.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/Gemfile +1 -1
- data/README.md +55 -1
- 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 +8 -6
- 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: 6f0751c88921f9665ac4a8d2f74d401c99eff1e1a82e16831196044725e8b01a
|
4
|
+
data.tar.gz: 4566fa5403529656cb21262456472fc4ec4d4c103ae750d2b48fc9076ff9c03c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1302ec85a68c7774c2d31304738fbaec99845dd5993bfa2d414ac74e1647e833ffa624411670432cce4fb8335766bcfd684d04be4065397ef9d593692f0f080
|
7
|
+
data.tar.gz: 8b45f8cdd06fcf7b75f6d5d5dbffc1266650e69c8a30e49e018ca42f51bf7445b2ef8b357280691bea526628dfc7b0a40f0704f48c9545ba4e2933908e152d3f
|
data/Gemfile
CHANGED
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-)
|
@@ -206,6 +207,7 @@ class Book < ApplicationRecord
|
|
206
207
|
crop_length 10
|
207
208
|
faceting max_values_per_facet: 2000
|
208
209
|
pagination max_total_hits: 1000
|
210
|
+
proximity_precision 'byWord'
|
209
211
|
end
|
210
212
|
end
|
211
213
|
```
|
@@ -229,7 +231,7 @@ harry_book.formatted # => {"id"=>"1", "name"=>"<em>Harry</em> Potter", "descript
|
|
229
231
|
👉 Don't forget that `attributes_to_highlight`, `attributes_to_crop`, and
|
230
232
|
`crop_length` can be set up in the `meilisearch` block of your model.
|
231
233
|
|
232
|
-
|
234
|
+
### 🔍 Sorted search
|
233
235
|
|
234
236
|
As an example of how to use the sort option, here is how you could achieve
|
235
237
|
returning all books sorted by title in ascending order:
|
@@ -240,6 +242,58 @@ Book.search('*', sort: ['title:asc'])
|
|
240
242
|
|
241
243
|
👉 Don't forget to set up the `sortable_attributes` option in the `meilisearch` block of your model.
|
242
244
|
|
245
|
+
## 🔍🔍 Multi search
|
246
|
+
|
247
|
+
Meilisearch supports searching multiple models at the same time (see [🔍 Custom search](#-custom-search) for search options):
|
248
|
+
|
249
|
+
```ruby
|
250
|
+
multi_search_results = MeiliSearch::Rails.multi_search(
|
251
|
+
Book => { q: 'Harry' },
|
252
|
+
Manga => { q: 'Attack' }
|
253
|
+
)
|
254
|
+
```
|
255
|
+
|
256
|
+
You can iterate through the results with `.each` or `.each_result`:
|
257
|
+
|
258
|
+
```erb
|
259
|
+
<% multi_search_results.each do |record| %>
|
260
|
+
<p><%= record.title %></p>
|
261
|
+
<p><%= record.author %></p>
|
262
|
+
<% end %>
|
263
|
+
|
264
|
+
<p>Harry Potter and the Philosopher's Stone</p>
|
265
|
+
<p>J. K. Rowling</p>
|
266
|
+
<p>Harry Potter and the Chamber of Secrets</p>
|
267
|
+
<p>J. K. Rowling</p>
|
268
|
+
<p>Attack on Titan</p>
|
269
|
+
<p>Iseyama</p>
|
270
|
+
```
|
271
|
+
|
272
|
+
```erb
|
273
|
+
<% multi_search_results.each_result do |klass, results| %>
|
274
|
+
<p><%= klass.name.pluralize %></p>
|
275
|
+
|
276
|
+
<ul>
|
277
|
+
<% results.each do |record| %>
|
278
|
+
<li><%= record.title %></li>
|
279
|
+
<% end %>
|
280
|
+
</ul>
|
281
|
+
<% end %>
|
282
|
+
|
283
|
+
|
284
|
+
<p>Books</p>
|
285
|
+
<ul>
|
286
|
+
<li>Harry Potter and the Philosopher's Stone</li>
|
287
|
+
<li>Harry Potter and the Chamber of Secrets</li>
|
288
|
+
</ul>
|
289
|
+
<p>Mangas</p>
|
290
|
+
<ul>
|
291
|
+
<li>Attack on Titan</li>
|
292
|
+
</ul>
|
293
|
+
```
|
294
|
+
|
295
|
+
See the [official multi search documentation](https://www.meilisearch.com/docs/reference/api/multi_search).
|
296
|
+
|
243
297
|
## 🪛 Options
|
244
298
|
|
245
299
|
### 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
|
@@ -66,6 +67,7 @@ module MeiliSearch
|
|
66
67
|
pagination
|
67
68
|
faceting
|
68
69
|
typo_tolerance
|
70
|
+
proximity_precision
|
69
71
|
].freeze
|
70
72
|
|
71
73
|
CAMELIZE_OPTIONS = %i[pagination faceting typo_tolerance].freeze
|
@@ -575,7 +577,7 @@ module MeiliSearch
|
|
575
577
|
ms_configurations.filter_map do |options, settings|
|
576
578
|
{
|
577
579
|
synchronous: synchronous || options[:synchronous],
|
578
|
-
index_uid: options
|
580
|
+
index_uid: ms_index_uid(options),
|
579
581
|
primary_key: primary_key
|
580
582
|
}.with_indifferent_access unless ms_indexing_disabled?(options)
|
581
583
|
end
|
@@ -760,6 +762,11 @@ module MeiliSearch
|
|
760
762
|
false
|
761
763
|
end
|
762
764
|
|
765
|
+
def ms_primary_key_method(options = nil)
|
766
|
+
options ||= meilisearch_options
|
767
|
+
options[:primary_key] || options[:id] || :id
|
768
|
+
end
|
769
|
+
|
763
770
|
protected
|
764
771
|
|
765
772
|
def ms_ensure_init(options = meilisearch_options, settings = meilisearch_settings, user_configuration = settings.to_settings)
|
@@ -814,11 +821,6 @@ module MeiliSearch
|
|
814
821
|
@configurations
|
815
822
|
end
|
816
823
|
|
817
|
-
def ms_primary_key_method(options = nil)
|
818
|
-
options ||= meilisearch_options
|
819
|
-
options[:primary_key] || options[:id] || :id
|
820
|
-
end
|
821
|
-
|
822
824
|
def ms_primary_key_of(doc, options = nil)
|
823
825
|
doc.send(ms_primary_key_method(options)).to_s
|
824
826
|
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.13.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-
|
11
|
+
date: 2024-05-10 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
|