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