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.
- checksums.yaml +5 -5
- data/.codeclimate.yml +1 -0
- data/.editorconfig +10 -0
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/ci.yml +75 -0
- data/.jrubyrc +1 -0
- data/.rubocop.yml +95 -10
- data/.travis.yml +26 -48
- data/CHANGELOG.md +179 -112
- data/CODE_OF_CONDUCT.md +76 -0
- data/CONTRIBUTING.md +5 -3
- data/Gemfile +6 -4
- data/LICENSE +1 -1
- data/README.md +307 -198
- data/Rakefile +7 -3
- data/lib/pg_search/configuration/association.rb +2 -0
- data/lib/pg_search/configuration/column.rb +2 -0
- data/lib/pg_search/configuration/foreign_column.rb +2 -0
- data/lib/pg_search/configuration.rb +20 -6
- data/lib/pg_search/document.rb +7 -5
- data/lib/pg_search/features/dmetaphone.rb +7 -7
- data/lib/pg_search/features/feature.rb +4 -2
- data/lib/pg_search/features/trigram.rb +31 -5
- data/lib/pg_search/features/tsearch.rb +18 -14
- data/lib/pg_search/features.rb +2 -0
- data/lib/pg_search/migration/dmetaphone_generator.rb +3 -1
- data/lib/pg_search/migration/generator.rb +4 -2
- data/lib/pg_search/migration/multisearch_generator.rb +2 -1
- data/lib/pg_search/migration/templates/add_pg_search_dmetaphone_support_functions.rb.erb +6 -6
- data/lib/pg_search/migration/templates/create_pg_search_documents.rb.erb +3 -3
- data/lib/pg_search/model.rb +57 -0
- data/lib/pg_search/multisearch/rebuilder.rb +14 -6
- data/lib/pg_search/multisearch.rb +23 -6
- data/lib/pg_search/multisearchable.rb +10 -6
- data/lib/pg_search/normalizer.rb +2 -0
- data/lib/pg_search/railtie.rb +2 -0
- data/lib/pg_search/scope_options.rb +26 -49
- data/lib/pg_search/tasks.rb +5 -1
- data/lib/pg_search/version.rb +3 -1
- data/lib/pg_search.rb +17 -55
- data/pg_search.gemspec +19 -11
- data/spec/.rubocop.yml +2 -2
- data/spec/integration/.rubocop.yml +11 -0
- data/spec/integration/associations_spec.rb +125 -162
- data/spec/integration/deprecation_spec.rb +33 -0
- data/spec/integration/pagination_spec.rb +10 -8
- data/spec/integration/pg_search_spec.rb +359 -306
- data/spec/integration/single_table_inheritance_spec.rb +18 -17
- data/spec/lib/pg_search/configuration/association_spec.rb +17 -13
- data/spec/lib/pg_search/configuration/column_spec.rb +2 -0
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +6 -4
- data/spec/lib/pg_search/features/dmetaphone_spec.rb +6 -4
- data/spec/lib/pg_search/features/trigram_spec.rb +51 -20
- data/spec/lib/pg_search/features/tsearch_spec.rb +29 -21
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +151 -85
- data/spec/lib/pg_search/multisearch_spec.rb +67 -37
- data/spec/lib/pg_search/multisearchable_spec.rb +217 -123
- data/spec/lib/pg_search/normalizer_spec.rb +14 -10
- data/spec/lib/pg_search_spec.rb +102 -89
- data/spec/spec_helper.rb +25 -6
- data/spec/support/database.rb +19 -21
- data/spec/support/with_model.rb +2 -0
- metadata +106 -29
- data/.autotest +0 -5
- data/.rubocop_todo.yml +0 -163
- 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(:
|
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
|
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(
|
47
|
-
|
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
|
58
|
+
def pg_search_rank_table_alias(include_counter: false)
|
68
59
|
components = [arel_table.name]
|
69
60
|
if include_counter
|
70
|
-
count =
|
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
|
-
|
80
|
-
|
81
|
-
|
82
|
-
@
|
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, :
|
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
|
-
|
109
|
-
|
110
|
-
|
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
|
-
:
|
141
|
-
:
|
142
|
-
:
|
143
|
-
}
|
116
|
+
dmetaphone: Features::DMetaphone,
|
117
|
+
tsearch: Features::TSearch,
|
118
|
+
trigram: Features::Trigram
|
119
|
+
}.freeze
|
144
120
|
|
145
|
-
def feature_for(feature_name)
|
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
|
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(
|
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.
|
152
|
+
new_scope.instance_eval { extend PgSearchRankTableAliasing }
|
176
153
|
end
|
177
154
|
end
|
178
155
|
end
|
data/lib/pg_search/tasks.rb
CHANGED
@@ -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,
|
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
|
data/lib/pg_search/version.rb
CHANGED
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
|
-
|
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
|
-
|
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
|
-
|
67
|
+
"to access the pg_search_highlight attribute on returned records"
|
102
68
|
end
|
103
69
|
end
|
104
70
|
end
|
105
71
|
|
106
|
-
|
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
|
-
|
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 =
|
12
|
-
s.description =
|
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', '>=
|
20
|
-
s.add_dependency 'activesupport', '>=
|
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'
|
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 '
|
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.
|
39
|
+
s.required_ruby_version = '>= 2.6'
|
32
40
|
end
|
data/spec/.rubocop.yml
CHANGED