pg_search 1.0.6 → 2.0.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.
@@ -1,4 +1,3 @@
1
- require "pg_search/compatibility"
2
1
  require "active_support/core_ext/module/delegation"
3
2
 
4
3
  module PgSearch
@@ -8,12 +7,6 @@ module PgSearch
8
7
  super + [:dictionary, :prefix, :negation, :any_word, :normalization, :tsvector_column, :highlight]
9
8
  end
10
9
 
11
- def initialize(*args)
12
- super
13
- checks_for_highlight
14
- checks_for_prefix
15
- end
16
-
17
10
  def conditions
18
11
  Arel::Nodes::Grouping.new(
19
12
  Arel::Nodes::InfixOperation.new("@@", arel_wrap(tsdocument), arel_wrap(tsquery))
@@ -30,22 +23,6 @@ module PgSearch
30
23
 
31
24
  private
32
25
 
33
- def checks_for_prefix
34
- if options[:prefix] && model.connection.send(:postgresql_version) < 80400
35
- raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
36
- Sorry, {:using => {:tsearch => {:prefix => true}}} only works in PostgreSQL 8.4 and above.")
37
- MESSAGE
38
- end
39
- end
40
-
41
- def checks_for_highlight
42
- if options[:highlight] && model.connection.send(:postgresql_version) < 90000
43
- raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
44
- Sorry, {:using => {:tsearch => {:highlight => true}}} only works in PostgreSQL 9.0 and above.")
45
- MESSAGE
46
- end
47
- end
48
-
49
26
  def ts_headline
50
27
  "ts_headline((#{document}), (#{tsquery}), '#{ts_headline_options}')"
51
28
  end
@@ -81,15 +58,15 @@ module PgSearch
81
58
  # If :prefix is true, then the term will have :* appended to the end.
82
59
  # If :negated is true, then the term will have ! prepended to the front.
83
60
  terms = [
84
- (Compatibility.build_quoted('!') if negated),
85
- Compatibility.build_quoted("' "),
61
+ (Arel::Nodes.build_quoted('!') if negated),
62
+ Arel::Nodes.build_quoted("' "),
86
63
  term_sql,
87
- Compatibility.build_quoted(" '"),
88
- (Compatibility.build_quoted(":*") if options[:prefix])
64
+ Arel::Nodes.build_quoted(" '"),
65
+ (Arel::Nodes.build_quoted(":*") if options[:prefix])
89
66
  ].compact
90
67
 
91
68
  tsquery_sql = terms.inject do |memo, term|
92
- Arel::Nodes::InfixOperation.new("||", memo, Compatibility.build_quoted(term))
69
+ Arel::Nodes::InfixOperation.new("||", memo, Arel::Nodes.build_quoted(term))
93
70
  end
94
71
 
95
72
  Arel::Nodes::NamedFunction.new(
@@ -141,7 +118,7 @@ module PgSearch
141
118
  end
142
119
 
143
120
  def dictionary
144
- Compatibility.build_quoted(options[:dictionary] || :simple)
121
+ Arel::Nodes.build_quoted(options[:dictionary] || :simple)
145
122
  end
146
123
 
147
124
  def arel_wrap(sql_string)
@@ -1,12 +1,6 @@
1
1
  class AddPgSearchDmetaphoneSupportFunctions < ActiveRecord::Migration
2
2
  def self.up
3
3
  say_with_time("Adding support functions for pg_search :dmetaphone") do
4
- if ActiveRecord::Base.connection.send(:postgresql_version) < 80400
5
- execute <<-'SQL'
6
- <%= read_sql_file "unnest" %>
7
- SQL
8
- end
9
-
10
4
  execute <<-'SQL'
11
5
  <%= read_sql_file "dmetaphone" %>
12
6
  SQL
@@ -18,12 +12,6 @@ class AddPgSearchDmetaphoneSupportFunctions < ActiveRecord::Migration
18
12
  execute <<-'SQL'
19
13
  <%= read_sql_file "uninstall_dmetaphone" %>
20
14
  SQL
21
-
22
- if ActiveRecord::Base.connection.send(:postgresql_version) < 80400
23
- execute <<-'SQL'
24
- <%= read_sql_file "uninstall_unnest" %>
25
- SQL
26
- end
27
15
  end
28
16
  end
29
17
  end
@@ -4,16 +4,9 @@ module PgSearch
4
4
  @config = config
5
5
  end
6
6
 
7
- def add_normalization(sql_expression) # rubocop:disable Metrics/AbcSize
7
+ def add_normalization(sql_expression)
8
8
  return sql_expression unless config.ignore.include?(:accents)
9
9
 
10
- if config.postgresql_version < 90000
11
- raise PgSearch::NotSupportedForPostgresqlVersion.new(<<-MESSAGE.strip_heredoc)
12
- Sorry, {:ignoring => :accents} only works in PostgreSQL 9.0 and above.
13
- #{config.inspect}
14
- MESSAGE
15
- end
16
-
17
10
  sql_node = case sql_expression
18
11
  when Arel::Nodes::Node
19
12
  sql_expression
@@ -79,6 +79,7 @@ module PgSearch
79
79
  private
80
80
 
81
81
  attr_writer :pg_search_scope_application_count
82
+
82
83
  def pg_search_scope_application_count
83
84
  @pg_search_scope_application_count ||= 0
84
85
  end
@@ -171,12 +172,9 @@ module PgSearch
171
172
  end
172
173
 
173
174
  def include_table_aliasing_for_rank(scope)
174
- if scope.included_modules.include?(PgSearchRankTableAliasing)
175
- scope
176
- else
177
- (::ActiveRecord::VERSION::MAJOR < 4 ? scope.scoped : scope.all.spawn).tap do |new_scope|
178
- new_scope.class_eval { include PgSearchRankTableAliasing }
179
- end
175
+ return scope if scope.included_modules.include?(PgSearchRankTableAliasing)
176
+ scope.all.spawn.tap do |new_scope|
177
+ new_scope.class_eval { include PgSearchRankTableAliasing }
180
178
  end
181
179
  end
182
180
  end
@@ -1,3 +1,3 @@
1
1
  module PgSearch
2
- VERSION = "1.0.6".freeze
2
+ VERSION = "2.0.0".freeze
3
3
  end
data/pg_search.gemspec CHANGED
@@ -1,31 +1,33 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
- require "pg_search/version"
3
+ require 'pg_search/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "pg_search"
6
+ s.name = 'pg_search'
7
7
  s.version = PgSearch::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Grant Hutchins", "Case Commons, LLC"]
10
- s.email = ["gems@nertzy.com", "casecommons-dev@googlegroups.com"]
11
- s.homepage = "https://github.com/Casecommons/pg_search"
9
+ s.authors = ['Grant Hutchins', 'Case Commons, LLC']
10
+ s.email = %w[gems@nertzy.com casecommons-dev@googlegroups.com]
11
+ s.homepage = 'https://github.com/Casecommons/pg_search'
12
12
  s.summary = %q(PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search)
13
13
  s.description = %q(PgSearch builds Active Record named scopes that take advantage of PostgreSQL's full text search)
14
- s.licenses = ["MIT"]
14
+ s.licenses = ['MIT']
15
15
 
16
16
  s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.require_paths = ["lib"]
17
+ s.test_files = `git ls-files -- spec/*`.split("\n")
18
+ s.require_paths = ['lib']
19
19
 
20
- s.add_dependency 'activerecord', '>= 3.1'
21
- s.add_dependency 'activesupport', '>= 3.1'
22
- s.add_dependency 'arel'
20
+ s.add_dependency 'activerecord', '>= 4.2'
21
+ s.add_dependency 'activesupport', '>= 4.2'
22
+ s.add_dependency 'arel', '>= 6'
23
23
 
24
24
  s.add_development_dependency 'rake'
25
25
  s.add_development_dependency 'pry'
26
26
  s.add_development_dependency 'rspec', '>= 3.3'
27
27
  s.add_development_dependency 'with_model', '>= 1.2'
28
28
  s.add_development_dependency 'rubocop', '>= 0.36'
29
+ s.add_development_dependency 'codeclimate-test-reporter'
30
+ s.add_development_dependency 'simplecov'
29
31
 
30
- s.required_ruby_version = ">= 1.9.2"
32
+ s.required_ruby_version = '>= 2.1'
31
33
  end
@@ -12,7 +12,7 @@ describe PgSearch do
12
12
  with_model :ModelWithoutAgainst do
13
13
  table do |t|
14
14
  t.string "title"
15
- t.belongs_to :another_model
15
+ t.belongs_to :another_model, :index => false
16
16
  end
17
17
 
18
18
  model do
@@ -49,7 +49,7 @@ describe PgSearch do
49
49
  with_model :ModelWithBelongsTo do
50
50
  table do |t|
51
51
  t.string 'title'
52
- t.belongs_to 'another_model'
52
+ t.belongs_to 'another_model', index: false
53
53
  end
54
54
 
55
55
  model do
@@ -79,7 +79,7 @@ describe PgSearch do
79
79
  with_model :AssociatedModelWithHasMany do
80
80
  table do |t|
81
81
  t.string 'title'
82
- t.belongs_to 'ModelWithHasMany'
82
+ t.belongs_to 'ModelWithHasMany', index: false
83
83
  end
84
84
  end
85
85
 
@@ -144,22 +144,20 @@ describe PgSearch do
144
144
  with_model :FirstAssociatedModel do
145
145
  table do |t|
146
146
  t.string 'title'
147
- t.belongs_to 'ModelWithManyAssociations'
147
+ t.belongs_to 'ModelWithManyAssociations', index: false
148
148
  end
149
- model {}
150
149
  end
151
150
 
152
151
  with_model :SecondAssociatedModel do
153
152
  table do |t|
154
153
  t.string 'title'
155
154
  end
156
- model {}
157
155
  end
158
156
 
159
157
  with_model :ModelWithManyAssociations do
160
158
  table do |t|
161
159
  t.string 'title'
162
- t.belongs_to 'model_of_second_type'
160
+ t.belongs_to 'model_of_second_type', index: false
163
161
  end
164
162
 
165
163
  model do
@@ -211,10 +209,9 @@ describe PgSearch do
211
209
  with_model :DoublyAssociatedModel do
212
210
  table do |t|
213
211
  t.string 'title'
214
- t.belongs_to 'ModelWithDoubleAssociation'
215
- t.belongs_to 'ModelWithDoubleAssociation_again'
212
+ t.belongs_to 'ModelWithDoubleAssociation', index: false
213
+ t.belongs_to 'ModelWithDoubleAssociation_again', index: false
216
214
  end
217
- model {}
218
215
  end
219
216
 
220
217
  with_model :ModelWithDoubleAssociation do
@@ -279,7 +276,7 @@ describe PgSearch do
279
276
 
280
277
  with_model :ModelWithAssociation do
281
278
  table do |t|
282
- t.belongs_to 'another_model'
279
+ t.belongs_to 'another_model', index: false
283
280
  end
284
281
 
285
282
  model do
@@ -406,7 +403,7 @@ describe PgSearch do
406
403
  with_model :AssociatedModel do
407
404
  table do |t|
408
405
  t.string :content
409
- t.belongs_to :model_with_association
406
+ t.belongs_to :model_with_association, index: false
410
407
  end
411
408
 
412
409
  model do
@@ -329,14 +329,12 @@ describe "an Active Record model which includes PgSearch" do
329
329
  expect(returned_record.attributes).to eq("id" => record.id)
330
330
  end
331
331
 
332
- unless ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 2
333
- it "supports #pluck" do
334
- record = ModelWithPgSearch.create!(:content => 'foo')
335
- other_record = ModelWithPgSearch.create!(:content => 'bar')
332
+ it "supports #pluck" do
333
+ record = ModelWithPgSearch.create!(:content => 'foo')
334
+ other_record = ModelWithPgSearch.create!(:content => 'bar')
336
335
 
337
- ids = ModelWithPgSearch.search_content('foo').pluck('id')
338
- expect(ids).to eq [record.id]
339
- end
336
+ ids = ModelWithPgSearch.search_content('foo').pluck('id')
337
+ expect(ids).to eq [record.id]
340
338
  end
341
339
 
342
340
  it "supports adding where clauses using the pg_search.rank" do
@@ -407,10 +405,10 @@ describe "an Active Record model which includes PgSearch" do
407
405
  end
408
406
 
409
407
  it 'allows pg_search_rank along with a join' do
410
- parent1 = ParentModel.create!(id: 98)
411
- parent2 = ParentModel.create!(id: 99)
412
- loser = ModelWithPgSearch.create!(:content => 'foo', parent_model: parent2)
413
- winner = ModelWithPgSearch.create!(:content => 'foo foo', parent_model: parent1)
408
+ parent_1 = ParentModel.create!(id: 98)
409
+ parent_2 = ParentModel.create!(id: 99)
410
+ loser = ModelWithPgSearch.create!(:content => 'foo', parent_model: parent_2)
411
+ winner = ModelWithPgSearch.create!(:content => 'foo foo', parent_model: parent_1)
414
412
 
415
413
  results = ModelWithPgSearch.joins(:parent_model).merge(ParentModel.active).search_content("foo").with_pg_search_rank
416
414
  expect(results.map(&:id)).to eq [winner.id, loser.id]
@@ -571,31 +569,23 @@ describe "an Active Record model which includes PgSearch" do
571
569
  }
572
570
  end
573
571
 
574
- if ActiveRecord::Base.connection.send(:postgresql_version) < 80400
575
- it "is unsupported in PostgreSQL 8.3 and earlier" do
576
- expect {
577
- ModelWithPgSearch.search_title_with_prefixes("abcd\303\251f")
578
- }.to raise_exception(PgSearch::NotSupportedForPostgresqlVersion)
572
+ context "with :prefix => true" do
573
+ it "returns rows that match the query and that are prefixed by the query" do
574
+ included = ModelWithPgSearch.create!(:title => 'prefix')
575
+ excluded = ModelWithPgSearch.create!(:title => 'postfix')
576
+
577
+ results = ModelWithPgSearch.search_title_with_prefixes("pre")
578
+ expect(results).to eq([included])
579
+ expect(results).not_to include(excluded)
579
580
  end
580
- else
581
- context "with :prefix => true" do
582
- it "returns rows that match the query and that are prefixed by the query" do
583
- included = ModelWithPgSearch.create!(:title => 'prefix')
584
- excluded = ModelWithPgSearch.create!(:title => 'postfix')
585
-
586
- results = ModelWithPgSearch.search_title_with_prefixes("pre")
587
- expect(results).to eq([included])
588
- expect(results).not_to include(excluded)
589
- end
590
581
 
591
- it "returns rows that match the query when the query has a hyphen" do
592
- included = ModelWithPgSearch.create!(:title => 'foo-bar')
593
- excluded = ModelWithPgSearch.create!(:title => 'foo bar')
582
+ it "returns rows that match the query when the query has a hyphen" do
583
+ included = ModelWithPgSearch.create!(:title => 'foo-bar')
584
+ excluded = ModelWithPgSearch.create!(:title => 'foo bar')
594
585
 
595
- results = ModelWithPgSearch.search_title_with_prefixes("foo-bar")
596
- expect(results).to include(included)
597
- expect(results).not_to include(excluded)
598
- end
586
+ results = ModelWithPgSearch.search_title_with_prefixes("foo-bar")
587
+ expect(results).to include(included)
588
+ expect(results).not_to include(excluded)
599
589
  end
600
590
  end
601
591
 
@@ -1104,22 +1094,14 @@ describe "an Active Record model which includes PgSearch" do
1104
1094
  :ignoring => :accents
1105
1095
  end
1106
1096
 
1107
- if ActiveRecord::Base.connection.send(:postgresql_version) < 90000
1108
- it "is unsupported in PostgreSQL 8.x" do
1109
- expect {
1110
- ModelWithPgSearch.search_title_without_accents("abcd\303\251f")
1111
- }.to raise_exception(PgSearch::NotSupportedForPostgresqlVersion)
1112
- end
1113
- else
1114
- it "returns rows that match the query but not its accents" do
1115
- # \303\241 is a with acute accent
1116
- # \303\251 is e with acute accent
1097
+ it "returns rows that match the query but not its accents" do
1098
+ # \303\241 is a with acute accent
1099
+ # \303\251 is e with acute accent
1117
1100
 
1118
- included = ModelWithPgSearch.create!(:title => "\303\241bcdef")
1101
+ included = ModelWithPgSearch.create!(:title => "\303\241bcdef")
1119
1102
 
1120
- results = ModelWithPgSearch.search_title_without_accents("abcd\303\251f")
1121
- expect(results).to eq([included])
1122
- end
1103
+ results = ModelWithPgSearch.search_title_without_accents("abcd\303\251f")
1104
+ expect(results).to eq([included])
1123
1105
  end
1124
1106
  end
1125
1107
 
@@ -1222,7 +1204,7 @@ describe "an Active Record model which includes PgSearch" do
1222
1204
  twice = ModelWithPgSearch.create!(:content => 'foo foo')
1223
1205
 
1224
1206
  results = ModelWithPgSearch.search_content_ranked_by_tsearch('foo')
1225
- expect(results.index(twice)).to be < results.index(once)
1207
+ expect(results.find_index(twice)).to be < results.find_index(once)
1226
1208
  end
1227
1209
  end
1228
1210
 
@@ -1237,7 +1219,7 @@ describe "an Active Record model which includes PgSearch" do
1237
1219
  exact = ModelWithPgSearch.create!(:content => 'abc')
1238
1220
 
1239
1221
  results = ModelWithPgSearch.search_content_ranked_by_trigram('abc')
1240
- expect(results.index(exact)).to be < results.index(close)
1222
+ expect(results.find_index(exact)).to be < results.find_index(close)
1241
1223
  end
1242
1224
  end
1243
1225
 
@@ -1252,7 +1234,7 @@ describe "an Active Record model which includes PgSearch" do
1252
1234
  twice = ModelWithPgSearch.create!(:content => 'Phoo Fu')
1253
1235
 
1254
1236
  results = ModelWithPgSearch.search_content_ranked_by_dmetaphone('foo')
1255
- expect(results.index(twice)).to be < results.index(once)
1237
+ expect(results.find_index(twice)).to be < results.find_index(once)
1256
1238
  end
1257
1239
  end
1258
1240
  end
@@ -1,76 +1,138 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe PgSearch::Configuration::Association do
4
- with_model :AssociatedModel do
4
+ with_model :Avatar do
5
5
  table do |t|
6
- t.string "title"
6
+ t.string :url
7
+ t.references :user
7
8
  end
8
9
  end
9
10
 
10
- with_model :Model do
11
+ with_model :User do
11
12
  table do |t|
12
- t.string "title"
13
- t.belongs_to :another_model
13
+ t.string :name
14
+ t.belongs_to :site
14
15
  end
15
16
 
16
17
  model do
17
18
  include PgSearch
18
- belongs_to :another_model, :class_name => 'AssociatedModel'
19
+ has_one :avatar, :class_name => "Avatar"
20
+ belongs_to :site
19
21
 
20
- pg_search_scope :with_another, :associated_against => {:another_model => :title}
22
+ pg_search_scope :with_avatar, :associated_against => {:avatar => :url}
23
+ pg_search_scope :with_site, :associated_against => {:site => :title}
21
24
  end
22
25
  end
23
26
 
24
- let(:association) { described_class.new(Model, :another_model, :title) }
27
+ with_model :Site do
28
+ table do |t|
29
+ t.string :title
30
+ end
25
31
 
26
- describe "#table_name" do
27
- it "returns the table name for the associated model" do
28
- expect(association.table_name).to eq AssociatedModel.table_name
32
+ model do
33
+ include PgSearch
34
+ has_many :users, :class_name => "User"
35
+
36
+ pg_search_scope :with_users, :associated_against => {:users => :name}
29
37
  end
30
38
  end
31
39
 
32
- describe "#join" do
33
- let(:expected_sql) do
34
- <<-EOS.gsub(/\s+/, ' ').strip
35
- LEFT OUTER JOIN
36
- (SELECT model_id AS id,
37
- #{column_select} AS #{association.columns.first.alias}
38
- FROM \"#{Model.table_name}\"
39
- INNER JOIN \"#{association.table_name}\"
40
- ON \"#{association.table_name}\".\"id\" = \"#{Model.table_name}\".\"another_model_id\"
41
- GROUP BY model_id) #{association.subselect_alias}
42
- ON #{association.subselect_alias}.id = model_id
43
- EOS
40
+ context "has_one" do
41
+ let(:association) { described_class.new(User, :avatar, :url) }
42
+
43
+ describe "#table_name" do
44
+ it "returns the table name for the associated model" do
45
+ expect(association.table_name).to eq Avatar.table_name
46
+ end
44
47
  end
45
48
 
46
- context "given postgresql_version 0..90_000" do
49
+ describe "#join" do
50
+ let(:expected_sql) do
51
+ <<-EOS.gsub(/\s+/, ' ').strip
52
+ LEFT OUTER JOIN
53
+ (SELECT model_id AS id,
54
+ #{column_select} AS #{association.columns.first.alias}
55
+ FROM \"#{User.table_name}\"
56
+ INNER JOIN \"#{association.table_name}\"
57
+ ON \"#{association.table_name}\".\"user_id\" = \"#{User.table_name}\".\"id\") #{association.subselect_alias}
58
+ ON #{association.subselect_alias}.id = model_id
59
+ EOS
60
+ end
47
61
  let(:column_select) do
48
- "array_to_string(array_agg(\"#{association.table_name}\".\"title\"::text), ' ')"
62
+ "\"#{association.table_name}\".\"url\"::text"
49
63
  end
50
64
 
51
65
  it "returns the correct SQL join" do
52
- allow(Model.connection).to receive(:postgresql_version).and_return(1)
53
66
  expect(association.join("model_id")).to eq(expected_sql)
54
67
  end
55
68
  end
69
+ end
70
+
71
+ context "belongs_to" do
72
+ let(:association) { described_class.new(User, :site, :title) }
73
+
74
+ describe "#table_name" do
75
+ it "returns the table name for the associated model" do
76
+ expect(association.table_name).to eq Site.table_name
77
+ end
78
+ end
56
79
 
57
- context "given any other postgresql_version" do
80
+ describe "#join" do
81
+ let(:expected_sql) do
82
+ <<-EOS.gsub(/\s+/, ' ').strip
83
+ LEFT OUTER JOIN
84
+ (SELECT model_id AS id,
85
+ #{column_select} AS #{association.columns.first.alias}
86
+ FROM \"#{User.table_name}\"
87
+ INNER JOIN \"#{association.table_name}\"
88
+ ON \"#{association.table_name}\".\"id\" = \"#{User.table_name}\".\"site_id\") #{association.subselect_alias}
89
+ ON #{association.subselect_alias}.id = model_id
90
+ EOS
91
+ end
58
92
  let(:column_select) do
59
- "string_agg(\"#{association.table_name}\".\"title\"::text, ' ')"
93
+ "\"#{association.table_name}\".\"title\"::text"
60
94
  end
61
95
 
62
96
  it "returns the correct SQL join" do
63
- allow(Model.connection).to receive(:postgresql_version).and_return(100_000)
64
97
  expect(association.join("model_id")).to eq(expected_sql)
65
98
  end
66
99
  end
67
100
  end
68
101
 
69
- describe "#subselect_alias" do
70
- it "returns a consistent string" do
71
- subselect_alias = association.subselect_alias
72
- expect(subselect_alias).to be_a String
73
- expect(association.subselect_alias).to eq subselect_alias
102
+ context "has_many" do
103
+ let(:association) { described_class.new(Site, :users, :name) }
104
+
105
+ describe "#table_name" do
106
+ it "returns the table name for the associated model" do
107
+ expect(association.table_name).to eq User.table_name
108
+ end
109
+ end
110
+
111
+ describe "#join" do
112
+ let(:expected_sql) do
113
+ <<-EOS.gsub(/\s+/, ' ').strip
114
+ LEFT OUTER JOIN
115
+ (SELECT model_id AS id,
116
+ string_agg(\"#{association.table_name}\".\"name\"::text, ' ') AS #{association.columns.first.alias}
117
+ FROM \"#{Site.table_name}\"
118
+ INNER JOIN \"#{association.table_name}\"
119
+ ON \"#{association.table_name}\".\"site_id\" = \"#{Site.table_name}\".\"id\"
120
+ GROUP BY model_id) #{association.subselect_alias}
121
+ ON #{association.subselect_alias}.id = model_id
122
+ EOS
123
+ end
124
+
125
+ it "returns the correct SQL join" do
126
+ expect(association.join("model_id")).to eq(expected_sql)
127
+ end
128
+
129
+ describe "#subselect_alias" do
130
+ it "returns a consistent string" do
131
+ subselect_alias = association.subselect_alias
132
+ expect(subselect_alias).to be_a String
133
+ expect(association.subselect_alias).to eq subselect_alias
134
+ end
135
+ end
74
136
  end
75
137
  end
76
138
  end