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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +16 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +18 -0
- data/.travis.yml +17 -23
- data/CHANGELOG.md +7 -0
- data/Gemfile +0 -4
- data/LICENSE +1 -1
- data/README.md +39 -80
- data/Rakefile +8 -2
- data/lib/pg_search.rb +0 -4
- data/lib/pg_search/configuration.rb +0 -4
- data/lib/pg_search/configuration/association.rb +21 -8
- data/lib/pg_search/features/tsearch.rb +6 -29
- data/lib/pg_search/migration/templates/add_pg_search_dmetaphone_support_functions.rb.erb +0 -12
- data/lib/pg_search/normalizer.rb +1 -8
- data/lib/pg_search/scope_options.rb +4 -6
- data/lib/pg_search/version.rb +1 -1
- data/pg_search.gemspec +14 -12
- data/spec/integration/associations_spec.rb +9 -12
- data/spec/integration/pg_search_spec.rb +32 -50
- data/spec/lib/pg_search/configuration/association_spec.rb +96 -34
- data/spec/lib/pg_search/features/trigram_spec.rb +1 -1
- data/spec/lib/pg_search/multisearch/rebuilder_spec.rb +17 -34
- data/spec/lib/pg_search/normalizer_spec.rb +32 -56
- data/spec/spec_helper.rb +2 -2
- data/spec/support/database.rb +21 -33
- metadata +38 -18
- data/lib/pg_search/compatibility.rb +0 -11
- data/lib/pg_search/extensions/arel.rb +0 -10
- data/lib/pg_search/migration/associated_against_generator.rb +0 -11
- data/lib/pg_search/migration/templates/add_pg_search_associated_against_support_functions.rb.erb +0 -21
- data/sql/array_agg.sql +0 -5
- data/sql/uninstall_array_agg.sql +0 -1
- data/sql/uninstall_unnest.sql +0 -1
- data/sql/unnest.sql +0 -8
@@ -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
|
-
(
|
85
|
-
|
61
|
+
(Arel::Nodes.build_quoted('!') if negated),
|
62
|
+
Arel::Nodes.build_quoted("' "),
|
86
63
|
term_sql,
|
87
|
-
|
88
|
-
(
|
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,
|
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
|
-
|
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
|
data/lib/pg_search/normalizer.rb
CHANGED
@@ -4,16 +4,9 @@ module PgSearch
|
|
4
4
|
@config = config
|
5
5
|
end
|
6
6
|
|
7
|
-
def add_normalization(sql_expression)
|
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
|
-
|
176
|
-
|
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
|
data/lib/pg_search/version.rb
CHANGED
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
|
3
|
+
require 'pg_search/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
6
|
+
s.name = 'pg_search'
|
7
7
|
s.version = PgSearch::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = [
|
10
|
-
s.email = [
|
11
|
-
s.homepage =
|
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 = [
|
14
|
+
s.licenses = ['MIT']
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
|
-
s.test_files = `git ls-files --
|
18
|
-
s.require_paths = [
|
17
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
18
|
+
s.require_paths = ['lib']
|
19
19
|
|
20
|
-
s.add_dependency 'activerecord', '>=
|
21
|
-
s.add_dependency 'activesupport', '>=
|
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 =
|
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
|
-
|
333
|
-
|
334
|
-
|
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
|
-
|
338
|
-
|
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
|
-
|
411
|
-
|
412
|
-
loser = ModelWithPgSearch.create!(:content => 'foo', parent_model:
|
413
|
-
winner = ModelWithPgSearch.create!(:content => 'foo foo', parent_model:
|
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
|
-
|
575
|
-
it "
|
576
|
-
|
577
|
-
|
578
|
-
|
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
|
-
|
592
|
-
|
593
|
-
|
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
|
-
|
596
|
-
|
597
|
-
|
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
|
-
|
1108
|
-
|
1109
|
-
|
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
|
-
|
1101
|
+
included = ModelWithPgSearch.create!(:title => "\303\241bcdef")
|
1119
1102
|
|
1120
|
-
|
1121
|
-
|
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.
|
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.
|
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.
|
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 :
|
4
|
+
with_model :Avatar do
|
5
5
|
table do |t|
|
6
|
-
t.string
|
6
|
+
t.string :url
|
7
|
+
t.references :user
|
7
8
|
end
|
8
9
|
end
|
9
10
|
|
10
|
-
with_model :
|
11
|
+
with_model :User do
|
11
12
|
table do |t|
|
12
|
-
t.string
|
13
|
-
t.belongs_to :
|
13
|
+
t.string :name
|
14
|
+
t.belongs_to :site
|
14
15
|
end
|
15
16
|
|
16
17
|
model do
|
17
18
|
include PgSearch
|
18
|
-
|
19
|
+
has_one :avatar, :class_name => "Avatar"
|
20
|
+
belongs_to :site
|
19
21
|
|
20
|
-
pg_search_scope :
|
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
|
-
|
27
|
+
with_model :Site do
|
28
|
+
table do |t|
|
29
|
+
t.string :title
|
30
|
+
end
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
33
|
-
let(:
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
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
|
-
"
|
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
|
-
|
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
|
-
"
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|