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.
Files changed (62) hide show
  1. data/History.txt +6 -8
  2. data/lib/composite_primary_keys.rb +53 -36
  3. data/lib/composite_primary_keys/associations/association.rb +23 -0
  4. data/lib/composite_primary_keys/associations/association_scope.rb +67 -0
  5. data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +31 -121
  6. data/lib/composite_primary_keys/associations/has_many_association.rb +27 -66
  7. data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +22 -0
  8. data/lib/composite_primary_keys/associations/join_dependency/join_part.rb +39 -0
  9. data/lib/composite_primary_keys/associations/preloader/association.rb +61 -0
  10. data/lib/composite_primary_keys/associations/preloader/belongs_to.rb +13 -0
  11. data/lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb +46 -0
  12. data/lib/composite_primary_keys/attribute_methods/dirty.rb +30 -0
  13. data/lib/composite_primary_keys/attribute_methods/read.rb +88 -0
  14. data/lib/composite_primary_keys/attribute_methods/write.rb +33 -0
  15. data/lib/composite_primary_keys/base.rb +18 -70
  16. data/lib/composite_primary_keys/composite_predicates.rb +53 -0
  17. data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +6 -4
  18. data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +19 -41
  19. data/lib/composite_primary_keys/fixtures.rb +19 -6
  20. data/lib/composite_primary_keys/persistence.rb +32 -13
  21. data/lib/composite_primary_keys/relation.rb +23 -16
  22. data/lib/composite_primary_keys/relation/calculations.rb +48 -0
  23. data/lib/composite_primary_keys/relation/finder_methods.rb +117 -0
  24. data/lib/composite_primary_keys/relation/query_methods.rb +24 -0
  25. data/lib/composite_primary_keys/validations/uniqueness.rb +19 -23
  26. data/lib/composite_primary_keys/version.rb +5 -5
  27. data/test/connections/native_mysql/connection.rb +1 -1
  28. data/test/fixtures/articles.yml +1 -0
  29. data/test/fixtures/products.yml +2 -4
  30. data/test/fixtures/readings.yml +1 -0
  31. data/test/fixtures/suburbs.yml +1 -4
  32. data/test/fixtures/users.yml +1 -0
  33. data/test/test_associations.rb +61 -63
  34. data/test/test_attributes.rb +16 -21
  35. data/test/test_create.rb +3 -3
  36. data/test/test_delete.rb +87 -84
  37. data/test/{test_clone.rb → test_dup.rb} +8 -5
  38. data/test/test_exists.rb +22 -10
  39. data/test/test_habtm.rb +0 -74
  40. data/test/test_ids.rb +2 -1
  41. data/test/test_miscellaneous.rb +2 -2
  42. data/test/test_polymorphic.rb +1 -1
  43. data/test/test_suite.rb +1 -1
  44. data/test/test_update.rb +3 -3
  45. metadata +76 -75
  46. data/lib/composite_primary_keys/association_preload.rb +0 -158
  47. data/lib/composite_primary_keys/associations.rb +0 -155
  48. data/lib/composite_primary_keys/associations/association_proxy.rb +0 -33
  49. data/lib/composite_primary_keys/associations/has_one_association.rb +0 -27
  50. data/lib/composite_primary_keys/associations/through_association_scope.rb +0 -103
  51. data/lib/composite_primary_keys/attribute_methods.rb +0 -84
  52. data/lib/composite_primary_keys/calculations.rb +0 -31
  53. data/lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb +0 -21
  54. data/lib/composite_primary_keys/connection_adapters/oracle_adapter.rb +0 -15
  55. data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +0 -17
  56. data/lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb +0 -15
  57. data/lib/composite_primary_keys/finder_methods.rb +0 -123
  58. data/lib/composite_primary_keys/primary_key.rb +0 -19
  59. data/lib/composite_primary_keys/query_methods.rb +0 -24
  60. data/lib/composite_primary_keys/read.rb +0 -25
  61. data/lib/composite_primary_keys/reflection.rb +0 -37
  62. data/lib/composite_primary_keys/write.rb +0 -18
