pg_search 2.3.2 → 2.3.7

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/ci.yml +80 -0
  4. data/.jrubyrc +1 -0
  5. data/.standard.yml +6 -0
  6. data/CHANGELOG.md +55 -20
  7. data/CODE_OF_CONDUCT.md +76 -0
  8. data/Gemfile +19 -6
  9. data/LICENSE +1 -1
  10. data/README.md +106 -43
  11. data/Rakefile +9 -6
  12. data/lib/pg_search/configuration/column.rb +6 -4
  13. data/lib/pg_search/configuration/foreign_column.rb +1 -1
  14. data/lib/pg_search/configuration.rb +13 -3
  15. data/lib/pg_search/document.rb +9 -9
  16. data/lib/pg_search/features/dmetaphone.rb +5 -7
  17. data/lib/pg_search/features/feature.rb +1 -1
  18. data/lib/pg_search/features/trigram.rb +4 -4
  19. data/lib/pg_search/features/tsearch.rb +26 -24
  20. data/lib/pg_search/migration/dmetaphone_generator.rb +2 -2
  21. data/lib/pg_search/migration/generator.rb +5 -5
  22. data/lib/pg_search/migration/multisearch_generator.rb +2 -2
  23. data/lib/pg_search/migration/templates/add_pg_search_dmetaphone_support_functions.rb.erb +6 -6
  24. data/lib/pg_search/migration/templates/create_pg_search_documents.rb.erb +2 -2
  25. data/lib/pg_search/model.rb +6 -6
  26. data/lib/pg_search/multisearch/rebuilder.rb +2 -2
  27. data/lib/pg_search/multisearch.rb +23 -4
  28. data/lib/pg_search/multisearchable.rb +7 -7
  29. data/lib/pg_search/normalizer.rb +5 -5
  30. data/lib/pg_search/scope_options.rb +31 -13
  31. data/lib/pg_search/tasks.rb +3 -3
  32. data/lib/pg_search/version.rb +1 -1
  33. data/lib/pg_search.rb +5 -5
  34. data/pg_search.gemspec +16 -24
  35. data/spec/.rubocop.yml +20 -7
  36. data/spec/integration/.rubocop.yml +11 -0
  37. data/spec/integration/associations_spec.rb +121 -160
  38. data/spec/integration/deprecation_spec.rb +7 -8
  39. data/spec/integration/pg_search_spec.rb +390 -332
  40. data/spec/integration/single_table_inheritance_spec.rb +5 -5
  41. data/spec/lib/pg_search/configuration/association_spec.rb +21 -19
  42. data/spec/lib/pg_search/configuration/column_spec.rb +13 -1
  43. data/spec/lib/pg_search/configuration/foreign_column_spec.rb +4 -4
  44. data/spec/lib/pg_search/features/dmetaphone_spec.rb +4 -4
  45. data/spec/lib/pg_search/features/trigram_spec.rb +32 -28
  46. data/spec/lib/pg_search/features/tsearch_spec.rb +57 -33
  47. data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +94 -63
  48. data/spec/lib/pg_search/multisearch_spec.rb +57 -29
  49. data/spec/lib/pg_search/multisearchable_spec.rb +160 -107
  50. data/spec/lib/pg_search/normalizer_spec.rb +12 -10
  51. data/spec/lib/pg_search_spec.rb +75 -64
  52. data/spec/spec_helper.rb +21 -9
  53. data/spec/support/database.rb +10 -8
  54. metadata +20 -134
  55. data/.autotest +0 -5
  56. data/.codeclimate.yml +0 -17
  57. data/.rubocop.yml +0 -56
  58. data/.travis.yml +0 -50
@@ -6,8 +6,8 @@ describe "a pg_search_scope on an STI subclass" do
6
6
  context "with the standard type column" do
7
7
  with_model :SuperclassModel do
8
8
  table do |t|
9
- t.text 'content'
10
- t.string 'type'
9
+ t.text "content"
10
+ t.string "type"
11
11
  end
12
12
 
13
13
  model do
@@ -46,13 +46,13 @@ describe "a pg_search_scope on an STI subclass" do
46
46
  context "with a custom type column" do
47
47
  with_model :SuperclassModel do
48
48
  table do |t|
