composite_primary_keys 3.1.11 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -8
- data/lib/composite_primary_keys.rb +53 -36
- data/lib/composite_primary_keys/associations/association.rb +23 -0
- data/lib/composite_primary_keys/associations/association_scope.rb +67 -0
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +31 -121
- data/lib/composite_primary_keys/associations/has_many_association.rb +27 -66
- data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +22 -0
- data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +39 -0
- data/lib/composite_primary_keys/associations/preloader/association.rb +61 -0
- data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +13 -0
- data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +46 -0
- data/lib/composite_primary_keys/attribute_methods/dirty.rb +30 -0
- data/lib/composite_primary_keys/attribute_methods/read.rb +88 -0
- data/lib/composite_primary_keys/attribute_methods/write.rb +33 -0
- data/lib/composite_primary_keys/base.rb +18 -70
- data/lib/composite_primary_keys/composite_predicates.rb +53 -0
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +6 -4
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +19 -41
- data/lib/composite_primary_keys/fixtures.rb +19 -6
- data/lib/composite_primary_keys/persistence.rb +32 -13
- data/lib/composite_primary_keys/relation.rb +23 -16
- data/lib/composite_primary_keys/relation/calculations.rb +48 -0
- data/lib/composite_primary_keys/relation/finder_methods.rb +117 -0
- data/lib/composite_primary_keys/relation/query_methods.rb +24 -0
- data/lib/composite_primary_keys/validations/uniqueness.rb +19 -23
- data/lib/composite_primary_keys/version.rb +5 -5
- data/test/connections/native_mysql/connection.rb +1 -1
- data/test/fixtures/articles.yml +1 -0
- data/test/fixtures/products.yml +2 -4
- data/test/fixtures/readings.yml +1 -0
- data/test/fixtures/suburbs.yml +1 -4
- data/test/fixtures/users.yml +1 -0
- data/test/test_associations.rb +61 -63
- data/test/test_attributes.rb +16 -21
- data/test/test_create.rb +3 -3
- data/test/test_delete.rb +87 -84
- data/test/{test_clone.rb → test_dup.rb} +8 -5
- data/test/test_exists.rb +22 -10
- data/test/test_habtm.rb +0 -74
- data/test/test_ids.rb +2 -1
- data/test/test_miscellaneous.rb +2 -2
- data/test/test_polymorphic.rb +1 -1
- data/test/test_suite.rb +1 -1
- data/test/test_update.rb +3 -3
- metadata +76 -75
- data/lib/composite_primary_keys/association_preload.rb +0 -158
- data/lib/composite_primary_keys/associations.rb +0 -155
- data/lib/composite_primary_keys/associations/association_proxy.rb +0 -33
- data/lib/composite_primary_keys/associations/has_one_association.rb +0 -27
- data/lib/composite_primary_keys/associations/through_association_scope.rb +0 -103
- data/lib/composite_primary_keys/attribute_methods.rb +0 -84
- data/lib/composite_primary_keys/calculations.rb +0 -31
- data/lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb +0 -21
- data/lib/composite_primary_keys/connection_adapters/oracle_adapter.rb +0 -15
- data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +0 -17
- data/lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb +0 -15
- data/lib/composite_primary_keys/finder_methods.rb +0 -123
- data/lib/composite_primary_keys/primary_key.rb +0 -19
- data/lib/composite_primary_keys/query_methods.rb +0 -24
- data/lib/composite_primary_keys/read.rb +0 -25
- data/lib/composite_primary_keys/reflection.rb +0 -37
- data/lib/composite_primary_keys/write.rb +0 -18
@@ -1,158 +0,0 @@
|
|
1
|
-
module CompositePrimaryKeys
|
2
|
-
module ActiveRecord
|
3
|
-
module AssociationPreload
|
4
|
-
def self.append_features(base)
|
5
|
-
super
|
6
|
-
base.send(:extend, ClassMethods)
|
7
|
-
end
|
8
|
-
|
9
|
-
# Composite key versions of Association functions
|
10
|
-
module ClassMethods
|
11
|
-
def preload_has_and_belongs_to_many_association(records, reflection, preload_options={})
|
12
|
-
table_name = reflection.klass.quoted_table_name
|
13
|
-
id_to_record_map, ids = construct_id_map(records)
|
14
|
-
records.each {|record| record.send(reflection.name).loaded}
|
15
|
-
options = reflection.options
|
16
|
-
|
17
|
-
if composite?
|
18
|
-
where = (primary_key * ids.size).in_groups_of(primary_key.size).map do |keys|
|
19
|
-
"(" + keys.map{|key| "t0.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
|
20
|
-
end.join(" OR ")
|
21
|
-
|
22
|
-
conditions = [where, ids].flatten
|
23
|
-
joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{full_composite_join_clause(reflection, reflection.klass.table_name, reflection.klass.primary_key, 't0', reflection.association_foreign_key)}"
|
24
|
-
parent_primary_keys = reflection.cpk_primary_key.map{|k| "t0.#{connection.quote_column_name(k)}"}
|
25
|
-
concat_arr = parent_primary_keys.zip(["'#{CompositePrimaryKeys::ID_SEP}'"] * (parent_primary_keys.size - 1)).flatten.compact
|
26
|
-
parent_record_id = connection.concat(*concat_arr)
|
27
|
-
else
|
28
|
-
conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}"
|
29
|
-
conditions << append_conditions(reflection, preload_options)
|
30
|
-
conditions = [conditions, ids]
|
31
|
-
joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}"
|
32
|
-
parent_record_id = reflection.primary_key_name
|
33
|
-
end
|
34
|
-
|
35
|
-
associated_records = reflection.klass.unscoped.where(conditions).
|
36
|
-
includes(options[:include]).
|
37
|
-
joins(joins).
|
38
|
-
select("#{options[:select] || table_name+'.*'}, #{parent_record_id} as the_parent_record_id").
|
39
|
-
order(options[:order]).to_a
|
40
|
-
|
41
|
-
set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'the_parent_record_id')
|
42
|
-
end
|
43
|
-
|
44
|
-
def preload_belongs_to_association(records, reflection, preload_options={})
|
45
|
-
return if records.first.send("loaded_#{reflection.name}?")
|
46
|
-
options = reflection.options
|
47
|
-
|
48
|
-
ids = Array.new
|
49
|
-
|
50
|
-
if options[:polymorphic]
|
51
|
-
# CPK
|
52
|
-
#polymorph_type = options[:foreign_type]
|
53
|
-
#klasses_and_ids = {}
|
54
|
-
|
55
|
-
# Construct a mapping from klass to a list of ids to load and a mapping of those ids back to their parent_records
|
56
|
-
#records.each do |record|
|
57
|
-
# if klass = record.send(polymorph_type)
|
58
|
-
# klass_id = record.send(primary_key_name)
|
59
|
-
# if klass_id
|
60
|
-
# id_map = klasses_and_ids[klass] ||= {}
|
61
|
-
# id_list_for_klass_id = (id_map[klass_id.to_s] ||= [])
|
62
|
-
# id_list_for_klass_id << record
|
63
|
-
# end
|
64
|
-
# end
|
65
|
-
#end
|
66
|
-
#klasses_and_ids = klasses_and_ids.to_a
|
67
|
-
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
68
|
-
else
|
69
|
-
# I need to keep the original ids for each record (as opposed to the stringified) so
|
70
|
-
# that they get properly converted for each db so the id_map ends up looking like:
|
71
|
-
#
|
72
|
-
# { '1,2' => {:id => [1,2], :records => [...records...]}}
|
73
|
-
id_map = {}
|
74
|
-
|
75
|
-
records.each do |record|
|
76
|
-
keys = record[reflection.cpk_primary_key]
|
77
|
-
ids << keys
|
78
|
-
|
79
|
-
mapped_records = (id_map[keys.to_s] ||= [])
|
80
|
-
mapped_records << record
|
81
|
-
end
|
82
|
-
|
83
|
-
klasses_and_ids = [[reflection.klass.name, id_map]]
|
84
|
-
end
|
85
|
-
|
86
|
-
klasses_and_ids.each do |klass_and_id|
|
87
|
-
klass_name, id_map = *klass_and_id
|
88
|
-
next if id_map.empty?
|
89
|
-
klass = klass_name.constantize
|
90
|
-
|
91
|
-
table_name = klass.quoted_table_name
|
92
|
-
primary_key = [reflection.options[:primary_key] || klass.primary_key].flatten
|
93
|
-
|
94
|
-
# CPK
|
95
|
-
conditions = id_map.map do |key, value|
|
96
|
-
"(" +
|
97
|
-
primary_key.map do |key|
|
98
|
-
"#{table_name}.#{connection.quote_column_name(key)} = ?"
|
99
|
-
end.join(' AND ') + ")"
|
100
|
-
end.join(' OR ')
|
101
|
-
|
102
|
-
conditions << append_conditions(reflection, preload_options)
|
103
|
-
|
104
|
-
conditions = [conditions] + ids.uniq.flatten
|
105
|
-
|
106
|
-
associated_records = klass.unscoped.where(conditions).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a
|
107
|
-
|
108
|
-
set_association_single_records(id_map, reflection.name, associated_records, primary_key)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def find_associated_records(ids, reflection, preload_options)
|
113
|
-
options = reflection.options
|
114
|
-
table_name = reflection.klass.quoted_table_name
|
115
|
-
|
116
|
-
if interface = reflection.options[:as]
|
117
|
-
conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'"
|
118
|
-
else
|
119
|
-
foreign_key = reflection.cpk_primary_key
|
120
|
-
|
121
|
-
where = (foreign_key * ids.size).in_groups_of(foreign_key.size).map do |keys|
|
122
|
-
"(" + keys.map{|key| "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
|
123
|
-
end.join(" OR ")
|
124
|
-
|
125
|
-
conditions = [where, ids].flatten
|
126
|
-
end
|
127
|
-
|
128
|
-
conditions[0] << append_conditions(reflection, preload_options)
|
129
|
-
|
130
|
-
find_options = {
|
131
|
-
:select => preload_options[:select] || options[:select] || "#{table_name}.*",
|
132
|
-
:include => preload_options[:include] || options[:include],
|
133
|
-
# CPK
|
134
|
-
# :conditions => [conditions, ids],
|
135
|
-
:conditions => conditions,
|
136
|
-
:joins => options[:joins],
|
137
|
-
:group => preload_options[:group] || options[:group],
|
138
|
-
:order => preload_options[:order] || options[:order]
|
139
|
-
}
|
140
|
-
|
141
|
-
reflection.klass.unscoped.apply_finder_options(find_options).to_a
|
142
|
-
end
|
143
|
-
|
144
|
-
def full_composite_join_clause(reflection, table1, full_keys1, table2, full_keys2)
|
145
|
-
connection = reflection.active_record.connection
|
146
|
-
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
|
147
|
-
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
|
148
|
-
where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
|
149
|
-
quoted1 = connection.quote_table_name(table1)
|
150
|
-
quoted2 = connection.quote_table_name(table2)
|
151
|
-
"#{quoted1}.#{connection.quote_column_name(key_pair.first)}=#{quoted2}.#{connection.quote_column_name(key_pair.last)}"
|
152
|
-
end.join(" AND ")
|
153
|
-
"(#{where_clause})"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
@@ -1,155 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Associations
|
3
|
-
module ClassMethods
|
4
|
-
class JoinDependency
|
5
|
-
class JoinBase
|
6
|
-
def aliased_primary_key
|
7
|
-
# CPK
|
8
|
-
# "#{aliased_prefix}_r0"
|
9
|
-
|
10
|
-
active_record.composite? ?
|
11
|
-
primary_key.inject([]) {|aliased_keys, key| aliased_keys << "#{ aliased_prefix }_r#{aliased_keys.length}"} :
|
12
|
-
"#{ aliased_prefix }_r0"
|
13
|
-
end
|
14
|
-
|
15
|
-
def record_id(row)
|
16
|
-
# CPK
|
17
|
-
# row[aliased_primary_key]
|
18
|
-
active_record.composite? ?
|
19
|
-
aliased_primary_key.map {|key| row[key]}.to_composite_keys :
|
20
|
-
row[aliased_primary_key]
|
21
|
-
end
|
22
|
-
|
23
|
-
def column_names_with_alias
|
24
|
-
unless defined?(@column_names_with_alias)
|
25
|
-
@column_names_with_alias = []
|
26
|
-
keys = active_record.composite? ? primary_key.map(&:to_s) : [primary_key]
|
27
|
-
(keys + (column_names - keys)).each_with_index do |column_name, i|
|
28
|
-
@column_names_with_alias << [column_name, "#{ aliased_prefix }_r#{ i }"]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
@column_names_with_alias
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
class JoinAssociation
|
36
|
-
# Ugly to include this twice, but I couldn't figure out how to make this
|
37
|
-
# work via a module
|
38
|
-
def composite_join_predicates(table1, keys1, table2, keys2)
|
39
|
-
attributes1 = [keys1].flatten.map do |key|
|
40
|
-
table1[key]
|
41
|
-
end
|
42
|
-
|
43
|
-
attributes2 = [keys2].flatten.map do |key|
|
44
|
-
table2[key]
|
45
|
-
end
|
46
|
-
|
47
|
-
[attributes1, attributes2].transpose.map do |attribute1, attribute2|
|
48
|
-
attribute1.eq(attribute2)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def association_join
|
53
|
-
return @join if @join
|
54
|
-
|
55
|
-
aliased_table = Arel::Table.new(table_name, :as => @aliased_table_name,
|
56
|
-
:engine => arel_engine,
|
57
|
-
:columns => klass.columns)
|
58
|
-
|
59
|
-
parent_table = Arel::Table.new(parent.table_name, :as => parent.aliased_table_name,
|
60
|
-
:engine => arel_engine,
|
61
|
-
:columns => parent.active_record.columns)
|
62
|
-
|
63
|
-
@join = case reflection.macro
|
64
|
-
when :has_and_belongs_to_many
|
65
|
-
join_table = Arel::Table.new(options[:join_table], :as => aliased_join_table_name, :engine => arel_engine)
|
66
|
-
fk = options[:foreign_key] || reflection.active_record.to_s.foreign_key
|
67
|
-
klass_fk = options[:association_foreign_key] || klass.to_s.foreign_key
|
68
|
-
|
69
|
-
[
|
70
|
-
join_table[fk].eq(parent_table[reflection.active_record.primary_key]),
|
71
|
-
aliased_table[klass.primary_key].eq(join_table[klass_fk])
|
72
|
-
]
|
73
|
-
when :has_many, :has_one
|
74
|
-
if reflection.options[:through]
|
75
|
-
join_table = Arel::Table.new(through_reflection.klass.table_name, :as => aliased_join_table_name, :engine => arel_engine)
|
76
|
-
jt_as_extra = jt_source_extra = jt_sti_extra = nil
|
77
|
-
first_key = second_key = as_extra = nil
|
78
|
-
|
79
|
-
if through_reflection.macro == :belongs_to
|
80
|
-
jt_primary_key = through_reflection.primary_key_name
|
81
|
-
jt_foreign_key = through_reflection.association_primary_key
|
82
|
-
else
|
83
|
-
jt_primary_key = through_reflection.active_record_primary_key
|
84
|
-
jt_foreign_key = through_reflection.primary_key_name
|
85
|
-
|
86
|
-
if through_reflection.options[:as] # has_many :through against a polymorphic join
|
87
|
-
jt_as_extra = join_table[through_reflection.options[:as].to_s + '_type'].eq(parent.active_record.base_class.name)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
case source_reflection.macro
|
92
|
-
when :has_many
|
93
|
-
if source_reflection.options[:as]
|
94
|
-
first_key = "#{source_reflection.options[:as]}_id"
|
95
|
-
second_key = options[:foreign_key] || primary_key
|
96
|
-
as_extra = aliased_table["#{source_reflection.options[:as]}_type"].eq(source_reflection.active_record.base_class.name)
|
97
|
-
else
|
98
|
-
first_key = through_reflection.klass.base_class.to_s.foreign_key
|
99
|
-
second_key = options[:foreign_key] || primary_key
|
100
|
-
end
|
101
|
-
|
102
|
-
unless through_reflection.klass.descends_from_active_record?
|
103
|
-
jt_sti_extra = join_table[through_reflection.active_record.inheritance_column].eq(through_reflection.klass.sti_name)
|
104
|
-
end
|
105
|
-
when :belongs_to
|
106
|
-
first_key = primary_key
|
107
|
-
if reflection.options[:source_type]
|
108
|
-
second_key = source_reflection.association_foreign_key
|
109
|
-
jt_source_extra = join_table[reflection.source_reflection.options[:foreign_type]].eq(reflection.options[:source_type])
|
110
|
-
else
|
111
|
-
second_key = source_reflection.primary_key_name
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
[
|
116
|
-
[parent_table[jt_primary_key].eq(join_table[jt_foreign_key]), jt_as_extra, jt_source_extra, jt_sti_extra].reject{|x| x.blank? },
|
117
|
-
aliased_table[first_key].eq(join_table[second_key])
|
118
|
-
]
|
119
|
-
elsif reflection.options[:as]
|
120
|
-
id_rel = aliased_table["#{reflection.options[:as]}_id"].eq(parent_table[parent.primary_key])
|
121
|
-
type_rel = aliased_table["#{reflection.options[:as]}_type"].eq(parent.active_record.base_class.name)
|
122
|
-
[id_rel, type_rel]
|
123
|
-
else
|
124
|
-
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
|
125
|
-
# CPK
|
126
|
-
#[aliased_table[foreign_key].eq(parent_table[reflection.options[:primary_key] || parent.primary_key])]
|
127
|
-
composite_join_predicates(aliased_table, foreign_key,
|
128
|
-
parent_table, reflection.options[:primary_key] || parent.primary_key)
|
129
|
-
end
|
130
|
-
when :belongs_to
|
131
|
-
#[aliased_table[options[:primary_key] || reflection.klass.primary_key].eq(parent_table[options[:foreign_key] || reflection.primary_key_name])]
|
132
|
-
composite_join_predicates(aliased_table, options[:primary_key] || reflection.klass.primary_key, parent_table, options[:foreign_key] || reflection.primary_key_name)
|
133
|
-
end
|
134
|
-
|
135
|
-
unless klass.descends_from_active_record?
|
136
|
-
sti_column = aliased_table[klass.inheritance_column]
|
137
|
-
sti_condition = sti_column.eq(klass.sti_name)
|
138
|
-
klass.descendants.each {|subclass| sti_condition = sti_condition.or(sti_column.eq(subclass.sti_name)) }
|
139
|
-
|
140
|
-
@join << sti_condition
|
141
|
-
end
|
142
|
-
|
143
|
-
[through_reflection, reflection].each do |ref|
|
144
|
-
if ref && ref.options[:conditions]
|
145
|
-
@join << process_conditions(ref.options[:conditions], aliased_table_name)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
@join
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Associations
|
3
|
-
class AssociationProxy
|
4
|
-
def full_columns_equals(table_name, keys, quoted_ids)
|
5
|
-
quoted_table_name = @owner.connection.quote_table_name(table_name)
|
6
|
-
|
7
|
-
keys = [keys].flatten
|
8
|
-
ids = [quoted_ids].flatten
|
9
|
-
|
10
|
-
[keys,ids].transpose.map do |key, id|
|
11
|
-
"(#{quoted_table_name}.#{@owner.connection.quote_column_name(key)} = #{id})"
|
12
|
-
end.join(' AND ')
|
13
|
-
end
|
14
|
-
|
15
|
-
def set_belongs_to_association_for(record)
|
16
|
-
if @reflection.options[:as]
|
17
|
-
record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
|
18
|
-
record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
|
19
|
-
else
|
20
|
-
unless @owner.new_record?
|
21
|
-
primary_keys = Array(@reflection.options[:primary_key] || :id)
|
22
|
-
# CPK
|
23
|
-
# record[@reflection.primary_key_name] = @owner.send(primary_key)
|
24
|
-
# Need to flatten because a key may be :id giving a composite key
|
25
|
-
values = primary_keys.map {|key| @owner.send(key)}.flatten
|
26
|
-
key_values = @reflection.cpk_primary_key.zip(values)
|
27
|
-
key_values.each {|key, value| record[key] = value}
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Associations
|
3
|
-
class HasOneAssociation
|
4
|
-
def construct_sql
|
5
|
-
case
|
6
|
-
when @reflection.options[:as]
|
7
|
-
@finder_sql =
|
8
|
-
"#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " +
|
9
|
-
"#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
|
10
|
-
else
|
11
|
-
# CPK
|
12
|
-
#@finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
|
13
|
-
@finder_sql = full_columns_equals(@reflection.table_name, @reflection.cpk_primary_key, owner_quoted_id)
|
14
|
-
end
|
15
|
-
@finder_sql << " AND (#{conditions})" if conditions
|
16
|
-
end
|
17
|
-
|
18
|
-
def owner_quoted_id
|
19
|
-
if (keys = @reflection.options[:primary_key])
|
20
|
-
keys.is_a?(Array) ? keys.collect {|k| @owner.class.quote_value(@owner.send(k)) } : @owner.class.quote_value(@owner.send(keys))
|
21
|
-
else
|
22
|
-
@owner.quoted_id
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,103 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Associations
|
3
|
-
module ThroughAssociationScope
|
4
|
-
def composite_join_clause(table1, keys1, table2, keys2)
|
5
|
-
predicates = composite_join_predicates(table1, keys1, table2, keys2)
|
6
|
-
|
7
|
-
join_clause = predicates.map do |predicate|
|
8
|
-
predicate.to_sql
|
9
|
-
end.join(" AND ")
|
10
|
-
|
11
|
-
"(#{join_clause})"
|
12
|
-
end
|
13
|
-
|
14
|
-
def composite_join_predicates(table1, keys1, table2, keys2)
|
15
|
-
attributes1 = [keys1].flatten.map do |key|
|
16
|
-
table1[key]
|
17
|
-
end
|
18
|
-
|
19
|
-
attributes2 = [keys2].flatten.map do |key|
|
20
|
-
table2[key]
|
21
|
-
end
|
22
|
-
|
23
|
-
[attributes1, attributes2].transpose.map do |attribute1, attribute2|
|
24
|
-
attribute1.eq(attribute2)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def composite_ids_hash(keys, ids)
|
29
|
-
[keys].flatten.zip([ids].flatten).inject(Hash.new) do |hash, (key, value)|
|
30
|
-
hash[key] = value
|
31
|
-
hash
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def construct_quoted_owner_attributes(reflection)
|
36
|
-
if as = reflection.options[:as]
|
37
|
-
{ "#{as}_id" => owner_quoted_id,
|
38
|
-
"#{as}_type" => reflection.klass.quote_value(
|
39
|
-
@owner.class.base_class.name.to_s,
|
40
|
-
reflection.klass.columns_hash["#{as}_type"]) }
|
41
|
-
elsif reflection.macro == :belongs_to
|
42
|
-
# CPK
|
43
|
-
# { reflection.klass.primary_key => @owner[reflection.primary_key_name] }
|
44
|
-
composite_ids_hash(reflection.klass.primary_key, @owner.quoted_id)
|
45
|
-
else
|
46
|
-
# CPK
|
47
|
-
#{ reflection.primary_key_name => owner_quoted_id }
|
48
|
-
composite_ids_hash(reflection.cpk_primary_key, @owner.quoted_id)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Construct attributes for associate pointing to owner.
|
53
|
-
def construct_owner_attributes(reflection)
|
54
|
-
if as = reflection.options[:as]
|
55
|
-
{ "#{as}_id" => @owner.id,
|
56
|
-
"#{as}_type" => @owner.class.base_class.name.to_s }
|
57
|
-
else
|
58
|
-
# CPK
|
59
|
-
# { reflection.primary_key_name => @owner.id }
|
60
|
-
composite_ids_hash(reflection.cpk_primary_key, @owner.id)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def construct_joins(custom_joins = nil)
|
65
|
-
polymorphic_join = nil
|
66
|
-
if @reflection.source_reflection.macro == :belongs_to
|
67
|
-
reflection_primary_key = @reflection.klass.primary_key
|
68
|
-
source_primary_key = @reflection.source_reflection.cpk_primary_key
|
69
|
-
if @reflection.options[:source_type]
|
70
|
-
polymorphic_join = "AND %s.%s = %s" % [
|
71
|
-
@reflection.through_reflection.quoted_table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
|
72
|
-
@owner.class.quote_value(@reflection.options[:source_type])
|
73
|
-
]
|
74
|
-
end
|
75
|
-
else
|
76
|
-
reflection_primary_key = @reflection.source_reflection.cpk_primary_key
|
77
|
-
source_primary_key = @reflection.through_reflection.klass.primary_key
|
78
|
-
if @reflection.source_reflection.options[:as]
|
79
|
-
polymorphic_join = "AND %s.%s = %s" % [
|
80
|
-
@reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
|
81
|
-
@owner.class.quote_value(@reflection.through_reflection.klass.name)
|
82
|
-
]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# CPK
|
87
|
-
# "INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]} #{custom_joins}" % [
|
88
|
-
# @reflection.through_reflection.quoted_table_name,
|
89
|
-
# @reflection.quoted_table_name, reflection_primary_key,
|
90
|
-
# @reflection.through_reflection.quoted_table_name, source_primary_key,
|
91
|
-
# polymorphic_join
|
92
|
-
# ]
|
93
|
-
|
94
|
-
"INNER JOIN %s ON %s %s #{@reflection.options[:joins]} #{custom_joins}" % [
|
95
|
-
@reflection.through_reflection.quoted_table_name,
|
96
|
-
composite_join_clause(@reflection.klass.arel_table, reflection_primary_key,
|
97
|
-
@reflection.through_reflection.klass.arel_table, source_primary_key),
|
98
|
-
polymorphic_join
|
99
|
-
]
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|