pg_search 2.3.0 → 2.3.6

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -0
  3. data/.github/dependabot.yml +11 -0
  4. data/.github/workflows/ci.yml +75 -0
  5. data/.jrubyrc +1 -0
  6. data/.rubocop.yml +88 -7
  7. data/.travis.yml +20 -33
  8. data/CHANGELOG.md +50 -16
  9. data/CODE_OF_CONDUCT.md +76 -0
  10. data/Gemfile +1 -1
  11. data/LICENSE +1 -1
  12. data/README.md +73 -26
  13. data/Rakefile +7 -1
  14. data/lib/pg_search/configuration.rb +12 -2
  15. data/lib/pg_search/document.rb +1 -1
  16. data/lib/pg_search/features/dmetaphone.rb +4 -6
  17. data/lib/pg_search/features/feature.rb +1 -1
  18. data/lib/pg_search/features/tsearch.rb +14 -13
  19. data/lib/pg_search/migration/templates/add_pg_search_dmetaphone_support_functions.rb.erb +6 -6
  20. data/lib/pg_search/migration/templates/create_pg_search_documents.rb.erb +2 -2
  21. data/lib/pg_search/multisearch/rebuilder.rb +7 -3
  22. data/lib/pg_search/multisearch.rb +21 -4
  23. data/lib/pg_search/scope_options.rb +5 -8
  24. data/lib/pg_search/tasks.rb +2 -1
  25. data/lib/pg_search/version.rb +1 -1
  26. data/lib/pg_search.rb +6 -8
  27. data/pg_search.gemspec +14 -7
  28. data/spec/.rubocop.yml +2 -2
  29. data/spec/integration/.rubocop.yml +11 -0
  30. data/spec/integration/associations_spec.rb +17 -56
  31. data/spec/integration/deprecation_spec.rb +1 -1
  32. data/spec/integration/pg_search_spec.rb +94 -52
  33. data/spec/lib/pg_search/configuration/association_spec.rb +8 -6
  34. data/spec/lib/pg_search/features/dmetaphone_spec.rb +2 -2
  35. data/spec/lib/pg_search/features/trigram_spec.rb +16 -12
  36. data/spec/lib/pg_search/features/tsearch_spec.rb +16 -10
  37. data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +116 -71
  38. data/spec/lib/pg_search/multisearch_spec.rb +57 -29
  39. data/spec/lib/pg_search/multisearchable_spec.rb +150 -97
  40. data/spec/lib/pg_search/normalizer_spec.rb +12 -10
  41. data/spec/lib/pg_search_spec.rb +66 -55
  42. data/spec/spec_helper.rb +22 -5
  43. data/spec/support/database.rb +7 -5
  44. metadata +109 -19
  45. data/.autotest +0 -5
data/README.md CHANGED
@@ -1,10 +1,7 @@
1
1
  # [pg_search](http://github.com/Casecommons/pg_search/)
2
2
 
