Remove ancient (and unused) composite_primary_keys gem

This commit is contained in:
Tom Hughes 2012-02-13 10:43:51 +00:00
parent 92feab9112
commit 2d2b6d7ed8
148 changed files with 0 additions and 6357 deletions

View file

@ -1,217 +0,0 @@
--- !ruby/object:Gem::Specification
name: composite_primary_keys
version: !ruby/object:Gem::Version
version: 2.2.2
platform: ruby
authors:
- Dr Nic Williams
autorequire:
bindir: bin
cert_chain: []
date: 2009-01-24 00:00:00 +00:00
default_executable:
dependencies:
- !ruby/object:Gem::Dependency
name: activerecord
type: :runtime
version_requirement:
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: 2.2.0
version:
- !ruby/object:Gem::Dependency
name: hoe
type: :development
version_requirement:
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: 1.8.3
version:
description: Composite key support for ActiveRecords
email: drnicwilliams@gmail.com
executables: []
extensions: []
extra_rdoc_files:
- History.txt
- Manifest.txt
- README.txt
- README_DB2.txt
- test/README_tests.txt
- website/index.txt
- website/version-raw.txt
- website/version.txt
files:
- History.txt
- Manifest.txt
- README.txt
- README_DB2.txt
- Rakefile
- init.rb
- install.rb
- lib/adapter_helper/base.rb
- lib/adapter_helper/mysql.rb
- lib/adapter_helper/oracle.rb
- lib/adapter_helper/postgresql.rb
- lib/adapter_helper/sqlite3.rb
- lib/composite_primary_keys.rb
- lib/composite_primary_keys/association_preload.rb
- lib/composite_primary_keys/associations.rb
- lib/composite_primary_keys/attribute_methods.rb
- lib/composite_primary_keys/base.rb
- lib/composite_primary_keys/calculations.rb
- lib/composite_primary_keys/composite_arrays.rb
- lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb
- lib/composite_primary_keys/connection_adapters/oracle_adapter.rb
- lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
- lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb
- lib/composite_primary_keys/fixtures.rb
- lib/composite_primary_keys/migration.rb
- lib/composite_primary_keys/reflection.rb
- lib/composite_primary_keys/version.rb
- loader.rb
- local/database_connections.rb.sample
- local/paths.rb.sample
- local/tasks.rb.sample
- scripts/console.rb
- scripts/txt2html
- scripts/txt2js
- tasks/activerecord_selection.rake
- tasks/databases.rake
- tasks/databases/mysql.rake
- tasks/databases/oracle.rake
- tasks/databases/postgresql.rake
- tasks/databases/sqlite3.rake
- tasks/deployment.rake
- tasks/local_setup.rake
- tasks/website.rake
- test/README_tests.txt
- test/abstract_unit.rb
- test/connections/native_ibm_db/connection.rb
- test/connections/native_mysql/connection.rb
- test/connections/native_oracle/connection.rb
- test/connections/native_postgresql/connection.rb
- test/connections/native_sqlite/connection.rb
- test/fixtures/article.rb
- test/fixtures/articles.yml
- test/fixtures/comment.rb
- test/fixtures/comments.yml
- test/fixtures/db_definitions/db2-create-tables.sql
- test/fixtures/db_definitions/db2-drop-tables.sql
- test/fixtures/db_definitions/mysql.sql
- test/fixtures/db_definitions/oracle.drop.sql
- test/fixtures/db_definitions/oracle.sql
- test/fixtures/db_definitions/postgresql.sql
- test/fixtures/db_definitions/sqlite.sql
- test/fixtures/department.rb
- test/fixtures/departments.yml
- test/fixtures/employee.rb
- test/fixtures/employees.yml
- test/fixtures/group.rb
- test/fixtures/groups.yml
- test/fixtures/hack.rb
- test/fixtures/hacks.yml
- test/fixtures/membership.rb
- test/fixtures/membership_status.rb
- test/fixtures/membership_statuses.yml
- test/fixtures/memberships.yml
- test/fixtures/product.rb
- test/fixtures/product_tariff.rb
- test/fixtures/product_tariffs.yml
- test/fixtures/products.yml
- test/fixtures/reading.rb
- test/fixtures/readings.yml
- test/fixtures/reference_code.rb
- test/fixtures/reference_codes.yml
- test/fixtures/reference_type.rb
- test/fixtures/reference_types.yml
- test/fixtures/street.rb
- test/fixtures/streets.yml
- test/fixtures/suburb.rb
- test/fixtures/suburbs.yml
- test/fixtures/tariff.rb
- test/fixtures/tariffs.yml
- test/fixtures/user.rb
- test/fixtures/users.yml
- test/hash_tricks.rb
- test/plugins/pagination.rb
- test/plugins/pagination_helper.rb
- test/test_associations.rb
- test/test_attribute_methods.rb
- test/test_attributes.rb
- test/test_clone.rb
- test/test_composite_arrays.rb
- test/test_create.rb
- test/test_delete.rb
- test/test_dummy.rb
- test/test_exists.rb
- test/test_find.rb
- test/test_ids.rb
- test/test_miscellaneous.rb
- test/test_pagination.rb
- test/test_polymorphic.rb
- test/test_santiago.rb
- test/test_tutorial_examle.rb
- test/test_update.rb
- tmp/test.db
- website/index.html
- website/index.txt
- website/javascripts/rounded_corners_lite.inc.js
- website/stylesheets/screen.css
- website/template.js
- website/template.rhtml
- website/version-raw.js
- website/version-raw.txt
- website/version.js
- website/version.txt
has_rdoc: true
homepage: http://compositekeys.rubyforge.org
post_install_message:
rdoc_options:
- --main
- README.txt
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: "0"
version:
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: "0"
version:
requirements: []
rubyforge_project: compositekeys
rubygems_version: 1.3.1
signing_key:
specification_version: 2
summary: Composite key support for ActiveRecords
test_files:
- test/test_associations.rb
- test/test_attribute_methods.rb
- test/test_attributes.rb
- test/test_clone.rb
- test/test_composite_arrays.rb
- test/test_create.rb
- test/test_delete.rb
- test/test_dummy.rb
- test/test_exists.rb
- test/test_find.rb
- test/test_ids.rb
- test/test_miscellaneous.rb
- test/test_pagination.rb
- test/test_polymorphic.rb
- test/test_santiago.rb
- test/test_tutorial_examle.rb
- test/test_update.rb

View file

@ -1,156 +0,0 @@
== 2.2.1 2009-01-21
* fix ActiveRecord#exists? to work when passing conditions instead of ids
== 2.2.0 2008-10-29
* Rails 2.2.0 compatibility
== 1.1.0 2008-10-29
* fixes to get cpk working for Rails 2.1.2
== 1.0.10 2008-10-22
* add composite key where clause creator method [timurv]
== 1.0.9 2008-09-08
* fix postgres tests
* fix for delete_records when has_many association has composite keys [darxriggs]
* more consistent table/column name quoting [pbrant]
== 1.0.8 2008-08-27
* fix has_many :through for non composite models [thx rcarver]
== 1.0.7 2008-08-12
* fix for the last fix -- when has_many is composite and belongs_to is single
== 1.0.6 2008-08-06
* fix associations create
== 1.0.5 2008-07-25
* fix for calculations with a group by clause [thx Sirius Black]
== 1.0.4 2008-07-15
* support for oracle_enhanced adapter [thx Raimonds Simanovskis]
== 1.0.3 2008-07-13
* more fixes and tests for has many through [thx Menno van der Sman]
== 1.0.2 2008-06-07
* fix for has many through when through association has composite keys
== 1.0.1 2008-06-06
* Oracle fixes
== 1.0.0 2008-06-05
* Support for Rails 2.1
== 0.9.93 2008-06-01
* set fixed dependency on activerecord 2.0.2
== 0.9.92 2008-02-22
* Support for has_and_belongs_to_many
== 0.9.91 2008-01-27
* Incremented activerecord dependency to 2.0.2 [thx emmanuel.pirsch]
== 0.9.90 2008-01-27
* Trial release for rails/activerecord 2.0.2 supported
== 0.9.1 2007-10-28
* Migrations fix - allow :primary_key => [:name] to work [no unit test] [thx Shugo Maeda]
== 0.9.0 2007-09-28
* Added support for polymorphs [thx nerdrew]
* init.rb file so gem can be installed as a plugin for Rails [thx nerdrew]
* Added ibm_db support [thx K Venkatasubramaniyan]
* Support for cleaning dependents [thx K Venkatasubramaniyan]
* Rafactored db rake tasks into namespaces
* Added namespaced tests (e.g. mysql:test for test_mysql)
== 0.8.6 / 2007-6-12
* 1 emergency fix due to Rails Core change
* Rails v7004 removed #quote; fixed with connection.quote_column_name [thx nerdrew]
== 0.8.5 / 2007-6-5
* 1 change due to Rails Core change
* Can no longer use RAILS_CONNECTION_ADAPTERS from Rails core
* 7 dev improvement:
* Changed History.txt syntax to rdoc format
* Added deploy tasks
* Removed CHANGELOG + migrated into History.txt
* Changed PKG_NAME -> GEM_NAME in Rakefile
* Renamed README -> README.txt for :publish_docs task
* Added :check_version task
* VER => VERS in rakefile
* 1 website improvement:
* website/index.txt includes link to "8 steps to fix other ppls code"
== 0.8.4 / 2007-5-3
* 1 bugfix
* Corrected ids_list => ids in the exception message. That'll teach me for not adding unit tests before fixing bugs.
== 0.8.3 / 2007-5-3
* 1 bugfix
* Explicit reference to ::ActiveRecord::RecordNotFound
* 1 website addition:
* Added routing help [Pete Sumskas]
== 0.8.2 / 2007-4-11
* 1 major enhancement:
* Oracle unit tests!! [Darrin Holst]
* And they work too
== 0.8.1 / 2007-4-10
* 1 bug fix:
* Fixed the distinct(count) for oracle (removed 'as')
== 0.8.0 / 2007-4-6
* 1 major enhancement:
* Support for calcualtions on associations
* 2 new DB supported:
* Tests run on sqlite
* Tests run on postgresql
* History.txt to keep track of changes like these
* Using Hoe for Rakefile
* Website generator rake tasks
== 0.3.3
* id=
* create now work
== 0.1.4
* it was important that #{primary_key} for composites --> 'key1,key2' and not 'key1key2' so created PrimaryKeys class
== 0.0.1
* Initial version
* set_primary_keys(*keys) is the activation class method to transform an ActiveRecord into a composite primary key AR
* find(*ids) supports the passing of
* id sets: Foo.find(2,1),
* lists of id sets: Foo.find([2,1], [7,3], [8,12]),
* and even stringified versions of the above:
* Foo.find '2,1' or Foo.find '2,1;7,3'

View file

@ -1,122 +0,0 @@
History.txt
Manifest.txt
README.txt
README_DB2.txt
Rakefile
init.rb
install.rb
lib/adapter_helper/base.rb
lib/adapter_helper/mysql.rb
lib/adapter_helper/oracle.rb
lib/adapter_helper/postgresql.rb
lib/adapter_helper/sqlite3.rb
lib/composite_primary_keys.rb
lib/composite_primary_keys/association_preload.rb
lib/composite_primary_keys/associations.rb
lib/composite_primary_keys/attribute_methods.rb
lib/composite_primary_keys/base.rb
lib/composite_primary_keys/calculations.rb
lib/composite_primary_keys/composite_arrays.rb
lib/composite_primary_keys/connection_adapters/ibm_db_adapter.rb
lib/composite_primary_keys/connection_adapters/oracle_adapter.rb
lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb
lib/composite_primary_keys/fixtures.rb
lib/composite_primary_keys/migration.rb
lib/composite_primary_keys/reflection.rb
lib/composite_primary_keys/version.rb
loader.rb
local/database_connections.rb.sample
local/paths.rb.sample
local/tasks.rb.sample
scripts/console.rb
scripts/txt2html
scripts/txt2js
tasks/activerecord_selection.rake
tasks/databases.rake
tasks/databases/mysql.rake
tasks/databases/oracle.rake
tasks/databases/postgresql.rake
tasks/databases/sqlite3.rake
tasks/deployment.rake
tasks/local_setup.rake
tasks/website.rake
test/README_tests.txt
test/abstract_unit.rb
test/connections/native_ibm_db/connection.rb
test/connections/native_mysql/connection.rb
test/connections/native_oracle/connection.rb
test/connections/native_postgresql/connection.rb
test/connections/native_sqlite/connection.rb
test/fixtures/article.rb
test/fixtures/articles.yml
test/fixtures/comment.rb
test/fixtures/comments.yml
test/fixtures/db_definitions/db2-create-tables.sql
test/fixtures/db_definitions/db2-drop-tables.sql
test/fixtures/db_definitions/mysql.sql
test/fixtures/db_definitions/oracle.drop.sql
test/fixtures/db_definitions/oracle.sql
test/fixtures/db_definitions/postgresql.sql
test/fixtures/db_definitions/sqlite.sql
test/fixtures/department.rb
test/fixtures/departments.yml
test/fixtures/employee.rb
test/fixtures/employees.yml
test/fixtures/group.rb
test/fixtures/groups.yml
test/fixtures/hack.rb
test/fixtures/hacks.yml
test/fixtures/membership.rb
test/fixtures/membership_status.rb
test/fixtures/membership_statuses.yml
test/fixtures/memberships.yml
test/fixtures/product.rb
test/fixtures/product_tariff.rb
test/fixtures/product_tariffs.yml
test/fixtures/products.yml
test/fixtures/reading.rb
test/fixtures/readings.yml
test/fixtures/reference_code.rb
test/fixtures/reference_codes.yml
test/fixtures/reference_type.rb
test/fixtures/reference_types.yml
test/fixtures/street.rb
test/fixtures/streets.yml
test/fixtures/suburb.rb
test/fixtures/suburbs.yml
test/fixtures/tariff.rb
test/fixtures/tariffs.yml
test/fixtures/user.rb
test/fixtures/users.yml
test/hash_tricks.rb
test/plugins/pagination.rb
test/plugins/pagination_helper.rb
test/test_associations.rb
test/test_attribute_methods.rb
test/test_attributes.rb
test/test_clone.rb
test/test_composite_arrays.rb
test/test_create.rb
test/test_delete.rb
test/test_dummy.rb
test/test_exists.rb
test/test_find.rb
test/test_ids.rb
test/test_miscellaneous.rb
test/test_pagination.rb
test/test_polymorphic.rb
test/test_santiago.rb
test/test_tutorial_examle.rb
test/test_update.rb
tmp/test.db
website/index.html
website/index.txt
website/javascripts/rounded_corners_lite.inc.js
website/stylesheets/screen.css
website/template.js
website/template.rhtml
website/version-raw.js
website/version-raw.txt
website/version.js
website/version.txt

