composite_primary_keys 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,7 @@
1
+ == 1.0.3 2008-07-13
2
+
3
+ * more fixes and tests for has many through [thx Menno van der Sman]
4
+
1
5
  == 1.0.2 2008-06-07
2
6
 
3
7
  * fix for has many through when through association has composite keys
@@ -228,43 +228,48 @@ module ActiveRecord::Associations
228
228
 
229
229
  def composite_where_clause(full_keys, ids)
230
230
  full_keys = full_keys.split(CompositePrimaryKeys::ID_SEP) if full_keys.is_a?(String)
231
+
231
232
  if ids.is_a?(String)
232
233
  ids = [[ids]]
233
234
  elsif not ids.first.is_a?(Array) # if single comp key passed, turn into an array of 1
234
235
  ids = [ids.to_composite_ids]
235
236
  end
237
+
236
238
  where_clause = ids.map do |id_set|
237
239
  transposed = id_set.size == 1 ? [[full_keys, id_set.first]] : [full_keys, id_set].transpose
238
240
  transposed.map do |full_key, id|
239
241
  "#{full_key.to_s}=#{@reflection.klass.sanitize(id)}"
240
242
  end.join(" AND ")
241
243
  end.join(") OR (")
244
+
242
245
  "(#{where_clause})"
243
246
  end
244
247
 
245
248
  def composite_join_clause(full_keys1, full_keys2)
246
249
  full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
247
250
  full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
251
+
248
252
  where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
249
253
  "#{key_pair.first}=#{key_pair.last}"
250
254
  end.join(" AND ")
255
+
251
256
  "(#{where_clause})"
252
257
  end
253
258
 
254
259
  def full_composite_join_clause(table1, full_keys1, table2, full_keys2)
255
260
  full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
256
261
  full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
262
+
257
263
  where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
258
264
  "#{table1}.#{key_pair.first}=#{table2}.#{key_pair.last}"
259
265
  end.join(" AND ")
266
+
260
267
  "(#{where_clause})"
261
268
  end
262
269
 
263
270
  def full_keys(table_name, keys)
264
271
  keys = keys.split(CompositePrimaryKeys::ID_SEP) if keys.is_a?(String)
265
- keys.is_a?(Array) ?
266
- keys.collect {|key| "#{table_name}.#{key}"}.join(CompositePrimaryKeys::ID_SEP) :
267
- "#{table_name}.#{keys}"
272
+ keys.is_a?(Array) ? keys.collect {|key| "#{table_name}.#{key}"}.join(CompositePrimaryKeys::ID_SEP) : "#{table_name}.#{keys}"
268
273
  end
269
274
 
270
275
  def full_columns_equals(table_name, keys, quoted_ids)
@@ -285,10 +290,7 @@ module ActiveRecord::Associations
285
290
  if @reflection.options[:finder_sql]
286
291
  @finder_sql = @reflection.options[:finder_sql]
287
292
  else
288
- @finder_sql = full_columns_equals(
289
- @reflection.options[:join_table],
290
- @reflection.primary_key_name,
291
- @owner.quoted_id)
293
+ @finder_sql = full_columns_equals(@reflection.options[:join_table], @reflection.primary_key_name, @owner.quoted_id)
292
294
  @finder_sql << " AND (#{conditions})" if conditions
293
295
  end
294
296
 
@@ -310,8 +312,7 @@ module ActiveRecord::Associations
310
312
  @finder_sql << " AND (#{conditions})" if conditions
311
313
 
312
314
  else
313
- @finder_sql = full_columns_equals(@reflection.klass.table_name,
314
- @reflection.primary_key_name, @owner.quoted_id)
315
+ @finder_sql = full_columns_equals(@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id)
315
316
  @finder_sql << " AND (#{conditions})" if conditions
316
317
  end
317
318
 
@@ -331,18 +332,18 @@ module ActiveRecord::Associations
331
332
  records.each { |r| r.destroy }
332
333
  else
333
334
  field_names = @reflection.primary_key_name.split(',')
334
- field_names.collect! {|n|
335
- n + " = NULL"
336
- }
337
- records.each { |r|
338
- where_class = nil
339
- if r.quoted_id.include?(',')
340
- where_class = [@reflection.klass.primary_key, r.quoted_id].transpose.map {|pair| "(#{pair[0]} = #{pair[1]})"}.join(" AND ")
341
- else
342
- where_class = @reflection.klass.primary_key + ' = ' + r.quoted_id
343
- end
344
- @reflection.klass.update_all( field_names.join(',') , where_class)
345
- }
335
+ field_names.collect! {|n| n + " = NULL"}
336
+ records.each do |r|
337
+ where_class = nil
338
+
339
+ if r.quoted_id.include?(',')
340
+ where_class = [@reflection.klass.primary_key, r.quoted_id].transpose.map {|pair| "(#{pair[0]} = #{pair[1]})"}.join(" AND ")
341
+ else
342
+ where_class = @reflection.klass.primary_key + ' = ' + r.quoted_id
343
+ end
344
+
345
+ @reflection.klass.update_all( field_names.join(',') , where_class)
346
+ end
346
347
  end