3
3
  [![Gem Version](https://img.shields.io/gem/v/pg_search.svg?style=flat)](https://rubygems.org/gems/pg_search)
4
- [![Build Status](https://secure.travis-ci.org/Casecommons/pg_search.svg?branch=master)](https://travis-ci.org/Casecommons/pg_search)
5
- [![Maintainability](https://api.codeclimate.com/v1/badges/ae1a7c021e473e9b2486/maintainability)](https://codeclimate.com/github/Casecommons/pg_search/maintainability)
6
- [![Test Coverage](https://codeclimate.com/github/Casecommons/pg_search/badges/coverage.svg)](https://codeclimate.com/github/Casecommons/pg_search/coverage)
7
- [![Inline docs](http://inch-ci.org/github/Casecommons/pg_search.svg?branch=master&style=flat)](http://inch-ci.org/github/Casecommons/pg_search)
4
+ [![Build Status](https://github.com/Casecommons/pg_search/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/Casecommons/pg_search/actions/workflows/ci.yml)
8
5
  [![Join the chat at https://gitter.im/Casecommons/pg_search](https://img.shields.io/badge/gitter-join%20chat-blue.svg)](https://gitter.im/Casecommons/pg_search?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
9
6
 
10
7
  ## DESCRIPTION
@@ -12,12 +9,12 @@
12
9
  PgSearch builds named scopes that take advantage of PostgreSQL's full text
13
10
  search.
14
11
 
15
- Read the blog post introducing PgSearch at https://content.pivotal.io/blog/pg-search-how-i-learned-to-stop-worrying-and-love-postgresql-full-text-search
12
+ Read the blog post introducing PgSearch at https://tanzu.vmware.com/content/blog/pg-search-how-i-learned-to-stop-worrying-and-love-postgresql-full-text-search
16
13
 
17
14
  ## REQUIREMENTS
18
15
 
19
- * Ruby 2.4+
20
- * ActiveRecord 4.2+
16
+ * Ruby 2.6+
17
+ * ActiveRecord 5.2+
21
18
  * PostgreSQL 9.2+
22
19
  * [PostgreSQL extensions](https://github.com/Casecommons/pg_search/wiki/Installing-PostgreSQL-Extensions) for certain features
23
20
 
@@ -53,6 +50,47 @@ class Shape < ActiveRecord::Base
53
50
  end
54
51
  ```
55
52
 
53
+ ### Contents
54
+ * [Multi-search vs. search scopes](#multi-search-vs-search-scopes)
55
+ * [Multi-search](#multi-search)
56
+ * [Setup](#setup)
57
+ * [`multisearchable`](#multisearchable)
58
+ * [More Options ](#more-options)
59
+ * [Multi-search associations](#multi-search-associations)
60
+ * [Searching in the global search index](#searching-in-the-global-search-index)
61
+ * [Chaining method calls onto the results](#chaining-method-calls-onto-the-results)
62
+ * [Configuring multi-search](#configuring-multi-search)
63
+ * [Rebuilding search documents for a given class](#rebuilding-search-documents-for-a-given-class)
64
+ * [Disabling multi-search indexing temporarily](#disabling-multi-search-indexing-temporarily)
65
+ * [`pg_search_scope`](#pg_search_scope)
66
+ * [Searching against one column](#searching-against-one-column)
67
+ * [Searching against multiple columns](#searching-against-multiple-columns)
68
+ * [Dynamic search scopes](#dynamic-search-scopes)
69
+ * [Searching through associations](#searching-through-associations)
70
+ * [Searching using different search features](#searching-using-different-search-features)
71
+ * [`:tsearch` (Full Text Search)](#tsearch-full-text-search)
72
+ * [Weighting](#weighting)
73
+ * [`:prefix` (PostgreSQL 8.4 and newer only)](#prefix-postgresql-84-and-newer-only)
74
+ * [`:negation`](#negation)
75
+ * [`:dictionary`](#dictionary)
76
+ * [`:normalization`](#normalization)
77
+ * [`:any_word`](#any_word)
78
+ * [`:sort_only`](#sort_only)
79
+ * [`:highlight`](#highlight)
80
+ * [`:dmetaphone` (Double Metaphone soundalike search)](#dmetaphone-double-metaphone-soundalike-search)
81
+ * [`:trigram` (Trigram search)](#trigram-trigram-search)
82
+ * [`:threshold`](#threshold)
83
+ * [`:word_similarity`](#word_similarity)
84
+ * [Limiting Fields When Combining Features](#limiting-fields-when-combining-features)
85
+ * [Ignoring accent marks](#ignoring-accent-marks)
86
+ * [Using tsvector columns](#using-tsvector-columns)
87
+ * [Combining multiple tsvectors](#combining-multiple-tsvectors)
88
+ * [Configuring ranking and ordering](#configuring-ranking-and-ordering)
89
+ * [`:ranked_by` (Choosing a ranking algorithm)](#ranked_by-choosing-a-ranking-algorithm)
90
+ * [`:order_within_rank` (Breaking ties)](#order_within_rank-breaking-ties)
91
+ * [`PgSearch#pg_search_rank` (Reading a record's rank as a Float)](#pgsearchpg_search_rank-reading-a-records-rank-as-a-float)
92
+ * [Search rank and chained scopes](#search-rank-and-chained-scopes)
93
+
56
94
  ### Multi-search vs. search scopes
57
95
 
58
96
  pg_search supports two different techniques for searching, multi-search and
@@ -175,15 +213,17 @@ multisearchable(
175
213
 
176
214
  **Specify additional attributes to be saved on the pg_search_documents table**
177
215
 
178
- You can specify `:additional_attributes` to be saved within the pg_search_documents table. For example, perhaps you are indexing a book model and an article model and wanted to include the author_id.
216
+ You can specify `:additional_attributes` to be saved within the `pg_search_documents` table. For example, perhaps you are indexing a book model and an article model and wanted to include the author_id.
179
217
 
180
- First, we need to add `author_id` to the migration creating our pg_search_documents table.
218
+ First, we need to add a reference to author to the migration creating our `pg_search_documents` table.
181
219
 
182
220
  ```ruby
183
221
  create_table :pg_search_documents do |t|
184
- t.text :content
185
- t.integer :author_id
186
- t.belongs_to :searchable, polymorphic: true, index: true
222
+ t.text :content
223
+ t.references :author, index: true
224
+ t.belongs_to :searchable, polymorphic: true, index: true
225
+ t.timestamps null: false
226
+ end
187
227
  ```
188
228
 
189
229
  Then, we can send in this additional attribute in a lambda
@@ -196,7 +236,10 @@ Then, we can send in this additional attribute in a lambda
196
236
  ```
197
237
 
198
238
  This allows much faster searches without joins later on by doing something like:
199
- `PgSearch.multisearch(params['search']).where(author_id: 2)`
239
+
240
+ ```ruby
241
+ PgSearch.multisearch(params['search']).where(author_id: 2)
242
+ ```
200
243
 
201
244
  *NOTE: You must currently manually call `record.update_pg_search_document` for the additional attribute to be included in the pg_search_documents table*
202
245
 
@@ -273,7 +316,7 @@ To remove all of the documents for a given class, you can simply delete all of
273
316
  the PgSearch::Document records.
274
317
 
275
318
  ```ruby
276
- PgSearch::Document.delete_all(searchable_type: "Animal")
319
+ PgSearch::Document.delete_by(searchable_type: "Animal")
277
320
  ```
278
321
 
279
322
  To regenerate the documents for a given class, run:
@@ -289,7 +332,14 @@ is your base class. You can prevent ```rebuild``` from deleting your records
289
332
  like so:
290
333
 
291
334
  ```ruby
292
- PgSearch::Multisearch.rebuild(Product, false)
335
+ PgSearch::Multisearch.rebuild(Product, clean_up: false)
336
+ ```
337
+
338
+ ```rebuild``` runs inside a single transaction. To run outside of a transaction,
339
+ you can pass ```transactional: false``` like so:
340
+
341
+ ```ruby
342
+ PgSearch::Multisearch.rebuild(Product, transactional: false)
293
343
  ```
294
344
 
295
345
  Rebuild is also available as a Rake task, for convenience.
@@ -333,11 +383,11 @@ class Movie < ActiveRecord::Base
333
383
 
334
384
  # More sophisticated approach
335
385
  def self.rebuild_pg_search_documents
336
- connection.execute <<-SQL
386
+ connection.execute <<~SQL.squish
337
387
  INSERT INTO pg_search_documents (searchable_type, searchable_id, content, created_at, updated_at)
338
388
  SELECT 'Movie' AS searchable_type,
339
389
  movies.id AS searchable_id,
340
- (movies.name || ' ' || directors.name) AS content,
390
+ CONCAT_WS(' ', movies.name, directors.name) AS content,
341
391
  now() AS created_at,
342
392
  now() AS updated_at
343
393
  FROM movies
@@ -347,6 +397,7 @@ class Movie < ActiveRecord::Base
347
397
  end
348
398
  end
349
399
  ```
400
+ **Note:** If using PostgreSQL before 9.1, replace the `CONCAT_WS()` function call with double-pipe concatenation, eg. `(movies.name || ' ' || directors.name)`. However, now be aware that if *any* of the joined values is NULL then the final `content` value will also be NULL, whereas `CONCAT_WS()` will selectively ignore NULL values.
350
401
 
351
402
  #### Disabling multi-search indexing temporarily
352
403
 
@@ -718,7 +769,7 @@ class Person < ActiveRecord::Base
718
769
  pg_search_scope :search,
719
770
  against: :name,
720
771
  using: {
721
- tsearch: {any_word: true}
772
+ tsearch: {any_word: true},
722
773
  dmetaphone: {any_word: true, sort_only: true}
723
774
  }
724
775
  end
@@ -890,7 +941,7 @@ class Sentence < ActiveRecord::Base
890
941
  include PgSearch::Model
891
942
 
892
943
  pg_search_scope :similarity_like,
893
- against: :words,
944
+ against: :name,
894
945
  using: {
895
946
  trigram: {
896
947
  word_similarity: true
@@ -898,7 +949,7 @@ class Sentence < ActiveRecord::Base
898
949
  }
899
950
 
900
951
  pg_search_scope :word_similarity_like,
901
- against: :words,
952
+ against: :name,
902
953
  using: [:trigram]
903
954
  end
904
955
 
@@ -1143,16 +1194,12 @@ Patterson](http://tenderlovemaking.com/) for the original version and to Caseboo
1143
1194
 
1144
1195
  ## CONTRIBUTIONS AND FEEDBACK
1145
1196
 
1146
- Welcomed! Feel free to join and contribute to our [public Pivotal Tracker
1147
- project](https://www.pivotaltracker.com/projects/228645) where we manage new
1148
- feature ideas and bugs.
1197
+ Please read our [CONTRIBUTING guide](https://github.com/Casecommons/pg_search/blob/master/CONTRIBUTING.md).
1149
1198
 
1150
1199
  We also have a [Google Group](http://groups.google.com/group/casecommons-dev)
1151
1200
  for discussing pg_search and other Casebook PBC open source projects.
1152
1201
 
1153
- Please read our [CONTRIBUTING guide](https://github.com/Casecommons/pg_search/blob/master/CONTRIBUTING.md).
1154
-
1155
1202
  ## LICENSE
1156
1203
 
1157
- Copyright © 2010–2019 [Casebook PBC](http://www.casebook.net).
1204
+ Copyright © 2010–2021 [Casebook PBC](http://www.casebook.net).
1158
1205
  Licensed under the MIT license, see [LICENSE](/LICENSE) file.
data/Rakefile CHANGED
@@ -11,4 +11,10 @@ RuboCop::RakeTask.new do |t|
11
11
  t.options = %w[--display-cop-names]
12
12
  end
13
13
 
14
- task default: %w[spec rubocop]
14
+ desc "Check test coverage"
15
+ task :undercover do
16
+ system("git fetch --unshallow") if ENV["CI"]
17
+ exit(1) unless system("bin/undercover --compare origin/master")
18
+ end
19
+
20
+ task default: %w[spec rubocop undercover]
@@ -92,8 +92,11 @@ module PgSearch
92
92
  }.freeze
93
93
 
94
94
  def assert_valid_options(options)
95
- unless options[:against] || options[:associated_against]
96
- raise ArgumentError, "the search scope #{@name} must have :against or :associated_against in its options"
95
+ unless options[:against] || options[:associated_against] || using_tsvector_column?(options[:using])
96
+ raise(
97
+ ArgumentError,
98
+ "the search scope #{@name} must have :against, :associated_against, or :tsvector_column in its options"
99
+ )
97
100
  end
98
101
 
99
102
  options.assert_valid_keys(VALID_KEYS)
@@ -104,5 +107,12 @@ module PgSearch
104
107
  end
105
108
  end
106
109
  end
110
+
111
+ def using_tsvector_column?(options)
112
+ return unless options.is_a?(Hash)
113
+
114
+ options.dig(:dmetaphone, :tsvector_column).present? ||
115
+ options.dig(:tsearch, :tsvector_column).present?
116
+ end
107
117
  end
108
118
  end
@@ -12,7 +12,7 @@ module PgSearch
12
12
  # The logger might not have loaded yet.
13
13
  # https://github.com/Casecommons/pg_search/issues/26
14
14
  def self.logger
15
- super || Logger.new(STDERR)
15
+ super || Logger.new($stderr)
16
16
  end
17
17
 
18
18
  pg_search_scope :search, lambda { |*args|
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/module/delegation"
4
+
3
5
  module PgSearch
4
6
  module Features
5
7
  class DMetaphone
@@ -9,13 +11,9 @@ module PgSearch
9
11
  @tsearch = TSearch.new(query, options, columns, model, dmetaphone_normalizer)
10
12
  end
11
13
 
12
- def conditions
13
- tsearch.conditions
14
- end
14
+ delegate :conditions, to: :tsearch
15
15
 
16
- def rank
17
- tsearch.rank
18
- end
16
+ delegate :rank, to: :tsearch
19
17
 
20
18
  private
21
19
 
@@ -10,7 +10,7 @@ module PgSearch
10
10
  %i[only sort_only]
11
11
  end
12
12
 
13
- delegate :connection, :quoted_table_name, to: :'@model'
13
+ delegate :connection, :quoted_table_name, to: :@model
14
14
 
15
15
  def initialize(query, options, all_columns, model, normalizer)
16
16
  @query = query
@@ -59,7 +59,7 @@ module PgSearch
59
59
  end
60
60
  end
61
61
 
62
- def deprecated_headline_options
62
+ def deprecated_headline_options # rubocop:disable Metrics/MethodLength
63
63
  indifferent_options = options.with_indifferent_access
64
64
 
65
65
  %w[
@@ -97,7 +97,7 @@ module PgSearch
97
97
 
98
98
  DISALLOWED_TSQUERY_CHARACTERS = /['?\\:‘’]/.freeze
99
99
 
100
- def tsquery_for_term(unsanitized_term) # rubocop:disable Metrics/AbcSize
100
+ def tsquery_for_term(unsanitized_term)
101
101
  if options[:negation] && unsanitized_term.start_with?("!")
102
102
  unsanitized_term[0] = ''
103
103
  negated = true
@@ -107,31 +107,32 @@ module PgSearch
107
107
 
108
108
  term_sql = Arel.sql(normalize(connection.quote(sanitized_term)))
109
109
 
110
- # After this, the SQL expression evaluates to a string containing the term surrounded by single-quotes.
111
- # If :prefix is true, then the term will have :* appended to the end.
112
- # If :negated is true, then the term will have ! prepended to the front.
110
+ tsquery = tsquery_expression(term_sql, negated: negated, prefix: options[:prefix])
111
+
112
+ Arel::Nodes::NamedFunction.new("to_tsquery", [dictionary, tsquery]).to_sql
113
+ end
114
+
115
+ # After this, the SQL expression evaluates to a string containing the term surrounded by single-quotes.
116
+ # If :prefix is true, then the term will have :* appended to the end.
117
+ # If :negated is true, then the term will have ! prepended to the front.
118
+ def tsquery_expression(term_sql, negated:, prefix:)
113
119
  terms = [
114
120
  (Arel::Nodes.build_quoted('!') if negated),
115
121
  Arel::Nodes.build_quoted("' "),
116
122
  term_sql,
117
123
  Arel::Nodes.build_quoted(" '"),
118
- (Arel::Nodes.build_quoted(":*") if options[:prefix])
124
+ (Arel::Nodes.build_quoted(":*") if prefix)
119
125
  ].compact
120
126
 
121
- tsquery_sql = terms.inject do |memo, term|
127
+ terms.inject do |memo, term|
122
128
  Arel::Nodes::InfixOperation.new("||", memo, Arel::Nodes.build_quoted(term))
123
129
  end
124
-
125
- Arel::Nodes::NamedFunction.new(
126
- "to_tsquery",
127
- [dictionary, tsquery_sql]
128
- ).to_sql
129
130
  end
130
131
 
131
132
  def tsquery
132
133
  return "''" if query.blank?
133
134
 
134
- query_terms = query.split(" ").compact
135
+ query_terms = query.split.compact
135
136
  tsquery_terms = query_terms.map { |term| tsquery_for_term(term) }
136
137
  tsquery_terms.join(options[:any_word] ? ' || ' : ' && ')
137
138
  end
@@ -1,16 +1,16 @@
1
1
  class AddPgSearchDmetaphoneSupportFunctions < ActiveRecord::Migration<%= migration_version %>
2
- def self.up
2
+ def up
3
3
  say_with_time("Adding support functions for pg_search :dmetaphone") do
4
- execute <<-'SQL'
5
- <%= read_sql_file "dmetaphone" %>
4
+ execute <<~'SQL'.squish
5
+ <%= indent(read_sql_file("dmetaphone"), 8) %>
6
6
  SQL
7
7
  end
8
8
  end
9
9
 
10
- def self.down
10
+ def down
11
11
  say_with_time("Dropping support functions for pg_search :dmetaphone") do
12
- execute <<-'SQL'
13
- <%= read_sql_file "uninstall_dmetaphone" %>
12
+ execute <<~'SQL'.squish
13
+ <%= indent(read_sql_file("uninstall_dmetaphone"), 8) %>
14
14
  SQL
15
15
  end
16
16
  end
@@ -1,5 +1,5 @@
1
1
  class CreatePgSearchDocuments < ActiveRecord::Migration<%= migration_version %>
2
- def self.up
2
+ def up
3
3
  say_with_time("Creating table for pg_search multisearch") do
4
4
  create_table :pg_search_documents do |t|
5
5
  t.text :content
@@ -9,7 +9,7 @@ class CreatePgSearchDocuments < ActiveRecord::Migration<%= migration_version %>
9
9
  end
10
10
  end
11
11
 
12
- def self.down
12
+ def down
13
13
  say_with_time("Dropping table for pg_search multisearch") do
14
14
  drop_table :pg_search_documents
15
15
  end
@@ -13,7 +13,7 @@ module PgSearch
13
13
  def rebuild
14
14
  if model.respond_to?(:rebuild_pg_search_documents)
15
15
  model.rebuild_pg_search_documents
16
- elsif conditional? || dynamic?
16
+ elsif conditional? || dynamic? || additional_attributes?
17
17
  model.find_each(&:update_pg_search_document)
18
18
  else
19
19
  model.connection.execute(rebuild_sql)
@@ -30,7 +30,11 @@ module PgSearch
30
30
 
31
31
  def dynamic?
32
32
  column_names = model.columns.map(&:name)
33
- columns.any? { |column| !column_names.include?(column.to_s) }
33
+ columns.any? { |column| column_names.exclude?(column.to_s) }
34
+ end
35
+
36
+ def additional_attributes?
37
+ model.pg_search_multisearchable_options.key?(:additional_attributes)
34
38
  end
35
39
 
36
40
  def connection
@@ -42,7 +46,7 @@ module PgSearch
42
46
  end
43
47
 
44
48
  def rebuild_sql_template
45
- <<-SQL.strip_heredoc
49
+ <<~SQL.squish
46
50
  INSERT INTO :documents_table (searchable_type, searchable_id, content, created_at, updated_at)
47
51
  SELECT :base_model_name AS searchable_type,
48
52
  :model_table.#{primary_key} AS searchable_id,
@@ -5,16 +5,33 @@ require "pg_search/multisearch/rebuilder"
5
5
  module PgSearch
6
6
  module Multisearch
7
7
  class << self
8
- def rebuild(model, clean_up = true)
9
- model.transaction do
10
- PgSearch::Document.where(searchable_type: model.base_class.name).delete_all if clean_up
11
- Rebuilder.new(model).rebuild
8
+ def rebuild(model, deprecated_clean_up = nil, clean_up: true, transactional: true)
9
+ unless deprecated_clean_up.nil?
10
+ ActiveSupport::Deprecation.warn(
11
+ "pg_search 3.0 will no longer accept a boolean second argument to PgSearchMultisearch.rebuild, " \
12
+ "use keyword argument `clean_up:` instead."
13
+ )
14
+ clean_up = deprecated_clean_up
12
15
  end
16
+
17
+ if transactional
18
+ model.transaction { execute(model, clean_up) }
19
+ else
20
+ execute(model, clean_up)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def execute(model, clean_up)
27
+ PgSearch::Document.where(searchable_type: model.base_class.name).delete_all if clean_up
28
+ Rebuilder.new(model).rebuild
13
29
  end
14
30
  end
15
31
 
16
32
  class ModelNotMultisearchable < StandardError
17
33
  def initialize(model_class)
34
+ super
18
35
  @model_class = model_class
19
36
  end
20
37
 
@@ -14,7 +14,7 @@ module PgSearch
14
14
 
15
15
  def apply(scope)
16
16
  scope = include_table_aliasing_for_rank(scope)
17
- rank_table_alias = scope.pg_search_rank_table_alias(:include_counter)
17
+ rank_table_alias = scope.pg_search_rank_table_alias(include_counter: true)
18
18
 
19
19
  scope
20
20
  .joins(rank_join(rank_table_alias))
@@ -37,11 +37,8 @@ module PgSearch
37
37
 
38
38
  def with_pg_search_highlight
39
39
  scope = self
40
- scope.select(pg_search_highlight_field)
41
- end
42
-
43
- def pg_search_highlight_field
44
- "(#{highlight}) AS pg_search_highlight, #{table_name}.*"
40
+ scope = scope.select("#{table_name}.*") unless scope.select_values.any?
41
+ scope.select("(#{highlight}) AS pg_search_highlight")
45
42
  end
46
43
 
47
44
  def highlight
@@ -58,7 +55,7 @@ module PgSearch
58
55
  end
59
56
 
60
57
  module PgSearchRankTableAliasing
61
- def pg_search_rank_table_alias(include_counter = false)
58
+ def pg_search_rank_table_alias(include_counter: false)
62
59
  components = [arel_table.name]
63
60
  if include_counter
64
61
  count = increment_counter
@@ -152,7 +149,7 @@ module PgSearch
152
149
  return scope if scope.included_modules.include?(PgSearchRankTableAliasing)
153
150
 
154
151
  scope.all.spawn.tap do |new_scope|
155
- new_scope.class_eval { include PgSearchRankTableAliasing }
152
+ new_scope.instance_eval { extend PgSearchRankTableAliasing }
156
153
  end
157
154
  end
158
155
  end
@@ -7,11 +7,12 @@ namespace :pg_search do
7
7
  namespace :multisearch do
8
8
  desc "Rebuild PgSearch multisearch records for a given model"
9
9
  task :rebuild, %i[model schema] => :environment do |_task, args|
10
- raise ArgumentError, <<-MESSAGE.strip_heredoc unless args.model
10
+ raise ArgumentError, <<~MESSAGE unless args.model
11
11
 
12
12
  You must pass a model as an argument.
13
13
  Example: rake pg_search:multisearch:rebuild[BlogPost]
14
14
  MESSAGE
15
+
15
16
  model_class = args.model.classify.constantize
16
17
  connection = PgSearch::Document.connection
17
18
  original_schema_search_path = connection.schema_search_path
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgSearch
4
- VERSION = '2.3.0'
4
+ VERSION = '2.3.6'
5
5
  end
data/lib/pg_search.rb CHANGED
@@ -15,8 +15,10 @@ require "pg_search/scope_options"
15
15
  require "pg_search/version"
16
16
 
17
17
  module PgSearch
18
+ autoload :Document, "pg_search/document"
19
+
18
20
  def self.included(base)
19
- ActiveSupport::Deprecation.warn <<-MESSAGE.strip_heredoc
21
+ ActiveSupport::Deprecation.warn <<~MESSAGE
20
22
  Directly including `PgSearch` into an Active Record model is deprecated and will be removed in pg_search 3.0.
21
23
 
22
24
  Please replace `include PgSearch` with `include PgSearch::Model`.
@@ -55,20 +57,16 @@ module PgSearch
55
57
  class PgSearchRankNotSelected < StandardError
56
58
  def message
57
59
  "You must chain .with_pg_search_rank after the pg_search_scope " \
58
- "to access the pg_search_rank attribute on returned records"
60
+ "to access the pg_search_rank attribute on returned records"
59
61
  end
60
62
  end
61
63
 
62
64
  class PgSearchHighlightNotSelected < StandardError
63
65
  def message
64
66
  "You must chain .with_pg_search_highlight after the pg_search_scope " \
65
- "to access the pg_search_highlight attribute on returned records"
67
+ "to access the pg_search_highlight attribute on returned records"
66
68
  end
67
69
  end
68
70
  end
69
71
 
70
- ActiveSupport.on_load(:active_record) do
71
- require "pg_search/document"
72
- end
73
-
74
- require "pg_search/railtie" if defined?(Rails)
72
+ require "pg_search/railtie" if defined?(Rails::Railtie)
data/pg_search.gemspec CHANGED
@@ -3,7 +3,7 @@
3
3
  $LOAD_PATH.push File.expand_path('lib', __dir__)
4
4
  require 'pg_search/version'
5
5
 
6
- Gem::Specification.new do |s|
6
+ Gem::Specification.new do |s| # rubocop:disable Metrics/BlockLength
7
7
  s.name = 'pg_search'
8
8
  s.version = PgSearch::VERSION
9
9
  s.platform = Gem::Platform::RUBY
@@ -13,21 +13,28 @@ Gem::Specification.new do |s|
13
13
  s.summary = "PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search"
14
14
  s.description = "PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search"
15
15
  s.licenses = ['MIT']
16
+ s.metadata["rubygems_mfa_required"] = "true"
16
17
 
17
18
  s.files = `git ls-files`.split("\n")
18
19
  s.test_files = `git ls-files -- spec/*`.split("\n")
19
20
  s.require_paths = ['lib']
20
21
 
21
- s.add_dependency 'activerecord', '>= 4.2'
22
- s.add_dependency 'activesupport', '>= 4.2'
22
+ s.add_dependency 'activerecord', '>= 5.2'
23
+ s.add_dependency 'activesupport', '>= 5.2'
23
24
 
24
25
  s.add_development_dependency 'pry'
25
26
  s.add_development_dependency 'rake'
26
- s.add_development_dependency 'rspec', '>= 3.3'
27
- s.add_development_dependency 'rubocop', '>= 0.68.1'
27
+ s.add_development_dependency 'rspec'
28
+ s.add_development_dependency 'rubocop'
28
29
  s.add_development_dependency 'rubocop-performance'
30
+ s.add_development_dependency 'rubocop-rails'
31
+ s.add_development_dependency 'rubocop-rake'
32
+ s.add_development_dependency 'rubocop-rspec'
29
33
  s.add_development_dependency 'simplecov'
30
- s.add_development_dependency 'with_model', '>= 1.2'
34
+ s.add_development_dependency 'simplecov-lcov'
35
+ s.add_development_dependency 'undercover'
36
+ s.add_development_dependency 'warning'
37
+ s.add_development_dependency 'with_model'
31
38
 
32
- s.required_ruby_version = '>= 2.4'
39
+ s.required_ruby_version = '>= 2.6'
33
40
  end
data/spec/.rubocop.yml CHANGED
@@ -1,10 +1,10 @@
1
1
  inherit_from:
2
2
  - ../.rubocop.yml
3
3
 
4
- Metrics/LineLength:
4
+ Layout/LineLength:
5
5
  Enabled: false
6
6
 
7
- Lint/HandleExceptions:
7
+ Lint/SuppressedException:
8
8
  Enabled: false
9
9
 
10
10
  Lint/UselessAssignment:
@@ -0,0 +1,11 @@
1
+ inherit_from:
2
+ - ../.rubocop.yml
3
+
4
+ RSpec/DescribeClass:
5
+ Enabled: false
6
+
7
+ RSpec/MultipleExpectations:
8
+ Enabled: false
9
+
10
+ RSpec/ExampleLength:
11
+ Enabled: false