View file

@ -1,41 +0,0 @@
= Composite Primary Keys for ActiveRecords
== Summary
ActiveRecords/Rails famously doesn't support composite primary keys.
This RubyGem extends the activerecord gem to provide CPK support.
== Installation
gem install composite_primary_keys
== Usage
require 'composite_primary_keys'
class ProductVariation
set_primary_keys :product_id, :variation_seq
end
pv = ProductVariation.find(345, 12)
It even supports composite foreign keys for associations.
See http://compositekeys.rubyforge.org for more.
== Running Tests
See test/README.tests.txt
== Url
http://compositekeys.rubyforge.org
== Questions, Discussion and Contributions
http://groups.google.com/compositekeys
== Author
Written by Dr Nic Williams, drnicwilliams@gmail
Contributions by many!

View file

@ -1,33 +0,0 @@
Composite Primary key support for db2
== Driver Support ==
DB2 support requires the IBM_DB driver provided by http://rubyforge.org/projects/rubyibm/
project. Install using gem install ibm_db. Tested against version 0.60 of the driver.
This rubyforge project appears to be permenant location for the IBM adapter.
Older versions of the driver available from IBM Alphaworks will not work.
== Driver Bug and workaround provided as part of this plugin ==
Unlike the basic quote routine available for Rails AR, the DB2 adapter's quote
method doesn't return " column_name = 1 " when string values (integers in string type variable)
are passed for quoting numeric column. Rather it returns "column_name = '1'.
DB2 doesn't accept single quoting numeric columns in SQL. Currently, as part of
this plugin a fix is provided for the DB2 adapter since this plugin does
pass string values like this. Perhaps a patch should be sent to the DB2 adapter
project for a permanant fix.
== Database Setup ==
Database must be manually created using a separate command. Read the rake task
for creating tables and change the db name, user and passwords accordingly.
== Tested Database Server version ==
This is tested against DB2 v9.1 in Ubuntu Feisty Fawn (7.04)
== Tested Database Client version ==
This is tested against DB2 v9.1 in Ubuntu Feisty Fawn (7.04)

View file

@ -1,65 +0,0 @@
require 'rubygems'
require 'rake'
require 'rake/clean'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/packagetask'
require 'rake/gempackagetask'
require 'rake/contrib/rubyforgepublisher'
require 'fileutils'
require 'hoe'
include FileUtils
require File.join(File.dirname(__FILE__), 'lib', 'composite_primary_keys', 'version')
AUTHOR = "Dr Nic Williams"
EMAIL = "drnicwilliams@gmail.com"
DESCRIPTION = "Composite key support for ActiveRecords"
GEM_NAME = "composite_primary_keys" # what ppl will type to install your gem
if File.exists?("~/.rubyforge/user-config.yml")
# TODO this should prob go in a local/ file
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
RUBYFORGE_USERNAME = config["username"]
end
RUBYFORGE_PROJECT = "compositekeys"
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
REV = nil #File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
VERS = ENV['VERSION'] || (CompositePrimaryKeys::VERSION::STRING + (REV ? ".#{REV}" : ""))
CLEAN.include ['**/.*.sw?', '*.gem', '.config','debug.log','*.db','logfile','log/**/*','**/.DS_Store', '.project']
RDOC_OPTS = ['--quiet', '--title', "newgem documentation",
"--opname", "index.html",
"--line-numbers",
"--main", "README",
"--inline-source"]
class Hoe
def extra_deps
@extra_deps.reject { |x| Array(x).first == 'hoe' }
end
end
# Generate all the Rake tasks
# Run 'rake -T' to see list of generated tasks (from gem root directory)
hoe = Hoe.new(GEM_NAME, VERS) do |p|
p.author = AUTHOR
p.description = DESCRIPTION
p.email = EMAIL
p.summary = DESCRIPTION
p.url = HOMEPATH
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
p.test_globs = ["test/**/test*.rb"]
p.clean_globs |= CLEAN #An array of file patterns to delete on clean.
# == Optional
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
p.extra_deps = [['activerecord', '>= 2.2.0']] #An array of rubygem dependencies.
#p.spec_extras - A hash of extra values to set in the gemspec.
end
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n")
PATH = RUBYFORGE_PROJECT
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
PROJECT_ROOT = File.expand_path(".")
require 'loader'

View file

@ -1,2 +0,0 @@
# Include hook code here
require_dependency 'composite_primary_keys'

View file

@ -1,30 +0,0 @@
require 'rbconfig'
require 'find'
require 'ftools'
include Config
# this was adapted from rdoc's install.rb by ways of Log4r
$sitedir = CONFIG["sitelibdir"]
unless $sitedir
version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
$libdir = File.join(CONFIG["libdir"], "ruby", version)
$sitedir = $:.find {|x| x =~ /site_ruby/ }
if !$sitedir
$sitedir = File.join($libdir, "site_ruby")
elsif $sitedir !~ Regexp.quote(version)
$sitedir = File.join($sitedir, version)
end
end
# the acual gruntwork
Dir.chdir("lib")
Find.find("composite_primary_keys", "composite_primary_keys.rb") { |f|
if f[-3..-1] == ".rb"
File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
else
File::makedirs(File.join($sitedir, *f.split(/\//)))
end
}

View file

@ -1,63 +0,0 @@
module AdapterHelper
class Base
class << self
attr_accessor :adapter
def load_connection_from_env(adapter)
self.adapter = adapter
unless ENV['cpk_adapters']
puts error_msg_setup_helper
exit
end
ActiveRecord::Base.configurations = YAML.load(ENV['cpk_adapters'])
unless spec = ActiveRecord::Base.configurations[adapter]
puts error_msg_adapter_helper
exit
end
spec[:adapter] = adapter
spec
end
def error_msg_setup_helper
<<-EOS
Setup Helper:
CPK now has a place for your individual testing configuration.
That is, instead of hardcoding it in the Rakefile and test/connections files,
there is now a local/database_connections.rb file that is NOT in the
repository. Your personal DB information (username, password etc) can
be stored here without making it difficult to submit patches etc.
Installation:
i) cp locals/database_connections.rb.sample locals/database_connections.rb
ii) For #{adapter} connection details see "Adapter Setup Helper" below.
iii) Rerun this task
#{error_msg_adapter_helper}
Current ENV:
#{ENV.inspect}
EOS
end
def error_msg_adapter_helper
<<-EOS
Adapter Setup Helper:
To run #{adapter} tests, you need to setup your #{adapter} connections.
In your local/database_connections.rb file, within the ENV['cpk_adapter'] hash, add:
"#{adapter}" => { adapter settings }
That is, it will look like:
ENV['cpk_adapters'] = {
"#{adapter}" => {
:adapter => "#{adapter}",
:username => "root",
:password => "root",
# ...
}
}.to_yaml
EOS
end
end
end
end

View file

@ -1,13 +0,0 @@
require File.join(File.dirname(__FILE__), 'base')
module AdapterHelper
class MySQL < Base
class << self
def load_connection_from_env
spec = super('mysql')
spec[:database] ||= 'composite_primary_keys_unittest'
spec
end
end
end
end

View file

@ -1,12 +0,0 @@
require File.join(File.dirname(__FILE__), 'base')
module AdapterHelper
class Oracle < Base
class << self
def load_connection_from_env
spec = super('oracle')
spec
end
end
end
end

View file

@ -1,13 +0,0 @@
require File.join(File.dirname(__FILE__), 'base')
module AdapterHelper
class Postgresql < Base
class << self
def load_connection_from_env
spec = super('postgresql')
spec[:database] ||= 'composite_primary_keys_unittest'
spec
end
end
end
end

View file

@ -1,13 +0,0 @@
require File.join(File.dirname(__FILE__), 'base')
module AdapterHelper
class Sqlite3 < Base
class << self
def load_connection_from_env
spec = super('sqlite3')
spec[:dbfile] ||= "tmp/test.db"
spec
end
end
end
end

View file

@ -1,55 +0,0 @@
#--
# Copyright (c) 2006 Nic Williams
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
$:.unshift(File.dirname(__FILE__)) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
unless defined?(ActiveRecord)
begin
require 'active_record'
rescue LoadError
require 'rubygems'
require_gem 'activerecord'
end
end
require 'composite_primary_keys/fixtures'
require 'composite_primary_keys/composite_arrays'
require 'composite_primary_keys/associations'
require 'composite_primary_keys/association_preload'
require 'composite_primary_keys/reflection'
require 'composite_primary_keys/base'
require 'composite_primary_keys/calculations'
require 'composite_primary_keys/migration'
require 'composite_primary_keys/attribute_methods'
ActiveRecord::Base.class_eval do
include CompositePrimaryKeys::ActiveRecord::Base
end
Dir[File.dirname(__FILE__) + '/composite_primary_keys/connection_adapters/*.rb'].each do |adapter|
begin
require adapter.gsub('.rb','')
rescue MissingSourceFile
end
end

View file

