meilisearch-rails 0.6.0 → 0.7.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0d3aeaf9f6e2549c11cdcd7cf5920fecb819fb1b2f03a25af11c19a5dd09444
4
- data.tar.gz: 0af07156e3e3ea69d492745f806751e2213ad7148553f57396528ad54fa3f02a
3
+ metadata.gz: affe6d35bf6c1c626570b32ae605e3b1e826c16c86e87d9ea4cc2e67cb4c1512
4
+ data.tar.gz: b950799c5e8296d5fcbc2e194480cbbc4fa5a60b704708db55859f7d0a6d8e4c
5
5
  SHA512:
6
- metadata.gz: a49c6d3b48de31033515e61c9fd182842d5d7d7ba90e140b6447339eeb6473139f3de4f1c3428f48a9176f3c36c5080ebc198897f4b53900f74e416bb817eaf1
7
- data.tar.gz: 63805d38ba88e0b020a0a147cce244ec35a0fb2a93715ff5b62df77ca87021b2b11581647626b2c76eaddc26ad15ab0a8e9d4e82c7e1895095829b7cce74965c
6
+ metadata.gz: 7a84a8fbbb00122c28c90c5573f1e5a93a3012a89f516ea35df68eba294aea20b7e169906400ad27b17d281359a2d3fb5933eda1338aecb2941e206b21b00002
7
+ data.tar.gz: c735267b627ef2100fc0cdd52bffa8d323d634b865c5ef5ba870d3839f8e2a0d03244e5478a056a26295fbd827c6ecbbd40a2994df8805fa194925add4c8533a
data/README.md CHANGED
@@ -30,6 +30,7 @@
30
30
  - [📖 Documentation](#-documentation)
31
31
  - [🤖 Compatibility with Meilisearch](#-compatibility-with-meilisearch)
32
32
  - [🚀 Getting Started](#-getting-started)
33
+ - [Compatibility](#-compatibility)
33
34
  - [⚙️ Settings](#️-settings)
34
35
  - [🔍 Custom search](#-custom-search)
35
36
  - [🪛 Options](#-options)
@@ -43,6 +44,7 @@
43
44
  - [Relations](#relations)
44
45
  - [Sanitize attributes](#sanitize-attributes)
45
46
  - [UTF-8 encoding](#utf-8-encoding)
47
+ - [Eager loading](#eager-loading)
46
48
  - [Manual operations](#manual-operations)
47
49
  - [Indexing & deletion](#indexing--deletion)
48
50
  - [Access the underlying index object](#access-the-underlying-index-object)
@@ -58,7 +60,7 @@ To learn more about Meilisearch, check out our [Documentation](https://docs.meil
58
60
 
59
61
  ## 🤖 Compatibility with Meilisearch
60
62
 
61
- This package only guarantees the compatibility with the [version v0.27.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.27.0).
63
+ This package only guarantees the compatibility with the [version v0.28.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.28.0).
62
64
 
63
65
  ## 🔧 Installation <!-- omit in toc -->
64
66
 
@@ -190,6 +192,10 @@ MeiliSearch::Rails.configuration = {
190
192
  }
191
193
  ```
192
194
 
195
+ ## Compatibility
196
+
197
+ If your model already has methods that meilisearch-rails defines such as `search` and `index`, they will not be redefined. You can target the meilisearch-rails-defined methods by prefixing with `ms_`, e.g. `Book.ms_search('harry potter')`.
198
+
193
199
  ## ⚙️ Settings
194
200
 
195
201
  You can configure the index settings by adding them inside the `meilisearch` block as shown below:
@@ -262,19 +268,7 @@ end
262
268
 
263
269
  #### Index UID according to the environment <!-- omit in toc -->
264
270
 
265
- You can suffix the index UID with the current Rails environment using one of the following options:
266
-
267
- By defining directly in your model:
268
-
269
- ```ruby
270
- class Book < ActiveRecord::Base
271
- include MeiliSearch::Rails
272
-
273
- meilisearch per_environment: true
274
- end
275
- ```
276
-
277
- Or setting it globally:
271
+ You can suffix the index UID with the current Rails environment by setting it globally:
278
272
 
279
273
  ```ruby
280
274
  MeiliSearch::Rails.configuration = {
@@ -284,7 +278,7 @@ MeiliSearch::Rails.configuration = {
284
278
  }
285
279
  ```
286
280
 
287
- Both options will make your index name look like this `"Book_#{Rails.env}"`.
281
+ This way your index UID will look like this `"Book_#{Rails.env}"`.
288
282
 
289
283
  ### Index configuration
290
284
 
@@ -324,15 +318,33 @@ end
324
318
 
325
319
  By default, the primary key is based on your record's id. You can change this behavior by specifying the `primary_key:` option.
326
320
 
327
- Note that the primary key must have a **unique value**.
321
+ Note that the primary key must return a **unique value** otherwise your data could be overwritten.
328
322
 
329
323
  ```ruby
330
324
  class Book < ActiveRecord::Base
331
325
  include MeiliSearch::Rails
332
326
 
333
- meilisearch primary_key: 'ISBN'
327
+ meilisearch primary_key: :isbn # isbn is a column in your table definition.
328
+ end
329
+ ```
330
+
331
+ You can also set the `primary_key` as a method, this method will be evaluated in runtime, and its return
332
+ will be used as the reference to the document when Meilisearch needs it.
333
+
334
+ ```rb
335
+ class Book < ActiveRecord::Base
336
+ include MeiliSearch::Rails
337
+
338
+ meilisearch primary_key: :my_custom_ms_id
339
+
340
+ private
341
+
342
+ def my_custom_ms_id
343
+ "isbn_#{primary_key}" # ensure this return is unique, otherwise you'll lose data.
344
+ end
334
345
  end
335
346
  ```
347
+
336
348
  #### Conditional indexing
337
349
 
338
350
  You can control if a record must be indexed by using the `if:` or `unless:` options.<br>
@@ -612,6 +624,20 @@ class Book < ActiveRecord::Base
612
624
  end
613
625
  ```
614
626
 
627
+ #### Eager loading
628
+
629
+ You can eager load associations using `meilisearch_import` scope.
630
+
631
+ ```ruby
632
+ class Author < ActiveRecord::Base
633
+ include MeiliSearch::Rails
634
+
635
+ has_many :books
636
+
637
+ scope :meilisearch_import, -> { includes(:books) }
638
+ end
639
+ ```
640
+
615
641
  ### Manual operations
616
642
 
617
643
  #### Indexing & deletion
@@ -16,6 +16,7 @@ module MeiliSearch
16
16
  configuration[:meilisearch_host] || 'http://localhost:7700',
17
17
  configuration[:meilisearch_api_key],
18
18
  configuration.slice(:timeout, :max_retries)
19
+ .merge(client_agents: MeiliSearch::Rails.qualified_version)
19
20
  )
20
21
  end
21
22
  end
@@ -2,6 +2,10 @@
2
2
 
3
3
  module MeiliSearch
4
4
  module Rails
5
- VERSION = '0.6.0'
5
+ VERSION = '0.7.2'
6
+
7
+ def self.qualified_version
8
+ "Meilisearch Rails (v#{VERSION})"
9
+ end
6
10
  end
7
11
  end
@@ -233,9 +233,13 @@ module MeiliSearch
233
233
  def initialize(index_uid, raise_on_failure, options)
234
234
  client = MeiliSearch::Rails.client
235
235
  primary_key = options[:primary_key] || MeiliSearch::Rails::IndexSettings::DEFAULT_PRIMARY_KEY
236
- client.create_index(index_uid, { primaryKey: primary_key })
237
- @index = client.index(index_uid)
238
236
  @raise_on_failure = raise_on_failure.nil? || raise_on_failure
237
+
238
+ SafeIndex.log_or_throw(nil, @raise_on_failure) do
239
+ client.create_index(index_uid, { primary_key: primary_key })
240
+ end
241
+
242
+ @index = client.index(index_uid)
239
243
  end
240
244
 
241
245
  ::MeiliSearch::Index.instance_methods(false).each do |m|
@@ -273,7 +277,7 @@ module MeiliSearch
273
277
 
274
278
  def self.log_or_throw(method, raise_on_failure, &block)
275
279
  yield
276
- rescue ::MeiliSearch::ApiError => e
280
+ rescue ::MeiliSearch::TimeoutError, ::MeiliSearch::ApiError => e
277
281
  raise e if raise_on_failure
278
282
 
279
283
  # log the error
@@ -282,7 +286,7 @@ module MeiliSearch
282
286
  case method.to_s
283
287
  when 'search'
284
288
  # some attributes are required
285
- { 'hits' => [], 'hitsPerPage' => 0, 'page' => 0, 'facetsDistribution' => {}, 'error' => e }
289
+ { 'hits' => [], 'hitsPerPage' => 0, 'page' => 0, 'facetDistribution' => {}, 'error' => e }
286
290
  else
287
291
  # empty answer
288
292
  { 'error' => e }
@@ -460,7 +464,7 @@ module MeiliSearch
460
464
  end
461
465
  last_task = index.add_documents(documents)
462
466
  end
463
- index.wait_for_task(last_task['uid']) if last_task && (synchronous || options[:synchronous])
467
+ index.wait_for_task(last_task['taskUid']) if last_task && (synchronous || options[:synchronous])
464
468
  end
465
469
  nil
466
470
  end
@@ -476,7 +480,7 @@ module MeiliSearch
476
480
 
477
481
  index = SafeIndex.new(ms_index_uid(options), true, options)
478
482
  task = index.update_settings(final_settings)
479
- index.wait_for_task(task['uid']) if synchronous
483
+ index.wait_for_task(task['taskUid']) if synchronous
480
484
  end
481
485
  end
482
486
 
@@ -486,7 +490,7 @@ module MeiliSearch
486
490
 
487
491
  index = ms_ensure_init(options, settings)
488
492
  task = index.add_documents(documents.map { |d| settings.get_attributes(d).merge ms_pk(options) => ms_primary_key_of(d, options) })
489
- index.wait_for_task(task['uid']) if synchronous || options[:synchronous]
493
+ index.wait_for_task(task['taskUid']) if synchronous || options[:synchronous]
490
494
  end
491
495
  end
492
496
 
@@ -583,7 +587,7 @@ module MeiliSearch
583
587
  end
584
588
 
585
589
  def ms_facets_distribution
586
- @ms_json['facetsDistribution']
590
+ @ms_json['facetDistribution']
587
591
  end
588
592
 
589
593
  private
@@ -595,23 +599,20 @@ module MeiliSearch
595
599
 
596
600
  def ms_search(query, params = {})
597
601
  if MeiliSearch::Rails.configuration[:pagination_backend]
598
-
599
602
  page = params[:page].nil? ? params[:page] : params[:page].to_i
600
603
  hits_per_page = params[:hitsPerPage].nil? ? params[:hitsPerPage] : params[:hitsPerPage].to_i
604
+ hits_per_page ||= params[:hits_per_page].nil? ? params[:hits_per_page] : params[:hits_per_page].to_i
605
+
606
+ %i[page hitsPerPage hits_per_page].each { |param| params.delete(param) }
601
607
 
602
- params.delete(:page)
603
- params.delete(:hitsPerPage)
604
608
  params[:limit] = 200
605
609
  end
606
610
 
607
611
  # Returns raw json hits as follows:
608
- # {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "nbHits"=>1,
609
- # "exhaustiveNbHits"=>false, "processingTimeMs"=>0, "query"=>"iphone"}
612
+ # {"hits"=>[{"id"=>"13", "href"=>"apple", "name"=>"iphone"}], "offset"=>0, "limit"=>|| 20, "estimatedTotalHits"=>1,
613
+ # "processingTimeMs"=>0, "query"=>"iphone"}
610
614
  json = ms_raw_search(query, params)
611
615
 
612
- # Returns the ids of the hits: 13
613
- hit_ids = json['hits'].map { |hit| hit[ms_pk(meilisearch_options).to_s] }
614
-
615
616
  # condition_key gets the primary key of the document; looks for "id" on the options
616
617
  condition_key = if defined?(::Mongoid::Document) && include?(::Mongoid::Document)
617
618
  ms_primary_key_method.in
@@ -619,6 +620,23 @@ module MeiliSearch
619
620
  ms_primary_key_method
620
621
  end
621
622
 
623
+ # The condition_key must be a valid column otherwise, the `.where` below will not work
624
+ # Since we provide a way to customize the primary_key value, `ms_pk(meilisearch_options)` may not
625
+ # respond with a valid database column. The blocks below prevent that from happening.
626
+ has_virtual_column_as_pk = if defined?(::Sequel::Model) && self < Sequel::Model
627
+ meilisearch_options[:type].columns.map(&:to_s).exclude?(condition_key.to_s)
628
+ else
629
+ meilisearch_options[:type].columns.map(&:name).map(&:to_s).exclude?(condition_key.to_s)
630
+ end
631
+
632
+ condition_key = meilisearch_options[:type].primary_key if has_virtual_column_as_pk
633
+
634
+ hit_ids = if has_virtual_column_as_pk
635
+ json['hits'].map { |hit| hit[condition_key] }
636
+ else
637
+ json['hits'].map { |hit| hit[ms_pk(meilisearch_options).to_s] }
638
+ end
639
+
622
640
  # meilisearch_options[:type] refers to the Model name (e.g. Product)
623
641
  # results_by_id creates a hash with the primaryKey of the document (id) as the key and doc itself as the value
624
642
  # {"13"=>#<Product id: 13, name: "iphone", href: "apple", tags: nil, type: nil,
@@ -827,7 +845,8 @@ module MeiliSearch
827
845
 
828
846
  def ms_find_in_batches(batch_size, &block)
829
847
  if (defined?(::ActiveRecord) && ancestors.include?(::ActiveRecord::Base)) || respond_to?(:find_in_batches)
830
- find_in_batches(batch_size: batch_size, &block)
848
+ scope = respond_to?(:meilisearch_import) ? meilisearch_import : all
849
+ scope.find_in_batches(batch_size: batch_size, &block)
831
850
  elsif defined?(::Sequel::Model) && self < Sequel::Model
832
851
  dataset.extension(:pagination).each_page(batch_size, &block)
833
852
  else
@@ -34,5 +34,5 @@ Gem::Specification.new do |s|
34
34
 
35
35
  s.required_ruby_version = '>= 2.6.0'
36
36
 
37
- s.add_dependency 'meilisearch', '~> 0.18'
37
+ s.add_dependency 'meilisearch', '~> 0.19.2'
38
38
  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.6.0
4
+ version: 0.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Meili
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-29 00:00:00.000000000 Z
11
+ date: 2022-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: meilisearch
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.18'
19
+ version: 0.19.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.18'
26
+ version: 0.19.2
27
27
  description: Meilisearch integration for Ruby on Rails. See https://github.com/meilisearch/meilisearch
28
28
  email: bonjour@meilisearch.com
29
29
  executables: []