/
join_table_matcher.rb
100 lines (82 loc) · 2.71 KB
/
join_table_matcher.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
module Shoulda
module Matchers
module ActiveRecord
module AssociationMatchers
# @private
class JoinTableMatcher
attr_reader :failure_message
alias :missing_option :failure_message
delegate :model_class, :join_table_name, :associated_class, :options,
:name, :option_verifier, to: :association_matcher
delegate :connection, to: :model_class
def initialize(association_matcher, reflector)
@association_matcher = association_matcher
@reflector = reflector
end
def matches?(subject)
join_table_option_correct? &&
join_table_exists? &&
join_table_has_correct_columns?
end
def join_table_option_correct?
if options.key?(:join_table_name)
if option_verifier.correct_for_string?(:join_table, options[:join_table_name])
true
else
@failure_message = "#{name} should use #{options[:join_table_name].inspect} for :join_table option"
false
end
else
true
end
end
def join_table_exists?
if RailsShim.tables_and_views(connection).include?(join_table_name.to_s)
true
else
@failure_message = missing_table_message
false
end
end
def join_table_has_correct_columns?
if missing_columns.empty?
true
else
@failure_message = missing_columns_message
false
end
end
protected
attr_reader :association_matcher, :reflector
private
delegate :foreign_key, :association_foreign_key, to: :reflector
def missing_columns
@missing_columns ||= expected_join_table_columns.select do |key|
!actual_join_table_columns.include?(key.to_s)
end
end
def expected_join_table_columns
[foreign_key, association_foreign_key]
end
def actual_join_table_columns
connection.columns(join_table_name).map(&:name)
end
def missing_table_message
"join table #{join_table_name} doesn't exist"
end
def missing_columns_message
missing = missing_columns.join(', ')
"join table #{join_table_name} missing #{column_label}: #{missing}"
end
def column_label
if missing_columns.count > 1
'columns'
else
'column'
end
end
end
end
end
end
end