@ -1,253 +0,0 @@
module CompositePrimaryKeys
module ActiveRecord
module AssociationPreload
def self.append_features(base)
super
base.send(:extend, ClassMethods)
end
# Composite key versions of Association functions
module ClassMethods
def preload_has_and_belongs_to_many_association(records, reflection, preload_options={})
table_name = reflection.klass.quoted_table_name
id_to_record_map, ids = construct_id_map_for_composite(records)
records.each {|record| record.send(reflection.name).loaded}
options = reflection.options
if composite?
primary_key = reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP)
where = (primary_key * ids.size).in_groups_of(primary_key.size).map do |keys|
"(" + keys.map{|key| "t0.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
end.join(" OR ")
conditions = [where, ids].flatten
joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{full_composite_join_clause(reflection, reflection.klass.table_name, reflection.klass.primary_key, 't0', reflection.association_foreign_key)}"
parent_primary_keys = reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP).map{|k| "t0.#{connection.quote_column_name(k)}"}
parent_record_id = connection.concat(*parent_primary_keys.zip(["','"] * (parent_primary_keys.size - 1)).flatten.compact)
else
conditions = ["t0.#{connection.quote_column_name(reflection.primary_key_name)} IN (?)", ids]
joins = "INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{connection.quote_column_name(reflection.klass.primary_key)} = t0.#{connection.quote_column_name(reflection.association_foreign_key)})"
parent_record_id = reflection.primary_key_name
end
conditions.first << append_conditions(reflection, preload_options)
associated_records = reflection.klass.find(:all,
:conditions => conditions,
:include => options[:include],
:joins => joins,
:select => "#{options[:select] || table_name+'.*'}, #{parent_record_id} as parent_record_id_",
:order => options[:order])
set_association_collection_records(id_to_record_map, reflection.name, associated_records, 'parent_record_id_')
end
def preload_has_many_association(records, reflection, preload_options={})
id_to_record_map, ids = construct_id_map_for_composite(records)
records.each {|record| record.send(reflection.name).loaded}
options = reflection.options
if options[:through]
through_records = preload_through_records(records, reflection, options[:through])
through_reflection = reflections[options[:through]]
through_primary_key = through_reflection.primary_key_name
unless through_records.empty?
source = reflection.source_reflection.name
#add conditions from reflection!
through_records.first.class.preload_associations(through_records, source, reflection.options)
through_records.each do |through_record|
key = through_primary_key.to_s.split(CompositePrimaryKeys::ID_SEP).map{|k| through_record.send(k)}.join(CompositePrimaryKeys::ID_SEP)
add_preloaded_records_to_collection(id_to_record_map[key], reflection.name, through_record.send(source))
end
end
else
associated_records = find_associated_records(ids, reflection, preload_options)
set_association_collection_records(id_to_record_map, reflection.name, associated_records, reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP))
end
end
def preload_through_records(records, reflection, through_association)
through_reflection = reflections[through_association]
through_primary_key = through_reflection.primary_key_name
if reflection.options[:source_type]
interface = reflection.source_reflection.options[:foreign_type]
preload_options = {:conditions => ["#{connection.quote_column_name interface} = ?", reflection.options[:source_type]]}
records.compact!
records.first.class.preload_associations(records, through_association, preload_options)
# Dont cache the association - we would only be caching a subset
through_records = []
records.each do |record|
proxy = record.send(through_association)
if proxy.respond_to?(:target)
through_records << proxy.target
proxy.reset
else # this is a has_one :through reflection
through_records << proxy if proxy
end
end
through_records.flatten!
else
records.first.class.preload_associations(records, through_association)
through_records = records.map {|record| record.send(through_association)}.flatten
end
through_records.compact!
through_records
end
def preload_belongs_to_association(records, reflection, preload_options={})
options = reflection.options
primary_key_name = reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP)
if options[:polymorphic]
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
else
# I need to keep the original ids for each record (as opposed to the stringified) so
# that they get properly converted for each db so the id_map ends up looking like:
#
# { '1,2' => {:id => [1,2], :records => [...records...]}}
id_map = {}
records.each do |record|
key = primary_key_name.map{|k| record.attributes[k]}
key_as_string = key.join(CompositePrimaryKeys::ID_SEP)
if key_as_string
mapped_records = (id_map[key_as_string] ||= {:id => key, :records => []})
mapped_records[:records] << record
end
end
klasses_and_ids = [[reflection.klass.name, id_map]]
end
klasses_and_ids.each do |klass_and_id|
klass_name, id_map = *klass_and_id
klass = klass_name.constantize
table_name = klass.quoted_table_name
connection = reflection.active_record.connection
if composite?
primary_key = klass.primary_key.to_s.split(CompositePrimaryKeys::ID_SEP)
ids = id_map.keys.uniq.map {|id| id_map[id][:id]}
where = (primary_key * ids.size).in_groups_of(primary_key.size).map do |keys|
"(" + keys.map{|key| "#{table_name}.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
end.join(" OR ")
conditions = [where, ids].flatten
else
conditions = ["#{table_name}.#{connection.quote_column_name(primary_key)} IN (?)", id_map.keys.uniq]
end
conditions.first << append_conditions(reflection, preload_options)
associated_records = klass.find(:all,
:conditions => conditions,
:include => options[:include],
:select => options[:select],
:joins => options[:joins],
:order => options[:order])
set_association_single_records(id_map, reflection.name, associated_records, primary_key)
end
end
def set_association_collection_records(id_to_record_map, reflection_name, associated_records, key)
associated_records.each do |associated_record|
associated_record_key = associated_record[key]
associated_record_key = associated_record_key.is_a?(Array) ? associated_record_key.join(CompositePrimaryKeys::ID_SEP) : associated_record_key.to_s
mapped_records = id_to_record_map[associated_record_key]
add_preloaded_records_to_collection(mapped_records, reflection_name, associated_record)
end
end
def set_association_single_records(id_to_record_map, reflection_name, associated_records, key)
seen_keys = {}
associated_records.each do |associated_record|
associated_record_key = associated_record[key]
associated_record_key = associated_record_key.is_a?(Array) ? associated_record_key.join(CompositePrimaryKeys::ID_SEP) : associated_record_key.to_s
#this is a has_one or belongs_to: there should only be one record.
#Unfortunately we can't (in portable way) ask the database for 'all records where foo_id in (x,y,z), but please
# only one row per distinct foo_id' so this where we enforce that
next if seen_keys[associated_record_key]
seen_keys[associated_record_key] = true
mapped_records = id_to_record_map[associated_record_key][:records]
mapped_records.each do |mapped_record|
mapped_record.send("set_#{reflection_name}_target", associated_record)
end
end
end
def find_associated_records(ids, reflection, preload_options)
options = reflection.options
table_name = reflection.klass.quoted_table_name
if interface = reflection.options[:as]
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
else
connection = reflection.active_record.connection
foreign_key = reflection.primary_key_name
conditions = ["#{table_name}.#{connection.quote_column_name(foreign_key)} IN (?)", ids]
if composite?
foreign_keys = foreign_key.to_s.split(CompositePrimaryKeys::ID_SEP)
where = (foreign_keys * ids.size).in_groups_of(foreign_keys.size).map do |keys|
"(" + keys.map{|key| "#{table_name}.#{connection.quote_column_name(key)} = ?"}.join(" AND ") + ")"
end.join(" OR ")
conditions = [where, ids].flatten
end
end
conditions.first << append_conditions(reflection, preload_options)
reflection.klass.find(:all,
:select => (preload_options[:select] || options[:select] || "#{table_name}.*"),
:include => preload_options[:include] || options[:include],
:conditions => conditions,
:joins => options[:joins],
:group => preload_options[:group] || options[:group],
:order => preload_options[:order] || options[:order])
end
# Given a collection of ActiveRecord objects, constructs a Hash which maps
# the objects' IDs to the relevant objects. Returns a 2-tuple
# <tt>(id_to_record_map, ids)</tt> where +id_to_record_map+ is the Hash,
# and +ids+ is an Array of record IDs.
def construct_id_map_for_composite(records)
id_to_record_map = {}
ids = []
records.each do |record|
primary_key ||= record.class.primary_key
ids << record.id
mapped_records = (id_to_record_map[record.id.to_s] ||= [])
mapped_records << record
end
ids.uniq!
return id_to_record_map, ids
end
def full_composite_join_clause(reflection, table1, full_keys1, table2, full_keys2)
connection = reflection.active_record.connection
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
quoted1 = connection.quote_table_name(table1)
quoted2 = connection.quote_table_name(table2)
"#{quoted1}.#{connection.quote_column_name(key_pair.first)}=#{quoted2}.#{connection.quote_column_name(key_pair.last)}"
end.join(" AND ")
"(#{where_clause})"
end
end
end
end
end

View file

@ -1,428 +0,0 @@
module CompositePrimaryKeys
module ActiveRecord
module Associations
def self.append_features(base)
super
base.send(:extend, ClassMethods)
end
# Composite key versions of Association functions
module ClassMethods
def construct_counter_sql_with_included_associations(options, join_dependency)
scope = scope(:find)
sql = "SELECT COUNT(DISTINCT #{quoted_table_columns(primary_key)})"
# A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
if !self.connection.supports_count_distinct?
sql = "SELECT COUNT(*) FROM (SELECT DISTINCT #{quoted_table_columns(primary_key)}"
end
sql << " FROM #{quoted_table_name} "
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
add_joins!(sql, options[:joins], scope)
add_conditions!(sql, options[:conditions], scope)
add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
if !self.connection.supports_count_distinct?
sql << ")"
end
return sanitize_sql(sql)
end
def construct_finder_sql_with_included_associations(options, join_dependency)
scope = scope(:find)
sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
add_joins!(sql, options[:joins], scope)
add_conditions!(sql, options[:conditions], scope)
add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && options[:limit]
sql << "ORDER BY #{options[:order]} " if options[:order]
add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
return sanitize_sql(sql)
end
def table_columns(columns)
columns.collect {|column| "#{self.quoted_table_name}.#{connection.quote_column_name(column)}"}
end
def quoted_table_columns(columns)
table_columns(columns).join(ID_SEP)
end
end
end
end
end
module ActiveRecord::Associations::ClassMethods
class JoinDependency
def construct_association(record, join, row)
case join.reflection.macro
when :has_many, :has_and_belongs_to_many
collection = record.send(join.reflection.name)
collection.loaded
join_aliased_primary_keys = join.active_record.composite? ?
join.aliased_primary_key : [join.aliased_primary_key]
return nil if
record.id.to_s != join.parent.record_id(row).to_s or not
join_aliased_primary_keys.select {|key| row[key].nil?}.blank?
association = join.instantiate(row)
collection.target.push(association) unless collection.target.include?(association)
when :has_one, :belongs_to
return if record.id.to_s != join.parent.record_id(row).to_s or
[*join.aliased_primary_key].any? { |key| row[key].nil? }
association = join.instantiate(row)
record.send("set_#{join.reflection.name}_target", association)
else
raise ConfigurationError, "unknown macro: #{join.reflection.macro}"
end
return association
end
class JoinBase
def aliased_primary_key
active_record.composite? ?
primary_key.inject([]) {|aliased_keys, key| aliased_keys << "#{ aliased_prefix }_r#{aliased_keys.length}"} :
"#{ aliased_prefix }_r0"
end
def record_id(row)
active_record.composite? ?
aliased_primary_key.map {|key| row[key]}.to_composite_ids :
row[aliased_primary_key]
end
def column_names_with_alias
unless @column_names_with_alias
@column_names_with_alias = []
keys = active_record.composite? ? primary_key.map(&:to_s) : [primary_key]
(keys + (column_names - keys)).each_with_index do |column_name, i|
@column_names_with_alias << [column_name, "#{ aliased_prefix }_r#{ i }"]
end
end
return @column_names_with_alias
end
end
class JoinAssociation < JoinBase
alias single_association_join association_join
def association_join
reflection.active_record.composite? ? composite_association_join : single_association_join
end
def composite_association_join
join = case reflection.macro
when :has_and_belongs_to_many
" LEFT OUTER JOIN %s ON %s " % [
table_alias_for(options[:join_table], aliased_join_table_name),
composite_join_clause(
full_keys(aliased_join_table_name, options[:foreign_key] || reflection.active_record.to_s.classify.foreign_key),
full_keys(reflection.active_record.table_name, reflection.active_record.primary_key)
)
] +
" LEFT OUTER JOIN %s ON %s " % [
table_name_and_alias,
composite_join_clause(
full_keys(aliased_table_name, klass.primary_key),
full_keys(aliased_join_table_name, options[:association_foreign_key] || klass.table_name.classify.foreign_key)
)
]
when :has_many, :has_one
case
when reflection.macro == :has_many && reflection.options[:through]
through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : ''
if through_reflection.options[:as] # has_many :through against a polymorphic join
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
else
if source_reflection.macro == :has_many && source_reflection.options[:as]
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
else
case source_reflection.macro
when :belongs_to
first_key = primary_key
second_key = options[:foreign_key] || klass.to_s.classify.foreign_key
when :has_many
first_key = through_reflection.klass.to_s.classify.foreign_key
second_key = options[:foreign_key] || primary_key
end
" LEFT OUTER JOIN %s ON %s " % [
table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
composite_join_clause(
full_keys(aliased_join_table_name, through_reflection.primary_key_name),
full_keys(parent.aliased_table_name, parent.primary_key)
)
] +
" LEFT OUTER JOIN %s ON %s " % [
table_name_and_alias,
composite_join_clause(
full_keys(aliased_table_name, first_key),
full_keys(aliased_join_table_name, second_key)
)
]
end
end
when reflection.macro == :has_many && reflection.options[:as]
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
when reflection.macro == :has_one && reflection.options[:as]
raise AssociationNotSupported, "Polymorphic joins not supported for composite keys"
else
foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key
" LEFT OUTER JOIN %s ON %s " % [
table_name_and_alias,
composite_join_clause(
full_keys(aliased_table_name, foreign_key),
full_keys(parent.aliased_table_name, parent.primary_key)),
]
end
when :belongs_to
" LEFT OUTER JOIN %s ON %s " % [
table_name_and_alias,
composite_join_clause(
full_keys(aliased_table_name, reflection.klass.primary_key),
full_keys(parent.aliased_table_name, options[:foreign_key] || klass.to_s.foreign_key)),
]
else
""
end || ''
join << %(AND %s.%s = %s ) % [
aliased_table_name,
reflection.active_record.connection.quote_column_name(reflection.active_record.inheritance_column),
klass.connection.quote(klass.name)] unless klass.descends_from_active_record?
join << "AND #{interpolate_sql(sanitize_sql(reflection.options[:conditions]))} " if reflection.options[:conditions]
join
end
def full_keys(table_name, keys)
connection = reflection.active_record.connection
quoted_table_name = connection.quote_table_name(table_name)
if keys.is_a?(Array)
keys.collect {|key| "#{quoted_table_name}.#{connection.quote_column_name(key)}"}.join(CompositePrimaryKeys::ID_SEP)
else
"#{quoted_table_name}.#{connection.quote_column_name(keys)}"
end
end
def composite_join_clause(full_keys1, full_keys2)
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
where_clause = [full_keys1, full_keys2].transpose.map do |key1, key2|
"#{key1}=#{key2}"
end.join(" AND ")
"(#{where_clause})"
end
end
end
end
module ActiveRecord::Associations
class AssociationProxy #:nodoc:
def composite_where_clause(full_keys, ids)
full_keys = full_keys.split(CompositePrimaryKeys::ID_SEP) if full_keys.is_a?(String)
if ids.is_a?(String)
ids = [[ids]]
elsif not ids.first.is_a?(Array) # if single comp key passed, turn into an array of 1
ids = [ids.to_composite_ids]
end
where_clause = ids.map do |id_set|
transposed = id_set.size == 1 ? [[full_keys, id_set.first]] : [full_keys, id_set].transpose
transposed.map do |full_key, id|
"#{full_key.to_s}=#{@reflection.klass.sanitize(id)}"
end.join(" AND ")
end.join(") OR (")
"(#{where_clause})"
end
def composite_join_clause(full_keys1, full_keys2)
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
where_clause = [full_keys1, full_keys2].transpose.map do |key1, key2|
"#{key1}=#{key2}"
end.join(" AND ")
"(#{where_clause})"
end
def full_composite_join_clause(table1, full_keys1, table2, full_keys2)
connection = @reflection.active_record.connection
full_keys1 = full_keys1.split(CompositePrimaryKeys::ID_SEP) if full_keys1.is_a?(String)
full_keys2 = full_keys2.split(CompositePrimaryKeys::ID_SEP) if full_keys2.is_a?(String)
quoted1 = connection.quote_table_name(table1)
quoted2 = connection.quote_table_name(table2)
where_clause = [full_keys1, full_keys2].transpose.map do |key_pair|
"#{quoted1}.#{connection.quote_column_name(key_pair.first)}=#{quoted2}.#{connection.quote_column_name(key_pair.last)}"
end.join(" AND ")
"(#{where_clause})"
end
def full_keys(table_name, keys)
connection = @reflection.active_record.connection
quoted_table_name = connection.quote_table_name(table_name)
keys = keys.split(CompositePrimaryKeys::ID_SEP) if keys.is_a?(String)
if keys.is_a?(Array)
keys.collect {|key| "#{quoted_table_name}.#{connection.quote_column_name(key)}"}.join(CompositePrimaryKeys::ID_SEP)
else
"#{quoted_table_name}.#{connection.quote_column_name(keys)}"
end
end
def full_columns_equals(table_name, keys, quoted_ids)
connection = @reflection.active_record.connection
quoted_table_name = connection.quote_table_name(table_name)
if keys.is_a?(Symbol) or (keys.is_a?(String) and keys == keys.to_s.split(CompositePrimaryKeys::ID_SEP))
return "#{quoted_table_name}.#{connection.quote_column_name(keys)} = #{quoted_ids}"
end
keys = keys.split(CompositePrimaryKeys::ID_SEP) if keys.is_a?(String)
quoted_ids = quoted_ids.split(CompositePrimaryKeys::ID_SEP) if quoted_ids.is_a?(String)
keys_ids = [keys, quoted_ids].transpose
keys_ids.collect {|key, id| "(#{quoted_table_name}.#{connection.quote_column_name(key)} = #{id})"}.join(' AND ')
end
def set_belongs_to_association_for(record)
if @reflection.options[:as]
record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
else
key_values = @reflection.primary_key_name.to_s.split(CompositePrimaryKeys::ID_SEP).zip([@owner.id].flatten)
key_values.each{|key, value| record[key] = value} unless @owner.new_record?
end
end
end
class HasAndBelongsToManyAssociation < AssociationCollection #:nodoc:
def construct_sql
@reflection.options[:finder_sql] &&= interpolate_sql(@reflection.options[:finder_sql])
if @reflection.options[:finder_sql]
@finder_sql = @reflection.options[:finder_sql]
else
@finder_sql = full_columns_equals(@reflection.options[:join_table], @reflection.primary_key_name, @owner.quoted_id)
@finder_sql << " AND (#{conditions})" if conditions
end
@join_sql = "INNER JOIN #{@reflection.active_record.connection.quote_table_name(@reflection.options[:join_table])} ON " +
full_composite_join_clause(@reflection.klass.table_name, @reflection.klass.primary_key, @reflection.options[:join_table], @reflection.association_foreign_key)
end
end
class HasManyAssociation < AssociationCollection #:nodoc:
def construct_sql
case
when @reflection.options[:finder_sql]
@finder_sql = interpolate_sql(@reflection.options[:finder_sql])
when @reflection.options[:as]
@finder_sql =
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
@finder_sql << " AND (#{conditions})" if conditions
else
@finder_sql = full_columns_equals(@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id)
@finder_sql << " AND (#{conditions})" if conditions
end
if @reflection.options[:counter_sql]
@counter_sql = interpolate_sql(@reflection.options[:counter_sql])
elsif @reflection.options[:finder_sql]
# replace the SELECT clause with COUNT(*), preserving any hints within /* ... */
@reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" }
@counter_sql = interpolate_sql(@reflection.options[:counter_sql])
else
@counter_sql = @finder_sql
end
end
def delete_records(records)
if @reflection.options[:dependent]
records.each { |r| r.destroy }
else
connection = @reflection.active_record.connection
field_names = @reflection.primary_key_name.split(',')
field_names.collect! {|n| connection.quote_column_name(n) + " = NULL"}
records.each do |r|
where_clause = nil
if r.quoted_id.to_s.include?(CompositePrimaryKeys::ID_SEP)
where_clause_terms = [@reflection.klass.primary_key, r.quoted_id].transpose.map do |pair|
"(#{connection.quote_column_name(pair[0])} = #{pair[1]})"
end
where_clause = where_clause_terms.join(" AND ")
else
where_clause = connection.quote_column_name(@reflection.klass.primary_key) + ' = ' + r.quoted_id
end
@reflection.klass.update_all( field_names.join(',') , where_clause)
end
end
end
end
class HasOneAssociation < BelongsToAssociation #:nodoc:
def construct_sql
case
when @reflection.options[:as]
@finder_sql =
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_id = #{@owner.quoted_id} AND " +
"#{@reflection.klass.quoted_table_name}.#{@reflection.options[:as]}_type = #{@owner.class.quote_value(@owner.class.base_class.name.to_s)}"
else
@finder_sql = full_columns_equals(@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id)
end
@finder_sql << " AND (#{conditions})" if conditions
end
end
class HasManyThroughAssociation < HasManyAssociation #:nodoc:
def construct_conditions_with_composite_keys
if @reflection.through_reflection.options[:as]
construct_conditions_without_composite_keys
else
conditions = full_columns_equals(@reflection.through_reflection.table_name, @reflection.through_reflection.primary_key_name, @owner.quoted_id)
conditions << " AND (#{sql_conditions})" if sql_conditions
conditions
end
end
alias_method_chain :construct_conditions, :composite_keys
def construct_joins_with_composite_keys(custom_joins = nil)
if @reflection.through_reflection.options[:as] || @reflection.source_reflection.options[:as]
construct_joins_without_composite_keys(custom_joins)
else
if @reflection.source_reflection.macro == :belongs_to
reflection_primary_key = @reflection.klass.primary_key
source_primary_key = @reflection.source_reflection.primary_key_name
else
reflection_primary_key = @reflection.source_reflection.primary_key_name
source_primary_key = @reflection.klass.primary_key
end
"INNER JOIN %s ON %s #{@reflection.options[:joins]} #{custom_joins}" % [
@reflection.through_reflection.quoted_table_name,
composite_join_clause(full_keys(@reflection.table_name, reflection_primary_key), full_keys(@reflection.through_reflection.table_name, source_primary_key))
]
end
end
alias_method_chain :construct_joins, :composite_keys
end
end

View file

@ -1,84 +0,0 @@
module CompositePrimaryKeys
module ActiveRecord
module AttributeMethods #:nodoc:
def self.append_features(base)
super
base.send(:extend, ClassMethods)
end
module ClassMethods
# Define an attribute reader method. Cope with nil column.
def define_read_method(symbol, attr_name, column)
cast_code = column.type_cast_code('v') if column
cast_code = "::#{cast_code}" if cast_code && cast_code.match('ActiveRecord::.*')
access_code = cast_code ? "(v=@attributes['#{attr_name}']) && #{cast_code}" : "@attributes['#{attr_name}']"
unless self.primary_keys.include?(attr_name.to_sym)
access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
end
if cache_attribute?(attr_name)
access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
end
evaluate_attribute_method attr_name, "def #{symbol}; #{access_code}; end"
end
# Evaluate the definition for an attribute related method
def evaluate_attribute_method(attr_name, method_definition, method_name=attr_name)
unless primary_keys.include?(method_name.to_sym)
generated_methods << method_name
end
begin
class_eval(method_definition, __FILE__, __LINE__)
rescue SyntaxError => err
generated_methods.delete(attr_name)
if logger
logger.warn "Exception occurred during reader method compilation."
logger.warn "Maybe #{attr_name} is not a valid Ruby identifier?"
logger.warn "#{err.message}"
end
end
end
end
# Allows access to the object attributes, which are held in the @attributes hash, as though they
# were first-class methods. So a Person class with a name attribute can use Person#name and
# Person#name= and never directly use the attributes hash -- except for multiple assigns with
# ActiveRecord#attributes=. A Milestone class can also ask Milestone#completed? to test that
# the completed attribute is not nil or 0.
#
# It's also possible to instantiate related objects, so a Client class belonging to the clients
# table with a master_id foreign key can instantiate master through Client#master.
def method_missing(method_id, *args, &block)
method_name = method_id.to_s
# If we haven't generated any methods yet, generate them, then
# see if we've created the method we're looking for.
if !self.class.generated_methods?
self.class.define_attribute_methods
if self.class.generated_methods.include?(method_name)
return self.send(method_id, *args, &block)
end
end
if self.class.primary_keys.include?(method_name.to_sym)
ids[self.class.primary_keys.index(method_name.to_sym)]
elsif md = self.class.match_attribute_method?(method_name)
attribute_name, method_type = md.pre_match, md.to_s
if @attributes.include?(attribute_name)
__send__("attribute#{method_type}", attribute_name, *args, &block)
else
super
end
elsif @attributes.include?(method_name)
read_attribute(method_name)
else
super
end
end
end
end
end

View file

@ -1,341 +0,0 @@
module CompositePrimaryKeys
module ActiveRecord #:nodoc:
class CompositeKeyError < StandardError #:nodoc:
end
module Base #:nodoc:
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
def self.append_features(base)
super
base.send(:include, InstanceMethods)
base.extend(ClassMethods)
end
module ClassMethods
def set_primary_keys(*keys)
keys = keys.first if keys.first.is_a?(Array)
keys = keys.map { |k| k.to_sym }
cattr_accessor :primary_keys
self.primary_keys = keys.to_composite_keys
class_eval <<-EOV
extend CompositeClassMethods
include CompositeInstanceMethods
include CompositePrimaryKeys::ActiveRecord::Associations
include CompositePrimaryKeys::ActiveRecord::AssociationPreload
include CompositePrimaryKeys::ActiveRecord::Calculations
include CompositePrimaryKeys::ActiveRecord::AttributeMethods
EOV
end
def composite?
false
end
end
module InstanceMethods
def composite?; self.class.composite?; end
end
module CompositeInstanceMethods
# A model instance's primary keys is always available as model.ids
# whether you name it the default 'id' or set it to something else.
def id
attr_names = self.class.primary_keys
CompositeIds.new(attr_names.map { |attr_name| read_attribute(attr_name) })
end
alias_method :ids, :id
def to_param
id.to_s
end
def id_before_type_cast #:nodoc:
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::NOT_IMPLEMENTED_YET
end
def quoted_id #:nodoc:
[self.class.primary_keys, ids].
transpose.
map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}.
to_composite_ids
end
# Sets the primary ID.
def id=(ids)
ids = ids.split(ID_SEP) if ids.is_a?(String)
ids.flatten!
unless ids.is_a?(Array) and ids.length == self.class.primary_keys.length
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
end
[primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
id
end
# Returns a clone of the record that hasn't been assigned an id yet and
# is treated as a new record. Note that this is a "shallow" clone:
# it copies the object's attributes only, not its associations.
# The extent of a "deep" clone is application-specific and is therefore
# left to the application to implement according to its need.
def clone
attrs = self.attributes_before_type_cast
self.class.primary_keys.each {|key| attrs.delete(key.to_s)}
self.class.new do |record|
record.send :instance_variable_set, '@attributes', attrs
end
end
private
# The xx_without_callbacks methods are overwritten as that is the end of the alias chain
# Creates a new record with values matching those of the instance attributes.
def create_without_callbacks
unless self.id
raise CompositeKeyError, "Composite keys do not generated ids from sequences, you must provide id values"
end
attributes_minus_pks = attributes_with_quotes(false)
quoted_pk_columns = self.class.primary_key.map { |col| connection.quote_column_name(col) }
cols = quoted_column_names(attributes_minus_pks) << quoted_pk_columns
vals = attributes_minus_pks.values << quoted_id
connection.insert(
"INSERT INTO #{self.class.quoted_table_name} " +
"(#{cols.join(', ')}) " +
"VALUES (#{vals.join(', ')})",
"#{self.class.name} Create",
self.class.primary_key,
self.id
)
@new_record = false
return true
end
# Updates the associated record with values matching those of the instance attributes.
def update_without_callbacks
where_clause_terms = [self.class.primary_key, quoted_id].transpose.map do |pair|
"(#{connection.quote_column_name(pair[0])} = #{pair[1]})"
end
where_clause = where_clause_terms.join(" AND ")
connection.update(
"UPDATE #{self.class.quoted_table_name} " +
"SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " +
"WHERE #{where_clause}",
"#{self.class.name} Update"
)
return true
end
# Deletes the record in the database and freezes this instance to reflect that no changes should
# be made (since they can't be persisted).
def destroy_without_callbacks
where_clause_terms = [self.class.primary_key, quoted_id].transpose.map do |pair|
"(#{connection.quote_column_name(pair[0])} = #{pair[1]})"
end
where_clause = where_clause_terms.join(" AND ")
unless new_record?
connection.delete(
"DELETE FROM #{self.class.quoted_table_name} " +
"WHERE #{where_clause}",
"#{self.class.name} Destroy"
)
end
freeze
end
end
module CompositeClassMethods
def primary_key; primary_keys; end
def primary_key=(keys); primary_keys = keys; end
def composite?
true
end
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
many_ids.map {|ids| "#{left_bracket}#{ids}#{right_bracket}"}.join(list_sep)
end
# Creates WHERE condition from list of composited ids
# User.update_all({:role => 'admin'}, :conditions => composite_where_clause([[1, 2], [2, 2]])) #=> UPDATE admins SET admin.role='admin' WHERE (admin.type=1 AND admin.type2=2) OR (admin.type=2 AND admin.type2=2)
# User.find(:all, :conditions => composite_where_clause([[1, 2], [2, 2]])) #=> SELECT * FROM admins WHERE (admin.type=1 AND admin.type2=2) OR (admin.type=2 AND admin.type2=2)
def composite_where_clause(ids)
if ids.is_a?(String)
ids = [[ids]]
elsif not ids.first.is_a?(Array) # if single comp key passed, turn into an array of 1
ids = [ids.to_composite_ids]
end
ids.map do |id_set|
[primary_keys, id_set].transpose.map do |key, id|
"#{table_name}.#{key.to_s}=#{sanitize(id)}"
end.join(" AND ")
end.join(") OR (")
end
# Returns true if the given +ids+ represents the primary keys of a record in the database, false otherwise.
# Example:
# Person.exists?(5,7)
def exists?(ids)
if ids.is_a?(Array) && ids.first.is_a?(String)
count(:conditions => ids) > 0
else
obj = find(ids) rescue false
!obj.nil? and obj.is_a?(self)
end
end
# Deletes the record with the given +ids+ without instantiating an object first, e.g. delete(1,2)
# If an array of ids is provided (e.g. delete([1,2], [3,4]), all of them
# are deleted.
def delete(*ids)
unless ids.is_a?(Array); raise "*ids must be an Array"; end
ids = [ids.to_composite_ids] if not ids.first.is_a?(Array)
where_clause = ids.map do |id_set|
[primary_keys, id_set].transpose.map do |key, id|
"#{quoted_table_name}.#{connection.quote_column_name(key.to_s)}=#{sanitize(id)}"
end.join(" AND ")
end.join(") OR (")
delete_all([ "(#{where_clause})" ])
end
# Destroys the record with the given +ids+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
# If an array of ids is provided, all of them are destroyed.
def destroy(*ids)
unless ids.is_a?(Array); raise "*ids must be an Array"; end
if ids.first.is_a?(Array)
ids = ids.map{|compids| compids.to_composite_ids}
else
ids = ids.to_composite_ids
end
ids.first.is_a?(CompositeIds) ? ids.each { |id_set| find(id_set).destroy } : find(ids).destroy
end
# Returns an array of column objects for the table associated with this class.
# Each column that matches to one of the primary keys has its
# primary attribute set to true
def columns
unless @columns
@columns = connection.columns(table_name, "#{name} Columns")
@columns.each {|column| column.primary = primary_keys.include?(column.name.to_sym)}
end
@columns
end
## DEACTIVATED METHODS ##
public
# Lazy-set the sequence name to the connection's default. This method
# is only ever called once since set_sequence_name overrides it.
def sequence_name #:nodoc:
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
end
def reset_sequence_name #:nodoc:
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
end
def set_primary_key(value = nil, &block)
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
end
private
def find_one(id, options)
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
end
def find_some(ids, options)
raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
end
def find_from_ids(ids, options)
ids = ids.first if ids.last == nil
conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
# if ids is just a flat list, then its size must = primary_key.length (one id per primary key, in order)
# if ids is list of lists, then each inner list must follow rule above
if ids.first.is_a? String
# find '2,1' -> ids = ['2,1']
# find '2,1;7,3' -> ids = ['2,1;7,3']
ids = ids.first.split(ID_SET_SEP).map {|id_set| id_set.split(ID_SEP).to_composite_ids}
# find '2,1;7,3' -> ids = [['2','1'],['7','3']], inner [] are CompositeIds
end
ids = [ids.to_composite_ids] if not ids.first.kind_of?(Array)
ids.each do |id_set|
unless id_set.is_a?(Array)
raise "Ids must be in an Array, instead received: #{id_set.inspect}"
end
unless id_set.length == primary_keys.length
raise "#{id_set.inspect}: Incorrect number of primary keys for #{class_name}: #{primary_keys.inspect}"
end
end
# Let keys = [:a, :b]
# If ids = [[10, 50], [11, 51]], then :conditions =>
# "(#{quoted_table_name}.a, #{quoted_table_name}.b) IN ((10, 50), (11, 51))"
conditions = ids.map do |id_set|
[primary_keys, id_set].transpose.map do |key, id|
col = columns_hash[key.to_s]
val = quote_value(id, col)
"#{quoted_table_name}.#{connection.quote_column_name(key.to_s)}=#{val}"
end.join(" AND ")
end.join(") OR (")
options.update :conditions => "(#{conditions})"
result = find_every(options)
if result.size == ids.size
ids.size == 1 ? result[0] : result
else
raise ::ActiveRecord::RecordNotFound, "Couldn't find all #{name.pluralize} with IDs (#{ids.inspect})#{conditions}"
end
end
end
end
end
end
module ActiveRecord
ID_SEP = ','
ID_SET_SEP = ';'
class Base
# Allows +attr_name+ to be the list of primary_keys, and returns the id
# of the object
# e.g. @object[@object.class.primary_key] => [1,1]
def [](attr_name)
if attr_name.is_a?(String) and attr_name != attr_name.split(ID_SEP).first
attr_name = attr_name.split(ID_SEP)
end
attr_name.is_a?(Array) ?
attr_name.map {|name| read_attribute(name)} :
read_attribute(attr_name)
end
# Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
# (Alias for the protected write_attribute method).
def []=(attr_name, value)
if attr_name.is_a?(String) and attr_name != attr_name.split(ID_SEP).first
attr_name = attr_name.split(ID_SEP)
end
if attr_name.is_a? Array
value = value.split(ID_SEP) if value.is_a? String
unless value.length == attr_name.length
raise "Number of attr_names and values do not match"
end
#breakpoint
[attr_name, value].transpose.map {|name,val| write_attribute(name.to_s, val)}
else
write_attribute(attr_name, value)
end
end
end
end

View file

@ -1,69 +0,0 @@
module CompositePrimaryKeys
module ActiveRecord
module Calculations
def self.append_features(base)
super
base.send(:extend, ClassMethods)
end
module ClassMethods
def construct_calculation_sql(operation, column_name, options) #:nodoc:
operation = operation.to_s.downcase
options = options.symbolize_keys
scope = scope(:find)
merged_includes = merge_includes(scope ? scope[:include] : [], options[:include])
aggregate_alias = column_alias_for(operation, column_name)
use_workaround = !connection.supports_count_distinct? && options[:distinct] && operation.to_s.downcase == 'count'
join_dependency = nil
if merged_includes.any? && operation.to_s.downcase == 'count'
options[:distinct] = true
use_workaround = !connection.supports_count_distinct?
column_name = options[:select] || primary_key.map{ |part| "#{quoted_table_name}.#{connection.quote_column_name(part)}"}.join(',')
end
sql = "SELECT #{operation}(#{'DISTINCT ' if options[:distinct]}#{column_name}) AS #{aggregate_alias}"
# A (slower) workaround if we're using a backend, like sqlite, that doesn't support COUNT DISTINCT.
sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
sql << ", #{connection.quote_column_name(options[:group_field])} AS #{options[:group_alias]}" if options[:group]
sql << " FROM (SELECT DISTINCT #{column_name}" if use_workaround
sql << " FROM #{quoted_table_name} "
if merged_includes.any?
join_dependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
end
add_joins!(sql, options[:joins], scope)
add_conditions!(sql, options[:conditions], scope)
add_limited_ids_condition!(sql, options, join_dependency) if \
join_dependency &&
!using_limitable_reflections?(join_dependency.reflections) &&
((scope && scope[:limit]) || options[:limit])
if options[:group]
group_key = connection.adapter_name == 'FrontBase' ? :group_alias : :group_field
sql << " GROUP BY #{connection.quote_column_name(options[group_key])} "
end
if options[:group] && options[:having]
# FrontBase requires identifiers in the HAVING clause and chokes on function calls
if connection.adapter_name == 'FrontBase'
options[:having].downcase!
options[:having].gsub!(/#{operation}\s*\(\s*#{column_name}\s*\)/, aggregate_alias)
end
sql << " HAVING #{options[:having]} "
end
sql << " ORDER BY #{options[:order]} " if options[:order]
add_limit!(sql, options, scope)
sql << ') w1' if use_workaround # assign a dummy table name as required for postgresql
sql
end
end
end
end
end

View file

@ -1,30 +0,0 @@
module CompositePrimaryKeys
ID_SEP = ','
ID_SET_SEP = ';'
module ArrayExtension
def to_composite_keys
CompositeKeys.new(self)
end
def to_composite_ids
CompositeIds.new(self)
end
end
class CompositeArray < Array
def to_s
join(ID_SEP)
end
end
class CompositeKeys < CompositeArray
end
class CompositeIds < CompositeArray
end
end
Array.send(:include, CompositePrimaryKeys::ArrayExtension)

View file

@ -1,21 +0,0 @@
module ActiveRecord
module ConnectionAdapters
class IBM_DBAdapter < AbstractAdapter
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
def supports_count_distinct? #:nodoc:
false
end
alias_method :quote_original, :quote
def quote(value, column = nil)
if value.kind_of?(String) && column && [:integer, :float].include?(column.type)
value = column.type == :integer ? value.to_i : value.to_f
value.to_s
else
quote_original(value, column)
end
end
end
end
end

View file

@ -1,15 +0,0 @@
module ActiveRecord
module ConnectionAdapters
class OracleAdapter < AbstractAdapter
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
def supports_count_distinct? #:nodoc:
false
end
def concat(*columns)
"(#{columns.join('||')})"
end
end
end
end

View file

@ -1,53 +0,0 @@
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter < AbstractAdapter
# This mightn't be in Core, but count(distinct x,y) doesn't work for me
def supports_count_distinct? #:nodoc:
false
end
def concat(*columns)
columns = columns.map { |c| "CAST(#{c} AS varchar)" }
"(#{columns.join('||')})"
end
# Executes an INSERT query and returns the new record's ID
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
# Extract the table from the insert sql. Yuck.
table = sql.split(" ", 4)[2].gsub('"', '')
# Try an insert with 'returning id' if available (PG >= 8.2)
if supports_insert_with_returning?
pk, sequence_name = *pk_and_sequence_for(table) unless pk
if pk
quoted_pk = if pk.is_a?(Array)
pk.map { |col| quote_column_name(col) }.join(ID_SEP)
else
quote_column_name(pk)
end
id = select_value("#{sql} RETURNING #{quoted_pk}")
clear_query_cache
return id
end
end
# Otherwise, insert then grab last_insert_id.
if insert_id = super
insert_id
else
# If neither pk nor sequence name is given, look them up.
unless pk || sequence_name
pk, sequence_name = *pk_and_sequence_for(table)
end
# If a pk is given, fallback to default sequence name.
# Don't fetch last insert id for a table without a pk.
if pk && sequence_name ||= default_sequence_name(table, pk)
last_insert_id(table, sequence_name)
end
end
end
end
end
end

View file

@ -1,15 +0,0 @@
require 'active_record/connection_adapters/sqlite_adapter'
module ActiveRecord
module ConnectionAdapters #:nodoc:
class SQLite3Adapter < SQLiteAdapter # :nodoc:
def supports_count_distinct? #:nodoc:
false
end
def concat(*columns)
"(#{columns.join('||')})"
end
end
end
end

View file

@ -1,8 +0,0 @@
class Fixture #:nodoc:
def [](key)
if key.is_a? Array
return key.map { |a_key| self[a_key.to_s] }.to_composite_ids.to_s
end
@fixture[key]
end
end

View file

@ -1,20 +0,0 @@
ActiveRecord::ConnectionAdapters::ColumnDefinition.send(:alias_method, :to_s_without_composite_keys, :to_s)
ActiveRecord::ConnectionAdapters::ColumnDefinition.class_eval <<-'EOF'
def to_s
if name.is_a? Array
"PRIMARY KEY (#{name.join(',')})"
else
to_s_without_composite_keys
end
end
EOF
ActiveRecord::ConnectionAdapters::TableDefinition.class_eval <<-'EOF'
def [](name)
@columns.find { |column|
!column.name.is_a?(Array) && column.name.to_s == name.to_s
}
end
EOF

View file

@ -1,19 +0,0 @@
module ActiveRecord
module Reflection
class AssociationReflection
def primary_key_name
return @primary_key_name if @primary_key_name
case
when macro == :belongs_to
@primary_key_name = options[:foreign_key] || class_name.foreign_key
when options[:as]
@primary_key_name = options[:foreign_key] || "#{options[:as]}_id"
else
@primary_key_name = options[:foreign_key] || active_record.name.foreign_key
end
@primary_key_name = @primary_key_name.to_composite_keys.to_s if @primary_key_name.is_a? Array
@primary_key_name
end
end
end
end

View file

@ -1,8 +0,0 @@
module CompositePrimaryKeys
module VERSION #:nodoc:
MAJOR = 2
MINOR = 2
TINY = 2
STRING = [MAJOR, MINOR, TINY].join('.')
end
end

View file

@ -1,24 +0,0 @@
# Load local config files in /local
begin
local_file_supported = Dir[File.join(PROJECT_ROOT, 'local/*.sample')].map { |path| File.basename(path).sub(".sample","") }
local_file_supported.each do |file|
require "local/#{file}"
end
rescue LoadError
puts <<-EOS
This Gem supports local developer extensions in local/ folder.
Supported files:
#{local_file_supported.map { |f| "local/#{f}"}.join(', ')}
Setup default sample files:
rake local:setup
Current warning: #{$!}
EOS
end
# Now load Rake tasks from /tasks
rakefiles = Dir[File.join(File.dirname(__FILE__), "tasks/**/*.rake")]
rakefiles.each { |rakefile| load File.expand_path(rakefile) }

View file

@ -1,10 +0,0 @@
require 'yaml'
ENV['cpk_adapters'] = {
"mysql" => {
:adapter => "mysql",
:username => "root",
:password => "root",
# ...
}
}.to_yaml

View file

@ -1,2 +0,0 @@
# location of folder containing activerecord, railties, etc folders for each Rails gem
ENV['EDGE_RAILS_DIR'] ||= "/path/to/copy/of/edge/rails"

View file

@ -1,2 +0,0 @@
# This file loaded into Rakefile
# Place any extra development tasks you want here

View file

@ -1,48 +0,0 @@
#!/usr/bin/env ruby
#
# if run as script, load the file as library while starting irb
#
if __FILE__ == $0
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
ENV['ADAPTER'] = ARGV[0]
exec "#{irb} -f -r #{$0} --simple-prompt"
end
#
# check if the given adapter is supported (default: mysql)
#
adapters = %w[mysql sqlite oracle oracle_enhanced postgresql ibm_db]
adapter = ENV['ADAPTER'] || 'mysql'
unless adapters.include? adapter
puts "Usage: #{__FILE__} <adapter>"
puts ''
puts 'Adapters: '
puts adapters.map{ |adapter| " #{adapter}" }.join("\n")
exit 1
end
#
# load all necessary libraries
#
require 'rubygems'
require 'local/database_connections'
$LOAD_PATH.unshift 'lib'
begin
require 'local/paths'
$LOAD_PATH.unshift "#{ENV['EDGE_RAILS_DIR']}/activerecord/lib" if ENV['EDGE_RAILS_DIR']
$LOAD_PATH.unshift "#{ENV['EDGE_RAILS_DIR']}/activesupport/lib" if ENV['EDGE_RAILS_DIR']
rescue
end
require 'active_support'
require 'active_record'
require "test/connections/native_#{adapter}/connection"
require 'composite_primary_keys'
PROJECT_ROOT = File.join(File.dirname(__FILE__), '..')
Dir[File.join(PROJECT_ROOT,'test/fixtures/*.rb')].each { |model| require model }

View file

@ -1,67 +0,0 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'redcloth'
require 'syntax/convertors/html'
require 'erb'
require File.dirname(__FILE__) + '/../lib/composite_primary_keys/version.rb'
version = CompositePrimaryKeys::VERSION::STRING
download = 'http://rubyforge.org/projects/compositekeys'
class Fixnum
def ordinal
# teens
return 'th' if (10..19).include?(self % 100)
# others
case self % 10
when 1: return 'st'
when 2: return 'nd'
when 3: return 'rd'
else return 'th'
end
end
end
class Time
def pretty
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
end
end
def convert_syntax(syntax, source)
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
end
if ARGV.length >= 1
src, template = ARGV
template ||= File.dirname(__FILE__) + '/../website/template.rhtml'
else
puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
exit!
end
template = ERB.new(File.open(template).read)
title = nil
body = nil
File.open(src) do |fsrc|
title_text = fsrc.readline
body_text = fsrc.read
syntax_items = []
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
ident = syntax_items.length
element, syntax, source = $1, $2, $3
syntax_items << "<#{element} class=\"syntax\">#{convert_syntax(syntax, source)}</#{element}>"
"syntax-temp-#{ident}"
}
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
body = RedCloth.new(body_text).to_html
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
end
stat = File.stat(src)
created = stat.ctime
modified = stat.mtime
$stdout << template.result(binding)

View file

@ -1,59 +0,0 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'redcloth'
require 'syntax/convertors/html'
require 'erb'
require 'active_support'
require File.dirname(__FILE__) + '/../lib/composite_primary_keys/version.rb'
version = CompositePrimaryKeys::VERSION::STRING
download = 'http://rubyforge.org/projects/compositekeys'
class Fixnum
def ordinal
# teens
return 'th' if (10..19).include?(self % 100)
# others
case self % 10
when 1: return 'st'
when 2: return 'nd'
when 3: return 'rd'
else return 'th'
end
end
end
class Time
def pretty
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
end
end
def convert_syntax(syntax, source)
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
end
if ARGV.length >= 1
src, template = ARGV
template ||= File.dirname(__FILE__) + '/../website/template.js'
else
puts("Usage: #{File.split($0).last} source.txt [template.js] > output.html")
exit!
end
template = ERB.new(File.open(template).read)
title = nil
body = nil
File.open(src) do |fsrc|
title_text = fsrc.readline
body_text = fsrc.read
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
body = RedCloth.new(body_text)
end
stat = File.stat(src)
created = stat.ctime
modified = stat.mtime
$stdout << template.result(binding)

View file

@ -1,43 +0,0 @@
namespace :ar do
desc 'Pre-load edge rails ActiveRecord'
task :edge do
unless path = ENV['EDGE_RAILS_DIR'] || ENV['EDGE_RAILS']
puts <<-EOS
Need to define env var EDGE_RAILS_DIR or EDGE_RAILS- root of edge rails on your machine.
i) Get copy of Edge Rails - http://dev.rubyonrails.org
ii) Set EDGE_RAILS_DIR to this folder in local/paths.rb - see local/paths.rb.sample for example
or
a) Set folder from environment or command line (rake ar:edge EDGE_RAILS_DIR=/path/to/rails)
EOS
exit
end
ENV['AR_LOAD_PATH'] = File.join(path, "activerecord/lib")
end
desc 'Pre-load ActiveRecord using VERSION=X.Y.Z, instead of latest'
task :set do
unless version = ENV['VERSION']
puts <<-EOS
Usage: rake ar:get_version VERSION=1.15.3
Specify the version number with VERSION=X.Y.Z; and make sure you have that activerecord gem version installed.
EOS
end
version = nil if version == "" || version == []
begin
version ? gem('activerecord', version) : gem('activerecord')
require 'active_record'
ENV['AR_LOAD_PATH'] = $:.reverse.find { |path| /activerecord/ =~ path }
rescue LoadError
puts <<-EOS
Missing: Cannot find activerecord #{version} installed.
Install: gem install activerecord -v #{version}
EOS
exit
end
end
end

