composite_primary_keys 5.0.4 → 5.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,15 @@
1
+ == 5.0.5 2012-05-05
2
+ * Count without slower subquery in cases where that is possible (Sammy Larbi)
3
+ * When you call association.build for a has_many association that uses a
4
+ composite foreign key, the newly built child record should have the values
5
+ in its belongs_to foreign_key populated from its owner's values (Tyler Rick).
6
+ * Removed test_has_many_with_primary_key method that wasn't being used because
7
+ another method by the same name was defined below it (Tyler Rick).
8
+ * Fixed a bug that was causing object.changes to raise TypeError (Tyler Rick)
9
+ * Fix error when running rake mysql:rebuild_databases (Tyler Rick)
10
+ * to_param should join with comma instead of minus sign (Tsutomu Kuroda)
11
+ * Fix the "Factories" section of README.rdoc (Tsutomu Kuroda)
12
+
1
13
  == 5.0.4 2012-03-23
2
14
  * Update ActiveRecord::AttributeMethods#Write for Rails 3.2.2 (Travis Warlick)
3
15
 
@@ -26,8 +26,10 @@ This RubyGem extends the activerecord gem to provide CPK support.
26
26
 
27
27
  FactoryGirl.define do
28
28
  factory :model_with_composite_keys do
29
- sequence( :id ) { |n| [n,Time.now] }
30
- name "Brett"
29
+ sequence( :id ) { |n| [n,Time.now] }
30
+ name "Brett"
31
+ end
32
+ end
31
33
 
32
34
 
33
35
  It even supports composite foreign keys for associations.
@@ -3,18 +3,21 @@ module ActiveRecord
3
3
  module Dirty
4
4
  def write_attribute(attr, value)
5
5
  # CPK
6
- # attr = attr.to_s
7
- attr = attr.to_s unless self.composite?
8
-
9
- # The attribute already has an unsaved change.
10
- if attribute_changed?(attr)
11
- old = @changed_attributes[attr]
12
- @changed_attributes.delete(attr) unless field_changed?(attr, old, value)
6
+ if attr.kind_of?(Array)
7
+ # A *composite* attribute can't be marked as changed! So do nothing now.
8
+ # We will come back in here with an *individual* attribute when Write#write_attribute looks through the individual attributes comprising this composite key:
9
+ # [attr_name, value].transpose.map {|name,val| write_attribute(name, val)}
13
10
  else
14
- old = clone_attribute_value(:read_attribute, attr)
15
- # Save Time objects as TimeWithZone if time_zone_aware_attributes == true
16
- old = old.in_time_zone if clone_with_time_zone_conversion_attribute?(attr, old)
17
- @changed_attributes[attr] = old if field_changed?(attr, old, value)
11
+ # The attribute already has an unsaved change.
12
+ if attribute_changed?(attr)
13
+ old = @changed_attributes[attr]
14
+ @changed_attributes.delete(attr) unless field_changed?(attr, old, value)
15
+ else
16
+ old = clone_attribute_value(:read_attribute, attr)
17
+ # Save Time objects as TimeWithZone if time_zone_aware_attributes == true
18
+ old = old.in_time_zone if clone_with_time_zone_conversion_attribute?(attr, old)
19
+ @changed_attributes[attr] = old if field_changed?(attr, old, value)
20
+ end
18
21
  end
19
22
 
20
23
  # Carry on.
@@ -148,6 +148,10 @@ module ActiveRecord
148
148
  def to_key
149
149
  ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
150
150
  end
151
+
152
+ def to_param
153
+ persisted? ? to_key.join(CompositePrimaryKeys::ID_SEP) : nil
154
+ end
151
155
  end
152
156
  end
153
157
  end
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
 
9
9
  def delete(id_or_array)
10
10
  ::ActiveRecord::IdentityMap.remove_by_id(self.symbolized_base_class, id_or_array) if ::ActiveRecord::IdentityMap.enabled?
11
- # CPK
11
+ # Without CPK:
12
12
  # where(primary_key => id_or_array).delete_all
13
13
 
14
14
  id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
