composite_primary_keys 0.1.4 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +11 -27
- data/lib/composite_primary_keys.rb +1 -0
- data/lib/composite_primary_keys/base.rb +63 -22
- data/lib/composite_primary_keys/composite_arrays.rb +28 -0
- data/lib/composite_primary_keys/version.rb +3 -3
- data/test/abstract_unit.rb +4 -3
- data/test/clone_test.rb +35 -0
- data/test/composite_arrays_test.rb +46 -0
- data/test/delete_test.rb +67 -0
- data/test/dummy_test.rb +19 -1
- data/test/find_test.rb +7 -9
- data/test/hash_tricks.rb +34 -0
- data/test/ids_test.rb +59 -0
- data/test/miscellaneous_test.rb +17 -15
- data/test/pagination_test.rb +9 -4
- data/test/update_test.rb +41 -0
- metadata +15 -10
- data/lib/composite_primary_keys/primary_keys.rb +0 -10
- data/test/primary_keys_test.rb +0 -20
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ require File.join(File.dirname(__FILE__), 'lib', 'composite_primary_keys', 'vers
|
|
9
9
|
|
10
10
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
11
11
|
PKG_NAME = 'composite_primary_keys'
|
12
|
-
PKG_VERSION =
|
12
|
+
PKG_VERSION = CompositePrimaryKeys::VERSION::STRING + PKG_BUILD
|
13
13
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
14
14
|
|
15
15
|
RELEASE_NAME = "REL #{PKG_VERSION}"
|
@@ -24,6 +24,7 @@ PKG_FILES = FileList[
|
|
24
24
|
|
25
25
|
desc "Default Task"
|
26
26
|
task :default => [ :test_mysql ] # UNTESTED =, :test_sqlite, :test_postgresql ]
|
27
|
+
task :test => [ :test_mysql ]
|
27
28
|
|
28
29
|
# Run the unit tests
|
29
30
|
|
@@ -38,18 +39,15 @@ end
|
|
38
39
|
SCHEMA_PATH = File.join(File.dirname(__FILE__), *%w(test fixtures db_definitions))
|
39
40
|
|
40
41
|
desc 'Build the MySQL test databases'
|
41
|
-
task :build_mysql_databases
|
42
|
+
task :build_mysql_databases do
|
42
43
|
puts File.join(SCHEMA_PATH, 'mysql.sql')
|
43
|
-
%x( mysqladmin -u root create
|
44
|
-
|
45
|
-
%x( mysql -u root activerecord_unittest < #{File.join(SCHEMA_PATH, 'mysql.sql')} )
|
46
|
-
#%x( mysql -u root activerecord_unittest < #{File.join(SCHEMA_PATH, 'mysql2.sql')} )
|
44
|
+
%x( mysqladmin -u root create "#{PKG_NAME}_unittest" )
|
45
|
+
%x( mysql -u root "#{PKG_NAME}_unittest" < #{File.join(SCHEMA_PATH, 'mysql.sql')} )
|
47
46
|
end
|
48
47
|
|
49
48
|
desc 'Drop the MySQL test databases'
|
50
49
|
task :drop_mysql_databases do
|
51
|
-
%x( mysqladmin -u root -f drop
|
52
|
-
#%x( mysqladmin -u root -f drop activerecord_unittest2 )
|
50
|
+
%x( mysqladmin -u root -f drop "#{PKG_NAME}_unittest" )
|
53
51
|
end
|
54
52
|
|
55
53
|
desc 'Rebuild the MySQL test databases'
|
@@ -57,16 +55,13 @@ task :rebuild_mysql_databases => [:drop_mysql_databases, :build_mysql_databases]
|
|
57
55
|
|
58
56
|
desc 'Build the PostgreSQL test databases'
|
59
57
|
task :build_postgresql_databases do
|
60
|
-
%x( createdb
|
61
|
-
%x(
|
62
|
-
%x( psql activerecord_unittest -f #{File.join(SCHEMA_PATH, 'postgresql.sql')} )
|
63
|
-
%x( psql activerecord_unittest2 -f #{File.join(SCHEMA_PATH, 'postgresql2.sql')} )
|
58
|
+
%x( createdb "#{PKG_NAME}_unittest" )
|
59
|
+
%x( psql "#{PKG_NAME}_unittest" -f #{File.join(SCHEMA_PATH, 'postgresql.sql')} )
|
64
60
|
end
|
65
61
|
|
66
62
|
desc 'Drop the PostgreSQL test databases'
|
67
63
|
task :drop_postgresql_databases do
|
68
|
-
%x( dropdb
|
69
|
-
%x( dropdb activerecord_unittest2 )
|
64
|
+
%x( dropdb "#{PKG_NAME}_unittest" )
|
70
65
|
end
|
71
66
|
|
72
67
|
desc 'Rebuild the PostgreSQL test databases'
|
@@ -117,8 +112,8 @@ spec = Gem::Specification.new do |s|
|
|
117
112
|
|
118
113
|
s.author = "Dr Nic Williams"
|
119
114
|
s.email = "drnicwilliams@gmail.com"
|
120
|
-
s.homepage = "http://
|
121
|
-
s.rubyforge_project = "
|
115
|
+
s.homepage = "http://compositekeys.rubyforge.org"
|
116
|
+
s.rubyforge_project = "compositekeys"
|
122
117
|
end
|
123
118
|
|
124
119
|
Rake::GemPackageTask.new(spec) do |p|
|
@@ -154,17 +149,6 @@ end
|
|
154
149
|
|
155
150
|
# Publishing ------------------------------------------------------
|
156
151
|
|
157
|
-
desc "Publish the beta gem"
|
158
|
-
task :pgem => [:package] do
|
159
|
-
Rake::SshFilePublisher.new("drnicwilliams@gmail.com", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
160
|
-
`ssh drnicwilliams@gmail.com './gemupdate.sh'`
|
161
|
-
end
|
162
|
-
|
163
|
-
desc "Publish the API documentation"
|
164
|
-
task :pdoc => [:rdoc] do
|
165
|
-
Rake::SshDirPublisher.new("drnicwilliams@gmail.com", "public_html/ar", "doc").upload
|
166
|
-
end
|
167
|
-
|
168
152
|
desc "Publish the release files to RubyForge."
|
169
153
|
task :release => [ :package ] do
|
170
154
|
`ruby scripts/rubyforge login`
|
@@ -3,6 +3,7 @@ module CompositePrimaryKeys
|
|
3
3
|
module Base #:nodoc:
|
4
4
|
|
5
5
|
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
6
|
+
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
6
7
|
|
7
8
|
def self.append_features(base)
|
8
9
|
super
|
@@ -12,8 +13,9 @@ module CompositePrimaryKeys
|
|
12
13
|
|
13
14
|
module ClassMethods
|
14
15
|
def set_primary_keys(*keys)
|
16
|
+
keys = keys.first if keys.first.is_a?(Array) or keys.first.is_a?(CompositeKeys)
|
15
17
|
cattr_accessor :primary_keys
|
16
|
-
self.primary_keys =
|
18
|
+
self.primary_keys = keys.to_composite_keys
|
17
19
|
|
18
20
|
class_eval <<-EOV
|
19
21
|
include CompositePrimaryKeys::ActiveRecord::Base::CompositeInstanceMethods
|
@@ -38,29 +40,22 @@ module CompositePrimaryKeys
|
|
38
40
|
# whether you name it the default 'id' or set it to something else.
|
39
41
|
def id
|
40
42
|
attr_names = self.class.primary_keys
|
41
|
-
|
43
|
+
CompositeIds.new(
|
44
|
+
attr_names.map {|attr_name| read_attribute(attr_name)}
|
45
|
+
)
|
42
46
|
end
|
43
47
|
alias_method :ids, :id
|
48
|
+
alias_method :to_param, :id
|
44
49
|
|
45
|
-
#id_to_s([1,2]) -> "1,2"
|
46
|
-
#id_to_s([1,2], '-') -> "1-2"
|
47
|
-
def id_to_s(ids, id_sep = CompositePrimaryKeys::ID_SEP)
|
48
|
-
ids.map{|id| self.class.sanitize(id)}.join("#{id_sep}")
|
49
|
-
end
|
50
|
-
|
51
|
-
# Enables Active Record objects to be used as URL parameters in Action Pack automatically.
|
52
|
-
def to_param
|
53
|
-
id_to_s(ids)
|
54
|
-
end
|
55
|
-
|
56
50
|
def id_before_type_cast #:nodoc:
|
57
|
-
|
58
|
-
read_attribute_before_type_cast(self.class.primary_key)
|
51
|
+
raise CompositePrimaryKeys::ActiveRecord::Base::NOT_IMPLEMENTED_YET
|
59
52
|
end
|
60
53
|
|
61
54
|
def quoted_id #:nodoc:
|
62
|
-
|
63
|
-
|
55
|
+
[self.class.primary_keys, ids].
|
56
|
+
transpose.
|
57
|
+
map {|attr_name,id| quote(id, column_for_attribute(attr_name))}.
|
58
|
+
to_composite_ids
|
64
59
|
end
|
65
60
|
|
66
61
|
# Sets the primary ID.
|
@@ -71,7 +66,33 @@ module CompositePrimaryKeys
|
|
71
66
|
end
|
72
67
|
ids.each {|id| write_attribute(self.class.primary_key , id)}
|
73
68
|
end
|
74
|
-
|
69
|
+
|
70
|
+
# Deletes the record in the database and freezes this instance to reflect that no changes should
|
71
|
+
# be made (since they can't be persisted).
|
72
|
+
def destroy
|
73
|
+
unless new_record?
|
74
|
+
connection.delete <<-end_sql, "#{self.class.name} Destroy"
|
75
|
+
DELETE FROM #{self.class.table_name}
|
76
|
+
WHERE (#{self.class.primary_key}) = (#{quoted_id})
|
77
|
+
end_sql
|
78
|
+
end
|
79
|
+
|
80
|
+
freeze
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns a clone of the record that hasn't been assigned an id yet and
|
84
|
+
# is treated as a new record. Note that this is a "shallow" clone:
|
85
|
+
# it copies the object's attributes only, not its associations.
|
86
|
+
# The extent of a "deep" clone is application-specific and is therefore
|
87
|
+
# left to the application to implement according to its need.
|
88
|
+
def clone
|
89
|
+
attrs = self.attributes_before_type_cast
|
90
|
+
self.class.primary_keys.each {|key| attrs.delete(key.to_s)}
|
91
|
+
self.class.new do |record|
|
92
|
+
record.send :instance_variable_set, '@attributes', attrs
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
75
96
|
# Define an attribute reader method. Cope with nil column.
|
76
97
|
def define_read_method(symbol, attr_name, column)
|
77
98
|
cast_code = column.type_cast_code('v') if column
|
@@ -110,6 +131,18 @@ module CompositePrimaryKeys
|
|
110
131
|
super
|
111
132
|
end
|
112
133
|
end
|
134
|
+
|
135
|
+
private
|
136
|
+
# Updates the associated record with values matching those of the instance attributes.
|
137
|
+
def update
|
138
|
+
connection.update(
|
139
|
+
"UPDATE #{self.class.table_name} " +
|
140
|
+
"SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " +
|
141
|
+
"WHERE (#{self.class.primary_key}) = (#{id})",
|
142
|
+
"#{self.class.name} Update"
|
143
|
+
)
|
144
|
+
return true
|
145
|
+
end
|
113
146
|
end
|
114
147
|
|
115
148
|
module CompositeClassMethods
|
@@ -121,9 +154,9 @@ module CompositePrimaryKeys
|
|
121
154
|
end
|
122
155
|
|
123
156
|
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
124
|
-
#ids_to_s([[1,2],[7,3]], ',', ';'
|
125
|
-
def ids_to_s(
|
126
|
-
|
157
|
+
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
158
|
+
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
159
|
+
many_ids.map {|ids| "#{left_bracket}#{ids}#{right_bracket}"}.join(list_sep)
|
127
160
|
end
|
128
161
|
|
129
162
|
# Returns true if the given +ids+ represents the primary keys of a record in the database, false otherwise.
|
@@ -138,13 +171,21 @@ module CompositePrimaryKeys
|
|
138
171
|
# If an array of ids is provided (e.g. delete([1,2], [3,4]), all of them
|
139
172
|
# are deleted.
|
140
173
|
def delete(*ids)
|
174
|
+
unless ids.is_a?(Array); raise "*ids must be an Array"; end
|
175
|
+
ids = [ids.to_composite_ids] if not ids.first.is_a?(Array)
|
141
176
|
delete_all([ "(#{primary_keys}) IN (#{ids_to_s(ids)})" ])
|
142
177
|
end
|
143
178
|
|
144
179
|
# Destroys the record with the given +ids+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
|
145
180
|
# If an array of ids is provided, all of them are destroyed.
|
146
181
|
def destroy(*ids)
|
147
|
-
ids.
|
182
|
+
unless ids.is_a?(Array); raise "*ids must be an Array"; end
|
183
|
+
if ids.first.is_a?(Array)
|
184
|
+
ids = ids.map{|compids| compids.to_composite_ids}
|
185
|
+
else
|
186
|
+
ids = ids.to_composite_ids
|
187
|
+
end
|
188
|
+
ids.first.is_a?(CompositeIds) ? ids.each { |id_set| find(id_set).destroy } : find(ids).destroy
|
148
189
|
end
|
149
190
|
|
150
191
|
# Returns an array of column objects for the table associated with this class.
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
ID_SEP = ','
|
3
|
+
module ArrayExtension
|
4
|
+
def to_composite_keys
|
5
|
+
CompositeKeys.new(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_composite_ids
|
9
|
+
CompositeIds.new(self)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class CompositeArray < Array
|
14
|
+
def to_s
|
15
|
+
join(ID_SEP)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class CompositeKeys < CompositeArray
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class CompositeIds < CompositeArray
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Array.send(:include, CompositePrimaryKeys::ArrayExtension)
|
data/test/abstract_unit.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
-
$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib')
|
3
2
|
|
4
3
|
require 'test/unit'
|
4
|
+
require 'hash_tricks'
|
5
5
|
require 'active_record'
|
6
6
|
require 'active_record/fixtures'
|
7
7
|
require 'active_support/binding_of_caller'
|
@@ -15,7 +15,7 @@ QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') unless Obj
|
|
15
15
|
class Test::Unit::TestCase #:nodoc:
|
16
16
|
self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
17
17
|
self.use_instantiated_fixtures = false
|
18
|
-
self.use_transactional_fixtures = (ENV['AR_NO_TX_FIXTURES'] != "yes")
|
18
|
+
self.use_transactional_fixtures = true #(ENV['AR_NO_TX_FIXTURES'] != "yes")
|
19
19
|
|
20
20
|
def create_fixtures(*table_names, &block)
|
21
21
|
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names, {}, &block)
|
@@ -55,7 +55,8 @@ protected
|
|
55
55
|
|
56
56
|
def testing_with(&block)
|
57
57
|
classes.keys.each do |@key_test|
|
58
|
-
@
|
58
|
+
@klass_info = classes[@key_test]
|
59
|
+
@klass, @primary_keys = @klass_info[:class], @klass_info[:primary_keys]
|
59
60
|
@first = @klass.find_first
|
60
61
|
yield
|
61
62
|
end
|
data/test/clone_test.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/reference_type'
|
3
|
+
require 'fixtures/reference_code'
|
4
|
+
|
5
|
+
class CloneTest < Test::Unit::TestCase
|
6
|
+
fixtures :reference_types, :reference_codes
|
7
|
+
|
8
|
+
CLASSES = {
|
9
|
+
:single => {
|
10
|
+
:class => ReferenceType,
|
11
|
+
:primary_keys => [:reference_type_id],
|
12
|
+
},
|
13
|
+
:dual => {
|
14
|
+
:class => ReferenceCode,
|
15
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
16
|
+
},
|
17
|
+
}
|
18
|
+
|
19
|
+
def setup
|
20
|
+
super
|
21
|
+
self.class.classes = CLASSES
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_truth
|
25
|
+
testing_with do
|
26
|
+
clone = @first.clone
|
27
|
+
assert_equal @first.attributes.block(@klass.primary_key), clone.attributes
|
28
|
+
if composite?
|
29
|
+
@klass.primary_key.each {|key| assert_nil clone[key], "Primary key '#{key}' should be nil"}
|
30
|
+
else
|
31
|
+
assert_nil clone[@klass.primary_key], "Sole primary key should be nil"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/reference_type'
|
3
|
+
require 'fixtures/reference_code'
|
4
|
+
|
5
|
+
class CompositeArraysTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_new_primary_keys
|
8
|
+
keys = CompositePrimaryKeys::CompositeKeys.new
|
9
|
+
assert_not_nil keys
|
10
|
+
assert_equal '', keys.to_s
|
11
|
+
assert_equal '', "#{keys}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_initialize_primary_keys
|
15
|
+
keys = CompositePrimaryKeys::CompositeKeys.new([1,2,3])
|
16
|
+
assert_not_nil keys
|
17
|
+
assert_equal '1,2,3', keys.to_s
|
18
|
+
assert_equal '1,2,3', "#{keys}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_to_composite_keys
|
22
|
+
keys = [1,2,3].to_composite_keys
|
23
|
+
assert_equal CompositePrimaryKeys::CompositeKeys, keys.class
|
24
|
+
assert_equal '1,2,3', keys.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_new_ids
|
28
|
+
keys = CompositePrimaryKeys::CompositeIds.new
|
29
|
+
assert_not_nil keys
|
30
|
+
assert_equal '', keys.to_s
|
31
|
+
assert_equal '', "#{keys}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_initialize_ids
|
35
|
+
keys = CompositePrimaryKeys::CompositeIds.new([1,2,3])
|
36
|
+
assert_not_nil keys
|
37
|
+
assert_equal '1,2,3', keys.to_s
|
38
|
+
assert_equal '1,2,3', "#{keys}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_to_composite_ids
|
42
|
+
keys = [1,2,3].to_composite_ids
|
43
|
+
assert_equal CompositePrimaryKeys::CompositeIds, keys.class
|
44
|
+
assert_equal '1,2,3', keys.to_s
|
45
|
+
end
|
46
|
+
end
|
data/test/delete_test.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/reference_type'
|
3
|
+
require 'fixtures/reference_code'
|
4
|
+
|
5
|
+
class DeleteTest < Test::Unit::TestCase
|
6
|
+
fixtures :reference_types, :reference_codes
|
7
|
+
|
8
|
+
CLASSES = {
|
9
|
+
:single => {
|
10
|
+
:class => ReferenceType,
|
11
|
+
:primary_keys => [:reference_type_id],
|
12
|
+
},
|
13
|
+
:dual => {
|
14
|
+
:class => ReferenceCode,
|
15
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
16
|
+
},
|
17
|
+
}
|
18
|
+
|
19
|
+
def setup
|
20
|
+
super
|
21
|
+
self.class.classes = CLASSES
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_destroy_one
|
25
|
+
testing_with do
|
26
|
+
#assert @first.destroy
|
27
|
+
assert true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_destroy_one_via_class
|
32
|
+
testing_with do
|
33
|
+
assert @klass.destroy(*@first.id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_destroy_one_alone_via_class
|
38
|
+
testing_with do
|
39
|
+
assert @klass.destroy(@first.id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_delete_one
|
44
|
+
testing_with do
|
45
|
+
assert @klass.delete(*@first.id) if composite?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_delete_one_alone
|
50
|
+
testing_with do
|
51
|
+
assert @klass.delete(@first.id)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_delete_many
|
56
|
+
testing_with do
|
57
|
+
to_delete = @klass.find(:all)[0..1]
|
58
|
+
assert_equal 2, to_delete.length
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_delete_all
|
63
|
+
testing_with do
|
64
|
+
@klass.delete_all
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/test/dummy_test.rb
CHANGED
@@ -3,8 +3,26 @@ require 'fixtures/reference_type'
|
|
3
3
|
require 'fixtures/reference_code'
|
4
4
|
|
5
5
|
class DummyTest < Test::Unit::TestCase
|
6
|
+
fixtures :reference_types, :reference_codes
|
6
7
|
|
8
|
+
CLASSES = {
|
9
|
+
:single => {
|
10
|
+
:class => ReferenceType,
|
11
|
+
:primary_keys => [:reference_type_id],
|
12
|
+
},
|
13
|
+
:dual => {
|
14
|
+
:class => ReferenceCode,
|
15
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
16
|
+
},
|
17
|
+
}
|
18
|
+
|
19
|
+
def setup
|
20
|
+
self.class.classes = CLASSES
|
21
|
+
end
|
22
|
+
|
7
23
|
def test_truth
|
8
|
-
|
24
|
+
testing_with do
|
25
|
+
assert true
|
26
|
+
end
|
9
27
|
end
|
10
28
|
end
|
data/test/find_test.rb
CHANGED
@@ -6,7 +6,7 @@ require 'fixtures/reference_code'
|
|
6
6
|
class FindTest < Test::Unit::TestCase
|
7
7
|
fixtures :reference_types, :reference_codes
|
8
8
|
|
9
|
-
|
9
|
+
CLASSES = {
|
10
10
|
:single => {
|
11
11
|
:class => ReferenceType,
|
12
12
|
:primary_keys => [:reference_type_id],
|
@@ -14,9 +14,14 @@ class FindTest < Test::Unit::TestCase
|
|
14
14
|
:dual => {
|
15
15
|
:class => ReferenceCode,
|
16
16
|
:primary_keys => [:reference_type_id, :reference_code],
|
17
|
-
}
|
17
|
+
},
|
18
18
|
}
|
19
19
|
|
20
|
+
def setup
|
21
|
+
super
|
22
|
+
self.class.classes = CLASSES
|
23
|
+
end
|
24
|
+
|
20
25
|
def test_find_first
|
21
26
|
testing_with do
|
22
27
|
obj = @klass.find_first
|
@@ -25,18 +30,11 @@ class FindTest < Test::Unit::TestCase
|
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
28
|
-
def test_ids
|
29
|
-
testing_with do
|
30
|
-
assert_equal @first.id, @first.ids if composite?
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
33
|
def test_find
|
35
34
|
testing_with do
|
36
35
|
found = @klass.find(*first_id) # e.g. find(1,1) or find 1,1
|
37
36
|
assert found
|
38
37
|
assert_equal @klass, found.class
|
39
|
-
#breakpoint
|
40
38
|
assert_equal found, @klass.find(found.id)
|
41
39
|
assert_equal found, @klass.find(found.to_param)
|
42
40
|
end
|
data/test/hash_tricks.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# From:
|
2
|
+
# http://www.bigbold.com/snippets/posts/show/2178
|
3
|
+
# http://blog.caboo.se/articles/2006/06/11/stupid-hash-tricks
|
4
|
+
#
|
5
|
+
# An example utilisation of these methods in a controller is:
|
6
|
+
# def some_action
|
7
|
+
# # some script kiddie also passed in :bee, which we don't want tampered with _here_.
|
8
|
+
# @model = Model.create(params.pass(:foo, :bar))
|
9
|
+
# end
|
10
|
+
class Hash
|
11
|
+
|
12
|
+
# lets through the keys in the argument
|
13
|
+
# >> {:one => 1, :two => 2, :three => 3}.pass(:one)
|
14
|
+
# => {:one=>1}
|
15
|
+
def pass(*keys)
|
16
|
+
keys = keys.first if keys.first.is_a?(Array)
|
17
|
+
tmp = self.clone
|
18
|
+
tmp.delete_if {|k,v| ! keys.include?(k.to_sym) }
|
19
|
+
tmp.delete_if {|k,v| ! keys.include?(k.to_s) }
|
20
|
+
tmp
|
21
|
+
end
|
22
|
+
|
23
|
+
# blocks the keys in the arguments
|
24
|
+
# >> {:one => 1, :two => 2, :three => 3}.block(:one)
|
25
|
+
# => {:two=>2, :three=>3}
|
26
|
+
def block(*keys)
|
27
|
+
keys = keys.first if keys.first.is_a?(Array)
|
28
|
+
tmp = self.clone
|
29
|
+
tmp.delete_if {|k,v| keys.include?(k.to_sym) }
|
30
|
+
tmp.delete_if {|k,v| keys.include?(k.to_s) }
|
31
|
+
tmp
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/test/ids_test.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/reference_type'
|
3
|
+
require 'fixtures/reference_code'
|
4
|
+
|
5
|
+
class IdsTest < Test::Unit::TestCase
|
6
|
+
fixtures :reference_types, :reference_codes
|
7
|
+
|
8
|
+
CLASSES = {
|
9
|
+
:single => {
|
10
|
+
:class => ReferenceType,
|
11
|
+
:primary_keys => [:reference_type_id],
|
12
|
+
},
|
13
|
+
:dual => {
|
14
|
+
:class => ReferenceCode,
|
15
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
16
|
+
},
|
17
|
+
}
|
18
|
+
|
19
|
+
def setup
|
20
|
+
super
|
21
|
+
self.class.classes = CLASSES
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_id
|
25
|
+
testing_with do
|
26
|
+
assert_equal @first.id, @first.ids if composite?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_id_to_s
|
31
|
+
testing_with do
|
32
|
+
assert_equal first_id_str, @first.id.to_s
|
33
|
+
assert_equal first_id_str, "#{@first.id}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_ids_to_s
|
38
|
+
testing_with do
|
39
|
+
to_test = @klass.find(:all)[0..1].map(&:id)
|
40
|
+
assert_equal '(1,1),(1,2)', @klass.ids_to_s(to_test) if @key_test == :dual
|
41
|
+
assert_equal '1,1;1,2', @klass.ids_to_s(to_test, ',', ';', '', '') if @key_test == :dual
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_primary_keys
|
46
|
+
testing_with do
|
47
|
+
if composite?
|
48
|
+
assert_not_nil @klass.primary_keys
|
49
|
+
assert_equal @primary_keys, @klass.primary_keys
|
50
|
+
assert_equal @klass.primary_keys, @klass.primary_key
|
51
|
+
else
|
52
|
+
assert_not_nil @klass.primary_key
|
53
|
+
assert_equal @primary_keys, [@klass.primary_key.to_sym]
|
54
|
+
end
|
55
|
+
assert_equal @primary_keys.join(','), @klass.primary_key.to_s
|
56
|
+
# Need a :primary_keys should be Array with to_s overridden
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/test/miscellaneous_test.rb
CHANGED
@@ -3,6 +3,23 @@ require 'fixtures/reference_type'
|
|
3
3
|
require 'fixtures/reference_code'
|
4
4
|
|
5
5
|
class MiscellaneousTest < Test::Unit::TestCase
|
6
|
+
fixtures :reference_types, :reference_codes
|
7
|
+
|
8
|
+
CLASSES = {
|
9
|
+
:single => {
|
10
|
+
:class => ReferenceType,
|
11
|
+
:primary_keys => [:reference_type_id],
|
12
|
+
},
|
13
|
+
:dual => {
|
14
|
+
:class => ReferenceCode,
|
15
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
16
|
+
},
|
17
|
+
}
|
18
|
+
|
19
|
+
def setup
|
20
|
+
super
|
21
|
+
self.class.classes = CLASSES
|
22
|
+
end
|
6
23
|
|
7
24
|
def test_composite_class
|
8
25
|
testing_with do
|
@@ -15,19 +32,4 @@ class MiscellaneousTest < Test::Unit::TestCase
|
|
15
32
|
assert_equal composite?, @first.composite?
|
16
33
|
end
|
17
34
|
end
|
18
|
-
|
19
|
-
def test_primary_keys
|
20
|
-
testing_with do
|
21
|
-
if composite?
|
22
|
-
assert_not_nil @klass.primary_keys
|
23
|
-
assert_equal @primary_keys, @klass.primary_keys
|
24
|
-
assert_equal @klass.primary_keys, @klass.primary_key
|
25
|
-
else
|
26
|
-
assert_not_nil @klass.primary_key
|
27
|
-
assert_equal @primary_keys, [@klass.primary_key.to_sym]
|
28
|
-
end
|
29
|
-
assert_equal @primary_keys.join(','), @klass.primary_key.to_s
|
30
|
-
# Need a :primary_keys should be Array with to_s overridden
|
31
|
-
end
|
32
|
-
end
|
33
35
|
end
|
data/test/pagination_test.rb
CHANGED
@@ -4,27 +4,32 @@ require 'fixtures/reference_code'
|
|
4
4
|
require 'action_controller/pagination'
|
5
5
|
|
6
6
|
class PaginationTest < Test::Unit::TestCase
|
7
|
+
fixtures :reference_types, :reference_codes
|
7
8
|
include ActionController::Pagination
|
8
9
|
DEFAULT_PAGE_SIZE = 2
|
9
|
-
|
10
|
-
|
10
|
+
|
11
|
+
CLASSES = {
|
11
12
|
:single => {
|
12
13
|
:class => ReferenceType,
|
13
14
|
:primary_keys => [:reference_type_id],
|
15
|
+
:table => :reference_types,
|
14
16
|
},
|
15
17
|
:dual => {
|
16
18
|
:class => ReferenceCode,
|
17
19
|
:primary_keys => [:reference_type_id, :reference_code],
|
18
|
-
|
20
|
+
:table => :reference_codes,
|
21
|
+
},
|
19
22
|
}
|
20
23
|
|
21
24
|
def setup
|
25
|
+
super
|
26
|
+
self.class.classes = CLASSES
|
22
27
|
@params = {}
|
23
28
|
end
|
24
29
|
|
25
30
|
def test_paginate_all
|
26
31
|
testing_with do
|
27
|
-
@object_pages, @objects = paginate :
|
32
|
+
@object_pages, @objects = paginate @klass_info[:table], :per_page => DEFAULT_PAGE_SIZE
|
28
33
|
assert_equal 2, @objects.length, "Each page should have #{DEFAULT_PAGE_SIZE} items"
|
29
34
|
end
|
30
35
|
end
|
data/test/update_test.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/reference_type'
|
3
|
+
require 'fixtures/reference_code'
|
4
|
+
|
5
|
+
class UpdateTest < Test::Unit::TestCase
|
6
|
+
fixtures :reference_types, :reference_codes
|
7
|
+
|
8
|
+
CLASSES = {
|
9
|
+
:single => {
|
10
|
+
:class => ReferenceType,
|
11
|
+
:primary_keys => [:reference_type_id],
|
12
|
+
:update => { :description => 'RT Desc' },
|
13
|
+
},
|
14
|
+
:dual => {
|
15
|
+
:class => ReferenceCode,
|
16
|
+
:primary_keys => [:reference_type_id, :reference_code],
|
17
|
+
:update => { :description => 'RT Desc' },
|
18
|
+
},
|
19
|
+
}
|
20
|
+
|
21
|
+
def setup
|
22
|
+
super
|
23
|
+
self.class.classes = CLASSES
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_setup
|
27
|
+
testing_with do
|
28
|
+
assert_not_nil @klass_info[:update]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_update_attributes
|
33
|
+
testing_with do
|
34
|
+
assert @first.update_attributes(@klass_info[:update])
|
35
|
+
assert @first.reload
|
36
|
+
@klass_info[:update].each_pair do |attr_name, new_value|
|
37
|
+
assert_equal new_value, @first[attr_name], "Attribute #{attr_name} is incorrect"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
CHANGED
@@ -3,14 +3,14 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: composite_primary_keys
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1
|
7
|
-
date: 2006-07-
|
6
|
+
version: 0.3.1
|
7
|
+
date: 2006-07-23 00:00:00 +02:00
|
8
8
|
summary: Support for composite primary keys in ActiveRecords
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: drnicwilliams@gmail.com
|
12
|
-
homepage: http://
|
13
|
-
rubyforge_project:
|
12
|
+
homepage: http://compositekeys.rubyforge.org
|
13
|
+
rubyforge_project: compositekeys
|
14
14
|
description: ActiveRecords only support a single primary key, preventing their use on legacy databases where tables have primary keys over 2+ columns. This solution allows an ActiveRecord to be extended to support multiple keys using the class method set_primary_keys.
|
15
15
|
autorequire: composite_primary_keys
|
16
16
|
default_executable:
|
@@ -34,18 +34,23 @@ files:
|
|
34
34
|
- CHANGELOG
|
35
35
|
- lib/composite_primary_keys
|
36
36
|
- lib/composite_primary_keys.rb
|
37
|
+
- lib/composite_primary_keys/fixtures.rb
|
38
|
+
- lib/composite_primary_keys/composite_arrays.rb
|
37
39
|
- lib/composite_primary_keys/version.rb
|
38
40
|
- lib/composite_primary_keys/base.rb
|
39
|
-
- lib/composite_primary_keys/fixtures.rb
|
40
|
-
- lib/composite_primary_keys/primary_keys.rb
|
41
41
|
- test/connections
|
42
|
-
- test/abstract_unit.rb
|
43
|
-
- test/dummy_test.rb
|
44
42
|
- test/fixtures
|
43
|
+
- test/composite_arrays_test.rb
|
44
|
+
- test/hash_tricks.rb
|
45
|
+
- test/delete_test.rb
|
46
|
+
- test/ids_test.rb
|
45
47
|
- test/find_test.rb
|
46
|
-
- test/
|
48
|
+
- test/update_test.rb
|
49
|
+
- test/abstract_unit.rb
|
47
50
|
- test/miscellaneous_test.rb
|
48
|
-
- test/
|
51
|
+
- test/pagination_test.rb
|
52
|
+
- test/dummy_test.rb
|
53
|
+
- test/clone_test.rb
|
49
54
|
- test/connections/native_mysql
|
50
55
|
- test/connections/native_mysql/connection.rb
|
51
56
|
- test/fixtures/reference_type.rb
|
data/test/primary_keys_test.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'abstract_unit'
|
2
|
-
require 'fixtures/reference_type'
|
3
|
-
require 'fixtures/reference_code'
|
4
|
-
|
5
|
-
class PrimaryKeyTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
def test_new
|
8
|
-
keys = CompositePrimaryKeys::PrimaryKeys.new
|
9
|
-
assert_not_nil keys
|
10
|
-
assert_equal '', keys.to_s
|
11
|
-
assert_equal '', "#{keys}"
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_initialize
|
15
|
-
keys = CompositePrimaryKeys::PrimaryKeys.new([1,2,3])
|
16
|
-
assert_not_nil keys
|
17
|
-
assert_equal '1,2,3', keys.to_s
|
18
|
-
assert_equal '1,2,3', "#{keys}"
|
19
|
-
end
|
20
|
-
end
|