49
- t.text 'content'
50
- t.string 'custom_type'
49
+ t.text "content"
50
+ t.string "custom_type"
51
51
  end
52
52
 
53
53
  model do
54
54
  include PgSearch::Model
55
- self.inheritance_column = 'custom_type'
55
+ self.inheritance_column = "custom_type"
56
56
  pg_search_scope :search_content, against: :content
57
57
  end
58
58
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "spec_helper"
4
4
 
5
+ # standard:disable RSpec/NestedGroups
5
6
  describe PgSearch::Configuration::Association do
6
7
  with_model :Avatar do
7
8
  table do |t|
@@ -21,8 +22,8 @@ describe PgSearch::Configuration::Association do
21
22
  has_one :avatar, class_name: "Avatar"
22
23
  belongs_to :site
23
24
 
24
- pg_search_scope :with_avatar, associated_against: { avatar: :url }
25
- pg_search_scope :with_site, associated_against: { site: :title }
25
+ pg_search_scope :with_avatar, associated_against: {avatar: :url}
26
+ pg_search_scope :with_site, associated_against: {site: :title}
26
27
  end
27
28
  end
28
29
 
@@ -35,11 +36,11 @@ describe PgSearch::Configuration::Association do
35
36
  include PgSearch::Model
36
37
  has_many :users, class_name: "User"
37
38
 
38
- pg_search_scope :with_users, associated_against: { users: :name }
39
+ pg_search_scope :with_users, associated_against: {users: :name}
39
40
  end
40
41
  end
41
42
 
42
- context "has_one" do
43
+ context "with has_one" do
43
44
  let(:association) { described_class.new(User, :avatar, :url) }
44
45
 
45
46
  describe "#table_name" do
@@ -50,13 +51,13 @@ describe PgSearch::Configuration::Association do
50
51
 
51
52
  describe "#join" do
52
53
  let(:expected_sql) do
53
- <<-SQL.gsub(/\s+/, ' ').strip
54
+ <<~SQL.squish
54
55
  LEFT OUTER JOIN
55
56
  (SELECT model_id AS id,
56
57
  #{column_select} AS #{association.columns.first.alias}
57
- FROM \"#{User.table_name}\"
58
- INNER JOIN \"#{association.table_name}\"
59
- ON \"#{association.table_name}\".\"user_id\" = \"#{User.table_name}\".\"id\") #{association.subselect_alias}
58
+ FROM "#{User.table_name}"
59
+ INNER JOIN "#{association.table_name}"
60
+ ON "#{association.table_name}"."user_id" = "#{User.table_name}"."id") #{association.subselect_alias}
60
61
  ON #{association.subselect_alias}.id = model_id
61
62
  SQL
62
63
  end
@@ -70,7 +71,7 @@ describe PgSearch::Configuration::Association do
70
71
  end
71
72
  end
72
73
 
73
- context "belongs_to" do
74
+ context "with belongs_to" do
74
75
  let(:association) { described_class.new(User, :site, :title) }
75
76
 
76
77
  describe "#table_name" do
@@ -81,13 +82,13 @@ describe PgSearch::Configuration::Association do
81
82
 
82
83
  describe "#join" do
83
84
  let(:expected_sql) do
84
- <<-SQL.gsub(/\s+/, ' ').strip
85
+ <<~SQL.squish
85
86
  LEFT OUTER JOIN
86
87
  (SELECT model_id AS id,
87
88
  #{column_select} AS #{association.columns.first.alias}
88
- FROM \"#{User.table_name}\"
89
- INNER JOIN \"#{association.table_name}\"
90
- ON \"#{association.table_name}\".\"id\" = \"#{User.table_name}\".\"site_id\") #{association.subselect_alias}
89
+ FROM "#{User.table_name}"
90
+ INNER JOIN "#{association.table_name}"
91
+ ON "#{association.table_name}"."id" = "#{User.table_name}"."site_id") #{association.subselect_alias}
91
92
  ON #{association.subselect_alias}.id = model_id
92
93
  SQL
93
94
  end
@@ -101,7 +102,7 @@ describe PgSearch::Configuration::Association do
101
102
  end
102
103
  end
103
104
 
