composite_primary_keys 0.7.5 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +75 -0
- data/Rakefile +83 -101
- data/lib/composite_primary_keys.rb +8 -0
- data/lib/composite_primary_keys/associations.rb +66 -18
- data/lib/composite_primary_keys/base.rb +169 -159
- data/lib/composite_primary_keys/calculations.rb +63 -0
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +11 -0
- data/lib/composite_primary_keys/version.rb +2 -2
- data/scripts/txt2html +4 -2
- data/scripts/txt2js +3 -2
- data/test/abstract_unit.rb +9 -2
- data/test/connections/native_mysql/connection.rb +5 -2
- data/test/connections/native_postgresql/connection.rb +15 -0
- data/test/connections/native_sqlite/connection.rb +10 -0
- data/test/fixtures/db_definitions/mysql.sql +20 -0
- data/test/fixtures/db_definitions/postgresql.sql +100 -0
- data/test/fixtures/db_definitions/sqlite.sql +84 -0
- data/test/fixtures/group.rb +3 -0
- data/test/fixtures/groups.yml +3 -0
- data/test/fixtures/membership.rb +7 -0
- data/test/fixtures/membership_status.rb +3 -0
- data/test/fixtures/membership_statuses.yml +8 -0
- data/test/fixtures/memberships.yml +6 -0
- data/test/{associations_test.rb → test_associations.rb} +22 -12
- data/test/{attributes_test.rb → test_attributes.rb} +4 -5
- data/test/{clone_test.rb → test_clone.rb} +2 -3
- data/test/{create_test.rb → test_create.rb} +2 -3
- data/test/{delete_test.rb → test_delete.rb} +2 -3
- data/test/{dummy_test.rb → test_dummy.rb} +4 -5
- data/test/{find_test.rb → test_find.rb} +3 -4
- data/test/{ids_test.rb → test_ids.rb} +4 -4
- data/test/{miscellaneous_test.rb → test_miscellaneous.rb} +2 -3
- data/test/{pagination_test.rb → test_pagination.rb} +4 -3
- data/test/{santiago_test.rb → test_santiago.rb} +5 -3
- data/test/test_tutorial_examle.rb +29 -0
- data/test/{update_test.rb → test_update.rb} +2 -3
- data/website/index.html +267 -201
- data/website/index.txt +74 -70
- data/website/stylesheets/screen.css +33 -3
- data/website/version-raw.js +1 -1
- data/website/version.js +1 -1
- metadata +80 -66
- data/scripts/http-access2-2.0.6.gem +0 -0
- data/scripts/rubyforge +0 -217
- data/scripts/rubyforge-orig +0 -217
- data/test/fixtures/db_definitions/mysql.drop.sql +0 -10
data/Manifest.txt
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
Manifest.txt
|
3
|
+
README
|
4
|
+
Rakefile
|
5
|
+
install.rb
|
6
|
+
lib/composite_primary_keys.rb
|
7
|
+
lib/composite_primary_keys/associations.rb
|
8
|
+
lib/composite_primary_keys/base.rb
|
9
|
+
lib/composite_primary_keys/calculations.rb
|
10
|
+
lib/composite_primary_keys/composite_arrays.rb
|
11
|
+
lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
|
12
|
+
lib/composite_primary_keys/fixtures.rb
|
13
|
+
lib/composite_primary_keys/reflection.rb
|
14
|
+
lib/composite_primary_keys/version.rb
|
15
|
+
scripts/txt2html
|
16
|
+
scripts/txt2js
|
17
|
+
test/abstract_unit.rb
|
18
|
+
test/composite_arrays_test.rb
|
19
|
+
test/connections/native_mysql/connection.rb
|
20
|
+
test/connections/native_oracle/connection.rb
|
21
|
+
test/connections/native_postgresql/connection.rb
|
22
|
+
test/connections/native_sqlite/connection.rb
|
23
|
+
test/fixtures/article.rb
|
24
|
+
test/fixtures/articles.yml
|
25
|
+
test/fixtures/db_definitions/mysql.sql
|
26
|
+
test/fixtures/db_definitions/postgresql.sql
|
27
|
+
test/fixtures/db_definitions/sqlite.sql
|
28
|
+
test/fixtures/group.rb
|
29
|
+
test/fixtures/groups.yml
|
30
|
+
test/fixtures/membership.rb
|
31
|
+
test/fixtures/membership_status.rb
|
32
|
+
test/fixtures/membership_statuses.yml
|
33
|
+
test/fixtures/memberships.yml
|
34
|
+
test/fixtures/product.rb
|
35
|
+
test/fixtures/product_tariff.rb
|
36
|
+
test/fixtures/product_tariffs.yml
|
37
|
+
test/fixtures/products.yml
|
38
|
+
test/fixtures/reading.rb
|
39
|
+
test/fixtures/readings.yml
|
40
|
+
test/fixtures/reference_code.rb
|
41
|
+
test/fixtures/reference_codes.yml
|
42
|
+
test/fixtures/reference_type.rb
|
43
|
+
test/fixtures/reference_types.yml
|
44
|
+
test/fixtures/street.rb
|
45
|
+
test/fixtures/streets.yml
|
46
|
+
test/fixtures/suburb.rb
|
47
|
+
test/fixtures/suburbs.yml
|
48
|
+
test/fixtures/tariff.rb
|
49
|
+
test/fixtures/tariffs.yml
|
50
|
+
test/fixtures/user.rb
|
51
|
+
test/fixtures/users.yml
|
52
|
+
test/hash_tricks.rb
|
53
|
+
test/test_associations.rb
|
54
|
+
test/test_attributes.rb
|
55
|
+
test/test_clone.rb
|
56
|
+
test/test_create.rb
|
57
|
+
test/test_delete.rb
|
58
|
+
test/test_dummy.rb
|
59
|
+
test/test_find.rb
|
60
|
+
test/test_ids.rb
|
61
|
+
test/test_miscellaneous.rb
|
62
|
+
test/test_pagination.rb
|
63
|
+
test/test_santiago.rb
|
64
|
+
test/test_tutorial_examle.rb
|
65
|
+
test/test_update.rb
|
66
|
+
website/index.html
|
67
|
+
website/index.txt
|
68
|
+
website/javascripts/rounded_corners_lite.inc.js
|
69
|
+
website/stylesheets/screen.css
|
70
|
+
website/template.js
|
71
|
+
website/template.rhtml
|
72
|
+
website/version-raw.js
|
73
|
+
website/version-raw.txt
|
74
|
+
website/version.js
|
75
|
+
website/version.txt
|
data/Rakefile
CHANGED
@@ -1,12 +1,56 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
require 'rake/clean'
|
3
4
|
require 'rake/testtask'
|
4
5
|
require 'rake/rdoctask'
|
5
6
|
require 'rake/packagetask'
|
6
7
|
require 'rake/gempackagetask'
|
7
8
|
require 'rake/contrib/rubyforgepublisher'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'hoe'
|
11
|
+
include FileUtils
|
8
12
|
require File.join(File.dirname(__FILE__), 'lib', 'composite_primary_keys', 'version')
|
9
13
|
|
14
|
+
AUTHOR = "Dr Nic Williams"
|
15
|
+
EMAIL = "drnicwilliams@gmail.com"
|
16
|
+
DESCRIPTION = "Composite key support for ActiveRecords"
|
17
|
+
GEM_NAME = "composite_primary_keys" # what ppl will type to install your gem
|
18
|
+
RUBYFORGE_PROJECT = "compositekeys"
|
19
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
20
|
+
|
21
|
+
REV = nil #File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
|
22
|
+
VERSION = ENV['VERSION'] || (CompositePrimaryKeys::VERSION::STRING + (REV ? ".#{REV}" : ""))
|
23
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
24
|
+
RDOC_OPTS = ['--quiet', '--title', "newgem documentation",
|
25
|
+
"--opname", "index.html",
|
26
|
+
"--line-numbers",
|
27
|
+
"--main", "README",
|
28
|
+
"--inline-source"]
|
29
|
+
|
30
|
+
class Hoe
|
31
|
+
def extra_deps
|
32
|
+
@extra_deps.reject { |x| Array(x).first == 'hoe' }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Generate all the Rake tasks
|
37
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
38
|
+
hoe = Hoe.new(GEM_NAME, VERSION) do |p|
|
39
|
+
p.author = AUTHOR
|
40
|
+
p.description = DESCRIPTION
|
41
|
+
p.email = EMAIL
|
42
|
+
p.summary = DESCRIPTION
|
43
|
+
p.url = HOMEPATH
|
44
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
45
|
+
p.test_globs = ["test/**/test*.rb"]
|
46
|
+
p.clean_globs = CLEAN #An array of file patterns to delete on clean.
|
47
|
+
|
48
|
+
# == Optional
|
49
|
+
#p.changes - A description of the release's latest changes.
|
50
|
+
p.extra_deps = [['activerecord', '>= 1.14.3']] #An array of rubygem dependencies.
|
51
|
+
#p.spec_extras - A hash of extra values to set in the gemspec.
|
52
|
+
end
|
53
|
+
|
10
54
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
11
55
|
PKG_NAME = 'composite_primary_keys'
|
12
56
|
PKG_VERSION = CompositePrimaryKeys::VERSION::STRING + PKG_BUILD
|
@@ -18,16 +62,10 @@ RUBY_FORGE_PROJECT = "compositekeys"
|
|
18
62
|
RUBY_FORGE_USER = "nicwilliams"
|
19
63
|
|
20
64
|
|
21
|
-
|
22
|
-
task :default => [ :test_mysql ] # UNTESTED =, :test_sqlite, :test_postgresql ]
|
23
|
-
task :test => [ :test_mysql ]
|
24
|
-
|
25
|
-
# Run the unit tests
|
26
|
-
|
27
|
-
for adapter in %w( mysql ) # UNTESTED - postgresql sqlite sqlite3 firebird sqlserver sqlserver_odbc db2 oracle sybase openbase )
|
65
|
+
for adapter in %w( mysql sqlite oracle postgresql ) # UNTESTED - firebird sqlserver sqlserver_odbc db2 sybase openbase )
|
28
66
|
Rake::TestTask.new("test_#{adapter}") { |t|
|
29
67
|
t.libs << "test" << "test/connections/native_#{adapter}"
|
30
|
-
t.pattern = "test
|
68
|
+
t.pattern = "test/test_*.rb"
|
31
69
|
t.verbose = true
|
32
70
|
}
|
33
71
|
end
|
@@ -37,121 +75,65 @@ SCHEMA_PATH = File.join(File.dirname(__FILE__), *%w(test fixtures db_definitions
|
|
37
75
|
desc 'Build the MySQL test databases'
|
38
76
|
task :build_mysql_databases do
|
39
77
|
puts File.join(SCHEMA_PATH, 'mysql.sql')
|
40
|
-
%
|
41
|
-
%
|
78
|
+
sh %{ mysqladmin -u root create "#{PKG_NAME}_unittest" }
|
79
|
+
sh %{ mysql -u root "#{PKG_NAME}_unittest" < #{File.join(SCHEMA_PATH, 'mysql.sql')} }
|
42
80
|
end
|
43
81
|
|
44
82
|
desc 'Drop the MySQL test databases'
|
45
83
|
task :drop_mysql_databases do
|
46
|
-
%
|
84
|
+
sh %{ mysqladmin -u root -f drop "#{PKG_NAME}_unittest" }
|
47
85
|
end
|
48
86
|
|
49
87
|
desc 'Rebuild the MySQL test databases'
|
88
|
+
|
50
89
|
task :rebuild_mysql_databases => [:drop_mysql_databases, :build_mysql_databases]
|
51
90
|
|
91
|
+
desc 'Build the sqlite test databases'
|
92
|
+
task :build_sqlite_databases do
|
93
|
+
file = File.join(SCHEMA_PATH, 'sqlite.sql')
|
94
|
+
cmd = "sqlite3 test.db < #{file}"
|
95
|
+
puts cmd
|
96
|
+
sh %{ #{cmd} }
|
97
|
+
end
|
98
|
+
|
99
|
+
desc 'Drop the sqlite test databases'
|
100
|
+
task :drop_sqlite_databases do
|
101
|
+
sh %{ rm -f test.db }
|
102
|
+
end
|
103
|
+
|
104
|
+
desc 'Rebuild the sqlite test databases'
|
105
|
+
task :rebuild_sqlite_databases => [:drop_sqlite_databases, :build_sqlite_databases]
|
106
|
+
|
52
107
|
desc 'Build the PostgreSQL test databases'
|
53
108
|
task :build_postgresql_databases do
|
54
|
-
%
|
55
|
-
%
|
109
|
+
sh %{ createdb "#{PKG_NAME}_unittest" }
|
110
|
+
sh %{ psql "#{PKG_NAME}_unittest" -f #{File.join(SCHEMA_PATH, 'postgresql.sql')} }
|
56
111
|
end
|
57
112
|
|
58
113
|
desc 'Drop the PostgreSQL test databases'
|
59
114
|
task :drop_postgresql_databases do
|
60
|
-
%
|
115
|
+
sh %{ dropdb "#{PKG_NAME}_unittest" }
|
61
116
|
end
|
62
117
|
|
63
118
|
desc 'Rebuild the PostgreSQL test databases'
|
64
119
|
task :rebuild_postgresql_databases => [:drop_postgresql_databases, :build_postgresql_databases]
|
65
120
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
72
|
-
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
73
|
-
rdoc.rdoc_files.include('README', 'CHANGELOG')
|
74
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
75
|
-
rdoc.rdoc_files.exclude('lib/active_record/vendor/*')
|
76
|
-
rdoc.rdoc_files.include('dev-utils/*.rb')
|
77
|
-
}
|
78
|
-
|
79
|
-
# Enhance rdoc task to copy referenced images also
|
80
|
-
task :rdoc do
|
81
|
-
FileUtils.mkdir_p "doc/files/examples/"
|
121
|
+
desc 'Generate website files'
|
122
|
+
task :website_generate do
|
123
|
+
sh %{ ruby scripts/txt2html website/index.txt > website/index.html }
|
124
|
+
sh %{ ruby scripts/txt2js website/version.txt > website/version.js }
|
125
|
+
sh %{ ruby scripts/txt2js website/version-raw.txt > website/version-raw.js }
|
82
126
|
end
|
83
127
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
s.version = PKG_VERSION
|
92
|
-
s.summary = "Support for composite primary keys in ActiveRecords"
|
93
|
-
s.description = %q{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.}
|
94
|
-
|
95
|
-
s.files = [ "Rakefile", "install.rb", "README", "CHANGELOG" ]
|
96
|
-
dist_dirs.each do |dir|
|
97
|
-
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
98
|
-
end
|
99
|
-
|
100
|
-
s.add_dependency('activerecord', '>= 1.14.3' + PKG_BUILD)
|
101
|
-
|
102
|
-
s.require_path = 'lib'
|
103
|
-
s.autorequire = 'composite_primary_keys'
|
104
|
-
|
105
|
-
s.has_rdoc = true
|
106
|
-
s.extra_rdoc_files = %w( README )
|
107
|
-
s.rdoc_options.concat ['--main', 'README']
|
108
|
-
|
109
|
-
s.author = "Dr Nic Williams"
|
110
|
-
s.email = "drnicwilliams@gmail.com"
|
111
|
-
s.homepage = "http://compositekeys.rubyforge.org"
|
112
|
-
s.rubyforge_project = "compositekeys"
|
113
|
-
end
|
114
|
-
|
115
|
-
Rake::GemPackageTask.new(spec) do |p|
|
116
|
-
p.gem_spec = spec
|
117
|
-
p.need_tar = false
|
118
|
-
p.need_zip = false
|
128
|
+
desc 'Upload website files to rubyforge'
|
129
|
+
task :website_upload do
|
130
|
+
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
131
|
+
host = "#{config["username"]}@rubyforge.org"
|
132
|
+
remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/"
|
133
|
+
local_dir = 'website'
|
134
|
+
sh %{rsync -av --delete #{local_dir}/ #{host}:#{remote_dir}}
|
119
135
|
end
|
120
136
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
for file_name in FileList["lib/composite_primary_keys/**/*.rb"]
|
125
|
-
next if file_name =~ /vendor/
|
126
|
-
f = File.open(file_name)
|
127
|
-
|
128
|
-
while line = f.gets
|
129
|
-
lines += 1
|
130
|
-
next if line =~ /^\s*$/
|
131
|
-
next if line =~ /^\s*#/
|
132
|
-
codelines += 1
|
133
|
-
end
|
134
|
-
puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}"
|
135
|
-
|
136
|
-
total_lines += lines
|
137
|
-
total_codelines += codelines
|
138
|
-
|
139
|
-
lines, codelines = 0, 0
|
140
|
-
end
|
141
|
-
|
142
|
-
puts "Total: Lines #{total_lines}, LOC #{total_codelines}"
|
137
|
+
desc 'Generate and upload website files'
|
138
|
+
task :website => [:website_generate, :website_upload] do
|
143
139
|
end
|
144
|
-
|
145
|
-
|
146
|
-
# Publishing ------------------------------------------------------
|
147
|
-
|
148
|
-
desc "Publish the release files to RubyForge."
|
149
|
-
task :release => [ :package ] do
|
150
|
-
`ruby scripts/rubyforge login`
|
151
|
-
|
152
|
-
for ext in %w( gem tgz zip )
|
153
|
-
release_command = "ruby scripts/rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
|
154
|
-
puts release_command
|
155
|
-
system(release_command)
|
156
|
-
end
|
157
|
-
end
|
@@ -39,7 +39,15 @@ require 'composite_primary_keys/composite_arrays'
|
|
39
39
|
require 'composite_primary_keys/associations'
|
40
40
|
require 'composite_primary_keys/reflection'
|
41
41
|
require 'composite_primary_keys/base'
|
42
|
+
require 'composite_primary_keys/calculations'
|
42
43
|
|
43
44
|
ActiveRecord::Base.class_eval do
|
44
45
|
include CompositePrimaryKeys::ActiveRecord::Base
|
45
46
|
end
|
47
|
+
|
48
|
+
RAILS_CONNECTION_ADAPTERS.each do |adapter|
|
49
|
+
begin
|
50
|
+
require "composite_primary_keys/connection_adapters/" + adapter + "_adapter"
|
51
|
+
rescue MissingSourceFile
|
52
|
+
end
|
53
|
+
end
|
@@ -125,10 +125,12 @@ module ActiveRecord::Associations::ClassMethods
|
|
125
125
|
def composite_association_join
|
126
126
|
join = case reflection.macro
|
127
127
|
when :has_and_belongs_to_many
|
128
|
+
# TODO replace (keys) = (ids), with key1=id1 and key2=id2
|
128
129
|
" LEFT OUTER JOIN %s ON (%s) = (%s) " % [
|
129
130
|
table_alias_for(options[:join_table], aliased_join_table_name),
|
130
131
|
full_keys(aliased_join_table_name, options[:foreign_key] || reflection.active_record.to_s.classify.foreign_key),
|
131
132
|
full_keys(reflection.active_record.table_name, reflection.active_record.primary_key)] +
|
133
|
+
# TODO replace (keys) = (ids), with key1=id1 and key2=id2
|
132
134
|
" LEFT OUTER JOIN %s ON (%s) = (%s) " % [
|
133
135
|
table_name_and_alias,
|
134
136
|
full_keys(aliased_table_name, klass.primary_key),
|
@@ -153,10 +155,12 @@ module ActiveRecord::Associations::ClassMethods
|
|
153
155
|
second_key = options[:foreign_key] || primary_key
|
154
156
|
end
|
155
157
|
|
158
|
+
# TODO replace (keys) = (ids), with key1=id1 and key2=id2
|
156
159
|
" LEFT OUTER JOIN %s ON (%s) = (%s) " % [
|
157
160
|
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
|
158
161
|
full_keys(aliased_join_table_name, through_reflection.primary_key_name),
|
159
162
|
full_keys(parent.aliased_table_name, parent.primary_key)] +
|
163
|
+
# TODO replace (keys) = (ids), with key1=id1 and key2=id2
|
160
164
|
" LEFT OUTER JOIN %s ON (%s) = (%s) " % [
|
161
165
|
table_name_and_alias,
|
162
166
|
full_keys(aliased_table_name, first_key),
|
@@ -171,17 +175,21 @@ module ActiveRecord::Associations::ClassMethods
|
|
171
175
|
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
|
172
176
|
else
|
173
177
|
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
|
174
|
-
|
178
|
+
# TODO replace (keys) = (ids), with key1=id1 and key2=id2
|
179
|
+
" LEFT OUTER JOIN %s ON %s " % [
|
175
180
|
table_name_and_alias,
|
176
|
-
|
177
|
-
|
181
|
+
composite_join_clause(
|
182
|
+
full_keys(aliased_table_name, foreign_key),
|
183
|
+
full_keys(parent.aliased_table_name, parent.primary_key)),
|
178
184
|
]
|
179
185
|
end
|
180
186
|
when :belongs_to
|
181
|
-
|
187
|
+
# TODO replace (keys) = (ids), with key1=id1 and key2=id2
|
188
|
+
" LEFT OUTER JOIN %s ON %s " % [
|
182
189
|
table_name_and_alias,
|
183
|
-
|
184
|
-
|
190
|
+
composite_join_clause(
|
191
|
+
full_keys(aliased_table_name, reflection.klass.primary_key),
|
192
|
+
full_keys(parent.aliased_table_name, options[:foreign_key] || klass.to_s.foreign_key)),
|
185
193
|
]
|
186
194
|
else
|
187
195
|
""
|
@@ -197,12 +205,47 @@ module ActiveRecord::Associations::ClassMethods
|
|
197
205
|
def full_keys(table_name, keys)
|
198
206
|
keys.collect {|key| "#{table_name}.#{key}"}.join(CompositePrimaryKeys::ID_SEP)
|
199
207
|
end
|
208
|
+
|
209
|
+
def composite_join_clause(full_keys1, full_keys2)
|
210
|
+
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
|
211
|
+
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
|
212
|
+
where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
|
213
|
+
"#{key_pair.first}=#{key_pair.last}"
|
214
|
+
end.join(" AND ")
|
215
|
+
"(#{where_clause})"
|
216
|
+
end
|
200
217
|
end
|
201
218
|
end
|
202
219
|
end
|
203
220
|
|
204
221
|
module ActiveRecord::Associations
|
205
222
|
class AssociationProxy #:nodoc:
|
223
|
+
|
224
|
+
def composite_where_clause(full_keys, ids)
|
225
|
+
full_keys = full_keys.split(CompositePrimaryKeys::ID_SEP) if full_keys.is_a?(String)
|
226
|
+
if ids.is_a?(String)
|
227
|
+
ids = [[ids]]
|
228
|
+
elsif not ids.first.is_a?(Array) # if single comp key passed, turn into an array of 1
|
229
|
+
ids = [ids.to_composite_ids]
|
230
|
+
end
|
231
|
+
where_clause = ids.map do |id_set|
|
232
|
+
transposed = id_set.size == 1 ? [[full_keys, id_set.first]] : [full_keys, id_set].transpose
|
233
|
+
transposed.map do |full_key, id|
|
234
|
+
"#{full_key.to_s}=#{@reflection.klass.sanitize(id)}"
|
235
|
+
end.join(" AND ")
|
236
|
+
end.join(") OR (")
|
237
|
+
"(#{where_clause})"
|
238
|
+
end
|
239
|
+
|
240
|
+
def composite_join_clause(full_keys1, full_keys2)
|
241
|
+
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
|
242
|
+
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
|
243
|
+
where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
|
244
|
+
"#{key_pair.first}=#{key_pair.last}"
|
245
|
+
end.join(" AND ")
|
246
|
+
"(#{where_clause})"
|
247
|
+
end
|
248
|
+
|
206
249
|
def full_keys(table_name, keys)
|
207
250
|
keys = keys.split(CompositePrimaryKeys::ID_SEP) if keys.is_a?(String)
|
208
251
|
keys.is_a?(Array) ?
|
@@ -211,7 +254,7 @@ module ActiveRecord::Associations
|
|
211
254
|
end
|
212
255
|
|
213
256
|
def full_columns_equals(table_name, keys, quoted_ids)
|
214
|
-
if keys.is_a?(Symbol) or (keys.is_a?(String) and keys == keys.split(CompositePrimaryKeys::ID_SEP))
|
257
|
+
if keys.is_a?(Symbol) or (keys.is_a?(String) and keys == keys.to_s.split(CompositePrimaryKeys::ID_SEP))
|
215
258
|
return "#{table_name}.#{keys} = #{quoted_ids}"
|
216
259
|
end
|
217
260
|
keys = keys.split(CompositePrimaryKeys::ID_SEP) if keys.is_a?(String)
|
@@ -259,10 +302,8 @@ module ActiveRecord::Associations
|
|
259
302
|
"#{@reflection.klass.table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
|
260
303
|
"#{@reflection.klass.table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote @owner.class.base_class.name.to_s}"
|
261
304
|
else
|
262
|
-
@finder_sql =
|
263
|
-
|
264
|
-
@owner.quoted_id
|
265
|
-
]
|
305
|
+
@finder_sql = full_columns_equals(@reflection.klass.table_name,
|
306
|
+
@reflection.primary_key_name, @owner.quoted_id)
|
266
307
|
end
|
267
308
|
@finder_sql << " AND (#{conditions})" if conditions
|
268
309
|
end
|
@@ -298,10 +339,11 @@ module ActiveRecord::Associations
|
|
298
339
|
end
|
299
340
|
end
|
300
341
|
|
301
|
-
"INNER JOIN %s ON
|
342
|
+
"INNER JOIN %s ON %s %s #{@reflection.options[:joins]} #{custom_joins}" % [
|
302
343
|
@reflection.through_reflection.table_name,
|
303
|
-
|
304
|
-
|
344
|
+
composite_join_clause(
|
345
|
+
full_keys(@reflection.table_name, reflection_primary_key),
|
346
|
+
full_keys(@reflection.through_reflection.table_name, source_primary_key)),
|
305
347
|
polymorphic_join
|
306
348
|
]
|
307
349
|
end
|
@@ -311,10 +353,16 @@ module ActiveRecord::Associations
|
|
311
353
|
when @reflection.options[:finder_sql]
|
312
354
|
@finder_sql = interpolate_sql(@reflection.options[:finder_sql])
|
313
355
|
|
314
|
-
@finder_sql
|
315
|
-
|
316
|
-
|
317
|
-
|
356
|
+
@finder_sql << " AND (#{conditions})" if conditions
|
357
|
+
when @reflection.options[:as]
|
358
|
+
@finder_sql =
|
359
|
+
"#{@reflection.klass.table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
|
360
|
+
"#{@reflection.klass.table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
|
361
|
+
@finder_sql << " AND (#{conditions})" if conditions
|
362
|
+
|
363
|
+
else
|
364
|
+
@finder_sql = composite_where_clause(
|
365
|
+
full_keys(@reflection.klass.table_name, @reflection.primary_key_name), @owner.quoted_id),
|
318
366
|
@finder_sql << " AND (#{conditions})" if conditions
|
319
367
|
end
|
320
368
|
|