pg_search 2.1.2 → 2.3.6

Sign up to get free protection for your applications and to get access to all the features.
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