@@ -23,12 +23,13 @@ module ActiveRecord
23
23
  end
24
24
 
25
25
  def destroy(id_or_array)
26
- # CPK
26
+ # Without CPK:
27
27
  #if id.is_a?(Array)
28
28
  # id.map { |one_id| destroy(one_id) }
29
29
  #else
30
30
  # find(id).destroy
31
31
  #end
32
+
32
33
  id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
33
34
  [id_or_array]
34
35
  else
@@ -44,16 +45,32 @@ module ActiveRecord
44
45
  end
45
46
  end
46
47
 
47
- alias :initialize_cpk :initialize
48
+ def add_cpk_where_values_hash
49
+ class << self
50
+ def where_values_hash
51
+ # CPK adds this so that it finds the Equality nodes beneath the And node:
52
+ nodes_from_and = with_default_scope.where_values.grep(Arel::Nodes::And).map {|and_node| and_node.children.grep(Arel::Nodes::Equality) }.flatten
53
+
54
+ equalities = (nodes_from_and + with_default_scope.where_values.grep(Arel::Nodes::Equality)).find_all { |node|
55
+ node.left.relation.name == table_name
56
+ }
57
+
58
+ Hash[equalities.map { |where| [where.left.name, where.right] }]
59
+ end
60
+ end
61
+ end
62
+
63
+ alias :initialize_without_cpk :initialize
48
64
  def initialize(klass, table)
49
- initialize_cpk(klass, table)
65
+ initialize_without_cpk(klass, table)
50
66
  add_cpk_support if klass.composite?
67
+ add_cpk_where_values_hash
51
68
  end
52
69
 
53
- alias :initialize_copy_cpk :initialize_copy
70
+ alias :initialize_copy_without_cpk :initialize_copy
54
71
  def initialize_copy(other)
55
- initialize_copy_cpk(other)
72
+ initialize_copy_without_cpk(other)
56
73
  add_cpk_support if klass.composite?
57
74
  end
58
75
  end
59
- end
76
+ end
@@ -55,8 +55,17 @@ module CompositePrimaryKeys
55
55
  else
56
56
  [Arel.sql(column_name == :all ? "#{@klass.quoted_table_name}.*" : column_name.to_s)]
57
57
  end
58
-
59
-
58
+
59
+ # do not use slower subquery if we're only counting on one column
60
+ if relation.select_values.count == 1
61
+ # exclude distinct table_name.* in case of joins where subbing * would change results
62
+ if (!distinct && column_name == :all) || column_name != :all
63
+ column = relation.select_values[0].gsub("#{@klass.quoted_table_name}.","")
64
+ relation.select_values = [operation_over_aggregate_column(column, 'count', distinct)]
65
+ return relation.arel
66
+ end
67
+ end
68
+
60
69
  relation.distinct(true)
61
70
  subquery = relation.arel.as(subquery_alias)
62
71
 
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION
3
3
  MAJOR = 5
4
4
  MINOR = 0
5
- TINY = 4
5
+ TINY = 5
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
@@ -19,7 +19,9 @@ namespace :mysql do
19
19
  file.read
20
20
  end
21
21
 
22
+ Rake::Task['mysql:load_connection'].reenable
22
23
  Rake::Task['mysql:load_connection'].invoke
24
+ #puts %(ActiveRecord::Base.connection.instance_variable_get(:@config)=#{(ActiveRecord::Base.connection.instance_variable_get(:@config)).inspect})
23
25
  ActiveRecord::Base.connection.execute(sql)
24
26
  end
25
27
 
@@ -33,5 +35,6 @@ namespace :mysql do
33
35
 
34
36
  task :load_connection do
35
37
  require File.join(PROJECT_ROOT, "test", "connections", "native_mysql", "connection")
38
+ establish_connection
36
39
  end
37
- end
40
+ end
@@ -8,6 +8,10 @@ def connection_string
8
8
  options.map { |key, value| "-#{key}#{value}" }.join(" ")
9
9
  end
10
10
 
11
- # Adapter config setup in text/connections/databases.yml
11
+ # Adapter config setup in test/connections/databases.yml
12
12
  SPEC = CompositePrimaryKeys::ConnectionSpec['mysql']
