composite_primary_keys 1.0.2 → 1.0.3

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,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