@@ -1,11 +1,6 @@
1
- == 3.1.11 2012-05-20
2
- Fix AssociationReflection#derive_primary_key for belongs_to relationships (Heinrich Lee Yu).
3
-
4
- == 3.1.10 2011-07-08
5
- * Bugfix for belongs_to with includes (John Ash)
6
- * Improved tests for calling clear on a habtm association, which involved (David Rueck)
7
- * Fixed bug that resulted in unrelated records being deleted when calling (David Rueck)
8
- * Output deprecation warnings about extra columns in join table CPK-aware (David Rueck)
1
+ == 4.0.0.beta1 2011-06-09
2
+ * ActiveRecord 3.1 compatibility. This required a significant rewrite due to
3
+ all the changes in AR 3.1 versus 3.0.
9
4
 
10
5
  == 3.1.9 2011-06-04
11
6
  * Improve HABTM association tests (David Rueck)
@@ -19,6 +14,7 @@ Fix AssociationReflection#derive_primary_key for belongs_to relationships (Heinr
19
14
  * Minor test cleanup (Charlie Savage)
20
15
  * Make version requirements more explicit (Charlie Savage)
21
16
  * Remove Arel extensions used for calculations (Charlie Savage)
17
+ * Fix test that included wrong error constant
22
18
 
23
19
  == 3.1.6 2011-04-03
24
20
  * Updated belongs_to association to be a bit more flexible with non-CPK (Charlie Savage)
@@ -27,12 +23,14 @@ Fix AssociationReflection#derive_primary_key for belongs_to relationships (Heinr
27
23
  * Fix write issue when one of they keys in a composite key is
28
24
  called id (Tom Hughes)
29
25
 
26
+
30
27
  == 3.1.5 2011-03-24
31
28
  * Fix simple calculation methods (Charlie Savage)
32
29
  * Fix instantiation of cpk records via associations (Charlie Savage)
33
30
  * Fix Relation#delete (Charlie Savage)
34
31
  * Fix Relation#destroy (Charlie Savage)
35
32
 
33
+
36
34
  == 3.1.4 2011-03-06
37
35
  * Support ActiveRecord 3.0.5 - interpolate_sql was removed and
38
36
  replaced by interpolate_and_sanitize_sql (Charlie Savage)
@@ -26,50 +26,67 @@ $:.unshift(File.dirname(__FILE__)) unless
26
26
 
27
27
  unless defined?(ActiveRecord)
28
28
  require 'rubygems'
29
- gem 'activerecord', '>= 3.0.5', '~> 3.0.0'
29
+ gem 'activerecord', '=3.1.0.rc1'
30
30
  require 'active_record'
31
31
  end
32
32
 
33
- require 'active_record/associations.rb'
34
- require 'active_record/associations/association_proxy.rb'
35
- require 'active_record/associations/association_collection'
36
- require 'active_record/associations/association_proxy'
37
- require 'active_record/associations/belongs_to_association'
38
- require 'active_record/associations/belongs_to_polymorphic_association'
33
+ # AR files we override
34
+ require 'active_record/fixtures'
35
+ require 'active_record/persistence'
36
+ require 'active_record/relation'
37
+
38
+ require 'active_record/associations/association'
39
+ require 'active_record/associations/association_scope'
39
40
  require 'active_record/associations/has_and_belongs_to_many_association'
40
41
  require 'active_record/associations/has_many_association'
41
- require 'active_record/associations/has_one_association'
42
- require 'active_record/associations/has_one_through_association'
43
- require 'active_record/associations/through_association_scope'
44
- require 'active_record/persistence'
42
+ require 'active_record/associations/join_dependency/join_part'
43
+ require 'active_record/associations/join_dependency/join_association'
44
+ require 'active_record/associations/preloader/association'
45
+ require 'active_record/associations/preloader/belongs_to'
46
+ require 'active_record/associations/preloader/has_and_belongs_to_many'
47
+
48
+ require 'active_record/attribute_methods/dirty'
49
+ require 'active_record/attribute_methods/read'
50
+ require 'active_record/attribute_methods/write'
51
+
52
+ require 'active_record/connection_adapters/abstract_adapter'
53
+ require 'active_record/connection_adapters/postgresql_adapter'
54
+
55
+ require 'active_record/relation/calculations'
56
+ require 'active_record/relation/finder_methods'
45
57
  require 'active_record/relation/query_methods'
46
- require 'active_record/attribute_methods/primary_key'
47
- require 'active_record/fixtures'
48
58
 
59
+ require 'active_record/validations/uniqueness'
60
+
61
+
62
+ # CPK files
63
+ require 'composite_primary_keys/base'
49
64
  require 'composite_primary_keys/composite_arrays'