13
- ActiveRecord::Base.establish_connection(SPEC)
13
+
14
+ def establish_connection
15
+ ActiveRecord::Base.establish_connection(SPEC)
16
+ end
17
+ establish_connection
@@ -162,9 +162,18 @@ class TestAssociations < ActiveSupport::TestCase
162
162
  assert_equal(rooms(:branner_room_1), room_assignment.room)
163
163
  end
164
164
 
165
- def test_has_many_with_primary_key
166
- @membership = Membership.find([1, 1])
167
- assert_equal 2, @membership.reading.id
165
+ def test_composite_belongs_to_changes
166
+ room_assignment = room_assignments(:jacksons_room)
167
+ room_assignment.room = rooms(:branner_room_2)
168
+ # This was raising an error before:
169
+ # TypeError: [:dorm_id, :room_id] is not a symbol
170
+ assert_equal({:room_id=>[1, 2]}, room_assignment.changes)
171
+
172
+ steve = employees(:steve)
173
+ steve.department = departments(:engineering)
174
+ # It was returning this before:
175
+ # {"[:department_id, :location_id]"=>[nil, [2, 1]]}
176
+ assert_equal({:department_id=>[1, 2]}, steve.changes)
168
177
  end
169
178
 
170
179
  def test_has_one_with_composite
@@ -173,14 +182,28 @@ class TestAssociations < ActiveSupport::TestCase
173
182
  assert_not_nil(department.head)
174
183
  end
175
184
 
185
+ def test_has_many_build__simple_key
186
+ user = users(:santiago)
187
+ reading = user.readings.build
188
+ assert_equal user.id, reading.user_id
189
+ assert_equal user, reading.user
190
+ end
191
+
192
+ def test_has_many_build__composite_key
193
+ department = departments(:engineering)
194
+ employee = department.employees.build
195
+ assert_equal department.department_id, employee.department_id
196
+ assert_equal department.location_id, employee.location_id
197
+ assert_equal department, employee.department
198
+ end
199
+
176
200
  def test_has_many_with_primary_key
177
201
  @membership = Membership.find([1, 1])
178
-
179
202
  assert_equal 2, @membership.readings.size
180
203
  end
181
204
 
182
205
  def test_has_many_with_composite_key
183
- # In this case a regular model has_many composite models
206
+ # In this case a regular model (Dorm) has_many composite models (Rooms)
184
207
  dorm = dorms(:branner)
185
208
  assert_equal(2, dorm.rooms.length)
186
209
  assert_equal(1, dorm.rooms[0].room_id)
@@ -238,4 +261,4 @@ class TestAssociations < ActiveSupport::TestCase
238
261
  assert_equal(1, memberships.length)
239
262
  assert_equal([1,1], memberships[0].id)
240
263
  end
241
- end
264
+ end
@@ -21,11 +21,4 @@ class CompositeArraysTest < ActiveSupport::TestCase
21
21
  assert_equal CompositePrimaryKeys::CompositeKeys, keys.class
22
22
  assert_equal '1,2,3', keys.to_s
23
23
  end
24
-
25
- def test_composite_keys_equality
26
- keys_array_1 = [1, Time.now].to_composite_keys
27
- keys_array_2 = [1, Time.now].to_composite_keys
28
- assert keys_array_1 == keys_array_2
29
- assert keys_array_1.eql? keys_array_2
30
- end
31
- end
24
+ end
@@ -32,6 +32,12 @@ class TestIds < ActiveSupport::TestCase
32
32
  end
33
33
  end
34
34
 
35
+ def test_to_param
36
+ testing_with do
37
+ assert_equal '1,1', @first.to_param if composite?
38
+ end
39
+ end
40
+
35
41
  def test_ids_to_s
36
42
  testing_with do
37
43
  order = @klass.primary_key.is_a?(String) ? @klass.primary_key : @klass.primary_key.join(',')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: composite_primary_keys
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.4
4
+ version: 5.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-03-23 00:00:00.000000000 Z
13
+ date: 2012-05-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord