composite_primary_keys 2.3.5.1 → 3.0.0.b2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +26 -0
- data/README.txt +1 -1
- data/Rakefile +41 -51
- data/lib/composite_primary_keys.rb +19 -7
- data/lib/composite_primary_keys/association_preload.rb +75 -170
- data/lib/composite_primary_keys/associations.rb +98 -400
- data/lib/composite_primary_keys/associations/association_proxy.rb +32 -0
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +30 -0
- data/lib/composite_primary_keys/associations/has_many_association.rb +72 -0
- data/lib/composite_primary_keys/associations/has_one_association.rb +19 -0
- data/lib/composite_primary_keys/associations/through_association_scope.rb +103 -0
- data/lib/composite_primary_keys/base.rb +148 -305
- data/lib/composite_primary_keys/calculations.rb +22 -64
- data/lib/composite_primary_keys/composite_arrays.rb +3 -10
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +9 -0
- data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +17 -0
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +1 -1
- data/lib/composite_primary_keys/finder_methods.rb +71 -0
- data/lib/composite_primary_keys/fixtures.rb +1 -1
- data/lib/composite_primary_keys/read.rb +25 -0
- data/lib/composite_primary_keys/reflection.rb +30 -10
- data/lib/composite_primary_keys/relation.rb +31 -0
- data/lib/composite_primary_keys/validations/uniqueness.rb +106 -66
- data/lib/composite_primary_keys/version.rb +4 -4
- data/scripts/console.rb +1 -1
- data/tasks/Rakefile.rb +13 -0
- data/tasks/databases/mysql.rake +11 -15
- data/tasks/databases/oracle.rake +10 -11
- data/tasks/databases/postgresql.rake +10 -13
- data/tasks/databases/sqlite3.rake +9 -9
- data/test/README_tests.txt +1 -45
- data/test/abstract_unit.rb +17 -14
- data/test/connections/connection_spec.rb +19 -0
- data/test/connections/databases.example.yml +11 -0
- data/test/connections/databases.yml +13 -0
- data/test/connections/native_mysql/connection.rb +10 -2
- data/test/connections/native_oracle/connection.rb +7 -4
- data/test/connections/native_oracle_enhanced/connection.rb +23 -0
- data/test/connections/native_postgresql/connection.rb +13 -5
- data/test/connections/native_sqlite/connection.rb +7 -3
- data/test/fixtures/article_group.rb +4 -0
- data/test/fixtures/article_groups.yml +7 -0
- data/test/fixtures/db_definitions/postgresql.sql +2 -1
- data/test/fixtures/debug.log +133 -0
- data/test/fixtures/dorm.rb +3 -0
- data/test/fixtures/dorms.yml +2 -0
- data/test/fixtures/kitchen_sink.rb +3 -0
- data/test/fixtures/kitchen_sinks.yml +5 -0
- data/test/fixtures/reference_codes.yml +2 -0
- data/test/fixtures/reference_type.rb +1 -1
- data/test/fixtures/restaurant.rb +6 -0
- data/test/fixtures/restaurants.yml +5 -0
- data/test/fixtures/restaurants_suburbs.yml +11 -0
- data/test/fixtures/room.rb +10 -0
- data/test/fixtures/room_assignment.rb +4 -0
- data/test/fixtures/room_assignments.yml +4 -0
- data/test/fixtures/room_attribute.rb +3 -0
- data/test/fixtures/room_attribute_assignment.rb +5 -0
- data/test/fixtures/room_attribute_assignments.yml +4 -0
- data/test/fixtures/room_attributes.yml +3 -0
- data/test/fixtures/rooms.yml +3 -0
- data/test/fixtures/seat.rb +5 -0
- data/test/fixtures/seats.yml +4 -0
- data/test/fixtures/student.rb +4 -0
- data/test/fixtures/students.yml +2 -0
- data/test/test_associations.rb +27 -50
- data/test/test_attributes.rb +15 -19
- data/test/test_composite_arrays.rb +2 -21
- data/test/test_create.rb +3 -3
- data/test/test_delete.rb +7 -20
- data/test/test_exists.rb +3 -7
- data/test/test_find.rb +0 -8
- data/test/test_ids.rb +3 -17
- data/test/test_polymorphic.rb +5 -4
- data/test/test_suite.rb +19 -0
- data/test/{test_tutorial_examle.rb → test_tutorial_example.rb} +0 -0
- metadata +110 -72
- data/Manifest.txt +0 -123
- data/lib/adapter_helper/base.rb +0 -63
- data/lib/adapter_helper/mysql.rb +0 -13
- data/lib/adapter_helper/oracle.rb +0 -12
- data/lib/adapter_helper/postgresql.rb +0 -13
- data/lib/adapter_helper/sqlite3.rb +0 -13
- data/lib/composite_primary_keys/migration.rb +0 -20
- data/local/database_connections.rb.sample +0 -12
- data/local/paths.rb.sample +0 -2
- data/local/tasks.rb.sample +0 -2
- data/tasks/activerecord_selection.rake +0 -43
- data/tasks/databases.rake +0 -12
- data/tasks/deployment.rake +0 -22
- data/tasks/local_setup.rake +0 -13
- data/test/test_dummy.rb +0 -28
- data/tmp/test.db +0 -0
- data/website/index.html +0 -195
- data/website/index.txt +0 -159
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -126
- data/website/template.js +0 -3
- data/website/template.rhtml +0 -53
- data/website/version-raw.js +0 -3
- data/website/version-raw.txt +0 -2
- data/website/version.js +0 -4
- data/website/version.txt +0 -3
data/Manifest.txt
DELETED
@@ -1,123 +0,0 @@
|
|
1
|
-
History.txt
|
2
|
-
Manifest.txt
|
3
|
-
README.txt
|
4
|
-
README_DB2.txt
|
5
|
-
Rakefile
|
6
|
-
init.rb
|
7
|
-
install.rb
|
8
|
-
lib/adapter_helper/base.rb
|
9
|
-
lib/adapter_helper/mysql.rb
|
10
|
-
lib/adapter_helper/oracle.rb
|
11
|
-
lib/adapter_helper/postgresql.rb
|
12
|
-
lib/adapter_helper/sqlite3.rb
|
13
|
-
lib/composite_primary_keys.rb
|
14
|
-
lib/composite_primary_keys/association_preload.rb
|
15
|
-
lib/composite_primary_keys/associations.rb
|
16
|
-
lib/composite_primary_keys/attribute_methods.rb
|
17
|
-
lib/composite_primary_keys/base.rb
|
18
|
-
lib/composite_primary_keys/calculations.rb
|
19
|
-
lib/composite_primary_keys/composite_arrays.rb
|
20
|
-
lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb
|
21
|
-
lib/composite_primary_keys/connection_adapters/oracle_adapter.rb
|
22
|
-
lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
|
23
|
-
lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb
|
24
|
-
lib/composite_primary_keys/fixtures.rb
|
25
|
-
lib/composite_primary_keys/migration.rb
|
26
|
-
lib/composite_primary_keys/reflection.rb
|
27
|
-
lib/composite_primary_keys/validations/uniqueness.rb
|
28
|
-
lib/composite_primary_keys/version.rb
|
29
|
-
loader.rb
|
30
|
-
local/database_connections.rb.sample
|
31
|
-
local/paths.rb.sample
|
32
|
-
local/tasks.rb.sample
|
33
|
-
scripts/console.rb
|
34
|
-
scripts/txt2html
|
35
|
-
scripts/txt2js
|
36
|
-
tasks/activerecord_selection.rake
|
37
|
-
tasks/databases.rake
|
38
|
-
tasks/databases/mysql.rake
|
39
|
-
tasks/databases/oracle.rake
|
40
|
-
tasks/databases/postgresql.rake
|
41
|
-
tasks/databases/sqlite3.rake
|
42
|
-
tasks/deployment.rake
|
43
|
-
tasks/local_setup.rake
|
44
|
-
tasks/website.rake
|
45
|
-
test/README_tests.txt
|
46
|
-
test/abstract_unit.rb
|
47
|
-
test/connections/native_ibm_db/connection.rb
|
48
|
-
test/connections/native_mysql/connection.rb
|
49
|
-
test/connections/native_oracle/connection.rb
|
50
|
-
test/connections/native_postgresql/connection.rb
|
51
|
-
test/connections/native_sqlite/connection.rb
|
52
|
-
test/fixtures/article.rb
|
53
|
-
test/fixtures/articles.yml
|
54
|
-
test/fixtures/comment.rb
|
55
|
-
test/fixtures/comments.yml
|
56
|
-
test/fixtures/db_definitions/db2-create-tables.sql
|
57
|
-
test/fixtures/db_definitions/db2-drop-tables.sql
|
58
|
-
test/fixtures/db_definitions/mysql.sql
|
59
|
-
test/fixtures/db_definitions/oracle.drop.sql
|
60
|
-
test/fixtures/db_definitions/oracle.sql
|
61
|
-
test/fixtures/db_definitions/postgresql.sql
|
62
|
-
test/fixtures/db_definitions/sqlite.sql
|
63
|
-
test/fixtures/department.rb
|
64
|
-
test/fixtures/departments.yml
|
65
|
-
test/fixtures/employee.rb
|
66
|
-
test/fixtures/employees.yml
|
67
|
-
test/fixtures/group.rb
|
68
|
-
test/fixtures/groups.yml
|
69
|
-
test/fixtures/hack.rb
|
70
|
-
test/fixtures/hacks.yml
|
71
|
-
test/fixtures/membership.rb
|
72
|
-
test/fixtures/membership_status.rb
|
73
|
-
test/fixtures/membership_statuses.yml
|
74
|
-
test/fixtures/memberships.yml
|
75
|
-
test/fixtures/product.rb
|
76
|
-
test/fixtures/product_tariff.rb
|
77
|
-
test/fixtures/product_tariffs.yml
|
78
|
-
test/fixtures/products.yml
|
79
|
-
test/fixtures/reading.rb
|
80
|
-
test/fixtures/readings.yml
|
81
|
-
test/fixtures/reference_code.rb
|
82
|
-
test/fixtures/reference_codes.yml
|
83
|
-
test/fixtures/reference_type.rb
|
84
|
-
test/fixtures/reference_types.yml
|
85
|
-
test/fixtures/street.rb
|
86
|
-
test/fixtures/streets.yml
|
87
|
-
test/fixtures/suburb.rb
|
88
|
-
test/fixtures/suburbs.yml
|
89
|
-
test/fixtures/tariff.rb
|
90
|
-
test/fixtures/tariffs.yml
|
91
|
-
test/fixtures/user.rb
|
92
|
-
test/fixtures/users.yml
|
93
|
-
test/hash_tricks.rb
|
94
|
-
test/plugins/pagination.rb
|
95
|
-
test/plugins/pagination_helper.rb
|
96
|
-
test/test_associations.rb
|
97
|
-
test/test_attribute_methods.rb
|
98
|
-
test/test_attributes.rb
|
99
|
-
test/test_clone.rb
|
100
|
-
test/test_composite_arrays.rb
|
101
|
-
test/test_create.rb
|
102
|
-
test/test_delete.rb
|
103
|
-
test/test_dummy.rb
|
104
|
-
test/test_exists.rb
|
105
|
-
test/test_find.rb
|
106
|
-
test/test_ids.rb
|
107
|
-
test/test_miscellaneous.rb
|
108
|
-
test/test_pagination.rb
|
109
|
-
test/test_polymorphic.rb
|
110
|
-
test/test_santiago.rb
|
111
|
-
test/test_tutorial_examle.rb
|
112
|
-
test/test_update.rb
|
113
|
-
tmp/test.db
|
114
|
-
website/index.html
|
115
|
-
website/index.txt
|
116
|
-
website/javascripts/rounded_corners_lite.inc.js
|
117
|
-
website/stylesheets/screen.css
|
118
|
-
website/template.js
|
119
|
-
website/template.rhtml
|
120
|
-
website/version-raw.js
|
121
|
-
website/version-raw.txt
|
122
|
-
website/version.js
|
123
|
-
website/version.txt
|
data/lib/adapter_helper/base.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
module AdapterHelper
|
2
|
-
class Base
|
3
|
-
class << self
|
4
|
-
attr_accessor :adapter
|
5
|
-
|
6
|
-
def load_connection_from_env(adapter)
|
7
|
-
self.adapter = adapter
|
8
|
-
unless ENV['cpk_adapters']
|
9
|
-
puts error_msg_setup_helper
|
10
|
-
exit
|
11
|
-
end
|
12
|
-
|
13
|
-
ActiveRecord::Base.configurations = YAML.load(ENV['cpk_adapters'])
|
14
|
-
unless spec = ActiveRecord::Base.configurations[adapter]
|
15
|
-
puts error_msg_adapter_helper
|
16
|
-
exit
|
17
|
-
end
|
18
|
-
spec[:adapter] = adapter
|
19
|
-
spec
|
20
|
-
end
|
21
|
-
|
22
|
-
def error_msg_setup_helper
|
23
|
-
<<-EOS
|
24
|
-
Setup Helper:
|
25
|
-
CPK now has a place for your individual testing configuration.
|
26
|
-
That is, instead of hardcoding it in the Rakefile and test/connections files,
|
27
|
-
there is now a local/database_connections.rb file that is NOT in the
|
28
|
-
repository. Your personal DB information (username, password etc) can
|
29
|
-
be stored here without making it difficult to submit patches etc.
|
30
|
-
|
31
|
-
Installation:
|
32
|
-
i) cp locals/database_connections.rb.sample locals/database_connections.rb
|
33
|
-
ii) For #{adapter} connection details see "Adapter Setup Helper" below.
|
34
|
-
iii) Rerun this task
|
35
|
-
|
36
|
-
#{error_msg_adapter_helper}
|
37
|
-
|
38
|
-
Current ENV:
|
39
|
-
#{ENV.inspect}
|
40
|
-
EOS
|
41
|
-
end
|
42
|
-
|
43
|
-
def error_msg_adapter_helper
|
44
|
-
<<-EOS
|
45
|
-
Adapter Setup Helper:
|
46
|
-
To run #{adapter} tests, you need to setup your #{adapter} connections.
|
47
|
-
In your local/database_connections.rb file, within the ENV['cpk_adapter'] hash, add:
|
48
|
-
"#{adapter}" => { adapter settings }
|
49
|
-
|
50
|
-
That is, it will look like:
|
51
|
-
ENV['cpk_adapters'] = {
|
52
|
-
"#{adapter}" => {
|
53
|
-
:adapter => "#{adapter}",
|
54
|
-
:username => "root",
|
55
|
-
:password => "root",
|
56
|
-
# ...
|
57
|
-
}
|
58
|
-
}.to_yaml
|
59
|
-
EOS
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
data/lib/adapter_helper/mysql.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'base')
|
2
|
-
|
3
|
-
module AdapterHelper
|
4
|
-
class MySQL < Base
|
5
|
-
class << self
|
6
|
-
def load_connection_from_env
|
7
|
-
spec = super('mysql')
|
8
|
-
spec[:database] ||= 'composite_primary_keys_unittest'
|
9
|
-
spec
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'base')
|
2
|
-
|
3
|
-
module AdapterHelper
|
4
|
-
class Postgresql < Base
|
5
|
-
class << self
|
6
|
-
def load_connection_from_env
|
7
|
-
spec = super('postgresql')
|
8
|
-
spec[:database] ||= 'composite_primary_keys_unittest'
|
9
|
-
spec
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
ActiveRecord::ConnectionAdapters::ColumnDefinition.send(:alias_method, :to_s_without_composite_keys, :to_s)
|
2
|
-
|
3
|
-
ActiveRecord::ConnectionAdapters::ColumnDefinition.class_eval <<-'EOF'
|
4
|
-
def to_s
|
5
|
-
if name.is_a? Array
|
6
|
-
"PRIMARY KEY (#{name.join(',')})"
|
7
|
-
else
|
8
|
-
to_s_without_composite_keys
|
9
|
-
end
|
10
|
-
end
|
11
|
-
EOF
|
12
|
-
|
13
|
-
ActiveRecord::ConnectionAdapters::TableDefinition.class_eval <<-'EOF'
|
14
|
-
def [](name)
|
15
|
-
@columns.find { |column|
|
16
|
-
!column.name.is_a?(Array) && column.name.to_s == name.to_s
|
17
|
-
}
|
18
|
-
end
|
19
|
-
EOF
|
20
|
-
|
data/local/paths.rb.sample
DELETED
data/local/tasks.rb.sample
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
namespace :ar do
|
2
|
-
desc 'Pre-load edge rails ActiveRecord'
|
3
|
-
task :edge do
|
4
|
-
unless path = ENV['EDGE_RAILS_DIR'] || ENV['EDGE_RAILS']
|
5
|
-
puts <<-EOS
|
6
|
-
|
7
|
-
Need to define env var EDGE_RAILS_DIR or EDGE_RAILS- root of edge rails on your machine.
|
8
|
-
i) Get copy of Edge Rails - http://dev.rubyonrails.org
|
9
|
-
ii) Set EDGE_RAILS_DIR to this folder in local/paths.rb - see local/paths.rb.sample for example
|
10
|
-
or
|
11
|
-
a) Set folder from environment or command line (rake ar:edge EDGE_RAILS_DIR=/path/to/rails)
|
12
|
-
|
13
|
-
EOS
|
14
|
-
exit
|
15
|
-
end
|
16
|
-
|
17
|
-
ENV['AR_LOAD_PATH'] = File.join(path, "activerecord/lib")
|
18
|
-
end
|
19
|
-
|
20
|
-
desc 'Pre-load ActiveRecord using VERSION=X.Y.Z, instead of latest'
|
21
|
-
task :set do
|
22
|
-
unless version = ENV['VERSION']
|
23
|
-
puts <<-EOS
|
24
|
-
Usage: rake ar:get_version VERSION=1.15.3
|
25
|
-
Specify the version number with VERSION=X.Y.Z; and make sure you have that activerecord gem version installed.
|
26
|
-
|
27
|
-
EOS
|
28
|
-
end
|
29
|
-
version = nil if version == "" || version == []
|
30
|
-
begin
|
31
|
-
version ? gem('activerecord', version) : gem('activerecord')
|
32
|
-
require 'active_record'
|
33
|
-
ENV['AR_LOAD_PATH'] = $:.reverse.find { |path| /activerecord/ =~ path }
|
34
|
-
rescue LoadError
|
35
|
-
puts <<-EOS
|
36
|
-
Missing: Cannot find activerecord #{version} installed.
|
37
|
-
Install: gem install activerecord -v #{version}
|
38
|
-
|
39
|
-
EOS
|
40
|
-
exit
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/tasks/databases.rake
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
|
-
# UNTESTED - firebird sqlserver sqlserver_odbc db2 sybase openbase
|
4
|
-
for adapter in %w( mysql sqlite oracle oracle_enhanced postgresql ibm_db )
|
5
|
-
Rake::TestTask.new("test_#{adapter}") { |t|
|
6
|
-
t.libs << "test" << "test/connections/native_#{adapter}"
|
7
|
-
t.pattern = "test/test_*.rb"
|
8
|
-
t.verbose = true
|
9
|
-
}
|
10
|
-
end
|
11
|
-
|
12
|
-
SCHEMA_PATH = File.join(PROJECT_ROOT, *%w(test fixtures db_definitions))
|
data/tasks/deployment.rake
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
desc 'Release the website and new gem version'
|
2
|
-
task :deploy => [:check_version, :website, :release] do
|
3
|
-
puts "Remember to create SVN tag:"
|
4
|
-
puts "svn copy svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
5
|
-
"svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
6
|
-
puts "Suggested comment:"
|
7
|
-
puts "Tagging release #{CHANGES}"
|
8
|
-
end
|
9
|
-
|
10
|
-
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
11
|
-
task :local_deploy => [:website_generate, :install_gem]
|
12
|
-
|
13
|
-
task :check_version do
|
14
|
-
unless ENV['VERSION']
|
15
|
-
puts 'Must pass a VERSION=x.y.z release version'
|
16
|
-
exit
|
17
|
-
end
|
18
|
-
unless ENV['VERSION'] == VERS
|
19
|
-
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
20
|
-
exit
|
21
|
-
end
|
22
|
-
end
|
data/tasks/local_setup.rake
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
namespace :local do
|
2
|
-
desc 'Copies over the same local files ready for editing'
|
3
|
-
task :setup do
|
4
|
-
sample_files = Dir[File.join(PROJECT_ROOT, "local/*.rb.sample")]
|
5
|
-
sample_files.each do |sample_file|
|
6
|
-
file = sample_file.sub(".sample","")
|
7
|
-
unless File.exists?(file)
|
8
|
-
puts "Copying #{sample_file} -> #{file}"
|
9
|
-
sh %{ cp #{sample_file} #{file} }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/test/test_dummy.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require 'abstract_unit'
|
2
|
-
require 'fixtures/reference_type'
|
3
|
-
require 'fixtures/reference_code'
|
4
|
-
|
5
|
-
class TestDummy < ActiveSupport::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
|
-
self.class.classes = classes
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_truth
|
24
|
-
testing_with do
|
25
|
-
assert true
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
data/tmp/test.db
DELETED
Binary file
|
data/website/index.html
DELETED
@@ -1,195 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
-
<head>
|
5
|
-
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
|
6
|
-
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
7
|
-
<title>
|
8
|
-
Composite Primary Keys
|
9
|
-
</title>
|
10
|
-
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
|
11
|
-
<style>
|
12
|
-
|
13
|
-
</style>
|
14
|
-
<script type="text/javascript">
|
15
|
-
window.onload = function() {
|
16
|
-
settings = {
|
17
|
-
tl: { radius: 10 },
|
18
|
-
tr: { radius: 10 },
|
19
|
-
bl: { radius: 10 },
|
20
|
-
br: { radius: 10 },
|
21
|
-
antiAlias: true,
|
22
|
-
autoPad: true,
|
23
|
-
validTags: ["div"]
|
24
|
-
}
|
25
|
-
var versionBox = new curvyCorners(settings, document.getElementById("version"));
|
26
|
-
versionBox.applyCornersToAll();
|
27
|
-
}
|
28
|
-
</script>
|
29
|
-
</head>
|
30
|
-
<body>
|
31
|
-
<div id="main">
|
32
|
-
|
33
|
-
<h1>Composite Primary Keys</h1>
|
34
|
-
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/compositekeys"; return false'>
|
35
|
-
Get Version
|
36
|
-
<a href="http://rubyforge.org/projects/compositekeys" class="numbers">2.3.5.1</a>
|
37
|
-
</div>
|
38
|
-
<h1>→ Ruby on Rails</h1>
|
39
|
-
<h1>→ ActiveRecords</h1>
|
40
|
-
<h2>What</h2>
|
41
|
-
<p>Ruby on Rails does not support composite primary keys. This free software is an extension <br />
|
42
|
-
to the database layer of Rails – <a href="http://wiki.rubyonrails.com/rails/pages/ActiveRecord">ActiveRecords</a> – to support composite primary keys as transparently as possible.</p>
|
43
|
-
<p>Any Ruby script using ActiveRecords can use Composite Primary Keys with this library.</p>
|
44
|
-
<h2>Installing</h2>
|
45
|
-
<p><pre class="syntax"><span class="ident">sudo</span> <span class="ident">gem</span> <span class="ident">install</span> <span class="ident">composite_primary_keys</span></pre></p>
|
46
|
-
<p>Rails: Add the following to the bottom of your <code>environment.rb</code> file</p>
|
47
|
-
<p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">composite_primary_keys</span><span class="punct">'</span></pre></p>
|
48
|
-
<p>Ruby scripts: Add the following to the top of your script</p>
|
49
|
-
<p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">rubygems</span><span class="punct">'</span>
|
50
|
-
<span class="ident">require</span> <span class="punct">'</span><span class="string">composite_primary_keys</span><span class="punct">'</span></pre></p>
|
51
|
-
<h2>The basics</h2>
|
52
|
-
<p>A model with composite primary keys would look like…</p>
|
53
|
-
<p><pre class="syntax"><span class="keyword">class </span><span class="class">Membership</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
54
|
-
<span class="comment"># set_primary_keys *keys - turns on composite key functionality</span>
|
55
|
-
<span class="ident">set_primary_keys</span> <span class="symbol">:user_id</span><span class="punct">,</span> <span class="symbol">:group_id</span>
|
56
|
-
<span class="ident">belongs_to</span> <span class="symbol">:user</span>
|
57
|
-
<span class="ident">belongs_to</span> <span class="symbol">:group</span>
|
58
|
-
<span class="ident">has_many</span> <span class="symbol">:statuses</span><span class="punct">,</span> <span class="symbol">:class_name</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">MembershipStatus</span><span class="punct">',</span> <span class="symbol">:foreign_key</span> <span class="punct">=></span> <span class="punct">[</span><span class="symbol">:user_id</span><span class="punct">,</span> <span class="symbol">:group_id</span><span class="punct">]</span>
|
59
|
-
<span class="keyword">end</span></pre></p>
|
60
|
-
<p>A model associated with a composite key model would be defined like…</p>
|
61
|
-
<p><pre class="syntax"><span class="keyword">class </span><span class="class">MembershipStatus</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
|
62
|
-
<span class="ident">belongs_to</span> <span class="symbol">:membership</span><span class="punct">,</span> <span class="symbol">:foreign_key</span> <span class="punct">=></span> <span class="punct">[</span><span class="symbol">:user_id</span><span class="punct">,</span> <span class="symbol">:group_id</span><span class="punct">]</span>
|
63
|
-
<span class="keyword">end</span></pre></p>
|
64
|
-
<p>That is, associations can include composite keys too. Nice.</p>
|
65
|
-
<h2>Demonstration of usage</h2>
|
66
|
-
<p>Once you’ve created your models to specify composite primary keys (such as the Membership class) and associations (such as MembershipStatus#membership), you can uses them like any normal model with associations.</p>
|
67
|
-
<p>But first, lets check out our primary keys.</p>
|
68
|
-
<p><pre class="syntax"><span class="constant">MembershipStatus</span><span class="punct">.</span><span class="ident">primary_key</span> <span class="comment"># => "id" # normal single key</span>
|
69
|
-
<span class="constant">Membership</span><span class="punct">.</span><span class="ident">primary_key</span> <span class="comment"># => [:user_id, :group_id] # composite keys</span>
|
70
|
-
<span class="constant">Membership</span><span class="punct">.</span><span class="ident">primary_key</span><span class="punct">.</span><span class="ident">to_s</span> <span class="comment"># => "user_id,group_id"</span></pre></p>
|
71
|
-
<p>Now we want to be able to find instances using the same syntax we always use for ActiveRecords…</p>
|
72
|
-
<p><pre class="syntax"><span class="constant">MembershipStatus</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="number">1</span><span class="punct">)</span> <span class="comment"># single id returns single instance</span>
|
73
|
-
<span class="punct">=></span> <span class="punct"><</span><span class="constant">MembershipStatus</span><span class="punct">:</span><span class="number">0x392a8c8</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">status</span><span class="punct">"=>"</span><span class="string">Active</span><span class="punct">"}></span>
|
74
|
-
<span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="number">1</span><span class="punct">,</span><span class="number">1</span><span class="punct">)</span> <span class="comment"># composite ids returns single instance</span>
|
75
|
-
<span class="punct">=></span> <span class="punct"><</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x39218b0</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">user_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">group_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">"}></span></pre></p>
|
76
|
-
<p>Using <a href="http://www.rubyonrails.org">Ruby on Rails</a>? You’ll want to your url_for helpers<br />
|
77
|
-
to convert composite keys into strings and back again…</p>
|
78
|
-
<p><pre class="syntax"><span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">).</span><span class="ident">to_param</span> <span class="comment"># => "1,1"</span></pre></p>
|
79
|
-
<p>And then use the string id within your controller to find the object again</p>
|
80
|
-
<p><pre class="syntax"><span class="ident">params</span><span class="punct">[</span><span class="symbol">:id</span><span class="punct">]</span> <span class="comment"># => '1,1'</span>
|
81
|
-
<span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:id</span><span class="punct">])</span>
|
82
|
-
<span class="punct">=></span> <span class="punct"><</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x3904288</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">user_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">group_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">"}></span></pre></p>
|
83
|
-
<p>That is, an ActiveRecord supporting composite keys behaves transparently<br />
|
84
|
-
throughout your application. Just like a normal ActiveRecord.</p>
|
85
|
-
<h2>Other tricks</h2>
|
86
|
-
<h3>Pass a list of composite ids to the <code>#find</code> method</h3>
|
87
|
-
<p><pre class="syntax"><span class="constant">Membership</span><span class="punct">.</span><span class="ident">find</span> <span class="punct">[</span><span class="number">1</span><span class="punct">,</span><span class="number">1</span><span class="punct">],</span> <span class="punct">[</span><span class="number">2</span><span class="punct">,</span><span class="number">1</span><span class="punct">]</span>
|
88
|
-
<span class="punct">=></span> <span class="punct">[</span>
|
89
|
-
<span class="punct"><</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x394ade8</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">user_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">",</span> <span class="punct">"</span><span class="string">group_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">"}>,</span>
|
90
|
-
<span class="punct"><</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x394ada0</span> <span class="attribute">@attributes</span><span class="punct">={"</span><span class="string">user_id</span><span class="punct">"=>"</span><span class="string">2</span><span class="punct">",</span> <span class="punct">"</span><span class="string">group_id</span><span class="punct">"=>"</span><span class="string">1</span><span class="punct">"}></span>
|
91
|
-
<span class="punct">]</span></pre></p>
|
92
|
-
<p>Perform <code>#count</code> operations</p>
|
93
|
-
<p><pre class="syntax"><span class="constant">MembershipStatus</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">).</span><span class="ident">memberships</span><span class="punct">.</span><span class="ident">count</span> <span class="comment"># => 1</span></pre></p>
|
94
|
-
<h3>Routes with Rails</h3>
|
95
|
-
<p>From Pete Sumskas:</p>
|
96
|
-
<blockquote>
|
97
|
-
<p>I ran into one problem that I didn’t see mentioned on <a href="http://groups.google.com/group/compositekeys">this list</a> – <br />
|
98
|
-
and I didn’t see any information about what I should do to address it in the<br />
|
99
|
-
documentation (might have missed it).</p>
|
100
|
-
<p>The problem was that the urls being generated for a ‘show’ action (for<br />
|
101
|
-
example) had a syntax like:</p>
|
102
|
-
<p><pre>/controller/show/123000,Bu70</pre></p>
|
103
|
-
<p>for a two-field composite PK. The default routing would not match that,<br />
|
104
|
-
so after working out how to do the routing I added:</p>
|
105
|
-
<p><pre class="syntax"><span class="ident">map</span><span class="punct">.</span><span class="ident">connect</span> <span class="punct">'</span><span class="string">:controller/:action/:id</span><span class="punct">',</span> <span class="symbol">:id</span> <span class="punct">=></span> <span class="punct">/</span><span class="regex"><span class="escape">\w</span>+(,<span class="escape">\w</span>+)*</span><span class="punct">/</span></pre></p>
|
106
|
-
<p>to my <code>route.rb</code> file.</p>
|
107
|
-
</blockquote>
|
108
|
-
<p><a name="dbs"></a></p>
|
109
|
-
<h2>Which databases?</h2>
|
110
|
-
<p>A suite of unit tests have been run on the following databases supported by ActiveRecord:</p>
|
111
|
-
<table>
|
112
|
-
<tr>
|
113
|
-
<th>Database</th>
|
114
|
-
<th>Test Success</th>
|
115
|
-
<th>User feedback</th>
|
116
|
-
</tr>
|
117
|
-
<tr>
|
118
|
-
<td>mysql </td>
|
119
|
-
<td><span class=success><span class="caps">YES</span></span></td>
|
120
|
-
<td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Mysql+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Mysql+is+failing">No…</a>)</td>
|
121
|
-
</tr>
|
122
|
-
<tr>
|
123
|
-
<td>sqlite3 </td>
|
124
|
-
<td><span class=success><span class="caps">YES</span></span></td>
|
125
|
-
<td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Sqlite3+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Sqlite3+is+failing">No…</a>)</td>
|
126
|
-
</tr>
|
127
|
-
<tr>
|
128
|
-
<td>postgresql</td>
|
129
|
-
<td><span class=success><span class="caps">YES</span></span></td>
|
130
|
-
<td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Postgresql+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Postgresql+is+failing">No…</a>)</td>
|
131
|
-
</tr>
|
132
|
-
<tr>
|
133
|
-
<td>oracle </td>
|
134
|
-
<td><span class=success><span class="caps">YES</span></span></td>
|
135
|
-
<td><span class=success><span class="caps">YES</span></span> (<a href="mailto:compositekeys@googlegroups.com?subject=Oracle+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Oracle+is+failing">No…</a>)</td>
|
136
|
-
</tr>
|
137
|
-
<tr>
|
138
|
-
<td>sqlserver </td>
|
139
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+SQLServer">I can help</a>)</td>
|
140
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=SQLServer+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=SQLServer+is+failing">No…</a>)</td>
|
141
|
-
</tr>
|
142
|
-
<tr>
|
143
|
-
<td>db2 </td>
|
144
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+DB2">I can help</a>)</td>
|
145
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=DB2+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=DB2+is+failing">No…</a>)</td>
|
146
|
-
</tr>
|
147
|
-
<tr>
|
148
|
-
<td>firebird </td>
|
149
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Firebird">I can help</a>)</td>
|
150
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Firebird+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Firebird+is+failing">No…</a>)</td>
|
151
|
-
</tr>
|
152
|
-
<tr>
|
153
|
-
<td>sybase </td>
|
154
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Sybase">I can help</a>)</td>
|
155
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Sybase+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Sybase+is+failing">No…</a>)</td>
|
156
|
-
</tr>
|
157
|
-
<tr>
|
158
|
-
<td>openbase </td>
|
159
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Openbase">I can help</a>)</td>
|
160
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Openbase+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Openbase+is+failing">No…</a>)</td>
|
161
|
-
</tr>
|
162
|
-
<tr>
|
163
|
-
<td>frontbase </td>
|
164
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Frontbase">I can help</a>)</td>
|
165
|
-
<td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Frontbase+is+working">Yes!</a> or <a href="mailto:compositekeys@googlegroups.com?subject=Frontbase+is+failing">No…</a>)</td>
|
166
|
-
</tr>
|
167
|
-
</table>
|
168
|
-
<h2>Dr Nic’s Blog</h2>
|
169
|
-
<p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> – for future announcements and<br />
|
170
|
-
other stories and things.</p>
|
171
|
-
<h2>Forum</h2>
|
172
|
-
<p><a href="http://groups.google.com/group/compositekeys">http://groups.google.com/group/compositekeys</a></p>
|
173
|
-
<h2>How to submit patches</h2>
|
174
|
-
<p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people’s code</a> and for section <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups">8b: Submit patch to Google Groups</a>, use the Google Group above.</p>
|
175
|
-
<p>The source for this project is available via git. You can <a href="http://github.com/drnic/composite_primary_keys/tree/master">browse and/or fork the source</a>, or to clone the project locally:</p>
|
176
|
-
<pre>git clone git://github.com/drnic/composite_primary_keys.git</pre>
|
177
|
-
<h2>Licence</h2>
|
178
|
-
<p>This code is free to use under the terms of the <span class="caps">MIT</span> licence.</p>
|
179
|
-
<h2>Contact</h2>
|
180
|
-
<p>Comments are welcome. Send an email to <a href="mailto:drnicwilliams@gmail.com">Dr Nic Williams</a>.</p>
|
181
|
-
<p class="coda">
|
182
|
-
<a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 13th February 2010<br>
|
183
|
-
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
184
|
-
</p>
|
185
|
-
</div>
|
186
|
-
|
187
|
-
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
188
|
-
</script>
|
189
|
-
<script type="text/javascript">
|
190
|
-
_uacct = "UA-567811-2";
|
191
|
-
urchinTracker();
|
192
|
-
</script>
|
193
|
-
|
194
|
-
</body>
|
195
|
-
</html>
|