50
- require 'composite_primary_keys/associations'
51
- require 'composite_primary_keys/associations/association_proxy'
52
- require 'composite_primary_keys/associations/has_one_association'
53
- require 'composite_primary_keys/associations/has_many_association'
54
- require 'composite_primary_keys/associations/has_and_belongs_to_many_association'
55
- require 'composite_primary_keys/associations/through_association_scope'
56
- require 'composite_primary_keys/association_preload'
65
+ require 'composite_primary_keys/composite_predicates'
66
+ require 'composite_primary_keys/fixtures'
57
67
  require 'composite_primary_keys/persistence'
58
- require 'composite_primary_keys/reflection'
59
68
  require 'composite_primary_keys/relation'
60
- require 'composite_primary_keys/read'
61
- require 'composite_primary_keys/write'
62
- require 'composite_primary_keys/finder_methods'
63
- require 'composite_primary_keys/base'
64
- require 'composite_primary_keys/calculations'
65
- require 'composite_primary_keys/validations/uniqueness'
66
- require 'composite_primary_keys/query_methods'
67
- require 'composite_primary_keys/primary_key'
68
- require 'composite_primary_keys/fixtures'
69
+ require 'composite_primary_keys/version'
69
70
 
70
- Dir[File.dirname(__FILE__) + '/composite_primary_keys/connection_adapters/*.rb'].each do |adapter|
71
- begin
72
- require adapter.gsub('.rb','')
73
- rescue MissingSourceFile
74
- end
75
- end
71
+ require 'composite_primary_keys/associations/association'
72
+ require 'composite_primary_keys/associations/association_scope'
73
+ require 'composite_primary_keys/associations/has_and_belongs_to_many_association'
74
+ require 'composite_primary_keys/associations/has_many_association'
75
+ require 'composite_primary_keys/associations/join_dependency/join_part'
76
+ require 'composite_primary_keys/associations/join_dependency/join_association'
77
+ require 'composite_primary_keys/associations/preloader/association'
78
+ require 'composite_primary_keys/associations/preloader/belongs_to'
79
+ require 'composite_primary_keys/associations/preloader/has_and_belongs_to_many'
80
+
81
+ require 'composite_primary_keys/attribute_methods/dirty'
82
+ require 'composite_primary_keys/attribute_methods/read'
83
+ require 'composite_primary_keys/attribute_methods/write'
84
+
85
+ require 'composite_primary_keys/connection_adapters/abstract_adapter'
86
+ require 'composite_primary_keys/connection_adapters/postgresql_adapter'
87
+
88
+ require 'composite_primary_keys/relation/calculations'
89
+ require 'composite_primary_keys/relation/finder_methods'
90
+ require 'composite_primary_keys/relation/query_methods'
91
+
92
+ require 'composite_primary_keys/validations/uniqueness'
@@ -0,0 +1,23 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class Association
4
+ def creation_attributes
5
+ attributes = {}
6
+
7
+ if reflection.macro.in?([:has_one, :has_many]) && !options[:through]
8
+ # CPK
9
+ # attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
10
+ Array(reflection.foreign_key).zip(Array(reflection.active_record_primary_key)).each do |key1, key2|
11
+ attributes[key1] = owner[key2]
12
+ end
13
+
14
+ if reflection.options[:as]
15
+ attributes[reflection.type] = owner.class.base_class.name
16
+ end
17
+ end
18
+
19
+ attributes
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,67 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class AssociationScope
4
+ def add_constraints(scope)
5
+ tables = construct_tables
6
+
7
+ chain.each_with_index do |reflection, i|
8
+ table, foreign_table = tables.shift, tables.first
9
+
10
+ if reflection.source_macro == :has_and_belongs_to_many
11
+ join_table = tables.shift
12
+
13
+ # CPK
14
+ # scope = scope.joins(join(
15
+ # join_table,
16
+ # table[reflection.active_record_primary_key].
17
+ # eq(join_table[reflection.association_foreign_key])
18
+ #))
19
+ predicate = cpk_join_predicate(table, reflection.association_primary_key,
20
+ join_table, reflection.association_foreign_key)
21
+ scope = scope.joins(join(join_table, predicate))
22
+
23
+ table, foreign_table = join_table, tables.first
24
+ end
25
+
26
+ if reflection.source_macro == :belongs_to
27
+ key = reflection.association_primary_key
28
+ foreign_key = reflection.foreign_key
29
+ else
30
+ key = reflection.foreign_key
31
+ foreign_key = reflection.active_record_primary_key
32
+ end
33
+
34
+ if reflection == chain.last
35
+ # CPK
36
+ # scope = scope.where(table[key].eq(owner[foreign_key]))
37
+ predicate = cpk_join_predicate(table, key, owner, foreign_key)
38
+ scope = scope.where(predicate)
39
+
40
+ conditions[i].each do |condition|
41
+ if options[:through] && condition.is_a?(Hash)
42
+ condition = { table.name => condition }
43
+ end
44
+
45
+ scope = scope.where(interpolate(condition))
46
+ end
47
+ else
48
+ # CPK
49
+ # constraint = table[key].eq(foreign_table[foreign_key])
50
+ constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
51
+ scope = scope.where(predicate)
52
+
53
+ join = join(foreign_table, constraint)
54
+
55
+ scope = scope.joins(join)
56
+
57
+ unless conditions[i].empty?
58
+ scope = scope.where(sanitize(conditions[i], table))
59
+ end
60
+ end
61
+ end
62
+
63
+ scope
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,143 +1,53 @@
1
1
  module ActiveRecord
