tyler-composite_primary_keys 1.1.0 → 1.1.1

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.
Files changed (47) hide show
  1. data/History.txt +0 -8
  2. data/Manifest.txt +0 -1
  3. data/Rakefile +65 -0
  4. data/init.rb +2 -0
  5. data/install.rb +30 -0
  6. data/lib/composite_primary_keys/association_preload.rb +2 -19
  7. data/lib/composite_primary_keys/associations.rb +2 -2
  8. data/lib/composite_primary_keys/base.rb +2 -6
  9. data/lib/composite_primary_keys/calculations.rb +1 -2
  10. data/lib/composite_primary_keys/version.rb +3 -3
  11. data/loader.rb +24 -0
  12. data/tmp/test.db +0 -0
  13. data/website/index.html +199 -0
  14. data/website/index.txt +159 -0
  15. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  16. data/website/stylesheets/screen.css +126 -0
  17. data/website/template.js +3 -0
  18. data/website/template.rhtml +53 -0
  19. data/website/version-raw.js +3 -0
  20. data/website/version-raw.txt +2 -0
  21. data/website/version.js +4 -0
  22. data/website/version.txt +3 -0
  23. metadata +78 -59
  24. data/lib/adapter_helper/oracle_enhanced.rb +0 -12
  25. data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +0 -9
  26. data/lib/composite_primary_keys/connection_adapters/oracle_enhanced_adapter.rb +0 -17
  27. data/test/connections/native_oracle_enhanced/connection.rb +0 -20
  28. data/test/fixtures/article_group.rb +0 -4
  29. data/test/fixtures/article_groups.yml +0 -7
  30. data/test/fixtures/dorm.rb +0 -3
  31. data/test/fixtures/dorms.yml +0 -2
  32. data/test/fixtures/kitchen_sink.rb +0 -3
  33. data/test/fixtures/kitchen_sinks.yml +0 -5
  34. data/test/fixtures/restaurant.rb +0 -6
  35. data/test/fixtures/restaurants.yml +0 -5
  36. data/test/fixtures/restaurants_suburbs.yml +0 -11
  37. data/test/fixtures/room.rb +0 -10
  38. data/test/fixtures/room_assignment.rb +0 -4
  39. data/test/fixtures/room_assignments.yml +0 -4
  40. data/test/fixtures/room_attribute.rb +0 -3
  41. data/test/fixtures/room_attribute_assignment.rb +0 -5
  42. data/test/fixtures/room_attribute_assignments.yml +0 -4
  43. data/test/fixtures/room_attributes.yml +0 -3
  44. data/test/fixtures/rooms.yml +0 -3
  45. data/test/fixtures/student.rb +0 -4
  46. data/test/fixtures/students.yml +0 -2
  47. data/test/test_exists.rb +0 -29
data/History.txt CHANGED
@@ -1,11 +1,3 @@
1
- == 2.2.1 2009-01-21
2
-
3
- * fix ActiveRecord#exists? to work when passing conditions instead of ids
4
-
5
- == 2.2.0 2008-10-29
6
-
7
- * Rails 2.2.0 compatibility
8
-
9
1
  == 1.1.0 2008-10-29
10
2
 
11
3
  * fixes to get cpk working for Rails 2.1.2
data/Manifest.txt CHANGED
@@ -100,7 +100,6 @@ test/test_composite_arrays.rb
100
100
  test/test_create.rb
101
101
  test/test_delete.rb
102
102
  test/test_dummy.rb
103
- test/test_exists.rb
104
103
  test/test_find.rb
105
104
  test/test_ids.rb
