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.
- data/History.txt +4 -0
- data/lib/composite_primary_keys/associations.rb +36 -77
- data/lib/composite_primary_keys/version.rb +1 -1
- data/test/fixtures/db_definitions/mysql.sql +12 -1
- data/test/fixtures/db_definitions/sqlite.sql +10 -0
- data/test/fixtures/user.rb +4 -1
- data/test/test_associations.rb +31 -1
- data/tmp/test.db +0 -0
- metadata +4 -3
data/History.txt
CHANGED
@@ -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
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
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
|
-
|
368
|
-
|
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
|
-
|
381
|
-
|
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
|
-
|
423
|
-
@
|
424
|
-
|
425
|
-
|
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
|
@@ -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
|
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
|
+
);
|
data/test/fixtures/user.rb
CHANGED
data/test/test_associations.rb
CHANGED
@@ -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
|
data/tmp/test.db
CHANGED
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.
|
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-
|
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
|
185
|
+
rubygems_version: 1.2.0
|
185
186
|
signing_key:
|
186
187
|
specification_version: 2
|
187
188
|
summary: Composite key support for ActiveRecords
|