347
348
  end
348
349
  end
@@ -355,79 +356,37 @@ module ActiveRecord::Associations
355
356
  "#{@reflection.klass.table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
356
357
  "#{@reflection.klass.table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
357
358
  else
358
- @finder_sql = full_columns_equals(@reflection.klass.table_name,
359
- @reflection.primary_key_name, @owner.quoted_id)
359
+ @finder_sql = full_columns_equals(@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id)
360
360
  end
361
+
361
362
  @finder_sql << " AND (#{conditions})" if conditions
362
363
  end
363
364
  end
365
+
364
366
 
365
367
  class HasManyThroughAssociation < HasManyAssociation #:nodoc:
366
368
  def construct_conditions
367
- conditions = if @reflection.through_reflection.options[:as]
368
- "#{@reflection.through_reflection.table_name}.#{@reflection.through_reflection.options[:as]}_id = #{@owner.quoted_id} " +
369
- "AND #{@reflection.through_reflection.table_name}.#{@reflection.through_reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
370
- else
371
- @finder_sql = full_columns_equals(@reflection.through_reflection.table_name,
372
- @reflection.through_reflection.primary_key_name, @owner.quoted_id)
373
- end
369
+ raise 'polymorphic joins are not supported by composite_primary_keys' if @reflection.through_reflection.options[:as]
370
+ conditions = full_columns_equals(@reflection.through_reflection.table_name, @reflection.through_reflection.primary_key_name, @owner.quoted_id)
374
371
  conditions << " AND (#{sql_conditions})" if sql_conditions
375
-
376
- return conditions
372
+ conditions
377
373
  end
378
374
 
379
- def construct_joins(custom_joins = nil)
380
- polymorphic_join = nil
381
- if @reflection.through_reflection.options[:as] || @reflection.source_reflection.macro == :belongs_to
375
+ def construct_joins(custom_joins = nil)
376
+ raise 'polymorphic joins are not supported by composite_primary_keys' if @reflection.through_reflection.options[:as] || @reflection.source_reflection.options[:as]
377
+
378
+ if @reflection.source_reflection.macro == :belongs_to
382
379
  reflection_primary_key = @reflection.klass.primary_key
383
380
  source_primary_key = @reflection.source_reflection.primary_key_name
384
381
  else
385
382
  reflection_primary_key = @reflection.source_reflection.primary_key_name
386
383
  source_primary_key = @reflection.klass.primary_key
387
- if @reflection.source_reflection.options[:as]
388
- polymorphic_join = "AND %s.%s = %s" % [
389
- @reflection.table_name, "#{@reflection.source_reflection.options[:as]}_type",
390
- @owner.class.quote_value(@reflection.through_reflection.klass.name)
391
- ]
392
- end
393
- end
394
-
395
- "INNER JOIN %s ON %s %s #{@reflection.options[:joins]} #{custom_joins}" % [
396
- @reflection.through_reflection.table_name,
397
- composite_join_clause(
398
- full_keys(@reflection.table_name, reflection_primary_key),
399
- full_keys(@reflection.through_reflection.table_name, source_primary_key)),
400
- polymorphic_join
401
- ]
402
- end
403
-
404
- def construct_sql
405
- case
406
- when @reflection.options[:finder_sql]
407
- @finder_sql = interpolate_sql(@reflection.options[:finder_sql])
408
-
409
- @finder_sql << " AND (#{conditions})" if conditions
410
- when @reflection.options[:as]
411
- @finder_sql =
412
- "#{@reflection.klass.table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
413
- "#{@reflection.klass.table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
414
- @finder_sql << " AND (#{conditions})" if conditions
415
-
416
- else
417
- @finder_sql = composite_where_clause(
418
- full_keys(@reflection.klass.table_name, @reflection.primary_key_name), @owner.quoted_id),
419
- @finder_sql << " AND (#{conditions})" if conditions
420
384
  end
421
385
 
422
- if @reflection.options[:counter_sql]
423
- @counter_sql = interpolate_sql(@reflection.options[:counter_sql])
424
- elsif @reflection.options[:finder_sql]
425
- # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */
426
- @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" }
427
- @counter_sql = interpolate_sql(@reflection.options[:counter_sql])
428
- else
429
- @counter_sql = @finder_sql
430
- end
386
+ "INNER JOIN %s ON %s #{@reflection.options[:joins]} #{custom_joins}" % [
387
+ @reflection.through_reflection.table_name,
388
+ composite_join_clause(full_keys(@reflection.table_name, reflection_primary_key), full_keys(@reflection.through_reflection.table_name, source_primary_key))
389
+ ]
431
390
  end