104
- context "has_many" do
105
+ context "with has_many" do
105
106
  let(:association) { described_class.new(Site, :users, :name) }
106
107
 
107
108
  describe "#table_name" do
@@ -112,13 +113,13 @@ describe PgSearch::Configuration::Association do
112
113
 
113
114
  describe "#join" do
114
115
  let(:expected_sql) do
115
- <<-SQL.gsub(/\s+/, ' ').strip
116
+ <<~SQL.squish
116
117
  LEFT OUTER JOIN
117
118
  (SELECT model_id AS id,
118
- string_agg(\"#{association.table_name}\".\"name\"::text, ' ') AS #{association.columns.first.alias}
119
- FROM \"#{Site.table_name}\"
120
- INNER JOIN \"#{association.table_name}\"
121
- ON \"#{association.table_name}\".\"site_id\" = \"#{Site.table_name}\".\"id\"
119
+ string_agg("#{association.table_name}"."name"::text, ' ') AS #{association.columns.first.alias}
120
+ FROM "#{Site.table_name}"
121
+ INNER JOIN "#{association.table_name}"
122
+ ON "#{association.table_name}"."site_id" = "#{Site.table_name}"."id"
122
123
  GROUP BY model_id) #{association.subselect_alias}
123
124
  ON #{association.subselect_alias}.id = model_id
124
125
  SQL
@@ -138,3 +139,4 @@ describe PgSearch::Configuration::Association do
138
139
  end
139
140
  end
140
141
  end
142
+ # standard:enable RSpec/NestedGroups
@@ -7,6 +7,7 @@ describe PgSearch::Configuration::Column do
7
7
  with_model :Model do
8
8
  table do |t|
9
9
  t.string :name
10
+ t.json :object
10
11
  end
11
12
  end
12
13
 
@@ -14,18 +15,29 @@ describe PgSearch::Configuration::Column do
14
15
  column = described_class.new("name", nil, Model)
15
16
  expect(column.full_name).to eq(%(#{Model.quoted_table_name}."name"))
16
17
  end
18
+
19
+ it "returns nested json attributes" do
20
+ column = described_class.new(Arel.sql("object->>'name'"), nil, Model)
21
+ expect(column.full_name).to eq(%(object->>'name'))
22
+ end
17
23
  end
18
24
 
19
25
  describe "#to_sql" do
20
26
  with_model :Model do
21
27
  table do |t|
22
28
  t.string :name
29
+ t.json :object
23
30
  end
24
31
  end
25
32
 
26
33
  it "returns an expression that casts the column to text and coalesces it with an empty string" do
27
34
  column = described_class.new("name", nil, Model)
28
- expect(column.to_sql).to eq(%{coalesce(#{Model.quoted_table_name}."name"::text, '')})
35
+ expect(column.to_sql).to eq(%{coalesce((#{Model.quoted_table_name}."name")::text, '')})
36
+ end
37
+
38
+ it "returns an expression that casts the nested json attribute to text and coalesces it with an empty string" do
39
+ column = described_class.new(Arel.sql("object->>'name'"), nil, Model)
40
+ expect(column.to_sql).to eq(%{coalesce((object->>'name')::text, '')})
29
41
  end
30
42
  end
31
43
  end
@@ -18,16 +18,16 @@ describe PgSearch::Configuration::ForeignColumn do
18
18
 
19
19
  model do
20
20
  include PgSearch::Model
21
- belongs_to :another_model, class_name: 'AssociatedModel'
21
+ belongs_to :another_model, class_name: "AssociatedModel"
22
22
 
23
- pg_search_scope :with_another, associated_against: { another_model: :title }
23
+ pg_search_scope :with_another, associated_against: {another_model: :title}
24
24
  end
25
25
  end
26
26
 
27
27
  it "returns a consistent string" do
28
28
  association = PgSearch::Configuration::Association.new(Model,
29
- :another_model,
30
- :title)
29
+ :another_model,
30
+ :title)
31
31
  foreign_column = described_class.new("title", nil, Model, association)
32
32
 
33
33
  column_alias = foreign_column.alias
@@ -18,12 +18,12 @@ describe PgSearch::Features::DMetaphone do
18
18
  PgSearch::Configuration::Column.new(:content, nil, Model)
19
19
  ]
20
20
  options = {}
21
- config = double(:config, ignore: [])
21
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
22
22
  normalizer = PgSearch::Normalizer.new(config)
23
23
 
24
24
  feature = described_class.new(query, options, columns, Model, normalizer)
25
25
  expect(feature.rank.to_sql).to eq(
26
- %{(ts_rank((to_tsvector('simple', pg_search_dmetaphone(coalesce(#{Model.quoted_table_name}."name"::text, ''))) || to_tsvector('simple', pg_search_dmetaphone(coalesce(#{Model.quoted_table_name}."content"::text, '')))), (to_tsquery('simple', ''' ' || pg_search_dmetaphone('query') || ' ''')), 0))}
26
+ %{(ts_rank((to_tsvector('simple', pg_search_dmetaphone(coalesce((#{Model.quoted_table_name}."name")::text, ''))) || to_tsvector('simple', pg_search_dmetaphone(coalesce((#{Model.quoted_table_name}."content")::text, '')))), (to_tsquery('simple', ''' ' || pg_search_dmetaphone('query') || ' ''')), 0))}
27
27
  )
28
28
  end
29
29
  end
@@ -43,12 +43,12 @@ describe PgSearch::Features::DMetaphone do
43
43
  PgSearch::Configuration::Column.new(:content, nil, Model)
44
44
  ]
45
45
  options = {}
46
- config = double(:config, ignore: [])
46
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
47
47
  normalizer = PgSearch::Normalizer.new(config)
48
48
 
49
49
  feature = described_class.new(query, options, columns, Model, normalizer)
50
50
  expect(feature.conditions.to_sql).to eq(
51
- %{((to_tsvector('simple', pg_search_dmetaphone(coalesce(#{Model.quoted_table_name}."name"::text, ''))) || to_tsvector('simple', pg_search_dmetaphone(coalesce(#{Model.quoted_table_name}."content"::text, '')))) @@ (to_tsquery('simple', ''' ' || pg_search_dmetaphone('query') || ' ''')))}
51
+ %{((to_tsvector('simple', pg_search_dmetaphone(coalesce((#{Model.quoted_table_name}."name")::text, ''))) || to_tsvector('simple', pg_search_dmetaphone(coalesce((#{Model.quoted_table_name}."content")::text, '')))) @@ (to_tsquery('simple', ''' ' || pg_search_dmetaphone('query') || ' ''')))}
52
52
  )
53
53
  end
54
54
  end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
- require 'ostruct'
3
+ require "spec_helper"
4
+ require "ostruct"
5
5
 
6
+ # standard:disable RSpec/MultipleMemoizedHelpers, RSpec/NestedGroups
6
7
  describe PgSearch::Features::Trigram do
7
8
  subject(:feature) { described_class.new(query, options, columns, Model, normalizer) }
8
- let(:query) { 'lolwut' }
9
+
10
+ let(:query) { "lolwut" }
9
11
  let(:options) { {} }
10
12
  let(:columns) {
11
13
  [
@@ -17,8 +19,10 @@ describe PgSearch::Features::Trigram do
17
19
  let(:config) { OpenStruct.new(ignore: []) }
18
20
 
19
21
  let(:coalesced_columns) do
20
- <<-SQL.strip_heredoc.chomp
21
- coalesce(#{Model.quoted_table_name}."name"::text, '') || ' ' || coalesce(#{Model.quoted_table_name}."content"::text, '')
22
+ <<~SQL.squish
23
+ coalesce((#{Model.quoted_table_name}."name")::text, '')
24
+ || ' '
25
+ || coalesce((#{Model.quoted_table_name}."content")::text, '')
22
26
  SQL
23
27
  end
24
28
 
@@ -29,15 +33,15 @@ describe PgSearch::Features::Trigram do
29
33
  end
30
34
  end
31
35
 
32
- describe 'conditions' do
33
- it 'escapes the search document and query' do
36
+ describe "conditions" do
37
+ it "escapes the search document and query" do
34
38
  config.ignore = []
35
39
  expect(feature.conditions.to_sql).to eq("('#{query}' % (#{coalesced_columns}))")
36
40
  end
37
41
 
38
- context 'searching by word_similarity' do
42
+ context "when searching by word_similarity" do
39
43
  let(:options) do
40
- { word_similarity: true }
44
+ {word_similarity: true}
41
45
  end
42
46
 
43
47
  it 'uses the "<%" operator when searching by word_similarity' do
@@ -46,17 +50,17 @@ describe PgSearch::Features::Trigram do
46
50
  end
47
51
  end
48
52
 
49
- context 'ignoring accents' do
50
- it 'escapes the search document and query, but not the accent function' do
53
+ context "when ignoring accents" do
54
+ it "escapes the search document and query, but not the accent function" do
51
55
  config.ignore = [:accents]
52
56
  expect(feature.conditions.to_sql).to eq("(unaccent('#{query}') % (unaccent(#{coalesced_columns})))")
53
57
  end
54
58
  end
55
59
 
56
- context 'when a threshold is specified' do
57
- context 'searching by similarity' do
60
+ context "when a threshold is specified" do
61
+ context "when searching by similarity" do
58
62
  let(:options) do
59
- { threshold: 0.5 }
63
+ {threshold: 0.5}
60
64
  end
61
65
 
62
66
  it 'uses a minimum similarity expression instead of the "%" operator' do
@@ -66,9 +70,9 @@ describe PgSearch::Features::Trigram do
66
70
  end
67
71
  end
68
72
 
69
- context 'searching by word_similarity' do
73
+ context "when searching by word_similarity" do
70
74
  let(:options) do
71
- { threshold: 0.5, word_similarity: true }
75
+ {threshold: 0.5, word_similarity: true}
72
76
  end
73
77
 
74
78
  it 'uses a minimum similarity expression instead of the "<%" operator' do
@@ -79,30 +83,30 @@ describe PgSearch::Features::Trigram do
79
83
  end
80
84
  end
81
85
 
82
- context 'only certain columns are selected' do
83
- context 'one column' do
84
- let(:options) { { only: :name } }
86
+ context "when only certain columns are selected" do
87
+ context "with one column" do
88
+ let(:options) { {only: :name} }
85
89
 
86
- it 'only searches against the select column' do
87
- options = { only: :name }
88
- coalesced_column = "coalesce(#{Model.quoted_table_name}.\"name\"::text, '')"
90
+ it "only searches against the select column" do
91
+ coalesced_column = "coalesce((#{Model.quoted_table_name}.\"name\")::text, '')"
89
92
  expect(feature.conditions.to_sql).to eq("('#{query}' % (#{coalesced_column}))")
90
93
  end
91
94
  end
92
- context 'multiple columns' do
93
- let(:options) { { only: %i[name content] } }
94
95
 
95
- it 'concatenates when multiples columns are selected' do
96
- options = { only: %i[name content] }
96
+ context "with multiple columns" do
97
+ let(:options) { {only: %i[name content]} }
98
+
99
+ it "concatenates when multiples columns are selected" do
97
100
  expect(feature.conditions.to_sql).to eq("('#{query}' % (#{coalesced_columns}))")
98
101
  end
99
102
  end
100
103
  end
101
104
  end
102
105
 
103
- describe '#rank' do
104
- it 'returns an expression using the similarity() function' do
106
+ describe "#rank" do
107
+ it "returns an expression using the similarity() function" do
105
108
  expect(feature.rank.to_sql).to eq("(similarity('#{query}', (#{coalesced_columns})))")
106
109
  end
107
110
  end
108
111
  end
112
+ # standard:enable RSpec/MultipleMemoizedHelpers, RSpec/NestedGroups
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spec_helper"
4
- require "active_support/deprecation"
4
+ require "active_support/core_ext/kernel/reporting"
5
5
 
6
6
  describe PgSearch::Features::TSearch do
7
7
  describe "#rank" do
@@ -19,14 +19,32 @@ describe PgSearch::Features::TSearch do
19
19
  PgSearch::Configuration::Column.new(:content, nil, Model)
20
20
  ]
21
21
  options = {}
22
- config = double(:config, ignore: [])
22
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
23
23
  normalizer = PgSearch::Normalizer.new(config)
24
24
 
25
25
  feature = described_class.new(query, options, columns, Model, normalizer)
26
26
  expect(feature.rank.to_sql).to eq(
27
- %{(ts_rank((to_tsvector('simple', coalesce(#{Model.quoted_table_name}."name"::text, '')) || to_tsvector('simple', coalesce(#{Model.quoted_table_name}."content"::text, ''))), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 0))}
27
+ %{(ts_rank((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 0))}
28
28
  )
29
29
  end
30
+
31
+ context "with a tsvector column and a custom normalization" do
32
+ it "works?" do
33
+ query = "query"
34
+ columns = [
35
+ PgSearch::Configuration::Column.new(:name, nil, Model),
36
+ PgSearch::Configuration::Column.new(:content, nil, Model)
37
+ ]
38
+ options = {tsvector_column: :my_tsvector, normalization: 2}
39
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
40
+ normalizer = PgSearch::Normalizer.new(config)
41
+
42
+ feature = described_class.new(query, options, columns, Model, normalizer)
43
+ expect(feature.rank.to_sql).to eq(
44
+ %{(ts_rank((#{Model.quoted_table_name}."my_tsvector"), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 2))}
45
+ )
46
+ end
47
+ end
30
48
  end
31
49
 
32
50
  describe "#conditions" do
@@ -44,12 +62,12 @@ describe PgSearch::Features::TSearch do
44
62
  PgSearch::Configuration::Column.new(:content, nil, Model)
45
63
  ]
46
64
  options = {}
47
- config = double(:config, ignore: [])
65
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
48
66
  normalizer = PgSearch::Normalizer.new(config)
49
67
 
50
68
  feature = described_class.new(query, options, columns, Model, normalizer)
51
69
  expect(feature.conditions.to_sql).to eq(
52
- %{((to_tsvector('simple', coalesce(#{Model.quoted_table_name}."name"::text, '')) || to_tsvector('simple', coalesce(#{Model.quoted_table_name}."content"::text, ''))) @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))}
70
+ %{((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))) @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))}
53
71
  )
54
72
  end
55
73
 
@@ -60,13 +78,13 @@ describe PgSearch::Features::TSearch do
60
78
  PgSearch::Configuration::Column.new(:name, nil, Model),
61
79
  PgSearch::Configuration::Column.new(:content, nil, Model)
62
80
  ]
63
- options = { negation: true }
64
- config = double(:config, ignore: [])
81
+ options = {negation: true}
82
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
65
83
  normalizer = PgSearch::Normalizer.new(config)
66
84
 
67
85
  feature = described_class.new(query, options, columns, Model, normalizer)
68
86
  expect(feature.conditions.to_sql).to eq(
69
- %{((to_tsvector('simple', coalesce(#{Model.quoted_table_name}."name"::text, '')) || to_tsvector('simple', coalesce(#{Model.quoted_table_name}."content"::text, ''))) @@ (to_tsquery('simple', '!' || ''' ' || 'query' || ' ''')))}
87
+ %{((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))) @@ (to_tsquery('simple', '!' || ''' ' || 'query' || ' ''')))}
70
88
  )
71
89
  end
72
90
  end
@@ -78,49 +96,49 @@ describe PgSearch::Features::TSearch do
78
96
  PgSearch::Configuration::Column.new(:name, nil, Model),
79
97
  PgSearch::Configuration::Column.new(:content, nil, Model)
80
98
  ]
81
- options = { negation: false }
82
- config = double(:config, ignore: [])
99
+ options = {negation: false}
100
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
83
101
  normalizer = PgSearch::Normalizer.new(config)
84
102
 
85
103
  feature = described_class.new(query, options, columns, Model, normalizer)
86
104
  expect(feature.conditions.to_sql).to eq(
87
- %{((to_tsvector('simple', coalesce(#{Model.quoted_table_name}."name"::text, '')) || to_tsvector('simple', coalesce(#{Model.quoted_table_name}."content"::text, ''))) @@ (to_tsquery('simple', ''' ' || '!query' || ' ''')))}
105
+ %{((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))) @@ (to_tsquery('simple', ''' ' || '!query' || ' ''')))}
88
106
  )
89
107
  end
90
108
  end
91
109
 
92
110
  context "when options[:tsvector_column] is a string" do
93
- it 'uses the tsvector column' do
111
+ it "uses the tsvector column" do
94
112
  query = "query"
95
113
  columns = [
96
114
  PgSearch::Configuration::Column.new(:name, nil, Model),
97
115
  PgSearch::Configuration::Column.new(:content, nil, Model)
98
116
  ]
99
- options = { tsvector_column: "my_tsvector" }
100
- config = double(:config, ignore: [])
117
+ options = {tsvector_column: "my_tsvector"}
118
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
101
119
  normalizer = PgSearch::Normalizer.new(config)
102
120
 
103
121
  feature = described_class.new(query, options, columns, Model, normalizer)
104
122
  expect(feature.conditions.to_sql).to eq(
105
- %{((#{Model.quoted_table_name}.\"my_tsvector\") @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))}
123
+ %{((#{Model.quoted_table_name}."my_tsvector") @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))}
106
124
  )
107
125
  end
108
126
  end
109
127
 
110
128
  context "when options[:tsvector_column] is an array of strings" do
111
- it 'uses the tsvector column' do
129
+ it "uses the tsvector column" do
112
130
  query = "query"
113
131
  columns = [
114
132
  PgSearch::Configuration::Column.new(:name, nil, Model),
115
133
  PgSearch::Configuration::Column.new(:content, nil, Model)
116
134
  ]
117
- options = { tsvector_column: ["tsvector1", "tsvector2"] }
118
- config = double(:config, ignore: [])
135
+ options = {tsvector_column: ["tsvector1", "tsvector2"]}
136
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
119
137
  normalizer = PgSearch::Normalizer.new(config)
120
138
 
121
139
  feature = described_class.new(query, options, columns, Model, normalizer)
122
140
  expect(feature.conditions.to_sql).to eq(
123
- %{((#{Model.quoted_table_name}.\"tsvector1\" || #{Model.quoted_table_name}.\"tsvector2\") @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))}
141
+ %{((#{Model.quoted_table_name}."tsvector1" || #{Model.quoted_table_name}."tsvector2") @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))}
124
142
  )
125
143
  end
126
144
  end
@@ -141,17 +159,18 @@ describe PgSearch::Features::TSearch do
141
159
  ]
142
160
  options = {}
143
161
 
144
- config = double(:config, ignore: [])
162
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
145
163
  normalizer = PgSearch::Normalizer.new(config)
146
164
 
147
165
  feature = described_class.new(query, options, columns, Model, normalizer)
148
166
  expect(feature.highlight.to_sql).to eq(
149
- "(ts_headline('simple', (coalesce(#{Model.quoted_table_name}.\"name\"::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), ''))"
167
+ "(ts_headline('simple', (coalesce((#{Model.quoted_table_name}.\"name\")::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), ''))"
150
168
  )
151
169
  end
152
170
 
153
171
  context "when options[:dictionary] is passed" do
154
- it 'uses the provided dictionary' do
172
+ # standard:disable RSpec/ExampleLength
173
+ it "uses the provided dictionary" do
155
174
  query = "query"
156
175
  columns = [
157
176
  PgSearch::Configuration::Column.new(:name, nil, Model),
@@ -165,18 +184,20 @@ describe PgSearch::Features::TSearch do
165
184
  }
166
185
  }
167
186
 
168
- config = double(:config, ignore: [])
187
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
169
188
  normalizer = PgSearch::Normalizer.new(config)
170
189
 
171
190
  feature = described_class.new(query, options, columns, Model, normalizer)
172
191
 
173
- expected_sql = %{(ts_headline('spanish', (coalesce(#{Model.quoted_table_name}."name"::text, '') || ' ' || coalesce(#{Model.quoted_table_name}."content"::text, '')), (to_tsquery('spanish', ''' ' || 'query' || ' ''')), 'StartSel = "<b>", StopSel = "</b>"'))}
192
+ expected_sql = %{(ts_headline('spanish', (coalesce((#{Model.quoted_table_name}."name")::text, '') || ' ' || coalesce((#{Model.quoted_table_name}."content")::text, '')), (to_tsquery('spanish', ''' ' || 'query' || ' ''')), 'StartSel = "<b>", StopSel = "</b>"'))}
174
193
 
175
194
  expect(feature.highlight.to_sql).to eq(expected_sql)
176
195
  end
196
+ # standard:enable RSpec/ExampleLength
177
197
  end
178
198
 
179
199
  context "when options[:highlight] has options set" do
200
+ # standard:disable RSpec/ExampleLength
180
201
  it "passes the options to ts_headline" do
181
202
  query = "query"
182
203
  columns = [
@@ -185,26 +206,28 @@ describe PgSearch::Features::TSearch do
185
206
  options = {
186
207
  highlight: {
187
208
  StartSel: '<start class="search">',
188
- StopSel: '<stop>',
209
+ StopSel: "<stop>",
189
210
  MaxWords: 123,
190
211
  MinWords: 456,
191
212
  ShortWord: 4,
192
213
  HighlightAll: true,
193
214
  MaxFragments: 3,
194
- FragmentDelimiter: '&hellip;'
215
+ FragmentDelimiter: "&hellip;"
195
216
  }
196
217
  }
197
218
 
198
- config = double(:config, ignore: [])
219
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
199
220
  normalizer = PgSearch::Normalizer.new(config)
200
221
 
201
222
  feature = described_class.new(query, options, columns, Model, normalizer)
202
223
 
203
- expected_sql = %{(ts_headline('simple', (coalesce(#{Model.quoted_table_name}."name"::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 'StartSel = "<start class=""search"">", StopSel = "<stop>", MaxFragments = 3, MaxWords = 123, MinWords = 456, ShortWord = 4, FragmentDelimiter = "&hellip;", HighlightAll = TRUE'))}
224
+ expected_sql = %{(ts_headline('simple', (coalesce((#{Model.quoted_table_name}."name")::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 'StartSel = "<start class=""search"">", StopSel = "<stop>", MaxFragments = 3, MaxWords = 123, MinWords = 456, ShortWord = 4, FragmentDelimiter = "&hellip;", HighlightAll = TRUE'))}
204
225
 
205
226
  expect(feature.highlight.to_sql).to eq(expected_sql)
206
227
  end
228
+ # standard:enable RSpec/ExampleLength
207
229
 
230
+ # standard:disable RSpec/ExampleLength
208
231
  it "passes deprecated options to ts_headline" do
209
232
  query = "query"
210
233
  columns = [
@@ -213,26 +236,27 @@ describe PgSearch::Features::TSearch do
213
236
  options = {
214
237
  highlight: {
215
238
  start_sel: '<start class="search">',
216
- stop_sel: '<stop>',
239
+ stop_sel: "<stop>",
217
240
  max_words: 123,
218
241
  min_words: 456,
219
242
  short_word: 4,
220
243
  highlight_all: false,
221
244
  max_fragments: 3,
222
- fragment_delimiter: '&hellip;'
245
+ fragment_delimiter: "&hellip;"
223
246
  }
224
247
  }
225
248
 
226
- config = double(:config, ignore: [])
249
+ config = instance_double(PgSearch::Configuration, :config, ignore: [])
227
250
  normalizer = PgSearch::Normalizer.new(config)
228
251
 
229
252
  feature = described_class.new(query, options, columns, Model, normalizer)
230
253
 
231
- highlight_sql = ActiveSupport::Deprecation.silence { feature.highlight.to_sql }
232
- expected_sql = %{(ts_headline('simple', (coalesce(#{Model.quoted_table_name}."name"::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 'StartSel = "<start class=""search"">", StopSel = "<stop>", MaxFragments = 3, MaxWords = 123, MinWords = 456, ShortWord = 4, FragmentDelimiter = "&hellip;", HighlightAll = FALSE'))}
254
+ highlight_sql = silence_warnings { feature.highlight.to_sql }
255
+ expected_sql = %{(ts_headline('simple', (coalesce((#{Model.quoted_table_name}."name")::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 'StartSel = "<start class=""search"">", StopSel = "<stop>", MaxFragments = 3, MaxWords = 123, MinWords = 456, ShortWord = 4, FragmentDelimiter = "&hellip;", HighlightAll = FALSE'))}
233
256
 
234
257
  expect(highlight_sql).to eq(expected_sql)
235
258
  end
259
+ # standard:enable RSpec/ExampleLength
236
260
  end
237
261
  end
238
262
  end