pg_search 2.1.2 → 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 (66) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +1 -0
  3. data/.editorconfig +10 -0
  4. data/.github/dependabot.yml +11 -0
  5. data/.github/workflows/ci.yml +75 -0
  6. data/.jrubyrc +1 -0
  7. data/.rubocop.yml +95 -10
  8. data/.travis.yml +26 -48
  9. data/CHANGELOG.md +179 -112
  10. data/CODE_OF_CONDUCT.md +76 -0
  11. data/CONTRIBUTING.md +5 -3
  12. data/Gemfile +6 -4
  13. data/LICENSE +1 -1
  14. data/README.md +307 -198
  15. data/Rakefile +7 -3
  16. data/lib/pg_search/configuration/association.rb +2 -0
  17. data/lib/pg_search/configuration/column.rb +2 -0
  18. data/lib/pg_search/configuration/foreign_column.rb +2 -0
  19. data/lib/pg_search/configuration.rb +20 -6
  20. data/lib/pg_search/document.rb +7 -5
  21. data/lib/pg_search/features/dmetaphone.rb +7 -7
  22. data/lib/pg_search/features/feature.rb +4 -2
  23. data/lib/pg_search/features/trigram.rb +31 -5
  24. data/lib/pg_search/features/tsearch.rb +18 -14
  25. data/lib/pg_search/features.rb +2 -0
  26. data/lib/pg_search/migration/dmetaphone_generator.rb +3 -1
  27. data/lib/pg_search/migration/generator.rb +4 -2
  28. data/lib/pg_search/migration/multisearch_generator.rb +2 -1
  29. data/lib/pg_search/migration/templates/add_pg_search_dmetaphone_support_functions.rb.erb +6 -6
  30. data/lib/pg_search/migration/templates/create_pg_search_documents.rb.erb +3 -3
  31. data/lib/pg_search/model.rb +57 -0
  32. data/lib/pg_search/multisearch/rebuilder.rb +14 -6
  33. data/lib/pg_search/multisearch.rb +23 -6
  34. data/lib/pg_search/multisearchable.rb +10 -6
  35. data/lib/pg_search/normalizer.rb +2 -0
  36. data/lib/pg_search/railtie.rb +2 -0
  37. data/lib/pg_search/scope_options.rb +26 -49
  38. data/lib/pg_search/tasks.rb +5 -1
  39. data/lib/pg_search/version.rb +3 -1
  40. data/lib/pg_search.rb +17 -55
  41. data/pg_search.gemspec +19 -11
  42. data/spec/.rubocop.yml +2 -2
  43. data/spec/integration/.rubocop.yml +11 -0
  44. data/spec/integration/associations_spec.rb +125 -162
  45. data/spec/integration/deprecation_spec.rb +33 -0
  46. data/spec/integration/pagination_spec.rb +10 -8
  47. data/spec/integration/pg_search_spec.rb +359 -306
  48. data/spec/integration/single_table_inheritance_spec.rb +18 -17
  49. data/spec/lib/pg_search/configuration/association_spec.rb +17 -13
  50. data/spec/lib/pg_search/configuration/column_spec.rb +2 -0
  51. data/spec/lib/pg_search/configuration/foreign_column_spec.rb +6 -4
  52. data/spec/lib/pg_search/features/dmetaphone_spec.rb +6 -4
  53. data/spec/lib/pg_search/features/trigram_spec.rb +51 -20
  54. data/spec/lib/pg_search/features/tsearch_spec.rb +29 -21
  55. data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +151 -85
  56. data/spec/lib/pg_search/multisearch_spec.rb +67 -37
  57. data/spec/lib/pg_search/multisearchable_spec.rb +217 -123
  58. data/spec/lib/pg_search/normalizer_spec.rb +14 -10
  59. data/spec/lib/pg_search_spec.rb +102 -89
  60. data/spec/spec_helper.rb +25 -6
  61. data/spec/support/database.rb +19 -21
  62. data/spec/support/with_model.rb +2 -0
  63. metadata +106 -29
  64. data/.autotest +0 -5
  65. data/.rubocop_todo.yml +0 -163
  66. data/Guardfile +0 -6
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/delegation"
2
4
 
3
5
  module PgSearch
@@ -12,23 +14,15 @@ module PgSearch
12
14
 