432
391
  end
433
392
  end
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
4
  MINOR = 0
5
- TINY = 2
5
+ TINY = 3
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
@@ -157,5 +157,16 @@ create table room_attributes (
157
157
  create table room_attribute_assignments (
158
158
  dorm_id int(11) not null,
159
159
  room_id int(11) not null,
160
- room_attribute_id integer not null
160
+ room_attribute_id int(11) not null
161
+ ) TYPE=InnoDB;
162
+
163
+ create table students (
164
+ id int(11) not null auto_increment,
165
+ primary key(id)
166
+ ) TYPE=InnoDB;
167
+
168
+ create table room_assignments (
169
+ student_id int(11) not null,
170
+ dorm_id int(11) not null,
171
+ room_id int(11) not null
161
172
  ) TYPE=InnoDB;
@@ -146,3 +146,13 @@ create table room_attribute_assignments (
146
146
  room_id integer not null,
147
147
  room_attribute_id integer not null
148
148
  );
149
+
150
+ create table students (
151
+ id integer not null primary key autoincrement
152
+ );
153
+
154
+ create table room_assignments (
155
+ student_id integer not null,
156
+ dorm_id integer not null,
157
+ room_id integer not null
158
+ );
@@ -2,5 +2,8 @@ class User < ActiveRecord::Base
2
2
  has_many :readings
3
3
  has_many :articles, :through => :readings
4
4
  has_many :comments, :as => :person
5
+
6
+ def find_custom_articles
7
+ articles.find(:all, :conditions => ["name = ?", "Article One"])
8
+ end
5
9
  end
6
-
@@ -9,16 +9,38 @@ require 'fixtures/dorm'
9
9
  require 'fixtures/room'
10
10
  require 'fixtures/room_attribute'
11
11
  require 'fixtures/room_attribute_assignment'
12
+ require 'fixtures/student'
13
+ require 'fixtures/room_assignment'
12
14
 
13
15
  class TestAssociations < Test::Unit::TestCase
14
16
  fixtures :products, :tariffs, :product_tariffs, :suburbs, :streets, :restaurants, :restaurants_suburbs,
15
- :dorms, :rooms, :room_attributes, :room_attribute_assignments
17
+ :dorms, :rooms, :room_attributes, :room_attribute_assignments, :students, :room_assignments
16
18
 
17
19
  def test_quoted_table_columns
18
20
  assert_equal "product_tariffs.product_id,product_tariffs.tariff_id,product_tariffs.tariff_start_date",
19
21
  ProductTariff.send(:quoted_table_columns, ProductTariff.primary_key)
20
22
  end
21
23
 
24
+ def test_has_many_through_with_conditions_when_through_association_is_not_composite
25
+ user = User.find(:first)
26
+ assert_equal 1, user.articles.find(:all, :conditions => ["articles.name = ?", "Article One"]).size
27
+ end
28
+
29
+ def test_has_many_through_with_conditions_when_through_association_is_composite
30
+ room = Room.find(:first)
31
+ assert_equal 0, room.room_attributes.find(:all, :conditions => ["room_attributes.name != ?", "keg"]).size
32
+ end
33
+
34
+ def test_has_many_through_on_custom_finder_when_through_association_is_not_composite
35
+ user = User.find(:first)
36
+ assert_equal 1, user.find_custom_articles.size
37
+ end
38
+
39
+ def test_has_many_through_on_custom_finder_when_through_association_is_composite
40
+ room = Room.find(:first)
41
+ assert_equal 0, room.find_custom_room_attributes.size
42
+ end
43
+
22
44
  def test_count
23
45
  assert_equal 2, Product.count(:include => :product_tariffs)
24
46
  assert_equal 3, Tariff.count(:include => :product_tariffs)
@@ -100,6 +122,14 @@ class TestAssociations < Test::Unit::TestCase
100
122
  "Incorrect number of tariffs returned"
101
123
  end
102
124
 
125
+ def test_has_many_through_when_not_pre_loaded
126
+ student = Student.find(:first)
127
+ rooms = student.rooms
128
+ assert_equal 1, rooms.size
129
+ assert_equal 1, rooms.first.dorm_id
130
+ assert_equal 1, rooms.first.room_id
131
+ end
132
+
103
133
  def test_has_many_through_when_through_association_is_composite
104
134
  dorm = Dorm.find(:first)
105
135
  assert_equal 1, dorm.rooms.length
Binary file
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: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dr Nic Williams
@@ -9,11 +9,12 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-06-07 00:00:00 -05:00
12
+ date: 2008-07-13 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -181,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
182
  requirements: []
182
183
 
183
184
  rubyforge_project: compositekeys
184
- rubygems_version: 1.0.1
185
+ rubygems_version: 1.2.0
185
186
  signing_key:
186
187
  specification_version: 2
187
188
  summary: Composite key support for ActiveRecords