pg_search 2.3.8 → 2.4.0
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 +4 -4
- data/.github/workflows/ci.yml +0 -6
- data/.github/workflows/codeql.yml +0 -1
- data/.gitignore +0 -1
- data/.standard.yml +1 -1
- data/CHANGELOG.md +70 -65
- data/CONTRIBUTING.md +1 -1
- data/LICENSE +1 -1
- data/README.md +2 -2
- data/doc/plans/2026-09-05-arel-stack.md +43 -0
- data/doc/plans/2026-09-06-arel-remaining-expressions.md +48 -0
- data/lib/pg_search/configuration/association.rb +37 -23
- data/lib/pg_search/configuration/column.rb +17 -12
- data/lib/pg_search/configuration/foreign_column.rb +3 -5
- data/lib/pg_search/features/dmetaphone.rb +3 -7
- data/lib/pg_search/features/feature.rb +8 -4
- data/lib/pg_search/features/trigram.rb +6 -20
- data/lib/pg_search/features/tsearch.rb +30 -36
- data/lib/pg_search/features.rb +2 -0
- data/lib/pg_search/migration/generator.rb +1 -5
- data/lib/pg_search/multisearch/rebuilder.rb +69 -65
- data/lib/pg_search/normalizer.rb +37 -18
- data/lib/pg_search/scope_options.rb +28 -52
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +4 -4
- data/spec/integration/associations_spec.rb +121 -0
- data/spec/integration/pg_search_spec.rb +48 -0
- data/spec/lib/pg_search/configuration/association_spec.rb +32 -58
- data/spec/lib/pg_search/configuration/column_spec.rb +73 -15
- data/spec/lib/pg_search/configuration/foreign_column_spec.rb +52 -20
- data/spec/lib/pg_search/features/dmetaphone_spec.rb +2 -2
- data/spec/lib/pg_search/features/trigram_spec.rb +3 -3
- data/spec/lib/pg_search/features/tsearch_spec.rb +8 -8
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +219 -229
- data/spec/lib/pg_search/multisearch_spec.rb +16 -16
- data/spec/lib/pg_search/normalizer_spec.rb +64 -11
- data/spec/lib/pg_search_spec.rb +2 -21
- metadata +8 -8
|
@@ -7,56 +7,109 @@ describe PgSearch::Normalizer do
|
|
|
7
7
|
describe "#add_normalization" do
|
|
8
8
|
context "when config[:ignore] includes :accents" do
|
|
9
9
|
context "when passed an Arel node" do
|
|
10
|
-
it "
|
|
10
|
+
it "returns an Arel node wrapping the expression in unaccent()" do
|
|
11
11
|
config = instance_double(PgSearch::Configuration, "config", ignore: [:accents])
|
|
12
12
|
node = Arel::Nodes::NamedFunction.new("foo", [Arel::Nodes.build_quoted("bar")])
|
|
13
13
|
|
|
14
14
|
normalizer = described_class.new(config)
|
|
15
|
-
|
|
15
|
+
result = normalizer.add_normalization(node)
|
|
16
|
+
expect(result).to be_an(Arel::Nodes::Node)
|
|
17
|
+
expect(result.to_sql).to eq("regexp_replace(unaccent(foo('bar')), '[''?\\:]', '', 'g')")
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
context "when a custom unaccent function is specified" do
|
|
19
|
-
it "
|
|
21
|
+
it "returns an Arel node using that function" do
|
|
20
22
|
allow(PgSearch).to receive(:unaccent_function).and_return("my_unaccent")
|
|
21
23
|
node = Arel::Nodes::NamedFunction.new("foo", [Arel::Nodes.build_quoted("bar")])
|
|
22
24
|
|
|
23
25
|
config = instance_double(PgSearch::Configuration, "config", ignore: [:accents])
|
|
24
26
|
|
|
25
27
|
normalizer = described_class.new(config)
|
|
26
|
-
|
|
28
|
+
result = normalizer.add_normalization(node)
|
|
29
|
+
expect(result).to be_an(Arel::Nodes::Node)
|
|
30
|
+
expect(result.to_sql).to eq("regexp_replace(my_unaccent(foo('bar')), '[''?\\:]', '', 'g')")
|
|
27
31
|
end
|
|
28
32
|
end
|
|
29
33
|
end
|
|
30
34
|
|
|
31
|
-
context "when passed a String" do
|
|
32
|
-
it "
|
|
35
|
+
context "when passed a String (trusted SQL expression)" do
|
|
36
|
+
it "returns an Arel node wrapping the expression in unaccent()" do
|
|
33
37
|
config = instance_double(PgSearch::Configuration, "config", ignore: [:accents])
|
|
34
38
|
|
|
35
39
|
normalizer = described_class.new(config)
|
|
36
|
-
|
|
40
|
+
result = normalizer.add_normalization("foo")
|
|
41
|
+
expect(result).to be_an(Arel::Nodes::Node)
|
|
42
|
+
expect(result.to_sql).to eq("regexp_replace(unaccent(foo), '[''?\\:]', '', 'g')")
|
|
37
43
|
end
|
|
38
44
|
|
|
39
45
|
context "when a custom unaccent function is specified" do
|
|
40
|
-
it "
|
|
46
|
+
it "returns an Arel node using that function" do
|
|
41
47
|
allow(PgSearch).to receive(:unaccent_function).and_return("my_unaccent")
|
|
42
48
|
|
|
43
49
|
config = instance_double(PgSearch::Configuration, "config", ignore: [:accents])
|
|
44
50
|
|
|
45
51
|
normalizer = described_class.new(config)
|
|
46
|
-
|
|
52
|
+
result = normalizer.add_normalization("foo")
|
|
53
|
+
expect(result).to be_an(Arel::Nodes::Node)
|
|
54
|
+
expect(result.to_sql).to eq("regexp_replace(my_unaccent(foo), '[''?\\:]', '', 'g')")
|
|
47
55
|
end
|
|
48
56
|
end
|
|
49
57
|
end
|
|
50
58
|
end
|
|
51
59
|
|
|
60
|
+
it "rejects unsupported inputs instead of turning them into SQL" do
|
|
61
|
+
config = instance_double(PgSearch::Configuration, ignore: [])
|
|
62
|
+
normalizer = described_class.new(config)
|
|
63
|
+
|
|
64
|
+
[nil, Object.new, 123].each do |input|
|
|
65
|
+
expect { normalizer.add_normalization(input) }.to raise_error(TypeError)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
52
69
|
context "when config[:ignore] does not include :accents" do
|
|
53
|
-
it "passes the expression through" do
|
|
70
|
+
it "passes the expression through as an Arel-compatible object" do
|
|
54
71
|
config = instance_double(PgSearch::Configuration, "config", ignore: [])
|
|
55
72
|
|
|
56
73
|
normalizer = described_class.new(config)
|
|
57
|
-
|
|
74
|
+
result = normalizer.add_normalization("foo")
|
|
75
|
+
expect(result).to eq("foo") # SqlLiteral is a String subclass, usable in Arel contexts
|
|
58
76
|
end
|
|
59
77
|
end
|
|
60
78
|
end
|
|
79
|
+
|
|
80
|
+
describe "executed against PostgreSQL" do
|
|
81
|
+
with_model :Book do
|
|
82
|
+
table { |t| t.string :title }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "strips accents and disallowed punctuation but preserves backslashes" do
|
|
86
|
+
Book.create!(title: "café's? déjà: vu\\path")
|
|
87
|
+
config = instance_double(PgSearch::Configuration, ignore: [:accents])
|
|
88
|
+
normalizer = described_class.new(config)
|
|
89
|
+
expression = normalizer.add_normalization(Book.arel_table[:title])
|
|
90
|
+
|
|
91
|
+
expect(Book.pick(expression)).to eq("cafes deja vu\\path")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "preserves attributes when accents are not ignored" do
|
|
95
|
+
book = Book.create!(title: "café's? déjà: vu\\path")
|
|
96
|
+
config = instance_double(PgSearch::Configuration, ignore: [])
|
|
97
|
+
normalizer = described_class.new(config)
|
|
98
|
+
expression = normalizer.add_normalization(Book.arel_table[:title])
|
|
99
|
+
|
|
100
|
+
expect(Book.pick(expression)).to eq(book.title)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "preserves quoted data rather than interpreting it as SQL" do
|
|
104
|
+
Book.create!
|
|
105
|
+
value = Arel::Nodes.build_quoted("café's? déjà: vu\\path")
|
|
106
|
+
config = instance_double(PgSearch::Configuration, ignore: [])
|
|
107
|
+
normalizer = described_class.new(config)
|
|
108
|
+
|
|
109
|
+
expect(normalizer.add_normalization(value)).to equal(value)
|
|
110
|
+
expect(Book.pick(normalizer.add_normalization(value)))
|
|
111
|
+
.to eq("café's? déjà: vu\\path")
|
|
112
|
+
end
|
|
113
|
+
end
|
|
61
114
|
end
|
|
62
115
|
# standard:enable RSpec/NestedGroups
|
data/spec/lib/pg_search_spec.rb
CHANGED
|
@@ -2,17 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
|
-
# For Active Record 5.x, the association reflection's cache needs be cleared
|
|
6
|
-
# because we're stubbing the related constants.
|
|
7
|
-
if ActiveRecord::VERSION::MAJOR == 5
|
|
8
|
-
def clear_searchable_cache
|
|
9
|
-
PgSearch::Document.reflect_on_association(:searchable).clear_association_scope_cache
|
|
10
|
-
end
|
|
11
|
-
else
|
|
12
|
-
def clear_searchable_cache
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
5
|
# standard:disable RSpec/NestedGroups
|
|
17
6
|
describe PgSearch do
|
|
18
7
|
describe ".multisearch" do
|
|
@@ -32,10 +21,7 @@ describe PgSearch do
|
|
|
32
21
|
end
|
|
33
22
|
|
|
34
23
|
context "with PgSearch.multisearch_options set to a Hash" do
|
|
35
|
-
subject
|
|
36
|
-
clear_searchable_cache
|
|
37
|
-
described_class.multisearch(query).map(&:searchable)
|
|
38
|
-
end
|
|
24
|
+
subject { described_class.multisearch(query).map(&:searchable) }
|
|
39
25
|
|
|
40
26
|
before { allow(described_class).to receive(:multisearch_options).and_return(using: :dmetaphone) }
|
|
41
27
|
|
|
@@ -57,10 +43,7 @@ describe PgSearch do
|
|
|
57
43
|
end
|
|
58
44
|
|
|
59
45
|
context "with PgSearch.multisearch_options set to a Proc" do
|
|
60
|
-
subject
|
|
61
|
-
clear_searchable_cache
|
|
62
|
-
described_class.multisearch(query, soundalike).map(&:searchable)
|
|
63
|
-
end
|
|
46
|
+
subject { described_class.multisearch(query, soundalike).map(&:searchable) }
|
|
64
47
|
|
|
65
48
|
before do
|
|
66
49
|
allow(described_class).to receive(:multisearch_options) do
|
|
@@ -169,7 +152,6 @@ describe PgSearch do
|
|
|
169
152
|
|
|
170
153
|
PgSearch::Multisearch.rebuild(SearchableSubclassModel)
|
|
171
154
|
|
|
172
|
-
clear_searchable_cache
|
|
173
155
|
expect(PgSearch::Document.count).to be 1
|
|
174
156
|
expect(PgSearch::Document.first.searchable.class).to be SearchableSubclassModel
|
|
175
157
|
expect(PgSearch::Document.first.searchable).to eq expected
|
|
@@ -184,7 +166,6 @@ describe PgSearch do
|
|
|
184
166
|
PgSearch::Multisearch.rebuild(SearchableSubclassModel)
|
|
185
167
|
expect(PgSearch::Document.count).to be 2
|
|
186
168
|
|
|
187
|
-
clear_searchable_cache
|
|
188
169
|
classes = PgSearch::Document.all.collect { |d| d.searchable.class }
|
|
189
170
|
expect(classes).to include SearchableSubclassModel
|
|
190
171
|
expect(classes).to include AnotherSearchableSubclassModel
|
metadata
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg_search
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Grant Hutchins
|
|
8
|
-
- Case Commons, LLC
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
@@ -16,33 +15,32 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '8.0'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '8.0'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: activesupport
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
30
29
|
requirements:
|
|
31
30
|
- - ">="
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
32
|
+
version: '8.0'
|
|
34
33
|
type: :runtime
|
|
35
34
|
prerelease: false
|
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
36
|
requirements:
|
|
38
37
|
- - ">="
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
39
|
+
version: '8.0'
|
|
41
40
|
description: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
|
|
42
41
|
full text search
|
|
43
42
|
email:
|
|
44
43
|
- gems@nertzy.com
|
|
45
|
-
- casecommons-dev@googlegroups.com
|
|
46
44
|
executables: []
|
|
47
45
|
extensions: []
|
|
48
46
|
extra_rdoc_files: []
|
|
@@ -63,6 +61,8 @@ files:
|
|
|
63
61
|
- LICENSE
|
|
64
62
|
- README.md
|
|
65
63
|
- Rakefile
|
|
64
|
+
- doc/plans/2026-09-05-arel-stack.md
|
|
65
|
+
- doc/plans/2026-09-06-arel-remaining-expressions.md
|
|
66
66
|
- lib/pg_search.rb
|
|
67
67
|
- lib/pg_search/configuration.rb
|
|
68
68
|
- lib/pg_search/configuration/association.rb
|
|
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
129
129
|
- !ruby/object:Gem::Version
|
|
130
130
|
version: '0'
|
|
131
131
|
requirements: []
|
|
132
|
-
rubygems_version: 4.0.
|
|
132
|
+
rubygems_version: 4.0.20
|
|
133
133
|
specification_version: 4
|
|
134
134
|
summary: PgSearch builds Active Record named scopes that take advantage of PostgreSQL's
|
|
135
135
|
full text search
|