2
2
  module Associations
3
3
  class HasAndBelongsToManyAssociation
4
- def construct_sql
5
- if @reflection.options[:finder_sql]
6
- @finder_sql = interpolate_and_sanitize_sql(@reflection.options[:finder_sql])
4
+ def insert_record(record, validate = true)
5
+ return if record.new_record? && !record.save(:validate => validate)
6
+
7
+ if options[:insert_sql]
8
+ owner.connection.insert(interpolate(options[:insert_sql], record))
7
9
  else
8
10
  # CPK
9
- # @finder_sql = "#{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.primary_key_name} = #{owner_quoted_id} "
10
- @finder_sql = full_columns_equals(@reflection.options[:join_table], @reflection.cpk_primary_key, owner_quoted_id)
11
- @finder_sql << " AND (#{conditions})" if conditions
12
- end
13
-
14
- join_condition = if composite?
15
- conditions = Array.new
16
- primary_keys.length.times do |i|
17
- conditions << "#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key[i]} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key[i]}"
11
+ #stmt = join_table.compile_insert(
12
+ # join_table[reflection.foreign_key] => owner.id,
13
+ # join_table[reflection.association_foreign_key] => record.id
14
+ #)
15
+ join_values = Hash.new
16
+ Array(reflection.foreign_key).zip(Array(owner.id)) do |name, value|
17
+ attribute = join_table[name]
18
+ join_values[attribute] = value
18
19
  end
19
- conditions.join(' AND ')
20
- else
21
- "#{@reflection.quoted_table_name}.#{@reflection.klass.primary_key} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key}"
22
- end
23
- #@join_sql = "INNER JOIN #{@owner.connection.quote_table_name @reflection.options[:join_table]} ON #{@reflection.quoted_table_name}.#{@reflection.klass.primary_key} = #{@owner.connection.quote_table_name @reflection.options[:join_table]}.#{@reflection.association_foreign_key}"
24
- @join_sql = "INNER JOIN #{@owner.connection.quote_table_name @reflection.options[:join_table]} ON (#{join_condition})"
25
20
 
26
- construct_counter_sql
27
- end
28
-
29
- def insert_record(record, force = true, validate = true)
30
- unless record.persisted?
31
- if force
32
- record.save!
33
- else
34
- return false unless record.save(:validate => validate)
21
+ Array(reflection.association_foreign_key).zip(Array(record.id)) do |name, value|
22
+ attribute = join_table[name]
23
+ join_values[attribute] = value
35
24
  end
36
- end
37
-
38
- if @reflection.options[:insert_sql]
39
- @owner.connection.insert(interpolate_and_sanitize_sql(@reflection.options[:insert_sql], record))
40
- else
41
- relation = Arel::Table.new(@reflection.options[:join_table])
42
- timestamps = record_timestamp_columns(record)
43
- timezone = record.send(:current_time_from_proper_timezone) if timestamps.any?
44
25
 
45
- # CPK
46
- #attributes = Hash[columns.map do |column|
47
- # name = column.name
48
- # value = case name.to_s
49
- # when @reflection.primary_key_name.to_s
50
- # @owner.id
51
- # when @reflection.association_foreign_key.to_s
52
- # record.id
53
- # when *timestamps
54
- # timezone
55
- # else
56
- # @owner.send(:quote_value, record[name], column) if record.has_attribute?(name)
57
- # end
58
- # [relation[name], value] unless value.nil?
59
- #end]
60
-
61
- # CPK
62
- owner_foreign_keys = @reflection.cpk_primary_key.map{|key| key.to_s}
63
- association_foreign_keys = Array(@reflection.association_foreign_key).map{|key| key.to_s}
26
+ stmt = join_table.compile_insert(join_values)
64
27
 
