composite_primary_keys 5.0.4 → 5.0.5

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.
@@ -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