13
15
  def apply(scope)
14
16
  scope = include_table_aliasing_for_rank(scope)
15
- rank_table_alias = scope.pg_search_rank_table_alias(:include_counter)
17
+ rank_table_alias = scope.pg_search_rank_table_alias(include_counter: true)
16
18
 
17
19
  scope
18
20
  .joins(rank_join(rank_table_alias))
19
21
  .order(Arel.sql("#{rank_table_alias}.rank DESC, #{order_within_rank}"))
20
- .extend(DisableEagerLoading)
21
22
  .extend(WithPgSearchRank)
22
23
  .extend(WithPgSearchHighlight[feature_for(:tsearch)])
23
24
  end
24
25
 
25
- # workaround for https://github.com/Casecommons/pg_search/issues/14
26
- module DisableEagerLoading
27
- def eager_loading?
28
- return false
29
- end
30
- end
31
-
32
26
  module WithPgSearchHighlight
33
27
  def self.[](tsearch)
34
28
  Module.new do
@@ -38,16 +32,13 @@ module PgSearch
38
32
  end
39
33
 
40
34
  def tsearch
41
- raise TypeError.new("You need to instantiate this module with []")
35
+ raise TypeError, "You need to instantiate this module with []"
42
36
  end
43
37
 
44
38
  def with_pg_search_highlight
45
39
  scope = self
46
- scope.select(pg_search_highlight_field)
47
- end
48
-
49
- def pg_search_highlight_field
50
- "(#{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")
51
42
  end
52
43
 
53
44
  def highlight
@@ -64,10 +55,10 @@ module PgSearch
64
55
  end
65
56
 
66
57
  module PgSearchRankTableAliasing
67
- def pg_search_rank_table_alias(include_counter = false)
58
+ def pg_search_rank_table_alias(include_counter: false)
68
59
  components = [arel_table.name]
69
60
  if include_counter
70
- count = pg_search_scope_application_count_plus_plus
61
+ count = increment_counter
71
62
  components << count if count > 0
72
63
  end
73
64
 
@@ -76,22 +67,16 @@ module PgSearch
76
67
 
77
68
  private
78
69
 
79
- attr_writer :pg_search_scope_application_count
80
-
81
- def pg_search_scope_application_count
82
- @pg_search_scope_application_count ||= 0
83
- end
84
-
85
- def pg_search_scope_application_count_plus_plus
86
- count = pg_search_scope_application_count
87
- self.pg_search_scope_application_count = pg_search_scope_application_count + 1
88
- count
70
+ def increment_counter
71
+ @counter ||= 0
72
+ ensure
73
+ @counter += 1
89
74
  end
90
75
  end
91
76
 
92
77
  private
93
78
 
94
- delegate :connection, :quoted_table_name, :to => :model
79
+ delegate :connection, :quoted_table_name, to: :model
95
80
 
96
81
  def subquery
97
82
  model
@@ -105,19 +90,10 @@ module PgSearch
105
90
  end
106
91
 
107
92
  def conditions
108
- conditions = config.features.reject do |_feature_name, feature_options|
109
- feature_options && feature_options[:sort_only]
110
- end
111
-
112
- conditions.map! do |feature_name, _feature_options|
113
- feature_for(feature_name).conditions
114
- end
115
-
116
- conditions = conditions.inject do |accumulator, expression|
117
- Arel::Nodes::Or.new(accumulator, expression)
118
- end
119
-
120
- conditions.to_sql
93
+ config.features
94
+ .reject { |_feature_name, feature_options| feature_options && feature_options[:sort_only] }
95
+ .map { |feature_name, _feature_options| feature_for(feature_name).conditions }
96
+ .inject { |accumulator, expression| Arel::Nodes::Or.new(accumulator, expression) }
121
97
  end
122
98
 
123
99
  def order_within_rank
@@ -137,16 +113,16 @@ module PgSearch
137
113
  end
138
114
 
139
115
  FEATURE_CLASSES = {
140
- :dmetaphone => Features::DMetaphone,
141
- :tsearch => Features::TSearch,
142
- :trigram => Features::Trigram
143
- }
116
+ dmetaphone: Features::DMetaphone,
117
+ tsearch: Features::TSearch,
118
+ trigram: Features::Trigram
119
+ }.freeze
144
120
 
145
- def feature_for(feature_name) # rubocop:disable Metrics/AbcSize
121
+ def feature_for(feature_name)
146
122
  feature_name = feature_name.to_sym
147
123
  feature_class = FEATURE_CLASSES[feature_name]
148
124
 
149
- raise ArgumentError.new("Unknown feature: #{feature_name}") unless feature_class
125
+ raise ArgumentError, "Unknown feature: #{feature_name}" unless feature_class
150
126
 
151
127
  normalizer = Normalizer.new(config)
152
128
 
@@ -161,7 +137,7 @@ module PgSearch
161
137
 
162
138
  def rank
163
139
  (config.ranking_sql || ":tsearch").gsub(/:(\w*)/) do
164
- feature_for($1).rank.to_sql
140
+ feature_for(Regexp.last_match(1)).rank.to_sql
165
141
  end
166
142
  end
167
143
 
@@ -171,8 +147,9 @@ module PgSearch
171
147
 
172
148
  def include_table_aliasing_for_rank(scope)
173
149
  return scope if scope.included_modules.include?(PgSearchRankTableAliasing)
150
+
174
151
  scope.all.spawn.tap do |new_scope|
175
- new_scope.class_eval { include PgSearchRankTableAliasing }
152
+ new_scope.instance_eval { extend PgSearchRankTableAliasing }
176
153
  end
177
154
  end
178
155
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake'
2
4
  require 'pg_search'
3
5
 
@@ -5,10 +7,12 @@ namespace :pg_search do
5
7
  namespace :multisearch do
6
8
  desc "Rebuild PgSearch multisearch records for a given model"
7
9
  task :rebuild, %i[model schema] => :environment do |_task, args|
8
- raise ArgumentError, <<-MESSAGE.strip_heredoc unless args.model
10
+ raise ArgumentError, <<~MESSAGE unless args.model
11
+
9
12
  You must pass a model as an argument.
10
13
  Example: rake pg_search:multisearch:rebuild[BlogPost]
11
14
  MESSAGE
15
+
12
16
  model_class = args.model.classify.constantize
13
17
  connection = PgSearch::Document.connection
14
18
  original_schema_search_path = connection.schema_search_path
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module PgSearch
2
- VERSION = "2.1.2".freeze
4
+ VERSION = '2.3.6'
3
5
  end
data/lib/pg_search.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record"
2
4
  require "active_support/concern"
3
5
  require "active_support/core_ext/module/attribute_accessors"
@@ -5,6 +7,7 @@ require "active_support/core_ext/string/strip"
5
7
 
6
8
  require "pg_search/configuration"
7
9
  require "pg_search/features"
10
+ require "pg_search/model"
8
11
  require "pg_search/multisearch"
9
12
  require "pg_search/multisearchable"
10
13
  require "pg_search/normalizer"
@@ -12,7 +15,17 @@ require "pg_search/scope_options"
12
15
  require "pg_search/version"
13
16
 
14
17
  module PgSearch
15
- extend ActiveSupport::Concern
18
+ autoload :Document, "pg_search/document"
19
+
20
+ def self.included(base)
21
+ ActiveSupport::Deprecation.warn <<~MESSAGE
22
+ Directly including `PgSearch` into an Active Record model is deprecated and will be removed in pg_search 3.0.
23
+
24
+ Please replace `include PgSearch` with `include PgSearch::Model`.
25
+ MESSAGE
26
+
27
+ base.include PgSearch::Model
28
+ end
16
29
 
17
30
  mattr_accessor :multisearch_options
18
31
  self.multisearch_options = {}
@@ -20,29 +33,6 @@ module PgSearch
20
33
  mattr_accessor :unaccent_function
21
34
  self.unaccent_function = "unaccent"
22
35
 
23
- module ClassMethods
24
- def pg_search_scope(name, options)
25
- options_proc = if options.respond_to?(:call)
26
- options
27
- else
28
- raise ArgumentError, "pg_search_scope expects a Hash or Proc" unless options.respond_to?(:merge)
29
- ->(query) { {:query => query}.merge(options) }
30
- end
31
-
32
- define_singleton_method(name) do |*args|
33
- config = Configuration.new(options_proc.call(*args), self)
34
- scope_options = ScopeOptions.new(config)
35
- scope_options.apply(self)
36
- end
37
- end
38
-
39
- def multisearchable(options = {})
40
- include PgSearch::Multisearchable # rubocop:disable Style/MixinUsage
41
- class_attribute :pg_search_multisearchable_options
42
- self.pg_search_multisearchable_options = options
43
- end
44
- end
45
-
46
36
  class << self
47
37
  def multisearch(*args)
48
38
  PgSearch::Document.search(*args)
@@ -64,47 +54,19 @@ module PgSearch
64
54
  end
65
55
  end
66
56
 
67
- def method_missing(symbol, *args)
68
- case symbol
69
- when :pg_search_rank
70
- raise PgSearchRankNotSelected.new unless respond_to?(:pg_search_rank)
71
- read_attribute(:pg_search_rank).to_f
72
- when :pg_search_highlight
73
- raise PgSearchHighlightNotSelected.new unless respond_to?(:pg_search_highlight)
74
- read_attribute(:pg_search_highlight)
75
- else
76
- super
77
- end
78
- end
79
-
80
- def respond_to_missing?(symbol, *args)
81
- case symbol
82
- when :pg_search_rank
83
- attributes.key?(:pg_search_rank)
84
- when :pg_search_highlight
85
- attributes.key?(:pg_search_highlight)
86
- else
87
- super
88
- end
89
- end
90
-
91
57
  class PgSearchRankNotSelected < StandardError
92
58
  def message
93
59
  "You must chain .with_pg_search_rank after the pg_search_scope " \
94
- "to access the pg_search_rank attribute on returned records"
60
+ "to access the pg_search_rank attribute on returned records"
95
61
  end
96
62
  end
97
63
 
98
64
  class PgSearchHighlightNotSelected < StandardError
99
65
  def message
100
66
  "You must chain .with_pg_search_highlight after the pg_search_scope " \
101
- "to access the pg_search_highlight attribute on returned records"
67
+ "to access the pg_search_highlight attribute on returned records"
102
68
  end
103
69
  end
104
70
  end
105
71
 
106
- ActiveSupport.on_load(:active_record) do
107
- require "pg_search/document"
108
- end
109
-
110
- require "pg_search/railtie" if defined?(Rails)
72
+ require "pg_search/railtie" if defined?(Rails::Railtie)
data/pg_search.gemspec CHANGED
@@ -1,32 +1,40 @@
1
- $LOAD_PATH.push File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('lib', __dir__)
2
4
  require 'pg_search/version'
3
5
 
4
- Gem::Specification.new do |s|
6
+ Gem::Specification.new do |s| # rubocop:disable Metrics/BlockLength
5
7
  s.name = 'pg_search'
6
8
  s.version = PgSearch::VERSION
7
9
  s.platform = Gem::Platform::RUBY
8
10
  s.authors = ['Grant Hutchins', 'Case Commons, LLC']
9
11
  s.email = %w[gems@nertzy.com casecommons-dev@googlegroups.com]
10
12
  s.homepage = 'https://github.com/Casecommons/pg_search'
11
- s.summary = %q(PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search)
12
- s.description = %q(PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search)
13
+ s.summary = "PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search"
14
+ s.description = "PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search"
13
15
  s.licenses = ['MIT']
16
+ s.metadata["rubygems_mfa_required"] = "true"
14
17
 
15
18
  s.files = `git ls-files`.split("\n")
16
19
  s.test_files = `git ls-files -- spec/*`.split("\n")
17
20
  s.require_paths = ['lib']
18
21
 
19
- s.add_dependency 'activerecord', '>= 4.2'
20
- s.add_dependency 'activesupport', '>= 4.2'
21
- s.add_dependency 'arel', '>= 6'
22
+ s.add_dependency 'activerecord', '>= 5.2'
23
+ s.add_dependency 'activesupport', '>= 5.2'
22
24
 
23
- s.add_development_dependency 'codeclimate-test-reporter'
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 'rspec'
27
28
  s.add_development_dependency 'rubocop'
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'
28
33
  s.add_development_dependency 'simplecov'
29
- 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'
30
38
 
31
- s.required_ruby_version = '>= 2.1'
39
+ s.required_ruby_version = '>= 2.6'
32
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