106
105
  test/test_miscellaneous.rb
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/packagetask'
7
+ require 'rake/gempackagetask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'fileutils'
10
+ require 'hoe'
11
+ include FileUtils
12
+ require File.join(File.dirname(__FILE__), 'lib', 'composite_primary_keys', 'version')
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
+ if File.exists?("~/.rubyforge/user-config.yml")
19
+ # TODO this should prob go in a local/ file
20
+ config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
21
+ RUBYFORGE_USERNAME = config["username"]
22
+ end
23
+ RUBYFORGE_PROJECT = "compositekeys"
24
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
25
+
26
+ REV = nil #File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
27
+ VERS = ENV['VERSION'] || (CompositePrimaryKeys::VERSION::STRING + (REV ? ".#{REV}" : ""))
28
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config','debug.log','*.db','logfile','log/**/*','**/.DS_Store', '.project']
29
+ RDOC_OPTS = ['--quiet', '--title', "newgem documentation",
30
+ "--opname", "index.html",
31
+ "--line-numbers",
32
+ "--main", "README",
33
+ "--inline-source"]
34
+
35
+ class Hoe
36
+ def extra_deps
37
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
38
+ end
39
+ end
40
+
41
+ # Generate all the Rake tasks
42
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
43
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
44
+ p.author = AUTHOR
45
+ p.description = DESCRIPTION
46
+ p.email = EMAIL
47
+ p.summary = DESCRIPTION
48
+ p.url = HOMEPATH
49
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
50
+ p.test_globs = ["test/**/test*.rb"]
51
+ p.clean_globs |= CLEAN #An array of file patterns to delete on clean.
52
+
53
+ # == Optional
54
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
55
+ p.extra_deps = [['activerecord', '>= 2.1.2']] #An array of rubygem dependencies.
56
+ #p.spec_extras - A hash of extra values to set in the gemspec.
57
+ end
58
+
59
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n")
60
+ PATH = RUBYFORGE_PROJECT
61
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
62
+
63
+ PROJECT_ROOT = File.expand_path(".")
64
+
65
+ require 'loader'
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ require_dependency 'composite_primary_keys'
data/install.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'rbconfig'
2
+ require 'find'
3
+ require 'ftools'
4
+
5
+ include Config
6
+
7
+ # this was adapted from rdoc's install.rb by ways of Log4r
8
+
9
+ $sitedir = CONFIG["sitelibdir"]
10
+ unless $sitedir
11
+ version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
12
+ $libdir = File.join(CONFIG["libdir"], "ruby", version)
13
+ $sitedir = $:.find {|x| x =~ /site_ruby/ }
14
+ if !$sitedir
15
+ $sitedir = File.join($libdir, "site_ruby")
16
+ elsif $sitedir !~ Regexp.quote(version)
17
+ $sitedir = File.join($sitedir, version)
18
+ end
19
+ end
20
+
21
+ # the acual gruntwork
22
+ Dir.chdir("lib")
23
+
24
+ Find.find("composite_primary_keys", "composite_primary_keys.rb") { |f|
25
+ if f[-3..-1] == ".rb"
26
+ File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
27
+ else
28
+ File::makedirs(File.join($sitedir, *f.split(/\//)))
29
+ end
30
+ }
@@ -10,7 +10,7 @@ module CompositePrimaryKeys
10
10
  module ClassMethods
11
11
  def preload_has_and_belongs_to_many_association(records, reflection, preload_options={})
12
12
  table_name = reflection.klass.quoted_table_name
13
- id_to_record_map, ids = construct_id_map_for_composite(records)
13
+ id_to_record_map, ids = construct_id_map(records)
14
14
  records.each {|record| record.send(reflection.name).loaded}
15
15
  options = reflection.options
16
16
 
@@ -43,7 +43,7 @@ module CompositePrimaryKeys
43
43
  end
44
44
 
45
45
  def preload_has_many_association(records, reflection, preload_options={})
46
- id_to_record_map, ids = construct_id_map_for_composite(records)
46
+ id_to_record_map, ids = construct_id_map(records)
47
47
  records.each {|record| record.send(reflection.name).loaded}
48
48
  options = reflection.options
49
49
 
@@ -219,23 +219,6 @@ module CompositePrimaryKeys
219
219
  :order => preload_options[:order] || options[:order])
220
220
  end
221
221
 
222
- # Given a collection of ActiveRecord objects, constructs a Hash which maps
223
- # the objects' IDs to the relevant objects. Returns a 2-tuple
224
- # <tt>(id_to_record_map, ids)</tt> where +id_to_record_map+ is the Hash,
225
- # and +ids+ is an Array of record IDs.
226
- def construct_id_map_for_composite(records)
227
- id_to_record_map = {}
228
- ids = []
229
- records.each do |record|
230
- primary_key ||= record.class.primary_key
231
- ids << record.id
232
- mapped_records = (id_to_record_map[record.id.to_s] ||= [])
233
- mapped_records << record
234
- end
235
- ids.uniq!
236
- return id_to_record_map, ids
237
- end
238
-
239
222
  def full_composite_join_clause(reflection, table1, full_keys1, table2, full_keys2)
240
223
  connection = reflection.active_record.connection
241
224
  full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
@@ -21,7 +21,7 @@ module CompositePrimaryKeys
21
21
  sql << " FROM #{quoted_table_name} "
22
22
  sql << join_dependency.join_associations.collect{|join| join.association_join }.join
23
23
 
24
- add_joins!(sql, options[:joins], scope)
24
+ add_joins!(sql, options, scope)
25
25
  add_conditions!(sql, options[:conditions], scope)
26
26
  add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
27
27
 
@@ -39,7 +39,7 @@ module CompositePrimaryKeys
39
39
  sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
40
40
  sql << join_dependency.join_associations.collect{|join| join.association_join }.join
41
41
 
42
- add_joins!(sql, options[:joins], scope)
42
+ add_joins!(sql, options, scope)
43
43
  add_conditions!(sql, options[:conditions], scope)
44
44
  add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && options[:limit]
45
45
 
@@ -186,12 +186,8 @@ module CompositePrimaryKeys
186
186
  # Example:
187
187
  # Person.exists?(5,7)
188
188
  def exists?(ids)
189
- if ids.is_a?(Array) && ids.first.is_a?(String)
190
- count(:conditions => ids) > 0
191
- else
192
- obj = find(ids) rescue false
193
- !obj.nil? and obj.is_a?(self)
194
- end
189
+ obj = find(ids) rescue false
190
+ !obj.nil? and obj.is_a?(self)
195
191
  end
196
192
 
197
193
  # Deletes the record with the given +ids+ without instantiating an object first, e.g. delete(1,2)
@@ -35,8 +35,7 @@ module CompositePrimaryKeys
35
35
  join_dependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
36
36
  sql << join_dependency.join_associations.collect{|join| join.association_join }.join
37
37
  end
38
-
39
- add_joins!(sql, options[:joins], scope)
38
+ add_joins!(sql, options, scope)
40
39
  add_conditions!(sql, options[:conditions], scope)
41
40
  add_limited_ids_condition!(sql, options, join_dependency) if \
42
41
  join_dependency &&
@@ -1,8 +1,8 @@
1
1
  module CompositePrimaryKeys
2
2
  module VERSION #:nodoc:
3
- MAJOR = 2
4
- MINOR = 2
5
- TINY = 2
3
+ MAJOR = 1
4
+ MINOR = 1
5
+ TINY = 0
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
data/loader.rb ADDED
@@ -0,0 +1,24 @@
1
+ # Load local config files in /local
2
+ begin
3
+ local_file_supported = Dir[File.join(PROJECT_ROOT, 'local/*.sample')].map { |path| File.basename(path).sub(".sample","") }
4
+ local_file_supported.each do |file|
5
+ require "local/#{file}"
6
+ end
7
+ rescue LoadError
8
+ puts <<-EOS
9
+ This Gem supports local developer extensions in local/ folder.
10
+ Supported files:
11
+ #{local_file_supported.map { |f| "local/#{f}"}.join(', ')}
12
+
13
+ Setup default sample files:
14
+ rake local:setup
15
+
16
+ Current warning: #{$!}
17
+
18
+ EOS
19
+ end
20
+
21
+
22
+ # Now load Rake tasks from /tasks
23
+ rakefiles = Dir[File.join(File.dirname(__FILE__), "tasks/**/*.rake")]
24
+ rakefiles.each { |rakefile| load File.expand_path(rakefile) }
data/tmp/test.db ADDED
Binary file
@@ -0,0 +1,199 @@
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">1.1.0</a>
37
+ </div>
38
+ <h1>&amp;#x2192; Ruby on Rails</h1>
39
+ <h1>&amp;#x2192; 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 &#8211; <a href="http://wiki.rubyonrails.com/rails/pages/ActiveRecord">ActiveRecords</a> &#8211; 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&#8230;</p>
53
+ <p><pre class="syntax"><span class="keyword">class </span><span class="class">Membership</span> <span class="punct">&lt;</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">=&gt;</span> <span class="punct">'</span><span class="string">MembershipStatus</span><span class="punct">',</span> <span class="symbol">:foreign_key</span> <span class="punct">=&gt;</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&#8230;</p>
61
+ <p><pre class="syntax"><span class="keyword">class </span><span class="class">MembershipStatus</span> <span class="punct">&lt;</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">=&gt;</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&#8217;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"># =&gt; &quot;id&quot; # normal single key</span>
69
+ <span class="constant">Membership</span><span class="punct">.</span><span class="ident">primary_key</span> <span class="comment"># =&gt; [: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"># =&gt; &quot;user_id,group_id&quot;</span></pre></p>
71
+ <p>Now we want to be able to find instances using the same syntax we always use for ActiveRecords&#8230;</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">=&gt;</span> <span class="punct">&lt;</span><span class="constant">MembershipStatus</span><span class="punct">:</span><span class="number">0x392a8c8</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">status</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">Active</span><span class="punct">&quot;}&gt;</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">=&gt;</span> <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x39218b0</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</span></pre></p>
76
+ <p>Using <a href="http://www.rubyonrails.org">Ruby on Rails</a>? You&#8217;ll want to your url_for helpers<br />
77
+ to convert composite keys into strings and back again&#8230;</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"># =&gt; &quot;1,1&quot;</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"># =&gt; '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">=&gt;</span> <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x3904288</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</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">=&gt;</span> <span class="punct">[</span>
89
+ <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x394ade8</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;,</span>
90
+ <span class="punct">&lt;</span><span class="constant">Membership</span><span class="punct">:</span><span class="number">0x394ada0</span> <span class="attribute">@attributes</span><span class="punct">={&quot;</span><span class="string">user_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">2</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">group_id</span><span class="punct">&quot;=&gt;&quot;</span><span class="string">1</span><span class="punct">&quot;}&gt;</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"># =&gt; 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&#8217;t see mentioned on <a href="http://groups.google.com/group/compositekeys">this list</a> &#8211; <br />
98
+ and I didn&#8217;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 &#8216;show&#8217; action (for<br />
101
+ example) had a syntax like:<br />
102
+ <br />
103
+ <pre>/controller/show/123000,Bu70</pre></p>
104
+ <p>for a two-field composite PK. The default routing would not match that,<br />
105
+ so after working out how to do the routing I added:<br />
106
+ <br />
107
+ <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">=&gt;</span> <span class="punct">/</span><span class="regex"><span class="escape">\w</span>+(,<span class="escape">\w</span>+)*</span><span class="punct">/</span></pre><br />
108
+ <br />
109
+ to my <code>route.rb</code> file.</p>
110
+ </blockquote>
111
+ <p><a name="dbs"></a></p>
112
+ <h2>Which databases?</h2>
113
+ <p>A suite of unit tests have been run on the following databases supported by ActiveRecord:</p>
114
+ <table>
115
+ <tr>
116
+ <th>Database</th>
117
+ <th>Test Success</th>
118
+ <th>User feedback</th>
119
+ </tr>
120
+ <tr>
121
+ <td>mysql </td>
122
+ <td><span class=success><span class="caps">YES</span></span></td>
123
+ <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&#8230;</a>)</td>
124
+ </tr>
125
+ <tr>
126
+ <td>sqlite3 </td>
127
+ <td><span class=success><span class="caps">YES</span></span></td>
128
+ <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&#8230;</a>)</td>
129
+ </tr>
130
+ <tr>
131
+ <td>postgresql</td>
132
+ <td><span class=success><span class="caps">YES</span></span></td>
133
+ <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&#8230;</a>)</td>
134
+ </tr>
135
+ <tr>
136
+ <td>oracle </td>
137
+ <td><span class=success><span class="caps">YES</span></span></td>
138
+ <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&#8230;</a>)</td>
139
+ </tr>
140
+ <tr>
141
+ <td>sqlserver </td>
142
+ <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+SQLServer">I can help</a>)</td>
143
+ <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&#8230;</a>)</td>
144
+ </tr>
145
+ <tr>
146
+ <td>db2 </td>
147
+ <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+DB2">I can help</a>)</td>
148
+ <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&#8230;</a>)</td>
149
+ </tr>
150
+ <tr>
151
+ <td>firebird </td>
152
+ <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Firebird">I can help</a>)</td>
153
+ <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&#8230;</a>)</td>
154
+ </tr>
155
+ <tr>
156
+ <td>sybase </td>
157
+ <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Sybase">I can help</a>)</td>
158
+ <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&#8230;</a>)</td>
159
+ </tr>
160
+ <tr>
161
+ <td>openbase </td>
162
+ <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Openbase">I can help</a>)</td>
163
+ <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&#8230;</a>)</td>
164
+ </tr>
165
+ <tr>
166
+ <td>frontbase </td>
167
+ <td><span class=unknown>???</span> (<a href="mailto:compositekeys@googlegroups.com?subject=Help+with+Frontbase">I can help</a>)</td>
168
+ <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&#8230;</a>)</td>
169
+ </tr>
170
+ </table>
171
+ <h2>Dr Nic&#8217;s Blog</h2>
172
+ <p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> &#8211; for future announcements and<br />
173
+ other stories and things.</p>
174
+ <h2>Forum</h2>
175
+ <p><a href="http://groups.google.com/group/compositekeys">http://groups.google.com/group/compositekeys</a></p>
176
+ <h2>How to submit patches</h2>
177
+ <p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people&#8217;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>
178
+ <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:<br />
179
+ <br />
180
+ <pre>git clone git://github.com/drnic/composite_primary_keys.git</pre></p>
181
+ <h2>Licence</h2>
182
+ <p>This code is free to use under the terms of the <span class="caps">MIT</span> licence.</p>
183
+ <h2>Contact</h2>
184
+ <p>Comments are welcome. Send an email to <a href="mailto:drnicwilliams@gmail.com">Dr Nic Williams</a>.</p>
185
+ <p class="coda">
186
+ <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 25th October 2008<br>
187
+ Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
188
+ </p>
189
+ </div>
190
+
191
+ <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
192
+ </script>
193
+ <script type="text/javascript">
194
+ _uacct = "UA-567811-2";
195
+ urchinTracker();
196
+ </script>
197
+
198
+ </body>
199
+ </html>