65
- attributes = Hash[columns.map do |column|
66
- name = column.name.to_s
67
- value = case
68
- when owner_foreign_keys.include?(name)
69
- index = owner_foreign_keys.index(name)
70
- primary_keys = Array(@owner.class.primary_key)
71
- primary_key = primary_keys[index]
72
- @owner[primary_key]
73
- when association_foreign_keys.include?(name)
74
- index = association_foreign_keys.index(name)
75
- primary_keys = Array(@reflection.klass.primary_key)
76
- primary_key = primary_keys[index]
77
- record[primary_key]
78
- when timestamps.include?(name)
79
- timezone
80
- else
81
- @owner.send(:quote_value, record[name], column) if record.has_attribute?(name)
82
- end
83
- [relation[name], value] unless value.nil?
84
- end]
85
-
86
- relation.insert(attributes)
28
+ owner.connection.insert stmt.to_sql
87
29
  end
88
30
 
89
- return true
31
+ record
90
32
  end
91
33
 
92
- # CPK
93
- #def delete_records(records)
94
- # if sql = @reflection.options[:delete_sql]
95
- # records.each { |record| @owner.connection.delete(interpolate_and_sanitize_sql(sql, record)) }
96
- # else
97
- # relation = Arel::Table.new(@reflection.options[:join_table])
98
- # relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
99
- # and(relation[@reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
100
- # ).delete
101
- # end
102
- #end
103
-
104
- # CPK
105
- def delete_records(records)
106
- if sql = @reflection.options[:delete_sql]
107
- records.each { |record| @owner.connection.delete(interpolate_and_sanitize_sql(sql, record)) }
34
+ def delete_records(records, method)
35
+ if sql = options[:delete_sql]
36
+ records.each { |record| owner.connection.delete(interpolate(sql, record)) }
108
37
  else
109
- relation = Arel::Table.new(@reflection.options[:join_table])
38
+ relation = join_table
39
+ # CPK
40
+ # stmt = relation.where(relation[reflection.foreign_key].eq(owner.id).
41
+ # and(relation[reflection.association_foreign_key].in(records.map { |x| x.id }.compact))
42
+ #).compile_delete
110
43
 
111
- if @reflection.cpk_primary_key.size > 1
112
- owner_conditions = []
113
- @reflection.cpk_primary_key.each_with_index do |column,i|
114
- owner_conditions << relation[column.to_sym].eq(@owner.id[i])
115
- end
116
- owner_conditions_arel = owner_conditions.inject { |conds, cond| conds.and(cond) }
117
- else
118
- owner_conditions_arel = relation[@reflection.primary_key_name].eq(@owner.id)
119
- end
44
+ predicate1 = cpk_id_predicate(relation, Array(reflection.foreign_key), Array(owner.id))
45
+ predicate2 = cpk_in_predicate(relation, Array(reflection.association_foreign_key), records.map { |x| x.id })
46
+ stmt = relation.where(predicate1.and(predicate2)).compile_delete
120
47
 
121
- if @reflection.association_foreign_key.kind_of?(Array)
122
- association_conditions = []
123
- records.each do |rec|
124
- record_conditions = []
125
- @reflection.association_foreign_key.each_with_index do |column,i|
126
- record_conditions << relation[column.to_sym].eq(rec.id[i])
127
- end
128
- association_conditions << record_conditions.inject { |conds, cond| conds.and(cond) }
129
- end
130
- association_conditions_arel = association_conditions.inject { |conds, cond| conds.or(cond) }
131
- else
132
- association_conditions_arel = relation[@reflection.association_foreign_key].in(records.map { |x| x.id }.compact)
133
- end
134
-
135
- all_conditions_arel = owner_conditions_arel.and(association_conditions_arel)
136
-
137
- relation.where(all_conditions_arel).delete
48
+ owner.connection.delete stmt.to_sql
138
49
  end
139
50
  end
140
-
141
51
  end
142
52
  end
143
53
  end
@@ -1,79 +1,40 @@
1
1
  module ActiveRecord
2
2
  module Associations
