Remove ancient (and unused) composite_primary_keys gem
This commit is contained in:
parent
92feab9112
commit
2d2b6d7ed8
148 changed files with 0 additions and 6357 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
156
vendor/gems/composite_primary_keys-2.2.2/History.txt
vendored
156
vendor/gems/composite_primary_keys-2.2.2/History.txt
vendored
|
@ -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'
|
|
@ -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
|
|
@ -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!
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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'
|
|
@ -1,2 +0,0 @@
|
|||
# Include hook code here
|
||||
require_dependency 'composite_primary_keys'
|
|
@ -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
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -1,8 +0,0 @@
|
|||
module CompositePrimaryKeys
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 2
|
||||
TINY = 2
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
||||
end
|
|
@ -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) }
|
Binary file not shown.
|
@ -1,10 +0,0 @@
|
|||
require 'yaml'
|
||||
|
||||
ENV['cpk_adapters'] = {
|
||||
"mysql" => {
|
||||
:adapter => "mysql",
|
||||
:username => "root",
|
||||
:password => "root",
|
||||
# ...
|
||||
}
|
||||
}.to_yaml
|
|
@ -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"
|
|
@ -1,2 +0,0 @@
|
|||
# This file loaded into Rakefile
|
||||
# Place any extra development tasks you want here
|
|
@ -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 }
|
||||
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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))
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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>
|
||||
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,5 +0,0 @@
|
|||
class Article < ActiveRecord::Base
|
||||
has_many :readings
|
||||
has_many :users, :through => :readings
|
||||
end
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
first:
|
||||
id: 1
|
||||
name: Article One
|
||||
second:
|
||||
id: 2
|
||||
name: Article Two
|
|
@ -1,6 +0,0 @@
|
|||
class Comment < ActiveRecord::Base
|
||||
set_primary_keys :id
|
||||
belongs_to :person, :polymorphic => true
|
||||
belongs_to :hack
|
||||
end
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
);
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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
|
||||
);
|
||||
|
|
@ -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
|
||||
);
|
||||
|
|
@ -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
|
||||
);
|
||||
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
department1-cpk:
|
||||
department_id: 1
|
||||
location_id: 1
|
|
@ -1,4 +0,0 @@
|
|||
class Employee < ActiveRecord::Base
|
||||
belongs_to :department, :foreign_key => [:department_id, :location_id]
|
||||
has_many :comments, :as => :person
|
||||
end
|
|
@ -1,9 +0,0 @@
|
|||
employee1:
|
||||
id: 1
|
||||
department_id: 1
|
||||
location_id: 1
|
||||
employee2:
|
||||
id: 2
|
||||
department_id: 1
|
||||
location_id: 1
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
class Group < ActiveRecord::Base
|
||||
has_many :memberships
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
cpk:
|
||||
id: 1
|
||||
name: Composite Primary Keys
|
|
@ -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
|
|
@ -1,2 +0,0 @@
|
|||
andrew:
|
||||
name: andrew
|
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
class MembershipStatus < ActiveRecord::Base
|
||||
belongs_to :membership, :foreign_key => [:user_id, :group_id]
|
||||
end
|
|
@ -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
|
|
@ -1,6 +0,0 @@
|
|||
santiago-cpk:
|
||||
user_id: 1
|
||||
group_id: 1
|
||||
drnic-cpk:
|
||||
user_id: 2
|
||||
group_id: 1
|
|
@ -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
Loading…
Add table
Reference in a new issue