View file

@ -1,12 +0,0 @@
require 'active_record'
# UNTESTED - firebird sqlserver sqlserver_odbc db2 sybase openbase
for adapter in %w( mysql sqlite oracle oracle_enhanced postgresql ibm_db )
Rake::TestTask.new("test_#{adapter}") { |t|
t.libs << "test" << "test/connections/native_#{adapter}"
t.pattern = "test/test_*.rb"
t.verbose = true
}
end
SCHEMA_PATH = File.join(PROJECT_ROOT, *%w(test fixtures db_definitions))

View file

@ -1,30 +0,0 @@
namespace :mysql do
desc 'Build the MySQL test databases'
task :build_databases => :load_connection do
puts File.join(SCHEMA_PATH, 'mysql.sql')
options_str = ENV['cpk_adapter_options_str']
# creates something like "-u#{username} -p#{password} -S#{socket}"
sh %{ mysqladmin #{options_str} create "#{GEM_NAME}_unittest" }
sh %{ mysql #{options_str} "#{GEM_NAME}_unittest" < #{File.join(SCHEMA_PATH, 'mysql.sql')} }
end
desc 'Drop the MySQL test databases'
task :drop_databases => :load_connection do
options_str = ENV['cpk_adapter_options_str']
sh %{ mysqladmin #{options_str} -f drop "#{GEM_NAME}_unittest" }
end
desc 'Rebuild the MySQL test databases'
task :rebuild_databases => [:drop_databases, :build_databases]
task :load_connection do
require File.join(PROJECT_ROOT, %w[lib adapter_helper mysql])
spec = AdapterHelper::MySQL.load_connection_from_env
options = {}
options['u'] = spec[:username] if spec[:username]
options['p'] = spec[:password] if spec[:password]
options['S'] = spec[:sock] if spec[:sock]
options_str = options.map { |key, value| "-#{key}#{value}" }.join(" ")
ENV['cpk_adapter_options_str'] = options_str
end
end

View file

@ -1,25 +0,0 @@
namespace :oracle do
desc 'Build the Oracle test databases'
task :build_databases => :load_connection do
puts File.join(SCHEMA_PATH, 'oracle.sql')
options_str = ENV['cpk_adapter_options_str']
sh %( sqlplus #{options_str} < #{File.join(SCHEMA_PATH, 'oracle.sql')} )
end
desc 'Drop the Oracle test databases'
task :drop_databases => :load_connection do
puts File.join(SCHEMA_PATH, 'oracle.drop.sql')
options_str = ENV['cpk_adapter_options_str']
sh %( sqlplus #{options_str} < #{File.join(SCHEMA_PATH, 'oracle.drop.sql')} )
end
desc 'Rebuild the Oracle test databases'
task :rebuild_databases => [:drop_databases, :build_databases]
task :load_connection do
require File.join(PROJECT_ROOT, %w[lib adapter_helper oracle])
spec = AdapterHelper::Oracle.load_connection_from_env
ENV['cpk_adapter_options_str'] = "#{spec[:username]}/#{spec[:password]}@#{spec[:host]}"
end
end

View file

@ -1,26 +0,0 @@
namespace :postgresql do
desc 'Build the PostgreSQL test databases'
task :build_databases => :load_connection do
sh %{ createdb "#{GEM_NAME}_unittest" }
sh %{ psql "#{GEM_NAME}_unittest" -f #{File.join(SCHEMA_PATH, 'postgresql.sql')} }
end
desc 'Drop the PostgreSQL test databases'
task :drop_databases => :load_connection do
sh %{ dropdb "#{GEM_NAME}_unittest" }
end
desc 'Rebuild the PostgreSQL test databases'
task :rebuild_databases => [:drop_databases, :build_databases]
task :load_connection do
require File.join(PROJECT_ROOT, %w[lib adapter_helper postgresql])
spec = AdapterHelper::Postgresql.load_connection_from_env
options = {}
options['u'] = spec[:username] if spec[:username]
options['p'] = spec[:password] if spec[:password]
options_str = options.map { |key, value| "-#{key}#{value}" }.join(" ")
ENV['cpk_adapter_options_str'] = options_str
end
end

View file

@ -1,28 +0,0 @@
namespace :sqlite3 do
desc 'Build the sqlite test databases'
task :build_databases => :load_connection do
file = File.join(SCHEMA_PATH, 'sqlite.sql')
dbfile = File.join(PROJECT_ROOT, ENV['cpk_adapter_options_str'])
cmd = "mkdir -p #{File.dirname(dbfile)}"
puts cmd
sh %{ #{cmd} }
cmd = "sqlite3 #{dbfile} < #{file}"
puts cmd
sh %{ #{cmd} }
end
desc 'Drop the sqlite test databases'
task :drop_databases => :load_connection do
dbfile = ENV['cpk_adapter_options_str']
sh %{ rm -f #{dbfile} }
end
desc 'Rebuild the sqlite test databases'
task :rebuild_databases => [:drop_databases, :build_databases]
task :load_connection do
require File.join(PROJECT_ROOT, %w[lib adapter_helper sqlite3])
spec = AdapterHelper::Sqlite3.load_connection_from_env
ENV['cpk_adapter_options_str'] = spec[:dbfile]
end
end

View file

@ -1,22 +0,0 @@
desc 'Release the website and new gem version'
task :deploy => [:check_version, :website, :release] do
puts "Remember to create SVN tag:"
puts "svn copy svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/trunk " +
"svn+ssh://#{RUBYFORGE_USERNAME}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
puts "Suggested comment:"
puts "Tagging release #{CHANGES}"
end
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
task :local_deploy => [:website_generate, :install_gem]
task :check_version do
unless ENV['VERSION']
puts 'Must pass a VERSION=x.y.z release version'
exit
end
unless ENV['VERSION'] == VERS
puts "Please update your version.rb to match the release version, currently #{VERS}"
exit
end
end

View file

@ -1,13 +0,0 @@
namespace :local do
desc 'Copies over the same local files ready for editing'
task :setup do
sample_files = Dir[File.join(PROJECT_ROOT, "local/*.rb.sample")]
sample_files.each do |sample_file|
file = sample_file.sub(".sample","")
unless File.exists?(file)
puts "Copying #{sample_file} -> #{file}"
sh %{ cp #{sample_file} #{file} }
end
end
end
end

View file

@ -1,18 +0,0 @@
desc 'Generate website files'
task :website_generate do
sh %{ ruby scripts/txt2html website/index.txt > website/index.html }
sh %{ ruby scripts/txt2js website/version.txt > website/version.js }
sh %{ ruby scripts/txt2js website/version-raw.txt > website/version-raw.js }
end
desc 'Upload website files to rubyforge'
task :website_upload do
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
host = "#{config["username"]}@rubyforge.org"
remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/"
local_dir = 'website'
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
end
desc 'Generate and upload website files'
task :website => [:website_generate, :website_upload, :publish_docs]

View file

@ -1,67 +0,0 @@
= Composite Primary Keys - Testing Readme
== Testing an adapter
There are tests available for the following adapters:
* ibmdb
* mysql
* oracle
* postgresql
* sqlite
To run the tests for on of the adapters, follow these steps (using mysql in the example):
* rake -T | grep mysql
rake mysql:build_databases # Build the MySQL test databases
rake mysql:drop_databases # Drop the MySQL test databases
rake mysql:rebuild_databases # Rebuild the MySQL test databases
rake test_mysql # Run tests for test_mysql
* rake mysql:build_databases
* rake test_mysql
== Testing against different ActiveRecord versions (or Edge Rails)
ActiveRecord is a RubyGem within Rails, and is constantly being improved/changed on
its repository (http://dev.rubyonrails.org). These changes may create errors for the CPK
gem. So, we need a way to test CPK against Edge Rails, as well as officially released RubyGems.
The default test (as above) uses the latest RubyGem in your cache.
You can select an older RubyGem version by running the following:
* rake ar:set VERSION=1.14.4 test_mysql
== Edge Rails
Before you can test CPK against Edge Rails, you must checkout a copy of edge rails somewhere (see http://dev.rubyonrails.org for for examples)
* cd /path/to/gems
* svn co http://svn.rubyonrails.org/rails/trunk rails
Say the rails folder is /path/to/gems/rails
Three ways to run CPK tests for Edge Rails:
i) Run:
EDGE_RAILS_DIR=/path/to/gems/rails rake ar:edge test_mysql
ii) In your .profile, set the environment variable EDGE_RAILS_DIR=/path/to/gems/rails,
and once you reload your profile, run:
rake ar:edge test_mysql
iii) Store the path in local/paths.rb. Run:
cp local/paths.rb.sample local/paths.rb
# Now set ENV['EDGE_RAILS_DIR']=/path/to/gems/rails
rake ar:edge test_mysql
These are all variations of the same theme:
* Set the environment variable EDGE_RAILS_DIR to the path to Rails (which contains the activerecord/lib folder)
* Run: rake ar:edge test_<adapter>

View file

@ -1,94 +0,0 @@
$:.unshift(ENV['AR_LOAD_PATH']) if ENV['AR_LOAD_PATH']
require 'test/unit'
require 'hash_tricks'
require 'rubygems'
require 'active_record'
require 'active_record/fixtures'
begin
require 'connection'
rescue MissingSourceFile => e
adapter = 'postgresql' #'sqlite'
require "#{File.dirname(__FILE__)}/connections/native_#{adapter}/connection"
end
require 'composite_primary_keys'
QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') unless Object.const_defined?(:QUOTED_TYPE)
class Test::Unit::TestCase #:nodoc:
self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
self.use_instantiated_fixtures = false
self.use_transactional_fixtures = true
def assert_date_from_db(expected, actual, message = nil)
# SQL Server doesn't have a separate column type just for dates,
# so the time is in the string and incorrectly formatted
if current_adapter?(:SQLServerAdapter)
assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
elsif current_adapter?(:SybaseAdapter)
assert_equal expected.to_s, actual.to_date.to_s, message
else
assert_equal expected.to_s, actual.to_s, message
end
end
def assert_queries(num = 1)
ActiveRecord::Base.connection.class.class_eval do
self.query_count = 0
alias_method :execute, :execute_with_query_counting
end
yield
ensure
ActiveRecord::Base.connection.class.class_eval do
alias_method :execute, :execute_without_query_counting
end
assert_equal num, ActiveRecord::Base.connection.query_count, "#{ActiveRecord::Base.connection.query_count} instead of #{num} queries were executed."
end
def assert_no_queries(&block)
assert_queries(0, &block)
end
cattr_accessor :classes
protected
def testing_with(&block)
classes.keys.each do |@key_test|
@klass_info = classes[@key_test]
@klass, @primary_keys = @klass_info[:class], @klass_info[:primary_keys]
order = @klass.primary_key.is_a?(String) ? @klass.primary_key : @klass.primary_key.join(',')
@first = @klass.find(:first, :order => order)
yield
end
end
def first_id
ids = (1..@primary_keys.length).map {|num| 1}
composite? ? ids.to_composite_ids : ids.first
end
def first_id_str
composite? ? first_id.join(CompositePrimaryKeys::ID_SEP) : first_id.to_s
end
def composite?
@key_test != :single
end
end
def current_adapter?(type)
ActiveRecord::ConnectionAdapters.const_defined?(type) &&
ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters.const_get(type))
end
ActiveRecord::Base.connection.class.class_eval do
cattr_accessor :query_count
alias_method :execute_without_query_counting, :execute
def execute_with_query_counting(sql, name = nil)
self.query_count += 1
execute_without_query_counting(sql, name)
end
end
#ActiveRecord::Base.logger = Logger.new(STDOUT)
#ActiveRecord::Base.colorize_logging = false

View file

@ -1,23 +0,0 @@
print "Using IBM2 \n"
require 'logger'
gem 'ibm_db'
require 'IBM_DB'
RAILS_CONNECTION_ADAPTERS = %w( mysql postgresql sqlite firebird sqlserver db2 oracle sybase openbase frontbase ibm_db )
ActiveRecord::Base.logger = Logger.new("debug.log")
db1 = 'composite_primary_keys_unittest'
connection_options = {
:adapter => "ibm_db",
:database => "ocdpdev",
:username => "db2inst1",
:password => "password",
:host => '192.168.2.21'
}
ActiveRecord::Base.configurations = { db1 => connection_options }
ActiveRecord::Base.establish_connection(connection_options)

View file

@ -1,13 +0,0 @@
print "Using native MySQL\n"
require 'fileutils'
require 'logger'
require 'adapter_helper/mysql'
log_path = File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. .. log]))
FileUtils.mkdir_p log_path
puts "Logging to #{log_path}/debug.log"
ActiveRecord::Base.logger = Logger.new("#{log_path}/debug.log")
# Adapter config setup in locals/database_connections.rb
connection_options = AdapterHelper::MySQL.load_connection_from_env
ActiveRecord::Base.establish_connection(connection_options)

View file

@ -1,14 +0,0 @@
print "Using native Oracle\n"
require 'fileutils'
require 'logger'
require 'adapter_helper/oracle'
log_path = File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. .. log]))
FileUtils.mkdir_p log_path
puts "Logging to #{log_path}/debug.log"
ActiveRecord::Base.logger = Logger.new("#{log_path}/debug.log")
# Adapter config setup in locals/database_connections.rb
connection_options = AdapterHelper::Oracle.load_connection_from_env
puts connection_options.inspect
ActiveRecord::Base.establish_connection(connection_options)

View file

@ -1,9 +0,0 @@
print "Using native Postgresql\n"
require 'logger'
require 'adapter_helper/postgresql'
ActiveRecord::Base.logger = Logger.new("debug.log")
# Adapter config setup in locals/database_connections.rb
connection_options = AdapterHelper::Postgresql.load_connection_from_env
ActiveRecord::Base.establish_connection(connection_options)

View file

@ -1,9 +0,0 @@
print "Using native Sqlite3\n"
require 'logger'
require 'adapter_helper/sqlite3'
ActiveRecord::Base.logger = Logger.new("debug.log")
# Adapter config setup in locals/database_connections.rb
connection_options = AdapterHelper::Sqlite3.load_connection_from_env
ActiveRecord::Base.establish_connection(connection_options)

View file

@ -1,5 +0,0 @@
class Article < ActiveRecord::Base
has_many :readings
has_many :users, :through => :readings
end

View file

@ -1,6 +0,0 @@
first:
id: 1
name: Article One
second:
id: 2
name: Article Two

View file

@ -1,6 +0,0 @@
class Comment < ActiveRecord::Base
set_primary_keys :id
belongs_to :person, :polymorphic => true
belongs_to :hack
end

View file

@ -1,16 +0,0 @@
comment1:
id: 1
person_id: 1
person_type: Employee
comment2:
id: 2
person_id: 1
person_type: User
hack_id: andrew
comment3:
id: 3
person_id: andrew
person_type: Hack

View file

@ -1,113 +0,0 @@
CREATE TABLE reference_types (
reference_type_id integer NOT NULL generated by default as identity (start with 100, increment by 1, no cache),
type_label varchar(50) default NULL,
abbreviation varchar(50) default NULL,
description varchar(50) default NULL,
PRIMARY KEY (reference_type_id)
);
CREATE TABLE reference_codes (
reference_type_id integer,
reference_code integer NOT NULL,
code_label varchar(50) default NULL,
abbreviation varchar(50) default NULL,
description varchar(50) default NULL,
PRIMARY KEY (reference_type_id,reference_code)
);
CREATE TABLE products (
id integer NOT NULL,
name varchar(50) default NULL,
PRIMARY KEY (id)
);
CREATE TABLE tariffs (
tariff_id integer NOT NULL,
start_date date NOT NULL,
amount integer default NULL,
PRIMARY KEY (tariff_id,start_date)
);
CREATE TABLE product_tariffs (
product_id integer NOT NULL,
tariff_id integer NOT NULL,
tariff_start_date date NOT NULL,
PRIMARY KEY (product_id,tariff_id,tariff_start_date)
);
CREATE TABLE suburbs (
city_id integer NOT NULL,
suburb_id integer NOT NULL,
name varchar(50) NOT NULL,
PRIMARY KEY (city_id,suburb_id)
);
CREATE TABLE streets (
id integer NOT NULL ,
city_id integer NOT NULL,
suburb_id integer NOT NULL,
name varchar(50) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE users (
id integer NOT NULL ,
name varchar(50) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE articles (
id integer NOT NULL ,
name varchar(50) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE readings (
id integer NOT NULL ,
user_id integer NOT NULL,
article_id integer NOT NULL,
rating integer NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE groups (
id integer NOT NULL ,
name varchar(50) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE memberships (
user_id integer NOT NULL,
group_id integer NOT NULL,
PRIMARY KEY (user_id,group_id)
);
CREATE TABLE membership_statuses (
id integer NOT NULL ,
user_id integer NOT NULL,
group_id integer NOT NULL,
status varchar(50) NOT NULL,
PRIMARY KEY (id)
);
create table kitchen_sinks (
id_1 integer not null,
id_2 integer not null,
a_date date,
a_string varchar(100),
primary key (id_1, id_2)
);
create table restaurants (
franchise_id integer not null,
store_id integer not null,
name varchar(100),
primary key (franchise_id, store_id)
);
create table restaurants_suburbs (
franchise_id integer not null,
store_id integer not null,
city_id integer not null,
suburb_id integer not null
);

View file

@ -1,16 +0,0 @@
drop table MEMBERSHIPS;
drop table REFERENCE_CODES;
drop table TARIFFS;
drop table ARTICLES;
drop table GROUPS;
drop table MEMBERSHIP_STATUSES;
drop table READINGS;
drop table REFERENCE_TYPES;
drop table STREETS;
drop table PRODUCTS;
drop table USERS;
drop table SUBURBS;
drop table PRODUCT_TARIFFS;
drop table KITCHEN_SINK;
drop table RESTAURANTS;
drop table RESTAURANTS_SUBURBS;

View file

@ -1,174 +0,0 @@
create table reference_types (
reference_type_id int(11) not null auto_increment,
type_label varchar(50) default null,
abbreviation varchar(50) default null,
description varchar(50) default null,
primary key (reference_type_id)
) type=InnoDB;
create table reference_codes (
reference_type_id int(11),
reference_code int(11) not null,
code_label varchar(50) default null,
abbreviation varchar(50) default null,
description varchar(50) default null,
primary key (reference_type_id, reference_code)
) type=InnoDB;
create table products (
id int(11) not null auto_increment,
name varchar(50) default null,
primary key (id)
) type=InnoDB;
create table tariffs (
tariff_id int(11) not null,
start_date date not null,
amount integer(11) default null,
primary key (tariff_id, start_date)
) type=InnoDB;
create table product_tariffs (
product_id int(11) not null,
tariff_id int(11) not null,
tariff_start_date date not null,
primary key (product_id, tariff_id, tariff_start_date)
) type=InnoDB;
create table suburbs (
city_id int(11) not null,
suburb_id int(11) not null,
name varchar(50) not null,
primary key (city_id, suburb_id)
) type=InnoDB;
create table streets (
id int(11) not null auto_increment,
city_id int(11) not null,
suburb_id int(11) not null,
name varchar(50) not null,
primary key (id)
) type=InnoDB;
create table users (
id int(11) not null auto_increment,
name varchar(50) not null,
primary key (id)
) type=InnoDB;
create table articles (
id int(11) not null auto_increment,
name varchar(50) not null,
primary key (id)
) type=InnoDB;
create table readings (
id int(11) not null auto_increment,
user_id int(11) not null,
article_id int(11) not null,
rating int(11) not null,
primary key (id)
) type=InnoDB;
create table groups (
id int(11) not null auto_increment,
name varchar(50) not null,
primary key (id)
) type=InnoDB;
create table memberships (
user_id int(11) not null,
group_id int(11) not null,
primary key (user_id,group_id)
) type=InnoDB;
create table membership_statuses (
id int(11) not null auto_increment,
user_id int(11) not null,
group_id int(11) not null,
status varchar(50) not null,
primary key (id)
) type=InnoDB;
create table departments (
department_id int(11) not null,
location_id int(11) not null,
primary key (department_id, location_id)
) type=InnoDB;
create table employees (
id int(11) not null auto_increment,
department_id int(11) default null,
location_id int(11) default null,
primary key (id)
) type=InnoDB;
create table comments (
id int(11) not null auto_increment,
person_id varchar(100) default null,
person_type varchar(100) default null,
hack_id varchar(100) default null,
primary key (id)
) type=InnoDB;
create table hacks (
name varchar(50) not null,
primary key (name)
) type=InnoDB;
create table kitchen_sinks (
id_1 int(11) not null,
id_2 int(11) not null,
a_date date,
a_string varchar(100),
primary key (id_1, id_2)
) type=InnoDB;
create table restaurants (
franchise_id int(11) not null,
store_id int(11) not null,
name varchar(100),
primary key (franchise_id, store_id)
) type=InnoDB;
create table restaurants_suburbs (
franchise_id int(11) not null,
store_id int(11) not null,
city_id int(11) not null,
suburb_id int(11) not null
) type=InnoDB;
create table dorms (
id int(11) not null auto_increment,
primary key(id)
) type=InnoDB;
create table rooms (
dorm_id int(11) not null,
room_id int(11) not null,
primary key (dorm_id, room_id)
) type=InnoDB;
create table room_attributes (
id int(11) not null auto_increment,
name varchar(50),
primary key(id)
) type=InnoDB;
create table room_attribute_assignments (
dorm_id int(11) not null,
room_id int(11) not null,
room_attribute_id int(11) not null
) type=InnoDB;
create table students (
id int(11) not null auto_increment,
primary key(id)
) type=InnoDB;
create table room_assignments (
student_id int(11) not null,
dorm_id int(11) not null,
room_id int(11) not null
) type=InnoDB;

View file

@ -1,39 +0,0 @@
drop table reference_types;
drop sequence reference_types_seq;
drop table reference_codes;
drop table products;
drop sequence products_seq;
drop table tariffs;
drop table product_tariffs;
drop table suburbs;
drop table streets;
drop sequence streets_seq;
drop table users;
drop sequence users_seq;
drop table articles;
drop sequence articles_seq;
drop table readings;
drop sequence readings_seq;
drop table groups;
drop sequence groups_seq;
drop table memberships;
drop table membership_statuses;
drop sequence membership_statuses_seq;
drop table departments;
drop table employees;
drop sequence employees_seq;
drop table comments;
drop sequence comments_seq;
drop table hacks;
drop table kitchen_sinks;
drop table restaurants;
drop table restaurants_suburbs;
drop table dorms;
drop sequence dorms_seq;
drop table rooms;
drop table room_attributes;
drop sequence room_attributes_seq;
drop table room_attribute_assignments;
drop table room_assignments;
drop table students;
drop sequence students_seq;

View file

@ -1,188 +0,0 @@
create sequence reference_types_seq start with 1000;
create table reference_types (
reference_type_id number(11) primary key,
type_label varchar2(50) default null,
abbreviation varchar2(50) default null,
description varchar2(50) default null
);
create table reference_codes (
reference_type_id number(11),
reference_code number(11),
code_label varchar2(50) default null,
abbreviation varchar2(50) default null,
description varchar2(50) default null
);
create sequence products_seq start with 1000;
create table products (
id number(11) primary key,
name varchar2(50) default null
);
create table tariffs (
tariff_id number(11),
start_date date,
amount number(11) default null,
constraint tariffs_pk primary key (tariff_id, start_date)
);
create table product_tariffs (
product_id number(11),
tariff_id number(11),
tariff_start_date date,
constraint product_tariffs_pk primary key (product_id, tariff_id, tariff_start_date)
);
create table suburbs (
city_id number(11),
suburb_id number(11),
name varchar2(50) not null,
constraint suburbs_pk primary key (city_id, suburb_id)
);
create sequence streets_seq start with 1000;
create table streets (
id number(11) primary key,
city_id number(11) not null,
suburb_id number(11) not null,
name varchar2(50) not null
);
create sequence users_seq start with 1000;
create table users (
id number(11) primary key,
name varchar2(50) not null
);
create sequence articles_seq start with 1000;
create table articles (
id number(11) primary key,
name varchar2(50) not null
);
create sequence readings_seq start with 1000;
create table readings (
id number(11) primary key,
user_id number(11) not null,
article_id number(11) not null,
rating number(11) not null
);
create sequence groups_seq start with 1000;
create table groups (
id number(11) primary key,
name varchar2(50) not null
);
create table memberships (
user_id number(11) not null,
group_id number(11) not null,
constraint memberships_pk primary key (user_id, group_id)
);
create sequence membership_statuses_seq start with 1000;
create table membership_statuses (
id number(11) primary key,
user_id number(11) not null,
group_id number(11) not null,
status varchar2(50) not null
);
create table departments (
department_id number(11) not null,
location_id number(11) not null,
constraint departments_pk primary key (department_id, location_id)
);
create sequence employees_seq start with 1000;
create table employees (
id number(11) not null primary key,
department_id number(11) default null,
location_id number(11) default null
);
create sequence comments_seq start with 1000;
create table comments (
id number(11) not null primary key,
person_id varchar(100) default null,
person_type varchar(100) default null,
hack_id varchar(100) default null
);
create table hacks (
name varchar(50) not null primary key
);
create table kitchen_sinks (
id_1 number(11) not null,
id_2 number(11) not null,
a_date date,
a_string varchar(100),
constraint kitchen_sinks_pk primary key (id_1, id_2)
);
create table restaurants (
franchise_id number(11) not null,
store_id number(11) not null,
name varchar(100),
constraint restaurants_pk primary key (franchise_id, store_id)
);
create table restaurants_suburbs (
franchise_id number(11) not null,
store_id number(11) not null,
city_id number(11) not null,
suburb_id number(11) not null
);
create sequence dorms_seq start with 1000;
create table dorms (
id number(11) not null,
constraint dorms_pk primary key (id)
);
create table rooms (
dorm_id number(11) not null,
room_id number(11) not null,
constraint rooms_pk primary key (dorm_id, room_id)
);
create sequence room_attributes_seq start with 1000;
create table room_attributes (
id number(11) not null,
name varchar(50),
constraint room_attributes_pk primary key (id)
);
create table room_attribute_assignments (
dorm_id number(11) not null,
room_id number(11) not null,
room_attribute_id number(11) not null
);
create sequence students_seq start with 1000;
create table students (
id number(11) not null,
constraint students_pk primary key (id)
);
create table room_assignments (
student_id number(11) not null,
dorm_id number(11) not null,
room_id number(11) not null
);

View file

@ -1,199 +0,0 @@
create sequence public.reference_types_seq start 1000;
create table reference_types (
reference_type_id int default nextval('public.reference_types_seq'),
type_label varchar(50) default null,
abbreviation varchar(50) default null,
description varchar(50) default null,
primary key (reference_type_id)
);
create table reference_codes (
reference_type_id int,
reference_code int not null,
code_label varchar(50) default null,
abbreviation varchar(50) default null,
description varchar(50) default null
);
create sequence public.products_seq start 1000;
create table products (
id int not null default nextval('public.products_seq'),
name varchar(50) default null,
primary key (id)
);
create table tariffs (
tariff_id int not null,
start_date date not null,
amount int default null,
primary key (tariff_id, start_date)
);
create table product_tariffs (
product_id int not null,
tariff_id int not null,
tariff_start_date date not null,
primary key (product_id, tariff_id, tariff_start_date)
);
create table suburbs (
city_id int not null,
suburb_id int not null,
name varchar(50) not null,
primary key (city_id, suburb_id)
);
create sequence public.streets_seq start 1000;
create table streets (
id int not null default nextval('public.streets_seq'),
city_id int not null,
suburb_id int not null,
name varchar(50) not null,
primary key (id)
);
create sequence public.users_seq start 1000;
create table users (
id int not null default nextval('public.users_seq'),
name varchar(50) not null,
primary key (id)
);
create sequence public.articles_seq start 1000;
create table articles (
id int not null default nextval('public.articles_seq'),
name varchar(50) not null,
primary key (id)
);
create sequence public.readings_seq start 1000;
create table readings (
id int not null default nextval('public.readings_seq'),
user_id int not null,
article_id int not null,
rating int not null,
primary key (id)
);
create sequence public.groups_seq start 1000;
create table groups (
id int not null default nextval('public.groups_seq'),
name varchar(50) not null,
primary key (id)
);
create table memberships (
user_id int not null,
group_id int not null,
primary key (user_id, group_id)
);
create sequence public.membership_statuses_seq start 1000;
create table membership_statuses (
id int not null default nextval('public.membership_statuses_seq'),
user_id int not null,
group_id int not null,
status varchar(50) not null,
primary key (id)
);
create table departments (
department_id int not null,
location_id int not null,
primary key (department_id, location_id)
);
create sequence public.employees_seq start 1000;
create table employees (
id int not null default nextval('public.employees_seq'),
department_id int default null,
location_id int default null,
primary key (id)
);
create sequence public.comments_seq start 1000;
create table comments (
id int not null default nextval('public.comments_seq'),
person_id varchar(100) default null,
person_type varchar(100) default null,
hack_id varchar(100) default null,
primary key (id)
);
create table hacks (
name varchar(50) not null,
primary key (name)
);
create table kitchen_sinks (
id_1 int not null,
id_2 int not null,
a_date date,
a_string varchar(100),
primary key (id_1, id_2)
);
create table restaurants (
franchise_id int not null,
store_id int not null,
name varchar(100),
primary key (franchise_id, store_id)
);
create table restaurants_suburbs (
franchise_id int not null,
store_id int not null,
city_id int not null,
suburb_id int not null
);
create sequence public.dorms_seq start 1000;
create table dorms (
id int not null default nextval('public.dorms_seq'),
primary key (id)
);
create table rooms (
dorm_id int not null,
room_id int not null,
primary key (dorm_id, room_id)
);
create sequence public.room_attributes_seq start 1000;
create table room_attributes (
id int not null default nextval('public.room_attributes_seq'),
name varchar(50),
primary key (id)
);
create table room_attribute_assignments (
dorm_id int not null,
room_id int not null,
room_attribute_id int not null
);
create sequence public.students_seq start 1000;
create table students (
id int not null default nextval('public.students_seq'),
primary key (id)
);
create table room_assignments (
student_id int not null,
dorm_id int not null,
room_id int not null
);

View file

@ -1,160 +0,0 @@
create table reference_types (
reference_type_id integer primary key,
type_label varchar(50) default null,
abbreviation varchar(50) default null,
description varchar(50) default null
);
create table reference_codes (
reference_type_id int(11),
reference_code int(11) not null,
code_label varchar(50) default null,
abbreviation varchar(50) default null,
description varchar(50) default null,
primary key (reference_type_id, reference_code)
);
create table products (
id int(11) not null primary key,
name varchar(50) default null
);
create table tariffs (
tariff_id int(11) not null,
start_date date not null,
amount integer(11) default null,
primary key (tariff_id, start_date)
);
create table product_tariffs (
product_id int(11) not null,
tariff_id int(11) not null,
tariff_start_date date not null,
primary key (product_id, tariff_id, tariff_start_date)
);
create table suburbs (
city_id int(11) not null,
suburb_id int(11) not null,
name varchar(50) not null,
primary key (city_id, suburb_id)
);
create table streets (
id integer not null primary key autoincrement,
city_id int(11) not null,
suburb_id int(11) not null,
name varchar(50) not null
);
create table users (
id integer not null primary key autoincrement,
name varchar(50) not null
);
create table articles (
id integer not null primary key autoincrement,
name varchar(50) not null
);
create table readings (
id integer not null primary key autoincrement,
user_id int(11) not null,
article_id int(11) not null,
rating int(11) not null
);
create table groups (
id integer not null primary key autoincrement,
name varchar(50) not null
);
create table memberships (
user_id int not null,
group_id int not null,
primary key (user_id, group_id)
);
create table membership_statuses (
id integer not null primary key autoincrement,
user_id int not null,
group_id int not null,
status varchar(50) not null
);
create table departments (
department_id integer not null,
location_id integer not null,
primary key (department_id, location_id)
);
create table employees (
id integer not null primary key autoincrement,
department_id integer null,
location_id integer null
);
create table comments (
id integer not null primary key autoincrement,
person_id varchar(100) null,
person_type varchar(100) null,
hack_id varchar(100) null
);
create table hacks (
name varchar(50) not null primary key
);
create table kitchen_sinks (
id_1 integer not null,
id_2 integer not null,
a_date date,
a_string varchar(100),
primary key (id_1, id_2)
);
create table restaurants (
franchise_id integer not null,
store_id integer not null,
name varchar(100),
primary key (franchise_id, store_id)
);
create table restaurants_suburbs (
franchise_id integer not null,
store_id integer not null,
city_id integer not null,
suburb_id integer not null
);
create table dorms (
id integer not null primary key autoincrement
);
create table rooms (
dorm_id integer not null,
room_id integer not null,
primary key (dorm_id, room_id)
);
create table room_attributes (
id integer not null primary key autoincrement,
name varchar(50)
);
create table room_attribute_assignments (
dorm_id integer not null,
room_id integer not null,
room_attribute_id integer not null
);
create table students (
id integer not null primary key autoincrement
);
create table room_assignments (
student_id integer not null,
dorm_id integer not null,
room_id integer not null
);

View file

@ -1,5 +0,0 @@
class Department < ActiveRecord::Base
# set_primary_keys *keys - turns on composite key functionality
set_primary_keys :department_id, :location_id
has_many :employees, :foreign_key => [:department_id, :location_id]
end

View file

@ -1,3 +0,0 @@
department1-cpk:
department_id: 1
location_id: 1

View file

@ -1,4 +0,0 @@
class Employee < ActiveRecord::Base
belongs_to :department, :foreign_key => [:department_id, :location_id]
has_many :comments, :as => :person
end

View file

@ -1,9 +0,0 @@
employee1:
id: 1
department_id: 1
location_id: 1
employee2:
id: 2
department_id: 1
location_id: 1

View file

@ -1,3 +0,0 @@
class Group < ActiveRecord::Base
has_many :memberships
end

View file

@ -1,3 +0,0 @@
cpk:
id: 1
name: Composite Primary Keys

View file

@ -1,6 +0,0 @@
class Hack < ActiveRecord::Base
set_primary_keys :name
has_many :comments, :as => :person
has_one :first_comment, :as => :person, :class_name => "Comment"
end

View file

@ -1,2 +0,0 @@
andrew:
name: andrew

View file

@ -1,7 +0,0 @@
class Membership < ActiveRecord::Base
# set_primary_keys *keys - turns on composite key functionality
set_primary_keys :user_id, :group_id
belongs_to :user
belongs_to :group
has_many :statuses, :class_name => 'MembershipStatus', :foreign_key => [:user_id, :group_id]
end

View file

@ -1,3 +0,0 @@
class MembershipStatus < ActiveRecord::Base
belongs_to :membership, :foreign_key => [:user_id, :group_id]
end

View file

@ -1,10 +0,0 @@
santiago-cpk:
id: 1
user_id: 1
group_id: 1
status: Active
drnic-cpk:
id: 2
user_id: 2
group_id: 1
status: Owner

View file

@ -1,6 +0,0 @@
santiago-cpk:
user_id: 1
group_id: 1
drnic-cpk:
user_id: 2
group_id: 1

View file

@ -1,7 +0,0 @@
class Product < ActiveRecord::Base
set_primary_keys :id # redundant
has_many :product_tariffs, :foreign_key => :product_id
has_one :product_tariff, :foreign_key => :product_id
has_many :tariffs, :through => :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
end

Some files were not shown because too many files have changed in this diff Show more