3
3
  class HasManyAssociation
4
- def construct_sql
5
- case
6
- when @reflection.options[:finder_sql]
7
- @finder_sql = interpolate_and_sanitize_sql(@reflection.options[:finder_sql])
8
-
9
- when @reflection.options[:as]
10
- @finder_sql =
11
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_id = #{owner_quoted_id} AND " +
12
- "#{@reflection.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
13
- @finder_sql << " AND (#{conditions})" if conditions
14
-
15
- else
16
- # CPK
17
- # @finder_sql = "#{@reflection.quoted_table_name}.#{@reflection.primary_key_name} = #{owner_quoted_id}"
18
- @finder_sql = full_columns_equals(@reflection.table_name, @reflection.cpk_primary_key, owner_quoted_id)
19
- @finder_sql << " AND (#{conditions})" if conditions
20
- end
21
-
22
- construct_counter_sql
23
- end
24
-
25
- def owner_quoted_id
26
- if (keys = @reflection.options[:primary_key])
27
- keys.is_a?(Array) ? keys.collect {|k| quote_value(@owner.send(k)) } : quote_value(@owner.send(keys))
4
+ def delete_records(records, method)
5
+ if method == :destroy
6
+ records.each { |r| r.destroy }
7
+ update_counter(-records.length) unless inverse_updates_counter_cache?
28
8
  else
29
- @owner.quoted_id
30
- end
31
- end
32
-
33
- def delete_records(records)
34
- case @reflection.options[:dependent]
35
- when :destroy
36
- records.each { |r| r.destroy }
37
- when :delete_all
38
- @reflection.klass.delete(records.map { |record| record.id })
39
- else
40
- relation = Arel::Table.new(@reflection.table_name)
41
- # CPK
42
- #relation.where(relation[@reflection.primary_key_name].eq(@owner.id).
43
- # and(relation[@reflection.klass.primary_key].in(records.map { |r| r.id }))
44
- #).update(relation[@reflection.primary_key_name] => nil)
45
-
46
- id_predicate = nil
47
- owner_key_values = @reflection.cpk_primary_key.zip([@owner.id].flatten)
48
- owner_key_values.each do |key, value|
49
- eq = relation[key].eq(value)
50
- id_predicate = id_predicate ? id_predicate.and(eq) : eq
9
+ # CPK
10
+ # keys = records.map { |r| r[reflection.association_primary_key] }
11
+ # scope = scoped.where(reflection.association_primary_key => keys)
12
+ table = Arel::Table.new(reflection.table_name)
13
+ and_conditions = records.map do |record|
14
+ eq_conditions = Array(reflection.association_primary_key).map do |name|
15
+ table[name].eq(record[name])
51
16
  end
17
+ Arel::Nodes::And.new(eq_conditions)
18
+ end
52
19
 
53
- record_predicates = nil
54
- records.each do |record|
55
- keys = [@reflection.klass.primary_key].flatten
56
- values = [record.id].flatten
57
-
58
- record_predicate = nil
59
- keys.zip(values).each do |key, value|
60
- eq = relation[key].eq(value)
61
- record_predicate = record_predicate ? record_predicate.and(eq) : eq
62
- end
63
- record_predicates = record_predicates ? record_predicates.or(record_predicate) : record_predicate
64
- end
20
+ condition = and_conditions.shift
21
+ and_conditions.each do |and_condition|
22
+ condition = condition.or(and_condition)
23
+ end
65
24
 
66
- relation = relation.where(id_predicate.and(record_predicates))
25
+ scope = scoped.where(condition)
67
26
 
68
- nullify_relation = Arel::Table.new(@reflection.table_name)
69
- nullify = @reflection.cpk_primary_key.inject(Hash.new) do |hash, key|
70
- hash[nullify_relation[key]] = nil
27
+ if method == :delete_all
28
+ update_counter(-scope.delete_all)
29
+ else
30
+ # CPK
31
+ # update_counter(-scope.update_all(reflection.foreign_key => nil))
32
+ updates = Array(reflection.foreign_key).inject(Hash.new) do |hash, name|
33
+ hash[name] = nil
71
34
  hash
72
35
  end
73
-
74
- relation.update(nullify)
75
-
76
- @owner.class.update_counters(@owner.id, cached_counter_attribute_name => -records.size) if has_cached_counter?
36
+ update_counter(-scope.update_all(updates))
37
+ end
77
38
  end
78
39
  end
79
40
  end