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,14 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
5
|
+
# rubocop:disable RSpec/NestedGroups
|
3
6
|
describe PgSearch::Normalizer do
|
4
7
|
describe "#add_normalization" do
|
5
8
|
context "when config[:ignore] includes :accents" do
|
6
9
|
context "when passed an Arel node" do
|
7
10
|
it "wraps the expression in unaccent()" do
|
8
|
-
config =
|
11
|
+
config = instance_double("PgSearch::Configuration", "config", ignore: [:accents])
|
9
12
|
node = Arel::Nodes::NamedFunction.new("foo", [Arel::Nodes.build_quoted("bar")])
|
10
13
|
|
11
|
-
normalizer =
|
14
|
+
normalizer = described_class.new(config)
|
12
15
|
expect(normalizer.add_normalization(node)).to eq("unaccent(foo('bar'))")
|
13
16
|
end
|
14
17
|
|
@@ -17,9 +20,9 @@ describe PgSearch::Normalizer do
|
|
17
20
|
allow(PgSearch).to receive(:unaccent_function).and_return("my_unaccent")
|
18
21
|
node = Arel::Nodes::NamedFunction.new("foo", [Arel::Nodes.build_quoted("bar")])
|
19
22
|
|
20
|
-
config =
|
23
|
+
config = instance_double("PgSearch::Configuration", "config", ignore: [:accents])
|
21
24
|
|
22
|
-
normalizer =
|
25
|
+
normalizer = described_class.new(config)
|
23
26
|
expect(normalizer.add_normalization(node)).to eq("my_unaccent(foo('bar'))")
|
24
27
|
end
|
25
28
|
end
|
@@ -27,9 +30,9 @@ describe PgSearch::Normalizer do
|
|
27
30
|
|
28
31
|
context "when passed a String" do
|
29
32
|
it "wraps the expression in unaccent()" do
|
30
|
-
config =
|
33
|
+
config = instance_double("PgSearch::Configuration", "config", ignore: [:accents])
|
31
34
|
|
32
|
-
normalizer =
|
35
|
+
normalizer = described_class.new(config)
|
33
36
|
expect(normalizer.add_normalization("foo")).to eq("unaccent(foo)")
|
34
37
|
end
|
35
38
|
|
@@ -37,9 +40,9 @@ describe PgSearch::Normalizer do
|
|
37
40
|
it "wraps the expression in that function" do
|
38
41
|
allow(PgSearch).to receive(:unaccent_function).and_return("my_unaccent")
|
39
42
|
|
40
|
-
config =
|
43
|
+
config = instance_double("PgSearch::Configuration", "config", ignore: [:accents])
|
41
44
|
|
42
|
-
normalizer =
|
45
|
+
normalizer = described_class.new(config)
|
43
46
|
expect(normalizer.add_normalization("foo")).to eq("my_unaccent(foo)")
|
44
47
|
end
|
45
48
|
end
|
@@ -48,11 +51,12 @@ describe PgSearch::Normalizer do
|
|
48
51
|
|
49
52
|
context "when config[:ignore] does not include :accents" do
|
50
53
|
it "passes the expression through" do
|
51
|
-
config =
|
54
|
+
config = instance_double("PgSearch::Configuration", "config", ignore: [])
|
52
55
|
|
53
|
-
normalizer =
|
56
|
+
normalizer = described_class.new(config)
|
54
57
|
expect(normalizer.add_normalization("foo")).to eq("foo")
|
55
58
|
end
|
56
59
|
end
|
57
60
|
end
|
58
61
|
end
|
62
|
+
# rubocop:enable RSpec/NestedGroups
|
data/spec/lib/pg_search_spec.rb
CHANGED
@@ -1,69 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
|
-
# For
|
5
|
+
# For Active Record 5.x, the association reflection's cache needs be cleared
|
4
6
|
# because we're stubbing the related constants.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def clear_searchable_cache
|
12
|
-
end
|
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
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
# rubocop:disable RSpec/NestedGroups
|
16
17
|
describe PgSearch do
|
17
18
|
describe ".multisearch" do
|
18
|
-
with_table "pg_search_documents",
|
19
|
+
with_table "pg_search_documents", &DOCUMENTS_SCHEMA
|
19
20
|
|
20
21
|
describe "delegation to PgSearch::Document.search" do
|
21
|
-
subject {
|
22
|
+
subject { described_class.multisearch(query) }
|
23
|
+
|
24
|
+
let(:query) { instance_double("String", "query") }
|
25
|
+
let(:relation) { instance_double("ActiveRecord::Relation", "relation") }
|
22
26
|
|
23
|
-
let(:query) { double(:query) }
|
24
|
-
let(:relation) { double(:relation) }
|
25
27
|
before do
|
26
|
-
|
28
|
+
allow(PgSearch::Document).to receive(:search).with(query).and_return(relation)
|
27
29
|
end
|
28
30
|
|
29
31
|
it { is_expected.to eq(relation) }
|
30
32
|
end
|
31
33
|
|
32
34
|
context "with PgSearch.multisearch_options set to a Hash" do
|
33
|
-
before { allow(PgSearch).to receive(:multisearch_options).and_return(:using => :dmetaphone) }
|
34
35
|
subject do
|
35
|
-
|
36
|
-
|
36
|
+
clear_searchable_cache
|
37
|
+
described_class.multisearch(query).map(&:searchable)
|
37
38
|
end
|
38
39
|
|
40
|
+
before { allow(described_class).to receive(:multisearch_options).and_return(using: :dmetaphone) }
|
41
|
+
|
39
42
|
with_model :MultisearchableModel do
|
40
43
|
table do |t|
|
41
44
|
t.string :title
|
42
45
|
end
|
43
46
|
model do
|
44
|
-
include PgSearch
|
45
|
-
multisearchable :
|
47
|
+
include PgSearch::Model
|
48
|
+
multisearchable against: :title
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
let!(:soundalike_record) { MultisearchableModel.create!(:
|
52
|
+
let!(:soundalike_record) { MultisearchableModel.create!(title: 'foning') }
|
50
53
|
let(:query) { "Phoning" }
|
54
|
+
|
51
55
|
it { is_expected.to include(soundalike_record) }
|
52
56
|
end
|
53
57
|
|
54
58
|
context "with PgSearch.multisearch_options set to a Proc" do
|
55
59
|
subject do
|
56
|
-
|
57
|
-
|
60
|
+
clear_searchable_cache
|
61
|
+
described_class.multisearch(query, soundalike).map(&:searchable)
|
58
62
|
end
|
59
63
|
|
60
64
|
before do
|
61
|
-
allow(
|
65
|
+
allow(described_class).to receive(:multisearch_options) do
|
62
66
|
lambda do |query, soundalike|
|
63
67
|
if soundalike
|
64
|
-
{:
|
68
|
+
{ using: :dmetaphone, query: query }
|
65
69
|
else
|
66
|
-
{:query
|
70
|
+
{ query: query }
|
67
71
|
end
|
68
72
|
end
|
69
73
|
end
|
@@ -74,26 +78,28 @@ describe PgSearch do
|
|
74
78
|
t.string :title
|
75
79
|
end
|
76
80
|
model do
|
77
|
-
include PgSearch
|
78
|
-
multisearchable :
|
81
|
+
include PgSearch::Model
|
82
|
+
multisearchable against: :title
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
82
|
-
let!(:soundalike_record) { MultisearchableModel.create!(:
|
86
|
+
let!(:soundalike_record) { MultisearchableModel.create!(title: 'foning') }
|
83
87
|
let(:query) { "Phoning" }
|
84
88
|
|
85
89
|
context "with soundalike true" do
|
86
90
|
let(:soundalike) { true }
|
91
|
+
|
87
92
|
it { is_expected.to include(soundalike_record) }
|
88
93
|
end
|
89
94
|
|
90
95
|
context "with soundalike false" do
|
91
96
|
let(:soundalike) { false }
|
97
|
+
|
92
98
|
it { is_expected.not_to include(soundalike_record) }
|
93
99
|
end
|
94
100
|
end
|
95
101
|
|
96
|
-
context "on an STI subclass" do
|
102
|
+
context "when on an STI subclass" do
|
97
103
|
context "with standard type column" do
|
98
104
|
with_model :SuperclassModel do
|
99
105
|
table do |t|
|
@@ -104,8 +110,8 @@ describe PgSearch do
|
|
104
110
|
|
105
111
|
before do
|
106
112
|
searchable_subclass_model = Class.new(SuperclassModel) do
|
107
|
-
include PgSearch
|
108
|
-
multisearchable :
|
113
|
+
include PgSearch::Model
|
114
|
+
multisearchable against: :content
|
109
115
|
end
|
110
116
|
stub_const("SearchableSubclassModel", searchable_subclass_model)
|
111
117
|
stub_const("AnotherSearchableSubclassModel", searchable_subclass_model)
|
@@ -113,43 +119,44 @@ describe PgSearch do
|
|
113
119
|
end
|
114
120
|
|
115
121
|
it "returns only results for that subclass" do
|
116
|
-
included = SearchableSubclassModel.create!(:
|
122
|
+
included = SearchableSubclassModel.create!(content: "foo bar")
|
117
123
|
|
118
|
-
SearchableSubclassModel.create!(:
|
119
|
-
SuperclassModel.create!(:
|
120
|
-
SuperclassModel.create!(:
|
121
|
-
NonSearchableSubclassModel.create!(:
|
122
|
-
NonSearchableSubclassModel.create!(:
|
124
|
+
SearchableSubclassModel.create!(content: "baz")
|
125
|
+
SuperclassModel.create!(content: "foo bar")
|
126
|
+
SuperclassModel.create!(content: "baz")
|
127
|
+
NonSearchableSubclassModel.create!(content: "foo bar")
|
128
|
+
NonSearchableSubclassModel.create!(content: "baz")
|
123
129
|
|
124
130
|
expect(SuperclassModel.count).to be 6
|
125
131
|
expect(SearchableSubclassModel.count).to be 2
|
126
132
|
|
127
133
|
expect(PgSearch::Document.count).to be 2
|
128
134
|
|
129
|
-
results =
|
135
|
+
results = described_class.multisearch("foo bar")
|
130
136
|
|
131
137
|
expect(results).to eq [included.pg_search_document]
|
132
138
|
end
|
133
139
|
|
134
140
|
it "updates an existing STI model does not create a new pg_search document" do
|
135
|
-
model = SearchableSubclassModel.create!(:
|
141
|
+
model = SearchableSubclassModel.create!(content: "foo bar")
|
136
142
|
expect(SearchableSubclassModel.count).to eq(1)
|
137
143
|
# We fetch the model from the database again otherwise
|
138
144
|
# the pg_search_document from the cache is used.
|
139
145
|
model = SearchableSubclassModel.find(model.id)
|
140
146
|
model.content = "foo"
|
141
147
|
model.save!
|
142
|
-
results =
|
148
|
+
results = described_class.multisearch("foo")
|
143
149
|
expect(results.size).to eq(SearchableSubclassModel.count)
|
144
150
|
end
|
145
151
|
|
146
|
-
|
147
|
-
|
148
|
-
NonSearchableSubclassModel.create!(:
|
149
|
-
|
150
|
-
|
151
|
-
SuperclassModel.create!(:
|
152
|
-
SuperclassModel.create!(:
|
152
|
+
# rubocop:disable RSpec/MultipleExpectations
|
153
|
+
specify "reindexing works" do
|
154
|
+
NonSearchableSubclassModel.create!(content: "foo bar")
|
155
|
+
NonSearchableSubclassModel.create!(content: "baz")
|
156
|
+
expected = SearchableSubclassModel.create!(content: "baz")
|
157
|
+
SuperclassModel.create!(content: "foo bar")
|
158
|
+
SuperclassModel.create!(content: "baz")
|
159
|
+
SuperclassModel.create!(content: "baz2")
|
153
160
|
|
154
161
|
expect(SuperclassModel.count).to be 6
|
155
162
|
expect(NonSearchableSubclassModel.count).to be 2
|
@@ -159,22 +166,23 @@ describe PgSearch do
|
|
159
166
|
|
160
167
|
PgSearch::Multisearch.rebuild(SearchableSubclassModel)
|
161
168
|
|
162
|
-
|
169
|
+
clear_searchable_cache
|
163
170
|
expect(PgSearch::Document.count).to be 1
|
164
171
|
expect(PgSearch::Document.first.searchable.class).to be SearchableSubclassModel
|
165
172
|
expect(PgSearch::Document.first.searchable).to eq expected
|
166
173
|
end
|
174
|
+
# rubocop:enable RSpec/MultipleExpectations
|
167
175
|
|
168
176
|
it "reindexing searchable STI doesn't clobber other related STI models" do
|
169
|
-
SearchableSubclassModel.create!(:
|
170
|
-
AnotherSearchableSubclassModel.create!(:
|
177
|
+
SearchableSubclassModel.create!(content: "baz")
|
178
|
+
AnotherSearchableSubclassModel.create!(content: "baz")
|
171
179
|
|
172
180
|
expect(PgSearch::Document.count).to be 2
|
173
181
|
PgSearch::Multisearch.rebuild(SearchableSubclassModel)
|
174
182
|
expect(PgSearch::Document.count).to be 2
|
175
183
|
|
176
|
-
|
177
|
-
classes = PgSearch::Document.all.collect {|d| d.searchable.class }
|
184
|
+
clear_searchable_cache
|
185
|
+
classes = PgSearch::Document.all.collect { |d| d.searchable.class }
|
178
186
|
expect(classes).to include SearchableSubclassModel
|
179
187
|
expect(classes).to include AnotherSearchableSubclassModel
|
180
188
|
end
|
@@ -194,8 +202,8 @@ describe PgSearch do
|
|
194
202
|
|
195
203
|
before do
|
196
204
|
searchable_subclass_model = Class.new(SuperclassModel) do
|
197
|
-
include PgSearch
|
198
|
-
multisearchable :
|
205
|
+
include PgSearch::Model
|
206
|
+
multisearchable against: :content
|
199
207
|
end
|
200
208
|
stub_const("SearchableSubclassModel", searchable_subclass_model)
|
201
209
|
stub_const("AnotherSearchableSubclassModel", searchable_subclass_model)
|
@@ -203,20 +211,20 @@ describe PgSearch do
|
|
203
211
|
end
|
204
212
|
|
205
213
|
it "returns only results for that subclass" do
|
206
|
-
included = SearchableSubclassModel.create!(:
|
214
|
+
included = SearchableSubclassModel.create!(content: "foo bar")
|
207
215
|
|
208
|
-
SearchableSubclassModel.create!(:
|
209
|
-
SuperclassModel.create!(:
|
210
|
-
SuperclassModel.create!(:
|
211
|
-
NonSearchableSubclassModel.create!(:
|
212
|
-
NonSearchableSubclassModel.create!(:
|
216
|
+
SearchableSubclassModel.create!(content: "baz")
|
217
|
+
SuperclassModel.create!(content: "foo bar")
|
218
|
+
SuperclassModel.create!(content: "baz")
|
219
|
+
NonSearchableSubclassModel.create!(content: "foo bar")
|
220
|
+
NonSearchableSubclassModel.create!(content: "baz")
|
213
221
|
|
214
222
|
expect(SuperclassModel.count).to be 6
|
215
223
|
expect(SearchableSubclassModel.count).to be 2
|
216
224
|
|
217
225
|
expect(PgSearch::Document.count).to be 2
|
218
226
|
|
219
|
-
results =
|
227
|
+
results = described_class.multisearch("foo bar")
|
220
228
|
|
221
229
|
expect(results).to eq [included.pg_search_document]
|
222
230
|
end
|
@@ -225,57 +233,62 @@ describe PgSearch do
|
|
225
233
|
end
|
226
234
|
|
227
235
|
describe ".disable_multisearch" do
|
228
|
-
it "
|
229
|
-
|
230
|
-
|
231
|
-
|
236
|
+
it "disables multisearch temporarily" do
|
237
|
+
multisearch_enabled_before = described_class.multisearch_enabled?
|
238
|
+
multisearch_enabled_inside = nil
|
239
|
+
described_class.disable_multisearch do
|
240
|
+
multisearch_enabled_inside = described_class.multisearch_enabled?
|
232
241
|
end
|
233
|
-
|
242
|
+
multisearch_enabled_after = described_class.multisearch_enabled?
|
234
243
|
|
235
|
-
expect(
|
236
|
-
expect(
|
237
|
-
expect(
|
244
|
+
expect(multisearch_enabled_before).to be(true)
|
245
|
+
expect(multisearch_enabled_inside).to be(false)
|
246
|
+
expect(multisearch_enabled_after).to be(true)
|
238
247
|
end
|
239
248
|
|
240
|
-
it "
|
241
|
-
|
249
|
+
it "reenables multisearch after an error" do
|
250
|
+
multisearch_enabled_before = described_class.multisearch_enabled?
|
251
|
+
multisearch_enabled_inside = nil
|
242
252
|
begin
|
243
|
-
|
244
|
-
|
253
|
+
described_class.disable_multisearch do
|
254
|
+
multisearch_enabled_inside = described_class.multisearch_enabled?
|
245
255
|
raise
|
246
256
|
end
|
247
257
|
rescue StandardError
|
248
258
|
end
|
259
|
+
multisearch_enabled_after = described_class.multisearch_enabled?
|
249
260
|
|
250
|
-
|
251
|
-
|
252
|
-
expect(
|
253
|
-
expect(@multisearch_enabled_inside).to be(false)
|
254
|
-
expect(@multisearch_enabled_after).to be(true)
|
261
|
+
expect(multisearch_enabled_before).to be(true)
|
262
|
+
expect(multisearch_enabled_inside).to be(false)
|
263
|
+
expect(multisearch_enabled_after).to be(true)
|
255
264
|
end
|
256
265
|
|
257
|
-
|
266
|
+
# rubocop:disable RSpec/ExampleLength
|
267
|
+
it "does not disable multisearch on other threads" do
|
258
268
|
values = Queue.new
|
259
269
|
sync = Queue.new
|
260
270
|
Thread.new do
|
261
|
-
values.push
|
271
|
+
values.push described_class.multisearch_enabled?
|
262
272
|
sync.pop # wait
|
263
|
-
values.push
|
273
|
+
values.push described_class.multisearch_enabled?
|
264
274
|
sync.pop # wait
|
265
|
-
values.push
|
275
|
+
values.push described_class.multisearch_enabled?
|
266
276
|
end
|
267
277
|
|
268
|
-
|
269
|
-
|
278
|
+
multisearch_enabled_before = values.pop
|
279
|
+
multisearch_enabled_inside = nil
|
280
|
+
described_class.disable_multisearch do
|
270
281
|
sync.push :go
|
271
|
-
|
282
|
+
multisearch_enabled_inside = values.pop
|
272
283
|
end
|
273
284
|
sync.push :go
|
274
|
-
|
285
|
+
multisearch_enabled_after = values.pop
|
275
286
|
|
276
|
-
expect(
|
277
|
-
expect(
|
278
|
-
expect(
|
287
|
+
expect(multisearch_enabled_before).to be(true)
|
288
|
+
expect(multisearch_enabled_inside).to be(true)
|
289
|
+
expect(multisearch_enabled_after).to be(true)
|
279
290
|
end
|
291
|
+
# rubocop:enable RSpec/ExampleLength
|
280
292
|
end
|
281
293
|
end
|
294
|
+
# rubocop:enable RSpec/NestedGroups
|
data/spec/spec_helper.rb
CHANGED
@@ -1,16 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'warning'
|
4
|
+
# Ignore Ruby 2.7 warnings from Active Record
|
5
|
+
Warning.ignore :keyword_separation
|
6
|
+
|
7
|
+
# https://github.com/grodowski/undercover#setting-up-required-lcov-reporting
|
1
8
|
require 'simplecov'
|
2
|
-
|
9
|
+
require 'simplecov-lcov'
|
10
|
+
SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
|
11
|
+
SimpleCov.formatter = SimpleCov::Formatter::LcovFormatter
|
12
|
+
SimpleCov.start do
|
13
|
+
add_filter(%r{^/spec/})
|
14
|
+
enable_coverage(:branch)
|
15
|
+
end
|
16
|
+
require 'undercover'
|
3
17
|
|
4
18
|
require "bundler/setup"
|
5
19
|
require "pg_search"
|
6
20
|
|
7
21
|
RSpec.configure do |config|
|
8
|
-
config.expect_with :rspec do |
|
9
|
-
|
22
|
+
config.expect_with :rspec do |expects|
|
23
|
+
expects.syntax = :expect
|
10
24
|
end
|
11
25
|
|
12
|
-
config.mock_with :rspec do |
|
13
|
-
|
26
|
+
config.mock_with :rspec do |mocks|
|
27
|
+
mocks.syntax = :expect
|
28
|
+
mocks.verify_doubled_constant_names = true
|
29
|
+
mocks.verify_partial_doubles = true
|
14
30
|
end
|
15
31
|
|
16
32
|
config.example_status_persistence_file_path = 'tmp/examples.txt'
|
@@ -20,7 +36,10 @@ require 'support/database'
|
|
20
36
|
require 'support/with_model'
|
21
37
|
|
22
38
|
DOCUMENTS_SCHEMA = lambda do |t|
|
23
|
-
t.belongs_to :searchable, :
|
39
|
+
t.belongs_to :searchable, polymorphic: true, index: true
|
24
40
|
t.text :content
|
25
41
|
t.timestamps null: false
|
42
|
+
|
43
|
+
# Used to test additional_attributes setup
|
44
|
+
t.text :additional_attribute_column
|
26
45
|
end
|
data/spec/support/database.rb
CHANGED
@@ -1,27 +1,24 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
case RUBY_PLATFORM
|
4
|
+
when "java"
|
2
5
|
require "activerecord-jdbc-adapter"
|
3
|
-
|
6
|
+
ERROR_CLASS = ActiveRecord::JDBCError
|
4
7
|
else
|
5
8
|
require "pg"
|
6
|
-
|
9
|
+
ERROR_CLASS = PG::Error
|
7
10
|
end
|
8
11
|
|
9
|
-
error_classes << ActiveRecord::NoDatabaseError if defined? ActiveRecord::NoDatabaseError
|
10
|
-
|
11
12
|
begin
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
ActiveRecord::Base.establish_connection(:adapter => 'postgresql',
|
19
|
-
:database => 'pg_search_test',
|
20
|
-
:username => database_user,
|
21
|
-
:min_messages => 'warning')
|
13
|
+
connection_options = { adapter: 'postgresql', database: 'pg_search_test', min_messages: 'warning' }
|
14
|
+
if ENV["CI"]
|
15
|
+
connection_options[:username] = 'postgres'
|
16
|
+
connection_options[:password] = 'postgres'
|
17
|
+
end
|
18
|
+
ActiveRecord::Base.establish_connection(connection_options)
|
22
19
|
connection = ActiveRecord::Base.connection
|
23
20
|
connection.execute("SELECT 1")
|
24
|
-
rescue
|
21
|
+
rescue ERROR_CLASS, ActiveRecord::NoDatabaseError => e
|
25
22
|
at_exit do
|
26
23
|
puts "-" * 80
|
27
24
|
puts "Unable to connect to database. Please run:"
|
@@ -29,31 +26,32 @@ rescue *error_classes => exception
|
|
29
26
|
puts " createdb pg_search_test"
|
30
27
|
puts "-" * 80
|
31
28
|
end
|
32
|
-
raise
|
29
|
+
raise e
|
33
30
|
end
|
34
31
|
|
35
32
|
if ENV["LOGGER"]
|
36
33
|
require "logger"
|
37
|
-
ActiveRecord::Base.logger = Logger.new(
|
34
|
+
ActiveRecord::Base.logger = Logger.new($stdout)
|
38
35
|
end
|
39
36
|
|
40
37
|
def install_extension(name)
|
41
38
|
connection = ActiveRecord::Base.connection
|
42
39
|
extension = connection.execute "SELECT * FROM pg_catalog.pg_extension WHERE extname = '#{name}';"
|
43
40
|
return unless extension.none?
|
41
|
+
|
44
42
|
connection.execute "CREATE EXTENSION #{name};"
|
45
|
-
rescue StandardError =>
|
43
|
+
rescue StandardError => e
|
46
44
|
at_exit do
|
47
45
|
puts "-" * 80
|
48
46
|
puts "Please install the #{name} extension"
|
49
47
|
puts "-" * 80
|
50
48
|
end
|
51
|
-
raise
|
49
|
+
raise e
|
52
50
|
end
|
53
51
|
|
54
52
|
def install_extension_if_missing(name, query, expected_result)
|
55
53
|
result = ActiveRecord::Base.connection.select_value(query)
|
56
|
-
raise "Unexpected output for #{query}: #{result.inspect}" unless result.
|
54
|
+
raise "Unexpected output for #{query}: #{result.inspect}" unless result.casecmp(expected_result).zero?
|
57
55
|
rescue StandardError
|
58
56
|
install_extension(name)
|
59
57
|
end
|