composite_primary_keys 3.1.1 → 3.1.2
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 +9 -1
- data/lib/composite_primary_keys/base.rb +1 -2
- data/lib/composite_primary_keys/calculations.rb +32 -19
- data/lib/composite_primary_keys/composite_arrays.rb +0 -4
- data/lib/composite_primary_keys/finder_methods.rb +36 -21
- data/lib/composite_primary_keys/fixtures.rb +1 -1
- data/lib/composite_primary_keys/version.rb +1 -1
- data/scripts/txt2html +3 -0
- data/tasks/website.rake +2 -2
- data/test/db_test.rb +53 -0
- data/test/fixtures/db_definitions/sqlite.sql +6 -0
- data/test/fixtures/reference_codes.yml +2 -3
- data/test/setup.rb +51 -0
- data/test/test_associations.rb +3 -3
- data/test/test_composite_arrays.rb +0 -6
- data/test/test_find.rb +33 -45
- metadata +9 -5
data/History.txt
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
== 3.1.
|
1
|
+
== 3.1.2 2011-02-26
|
2
|
+
* Add back in support for find('3,3') which makes it possible to
|
3
|
+
do find(params[id]). This implementation is simpler than earlier version
|
4
|
+
improving code readability.
|
5
|
+
* Support for finding multiple records either via find([1,2], [3,4])
|
6
|
+
* Remove to_composite_ids method which is no longer needed
|
7
|
+
|
8
|
+
|
9
|
+
== 3.1.1 2011-02-07
|
2
10
|
* Implement id_before_type_cast (Jason Lewis)
|
3
11
|
* Add in tests for Model.includes(:other_model)
|
4
12
|
* Fix object comparison with nil in composite primary keys (StackNG)
|
@@ -125,8 +125,7 @@ module ActiveRecord
|
|
125
125
|
def quoted_id #:nodoc:
|
126
126
|
[self.class.primary_keys, ids].
|
127
127
|
transpose.
|
128
|
-
map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}
|
129
|
-
to_composite_ids
|
128
|
+
map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}
|
130
129
|
end
|
131
130
|
|
132
131
|
# Sets the primary ID.
|
@@ -1,29 +1,42 @@
|
|
1
|
-
# TODO - This code doesn't work with ActiveRecord 3.0.3...
|
2
|
-
|
3
1
|
#module ActiveRecord
|
4
2
|
# module Calculations
|
3
|
+
# alias :execute_simple_calculation_original :execute_simple_calculation
|
4
|
+
#
|
5
5
|
# def execute_simple_calculation(operation, column_name, distinct)
|
6
|
-
# # CPK changes
|
7
6
|
# if column_name.kind_of?(Array)
|
8
|
-
#
|
9
|
-
# table[primary_key_column].to_sql
|
10
|
-
# end
|
11
|
-
# projection = "DISTINCT #{columns.join(',')}"
|
12
|
-
# subquery = "(#{table.project(projection).to_sql}) AS subquery"
|
13
|
-
# relation = Arel::Table.new(subquery).project(Arel::SqlLiteral.new('*').count)
|
14
|
-
# type_cast_calculated_value(@klass.connection.select_value(relation.to_sql),
|
15
|
-
# column_for(column_name.first), operation)
|
7
|
+
# execute_simple_calculation_cpk(operation, column_name, distinct)
|
16
8
|
# else
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
9
|
+
# execute_simple_calculation_original(operation, column_name, distinct)
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# def execute_simple_calculation_cpk(operation, column_name, distinct)
|
14
|
+
# # SELECT COUNT(field1, field2) doens't work so make a subquery
|
15
|
+
# # like SELECT COUNT(*) FROM (SELECT DISTINCT field1, field2)
|
22
16
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# type_cast_calculated_value(@klass.connection.select_value(relation.to_sql), column_for(column_name), operation)
|
17
|
+
# columns = column_name.map do |primary_key_column|
|
18
|
+
# table[primary_key_column]
|
26
19
|
# end
|
20
|
+
#
|
21
|
+
# subquery = clone.project(columns)
|
22
|
+
# subquery = "(#{subquery.to_sql}) AS calculation_subquery"
|
23
|
+
# relation = Arel::Table.new(Arel::SqlLiteral.new(subquery))#.project(Arel::SqlLiteral.new('*').count)
|
24
|
+
# puts relation.to_sql
|
25
|
+
#
|
26
|
+
# #projection = "DISTINCT #{columns.join(',')}"
|
27
|
+
# #subquery = "(#{table.project(projection).to_sql}) AS subquery"
|
28
|
+
#
|
29
|
+
# #select_value = ::Arel::Nodes::Count.new(columns, distinct)
|
30
|
+
# # relation.select_values = columns
|
31
|
+
# # puts @klass.connection.select_value(relation.to_sql)
|
32
|
+
##
|
33
|
+
# #type_cast_calculated_value(@klass.connection.select_value(relation.to_sql), column_for(column_name), operation)
|
34
|
+
# #relation.select_values = [count_node]
|
35
|
+
# #projection = "DISTINCT #{columns.join(',')}"
|
36
|
+
# #subquery = "(#{table.project(projection).to_sql}) AS subquery"
|
37
|
+
# #relation = Arel::Table.new(subquery).project(Arel::SqlLiteral.new('*').count)
|
38
|
+
# type_cast_calculated_value(@klass.connection.select_value(relation.to_sql),
|
39
|
+
# column_for(column_name.first), operation)
|
27
40
|
# end
|
28
41
|
# end
|
29
42
|
#end
|
@@ -74,34 +74,49 @@ module CompositePrimaryKeys
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def find_with_ids(*ids, &block)
|
77
|
-
return to_a.find(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
77
|
+
return to_a.find { |*block_args| yield(*block_args) } if block_given?
|
78
|
+
|
79
|
+
# Supports:
|
80
|
+
# find('1,2') -> ['1,2']
|
81
|
+
# find(1,2) -> [1,2]
|
82
|
+
# find([1,2]) -> [['1,2']]
|
83
|
+
# find([1,2], [3,4]) -> [[1,2],[3,4]]
|
84
|
+
#
|
85
|
+
# Does *not* support:
|
86
|
+
# find('1,2', '3,4') -> ['1,2','3,4']
|
87
|
+
|
88
|
+
# Normalize incoming data. Note the last arg can be nil. Happens
|
89
|
+
# when find is called with nil options like the reload method does.
|
90
|
+
ids.compact!
|
91
|
+
ids = [ids] unless ids.first.kind_of?(Array)
|
92
|
+
|
93
|
+
results = ids.map do |cpk_ids|
|
94
|
+
cpk_ids = if cpk_ids.length == 1
|
95
|
+
cpk_ids.first.split(CompositePrimaryKeys::ID_SEP).to_composite_keys
|
96
|
+
else
|
97
|
+
cpk_ids.to_composite_keys
|
85
98
|
end
|
86
|
-
|
87
|
-
|
99
|
+
|
100
|
+
unless cpk_ids.length == @klass.primary_keys.length
|
101
|
+
raise "#{cpk_ids.inspect}: Incorrect number of primary keys for #{@klass.name}: #{@klass.primary_keys.inspect}"
|
88
102
|
end
|
89
|
-
end
|
90
103
|
|
91
|
-
|
92
|
-
|
93
|
-
[@klass.primary_keys, id_set].transpose.map do |key, id|
|
104
|
+
new_relation = clone
|
105
|
+
[@klass.primary_keys, cpk_ids].transpose.map do |key, id|
|
94
106
|
new_relation = new_relation.where(key => id)
|
95
107
|
end
|
96
|
-
|
108
|
+
|
109
|
+
records = new_relation.to_a
|
97
110
|
|
98
|
-
|
111
|
+
if records.empty?
|
112
|
+
conditions = new_relation.arel.where_sql
|
113
|
+
raise(::ActiveRecord::RecordNotFound,
|
114
|
+
"Couldn't find #{@klass.name} with ID=#{cpk_ids} #{conditions}")
|
115
|
+
end
|
116
|
+
records
|
117
|
+
end.flatten
|
99
118
|
|
100
|
-
|
101
|
-
ids.size == 1 ? result[0] : result
|
102
|
-
else
|
103
|
-
raise ::ActiveRecord::RecordNotFound, "Couldn't find all #{@klass.name} with IDs (#{ids.inspect})"
|
104
|
-
end
|
119
|
+
ids.length == 1 ? results.first : results
|
105
120
|
end
|
106
121
|
end
|
107
122
|
end
|
data/scripts/txt2html
CHANGED
data/tasks/website.rake
CHANGED
@@ -8,8 +8,8 @@ end
|
|
8
8
|
desc 'Upload website files to rubyforge'
|
9
9
|
task :website_upload do
|
10
10
|
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
11
|
-
host = "
|
12
|
-
remote_dir = "/var/www/gforge-projects/compositekeys"
|
11
|
+
host = "#{config["username"]}@rubyforge.org"
|
12
|
+
remote_dir = "/var/www/gforge-projects/compositekeys/"
|
13
13
|
local_dir = 'website'
|
14
14
|
sh %{scp -r #{local_dir}/* #{host}:#{remote_dir}}
|
15
15
|
end
|
data/test/db_test.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# assoc_test.rb
|
2
|
+
|
3
|
+
path = File.expand_path(File.join(File.basename(__FILE__), "..", "lib", "composite_primary_keys"))
|
4
|
+
puts path
|
5
|
+
|
6
|
+
require File.join(path)
|
7
|
+
require 'active_record'
|
8
|
+
|
9
|
+
$configuration = {
|
10
|
+
:adapter => 'postgresql',
|
11
|
+
:database => 'cpk_test',
|
12
|
+
:username => 'postgres'
|
13
|
+
}
|
14
|
+
|
15
|
+
ActiveRecord::Base.establish_connection($configuration) unless ActiveRecord::Base.connected?
|
16
|
+
|
17
|
+
module GlobePG
|
18
|
+
class PGBase < ActiveRecord::Base
|
19
|
+
self.abstract_class = true
|
20
|
+
# establish_connection($configuration) unless connected?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module GlobePG
|
25
|
+
class TeacherToSchool < PGBase
|
26
|
+
set_table_name 'teacher_to_school'
|
27
|
+
set_primary_keys ['teacherid', 'schoolid']
|
28
|
+
|
29
|
+
belongs_to :globe_teacher, :foreign_key => 'teacherid'
|
30
|
+
belongs_to :globe_school, :foreign_key => 'schoolid'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module GlobePG
|
35
|
+
class GlobeSchool < PGBase
|
36
|
+
set_table_name 'globe_school'
|
37
|
+
set_primary_key 'schoolid'
|
38
|
+
has_many :teacher_to_schools, :foreign_key => :schoolid
|
39
|
+
has_many :globe_teachers, :through => :teacher_to_schools
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module GlobePG
|
44
|
+
class GlobeTeacher < PGBase
|
45
|
+
set_table_name 'globe_teacher'
|
46
|
+
set_primary_key 'teacherid'
|
47
|
+
has_many :teacher_to_schools, :foreign_key => :teacherid
|
48
|
+
has_many :globe_schools, :through => :teacher_to_schools
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
teacher = GlobePG::GlobeTeacher.find_by_teacherid('ZZGLOBEY')
|
53
|
+
p teacher.globe_schools
|
data/test/setup.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# setup_db.rb
|
2
|
+
require 'dbi'
|
3
|
+
|
4
|
+
# Run "createdb cpk_test" first
|
5
|
+
|
6
|
+
teacher_to_school = %Q{
|
7
|
+
create table teacher_to_school(
|
8
|
+
schoolid varchar(8),
|
9
|
+
teacherid varchar(8),
|
10
|
+
datebegin date,
|
11
|
+
teacherrole varchar(20),
|
12
|
+
primary key (schoolid, teacherid)
|
13
|
+
);
|
14
|
+
|
15
|
+
}
|
16
|
+
|
17
|
+
globe_teacher = %Q{
|
18
|
+
create table globe_teacher(
|
19
|
+
teacherid varchar(8) primary key,
|
20
|
+
currentschoolid varchar(8),
|
21
|
+
userid varchar(16)
|
22
|
+
);
|
23
|
+
|
24
|
+
}
|
25
|
+
|
26
|
+
globe_school = %Q{
|
27
|
+
create table globe_school(
|
28
|
+
schoolid varchar(8) primary key,
|
29
|
+
schoolname varchar(100) not null,
|
30
|
+
city varchar(35) not null
|
31
|
+
)
|
32
|
+
|
33
|
+
}
|
34
|
+
|
35
|
+
add_records = [
|
36
|
+
"insert into globe_teacher values ('ZZGLOBEY', 'ZZGLOBE1',
|
37
|
+
'dberger');",
|
38
|
+
"insert into globe_school values ('ZZCOUCAR', 'NCAR Foothills Lab',
|
39
|
+
'Boulder');",
|
40
|
+
"insert into globe_school values ('ZZGLOBE1', 'The GLOBE Program',
|
41
|
+
'Boulder');",
|
42
|
+
"insert into teacher_to_school values('ZZGLOBE1', 'ZZGLOBEY', '1-JUN-2010', 'GLOBE OFFICE');",
|
43
|
+
"insert into teacher_to_school values('ZZCOUCAR', 'ZZGLOBEY', '1-AUG-2010', 'GLOBE Teacher');"
|
44
|
+
]
|
45
|
+
|
46
|
+
DBI.connect('dbi:Pg:cpk_test', 'postgres') do |dbh|
|
47
|
+
dbh.execute(teacher_to_school)
|
48
|
+
dbh.execute(globe_teacher)
|
49
|
+
dbh.execute(globe_school)
|
50
|
+
add_records.each{ |sql| dbh.execute(sql) }
|
51
|
+
end
|
data/test/test_associations.rb
CHANGED
@@ -26,9 +26,9 @@ class TestAssociations < ActiveSupport::TestCase
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_count
|
29
|
-
assert_equal
|
30
|
-
assert_equal
|
31
|
-
assert_equal
|
29
|
+
assert_equal(2, Product.count(:include => :product_tariffs))
|
30
|
+
assert_equal(3, Tariff.count(:include => :product_tariffs))
|
31
|
+
assert_equal(2, Tariff.count(:group => :start_date))
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_products
|
@@ -21,10 +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_to_composite_ids
|
26
|
-
keys = [1,2,3].to_composite_ids
|
27
|
-
assert_equal Array, keys.class
|
28
|
-
assert_equal '123', keys.to_s
|
29
|
-
end
|
30
24
|
end
|
data/test/test_find.rb
CHANGED
@@ -4,66 +4,54 @@ require 'abstract_unit'
|
|
4
4
|
class TestFind < ActiveSupport::TestCase
|
5
5
|
fixtures :capitols, :reference_types, :reference_codes, :suburbs
|
6
6
|
|
7
|
-
|
8
|
-
:
|
9
|
-
|
10
|
-
|
11
|
-
},
|
12
|
-
:dual => {
|
13
|
-
:class => ReferenceCode,
|
14
|
-
:primary_keys => [:reference_type_id, :reference_code],
|
15
|
-
},
|
16
|
-
:dual_strs => {
|
17
|
-
:class => ReferenceCode,
|
18
|
-
:primary_keys => ['reference_type_id', 'reference_code'],
|
19
|
-
},
|
20
|
-
}
|
21
|
-
|
22
|
-
def setup
|
23
|
-
self.class.classes = CLASSES
|
7
|
+
def test_find_first
|
8
|
+
ref_code = ReferenceCode.find(:first, :order => 'reference_type_id, reference_code')
|
9
|
+
assert_kind_of(ReferenceCode, ref_code)
|
10
|
+
assert_equal([1,1], ref_code.id)
|
24
11
|
end
|
25
12
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
assert_equal @klass, obj.class
|
31
|
-
end
|
13
|
+
def test_find_last
|
14
|
+
ref_code = ReferenceCode.find(:last, :order => 'reference_type_id, reference_code')
|
15
|
+
assert_kind_of(ReferenceCode, ref_code)
|
16
|
+
assert_equal([2,2], ref_code.id)
|
32
17
|
end
|
33
18
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
assert_equal @klass, found.class
|
39
|
-
assert_equal found, @klass.find(found.id)
|
40
|
-
end
|
19
|
+
def test_find_one
|
20
|
+
ref_code = ReferenceCode.find([1,3])
|
21
|
+
assert_not_nil(ref_code)
|
22
|
+
assert_equal([1,3], ref_code.id)
|
41
23
|
end
|
42
24
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
assert_equal @klass, found.class
|
48
|
-
assert_equal found, @klass.find(found.id)
|
49
|
-
end
|
25
|
+
def test_find_one_string
|
26
|
+
ref_code = ReferenceCode.find('1,3')
|
27
|
+
assert_kind_of(ReferenceCode, ref_code)
|
28
|
+
assert_equal([1,3], ref_code.id)
|
50
29
|
end
|
51
30
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
31
|
+
def test_find_some
|
32
|
+
ref_codes = ReferenceCode.find([1,3], [2,1])
|
33
|
+
assert_kind_of(Array, ref_codes)
|
34
|
+
assert_equal(2, ref_codes.length)
|
35
|
+
|
36
|
+
ref_code = ref_codes[0]
|
37
|
+
assert_equal([1,3], ref_code.id)
|
38
|
+
|
39
|
+
ref_code = ref_codes[1]
|
40
|
+
assert_equal([2,1], ref_code.id)
|
56
41
|
end
|
57
42
|
|
58
43
|
def test_find_with_strings_as_composite_keys
|
59
|
-
|
60
|
-
|
44
|
+
capitol = Capitol.find(['The Netherlands', 'Amsterdam'])
|
45
|
+
assert_kind_of(Capitol, capitol)
|
46
|
+
assert_equal(['The Netherlands', 'Amsterdam'], capitol.id)
|
61
47
|
end
|
62
48
|
|
63
49
|
def test_not_found
|
64
|
-
assert_raise(::ActiveRecord::RecordNotFound) do
|
50
|
+
error = assert_raise(::ActiveRecord::RecordNotFound) do
|
65
51
|
ReferenceCode.find(['999', '999'])
|
66
52
|
end
|
53
|
+
assert_equal("Couldn't find ReferenceCode with ID=999,999 WHERE \"reference_codes\".\"reference_type_id\" = 999 AND \"reference_codes\".\"reference_code\" = 999",
|
54
|
+
error.message)
|
67
55
|
end
|
68
56
|
|
69
57
|
def test_find_last_suburb
|
@@ -76,4 +64,4 @@ class TestFind < ActiveSupport::TestCase
|
|
76
64
|
suburb = Suburb.find(:last, :order => 'suburbs.city_id DESC')
|
77
65
|
assert_equal([1,1], suburb.id)
|
78
66
|
end
|
79
|
-
end
|
67
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composite_primary_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 3.1.
|
9
|
+
- 2
|
10
|
+
version: 3.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Dr Nic Williams
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-02-
|
19
|
+
date: 2011-02-26 00:00:00 -07:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -112,6 +112,7 @@ files:
|
|
112
112
|
- test/connections/native_oracle_enhanced/connection.rb
|
113
113
|
- test/connections/native_postgresql/connection.rb
|
114
114
|
- test/connections/native_sqlite/connection.rb
|
115
|
+
- test/db_test.rb
|
115
116
|
- test/debug.log
|
116
117
|
- test/fixtures/article.rb
|
117
118
|
- test/fixtures/articles.yml
|
@@ -181,6 +182,7 @@ files:
|
|
181
182
|
- test/plugins/pagination.rb
|
182
183
|
- test/plugins/pagination_helper.rb
|
183
184
|
- test/README_tests.txt
|
185
|
+
- test/setup.rb
|
184
186
|
- test/test_associations.rb
|
185
187
|
- test/test_attributes.rb
|
186
188
|
- test/test_attribute_methods.rb
|
@@ -232,15 +234,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
232
234
|
requirements: []
|
233
235
|
|
234
236
|
rubyforge_project: compositekeys
|
235
|
-
rubygems_version: 1.5.
|
237
|
+
rubygems_version: 1.5.2
|
236
238
|
signing_key:
|
237
239
|
specification_version: 3
|
238
240
|
summary: Composite key support for ActiveRecord
|
239
241
|
test_files:
|
240
242
|
- test/abstract_unit.rb
|
243
|
+
- test/db_test.rb
|
241
244
|
- test/debug.log
|
242
245
|
- test/hash_tricks.rb
|
243
246
|
- test/README_tests.txt
|
247
|
+
- test/setup.rb
|
244
248
|
- test/test_associations.rb
|
245
249
|
- test/test_attributes.rb
|
246
250
|
- test/test_attribute_methods.rb
|