composite_primary_keys 5.0.0.rc1 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +15 -0
- data/lib/composite_primary_keys.rb +2 -2
- data/lib/composite_primary_keys/base.rb +22 -8
- data/lib/composite_primary_keys/composite_predicates.rb +19 -6
- data/lib/composite_primary_keys/relation/calculations.rb +25 -2
- data/lib/composite_primary_keys/relation/finder_methods.rb +7 -3
- data/lib/composite_primary_keys/version.rb +1 -1
- data/tasks/databases/mysql.rake +19 -9
- data/tasks/databases/postgresql.rake +26 -6
- data/test/abstract_unit.rb +4 -2
- data/test/connections/databases.yml +2 -1
- data/test/db_test.rb +3 -3
- data/test/fixtures/capitol.rb +1 -1
- data/test/fixtures/db_definitions/mysql.sql +83 -83
- data/test/fixtures/department.rb +1 -1
- data/test/fixtures/dorm.rb +1 -1
- data/test/fixtures/membership.rb +2 -2
- data/test/fixtures/product.rb +1 -1
- data/test/fixtures/product_tariff.rb +1 -1
- data/test/fixtures/reference_code.rb +1 -1
- data/test/fixtures/reference_type.rb +1 -1
- data/test/fixtures/restaurant.rb +1 -1
- data/test/fixtures/room.rb +1 -1
- data/test/fixtures/room_assignment.rb +1 -1
- data/test/fixtures/room_attribute_assignment.rb +1 -1
- data/test/fixtures/seat.rb +1 -1
- data/test/fixtures/suburb.rb +1 -1
- data/test/fixtures/tariff.rb +1 -1
- data/test/test_associations.rb +0 -21
- data/test/test_calculations.rb +33 -0
- data/test/test_exists.rb +6 -1
- data/test/test_find.rb +7 -1
- data/test/test_miscellaneous.rb +0 -5
- data/test/test_predicates.rb +10 -4
- data/test/test_suite.rb +1 -0
- metadata +13 -12
data/History.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
== 5.0.0 2012-02-12
|
2
|
+
* Fix tests so they pass on MySql (Charlie Savage)
|
3
|
+
* Fix calculations to work with duplicate column names (cleesmith)
|
4
|
+
* Switch rake tasks for Postgresql and MySql to use ActiveRecord API for
|
5
|
+
creating and dropping databases (Charlie Savage)
|
6
|
+
* Follow AR 3.2 lead and introduce self.primary_keys and deprecate set_primary_keys (Charlie Savage)
|
7
|
+
* Switch from set_primary_key to self.primary_key= to avoid Rails deprecation (Charlie Savage)
|
8
|
+
* Fix issue when using multiple database connections (David Doan)
|
9
|
+
* Fix homepage in gemspec and remove email address (Charlie Savage)
|
10
|
+
* Add support for string keys to exists? (Jan Vlnas)
|
11
|
+
* Fix typo (Jason Karns)
|
12
|
+
|
13
|
+
== 5.0.0.rc1 2012-01-16
|
14
|
+
* ActiveRecord 3.2 support
|
15
|
+
|
1
16
|
== 4.1.2 2012-01-12
|
2
17
|
* Helper to allow the same tests to be used for both Oracle and other DBs
|
3
18
|
by replacing quoted identifiers with all-caps equivalents on Oracle (Rhett Sutphin)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2006 Nic Williams
|
2
|
+
# Copyright (c) 2006-2012 Nic Williams and Charlie Savage
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -26,7 +26,7 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
26
26
|
|
27
27
|
unless defined?(ActiveRecord)
|
28
28
|
require 'rubygems'
|
29
|
-
gem 'activerecord', '~> 3.2.0
|
29
|
+
gem 'activerecord', '~> 3.2.0'
|
30
30
|
require 'active_record'
|
31
31
|
end
|
32
32
|
|
@@ -7,16 +7,17 @@ module ActiveRecord
|
|
7
7
|
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
8
8
|
|
9
9
|
class << self
|
10
|
-
def
|
11
|
-
|
10
|
+
def primary_keys
|
11
|
+
@primary_keys
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
def primary_keys=(keys)
|
15
|
+
unless keys.kind_of?(Array)
|
16
|
+
self.primary_key = keys
|
15
17
|
return
|
16
18
|
end
|
17
19
|
|
18
|
-
|
19
|
-
self.primary_keys = keys.map { |k| k.to_sym }.to_composite_keys
|
20
|
+
@primary_keys = keys.map { |k| k.to_sym }.to_composite_keys
|
20
21
|
|
21
22
|
class_eval <<-EOV
|
22
23
|
extend CompositeClassMethods
|
@@ -24,6 +25,19 @@ module ActiveRecord
|
|
24
25
|
EOV
|
25
26
|
end
|
26
27
|
|
28
|
+
def set_primary_keys(*keys)
|
29
|
+
ActiveSupport::Deprecation.warn(
|
30
|
+
"Calling self.primary_keys = is deprecated. Please use `self.primary_keys = keys` instead."
|
31
|
+
)
|
32
|
+
|
33
|
+
keys = keys.first if keys.first.is_a?(Array)
|
34
|
+
if keys.length == 1
|
35
|
+
self.primary_key = keys.first
|
36
|
+
else
|
37
|
+
self.primary_keys = keys
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
27
41
|
def composite?
|
28
42
|
false
|
29
43
|
end
|
@@ -107,7 +121,7 @@ module ActiveRecord
|
|
107
121
|
unless ids.is_a?(Array) and ids.length == self.class.primary_keys.length
|
108
122
|
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
109
123
|
end
|
110
|
-
[primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
124
|
+
[self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
111
125
|
id
|
112
126
|
end
|
113
127
|
|
@@ -120,7 +134,7 @@ module ActiveRecord
|
|
120
134
|
end
|
121
135
|
|
122
136
|
# Returns this record's primary keys values in an Array
|
123
|
-
# if any value is
|
137
|
+
# if any value is available
|
124
138
|
def to_key
|
125
139
|
ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
|
126
140
|
end
|
@@ -7,12 +7,25 @@ module CompositePrimaryKeys
|
|
7
7
|
Arel::Nodes::And.new(predicates)
|
8
8
|
end
|
9
9
|
end
|
10
|
-
|
11
|
-
def
|
12
|
-
|
13
|
-
|
10
|
+
|
11
|
+
def figure_engine(table)
|
12
|
+
case table
|
13
|
+
when Arel::Nodes::TableAlias
|
14
|
+
table.left.engine
|
15
|
+
when Arel::Table
|
16
|
+
table.engine
|
17
|
+
when ::ActiveRecord::Base
|
18
|
+
table
|
19
|
+
else
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def cpk_or_predicate(predicates, table = nil)
|
25
|
+
engine = figure_engine(table)
|
14
26
|
predicates = predicates.map do |predicate|
|
15
|
-
|
27
|
+
predicate_sql = engine ? predicate.to_sql(engine) : predicate.to_sql
|
28
|
+
"(#{predicate_sql})"
|
16
29
|
end
|
17
30
|
predicates = "(#{predicates.join(" OR ")})"
|
18
31
|
Arel::Nodes::SqlLiteral.new(predicates)
|
@@ -43,7 +56,7 @@ module CompositePrimaryKeys
|
|
43
56
|
cpk_and_predicate(eq_predicates)
|
44
57
|
end
|
45
58
|
|
46
|
-
cpk_or_predicate(and_predicates)
|
59
|
+
cpk_or_predicate(and_predicates, table)
|
47
60
|
end
|
48
61
|
end
|
49
62
|
end
|
@@ -1,6 +1,19 @@
|
|
1
1
|
module CompositePrimaryKeys
|
2
2
|
module ActiveRecord
|
3
3
|
module Calculations
|
4
|
+
def aggregate_column(column_name)
|
5
|
+
# CPK
|
6
|
+
if column_name.kind_of?(Array)
|
7
|
+
column_name.map do |column|
|
8
|
+
Arel::Attribute.new(@klass.unscoped.table, column)
|
9
|
+
end
|
10
|
+
elsif @klass.column_names.include?(column_name.to_s)
|
11
|
+
Arel::Attribute.new(@klass.unscoped.table, column_name)
|
12
|
+
else
|
13
|
+
Arel.sql(column_name == :all ? "*" : column_name.to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
4
17
|
def execute_simple_calculation(operation, column_name, distinct)
|
5
18
|
# Postgresql doesn't like ORDER BY when there are no GROUP BY
|
6
19
|
relation = reorder(nil)
|
@@ -33,8 +46,18 @@ module CompositePrimaryKeys
|
|
33
46
|
# CPK
|
34
47
|
# aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
|
35
48
|
# relation.select_values = [aliased_column]
|
36
|
-
|
37
|
-
|
49
|
+
relation.select_values = if column_name.kind_of?(Array)
|
50
|
+
column_name.map do |column|
|
51
|
+
Arel::Attribute.new(@klass.unscoped.table, column)
|
52
|
+
end
|
53
|
+
elsif @klass.column_names.include?(column_name.to_s)
|
54
|
+
[Arel::Attribute.new(@klass.unscoped.table, column_name)]
|
55
|
+
else
|
56
|
+
[Arel.sql(column_name == :all ? "#{@klass.quoted_table_name}.*" : column_name.to_s)]
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
relation.distinct(true)
|
38
61
|
subquery = relation.arel.as(subquery_alias)
|
39
62
|
|
40
63
|
sm = Arel::SelectManager.new relation.engine
|
@@ -56,9 +56,11 @@ module CompositePrimaryKeys
|
|
56
56
|
when CompositePrimaryKeys::CompositeKeys
|
57
57
|
relation = relation.where(cpk_id_predicate(table, primary_key, id))
|
58
58
|
when Array
|
59
|
-
|
59
|
+
pk_length = @klass.primary_keys.length
|
60
|
+
|
61
|
+
if id.length == pk_length # E.g. id = ['France', 'Paris']
|
60
62
|
return self.exists?(id.to_composite_keys)
|
61
|
-
else
|
63
|
+
else # Assume that id contains where relation
|
62
64
|
relation = relation.where(id)
|
63
65
|
end
|
64
66
|
when Hash
|
@@ -80,8 +82,10 @@ module CompositePrimaryKeys
|
|
80
82
|
# find('1,2', '3,4') -> ['1,2','3,4']
|
81
83
|
|
82
84
|
# Normalize incoming data. Note the last arg can be nil. Happens
|
83
|
-
# when find is called with nil options
|
85
|
+
# when find is called with nil options which is then passed on
|
86
|
+
# to find_with_ids.
|
84
87
|
ids.compact!
|
88
|
+
|
85
89
|
ids = [ids] unless ids.first.kind_of?(Array)
|
86
90
|
|
87
91
|
results = ids.map do |cpk_ids|
|
data/tasks/databases/mysql.rake
CHANGED
@@ -2,20 +2,30 @@ require File.join(PROJECT_ROOT, 'lib', 'composite_primary_keys')
|
|
2
2
|
require File.join(PROJECT_ROOT, 'test', 'connections', 'connection_spec')
|
3
3
|
|
4
4
|
namespace :mysql do
|
5
|
+
desc 'Create the MySQL test databases'
|
6
|
+
task :create_database do
|
7
|
+
ActiveRecord::Base.clear_all_connections!
|
8
|
+
spec = CompositePrimaryKeys::ConnectionSpec['mysql'].dup
|
9
|
+
database_name = spec.delete('database')
|
10
|
+
connection = ActiveRecord::Base.establish_connection(spec)
|
11
|
+
ActiveRecord::Base.connection.create_database(database_name)
|
12
|
+
ActiveRecord::Base.clear_all_connections!
|
13
|
+
end
|
14
|
+
|
5
15
|
desc 'Build the MySQL test databases'
|
6
|
-
task :build_databases => :
|
7
|
-
|
8
|
-
|
9
|
-
|
16
|
+
task :build_databases => [:create_database] do
|
17
|
+
path = File.join(PROJECT_ROOT, 'test', 'fixtures', 'db_definitions', 'mysql.sql')
|
18
|
+
sql = File.open(path, 'rb') do |file|
|
19
|
+
file.read
|
20
|
+
end
|
10
21
|
|
11
|
-
|
12
|
-
|
22
|
+
Rake::Task['mysql:load_connection'].invoke
|
23
|
+
ActiveRecord::Base.connection.execute(sql)
|
13
24
|
end
|
14
25
|
|
15
26
|
desc 'Drop the MySQL test databases'
|
16
|
-
task :drop_databases => :load_connection do
|
17
|
-
|
18
|
-
sh %{ mysqladmin #{options_str} -f drop "#{SPEC['database']}" }
|
27
|
+
task :drop_databases => :load_connection do
|
28
|
+
ActiveRecord::Base.connection.drop_database(SPEC['database'])
|
19
29
|
end
|
20
30
|
|
21
31
|
desc 'Rebuild the MySQL test databases'
|
@@ -2,17 +2,37 @@ require File.join(PROJECT_ROOT, 'lib', 'composite_primary_keys')
|
|
2
2
|
require File.join(PROJECT_ROOT, 'test', 'connections', 'connection_spec')
|
3
3
|
|
4
4
|
namespace :postgresql do
|
5
|
+
desc 'Create the PostgreSQL test databases'
|
6
|
+
task :create_database do
|
7
|
+
ActiveRecord::Base.clear_all_connections!
|
8
|
+
spec = CompositePrimaryKeys::ConnectionSpec['postgresql'].dup
|
9
|
+
database_name = spec.delete('database')
|
10
|
+
spec['database'] = 'postgres'
|
11
|
+
connection = ActiveRecord::Base.establish_connection(spec)
|
12
|
+
ActiveRecord::Base.connection.create_database(database_name)
|
13
|
+
ActiveRecord::Base.clear_all_connections!
|
14
|
+
end
|
15
|
+
|
5
16
|
desc 'Build the PostgreSQL test databases'
|
6
|
-
task :build_databases => :
|
7
|
-
|
17
|
+
task :build_databases => [:create_database] do
|
18
|
+
path = File.join(PROJECT_ROOT, 'test', 'fixtures', 'db_definitions', 'postgresql.sql')
|
19
|
+
sql = File.open(path, 'rb') do |file|
|
20
|
+
file.read
|
21
|
+
end
|
8
22
|
|
9
|
-
|
10
|
-
|
23
|
+
Rake::Task['postgresql:load_connection'].invoke
|
24
|
+
ActiveRecord::Base.connection.execute(sql)
|
11
25
|
end
|
12
26
|
|
13
27
|
desc 'Drop the PostgreSQL test databases'
|
14
|
-
task :drop_databases => :load_connection do
|
15
|
-
|
28
|
+
task :drop_databases => :load_connection do
|
29
|
+
ActiveRecord::Base.clear_all_connections!
|
30
|
+
spec = CompositePrimaryKeys::ConnectionSpec['postgresql'].dup
|
31
|
+
database_name = spec.delete('database')
|
32
|
+
spec['database'] = 'postgres'
|
33
|
+
connection = ActiveRecord::Base.establish_connection(spec)
|
34
|
+
ActiveRecord::Base.connection.drop_database(SPEC['database'])
|
35
|
+
ActiveRecord::Base.clear_all_connections!
|
16
36
|
end
|
17
37
|
|
18
38
|
desc 'Rebuild the PostgreSQL test databases'
|
data/test/abstract_unit.rb
CHANGED
@@ -9,11 +9,13 @@ require 'composite_primary_keys'
|
|
9
9
|
|
10
10
|
# Now load the connection spec
|
11
11
|
require File.join(PROJECT_ROOT, "test", "connections", "connection_spec")
|
12
|
-
|
12
|
+
|
13
|
+
spec_name = ENV['ADAPTER'] || 'postgresql'
|
14
|
+
spec = CompositePrimaryKeys::ConnectionSpec[spec_name]
|
13
15
|
|
14
16
|
# And now connect to the database
|
15
17
|
adapter = spec['adapter']
|
16
|
-
require File.join(PROJECT_ROOT, "test", "connections", "native_#{
|
18
|
+
require File.join(PROJECT_ROOT, "test", "connections", "native_#{spec_name}", "connection")
|
17
19
|
|
18
20
|
# Tell active record about the configuration
|
19
21
|
ActiveRecord::Base.configurations[:test] = spec
|
data/test/db_test.rb
CHANGED
@@ -24,7 +24,7 @@ end
|
|
24
24
|
module GlobePG
|
25
25
|
class TeacherToSchool < PGBase
|
26
26
|
set_table_name 'teacher_to_school'
|
27
|
-
|
27
|
+
self.primary_keys = ['teacherid', 'schoolid']
|
28
28
|
|
29
29
|
belongs_to :globe_teacher, :foreign_key => 'teacherid'
|
30
30
|
belongs_to :globe_school, :foreign_key => 'schoolid'
|
@@ -34,7 +34,7 @@ end
|
|
34
34
|
module GlobePG
|
35
35
|
class GlobeSchool < PGBase
|
36
36
|
set_table_name 'globe_school'
|
37
|
-
|
37
|
+
self.primary_key = 'schoolid'
|
38
38
|
has_many :teacher_to_schools, :foreign_key => :schoolid
|
39
39
|
has_many :globe_teachers, :through => :teacher_to_schools
|
40
40
|
end
|
@@ -43,7 +43,7 @@ end
|
|
43
43
|
module GlobePG
|
44
44
|
class GlobeTeacher < PGBase
|
45
45
|
set_table_name 'globe_teacher'
|
46
|
-
|
46
|
+
self.primary_key = 'teacherid'
|
47
47
|
has_many :teacher_to_schools, :foreign_key => :teacherid
|
48
48
|
has_many :globe_schools, :through => :teacher_to_schools
|
49
49
|
end
|
data/test/fixtures/capitol.rb
CHANGED
@@ -1,186 +1,186 @@
|
|
1
1
|
create table reference_types (
|
2
|
-
reference_type_id int
|
2
|
+
reference_type_id int not null auto_increment,
|
3
3
|
type_label varchar(50) default null,
|
4
4
|
abbreviation varchar(50) default null,
|
5
5
|
description varchar(50) default null,
|
6
6
|
primary key (reference_type_id)
|
7
|
-
)
|
7
|
+
);
|
8
8
|
|
9
9
|
create table reference_codes (
|
10
|
-
reference_type_id int
|
11
|
-
reference_code int
|
10
|
+
reference_type_id int not null,
|
11
|
+
reference_code int not null,
|
12
12
|
code_label varchar(50) default null,
|
13
13
|
abbreviation varchar(50) default null,
|
14
14
|
description varchar(50) default null,
|
15
15
|
primary key (reference_type_id, reference_code)
|
16
|
-
)
|
16
|
+
);
|
17
17
|
|
18
18
|
create table products (
|
19
|
-
id int
|
19
|
+
id int not null auto_increment,
|
20
20
|
name varchar(50) default null,
|
21
21
|
primary key (id)
|
22
|
-
)
|
22
|
+
);
|
23
23
|
|
24
24
|
create table tariffs (
|
25
|
-
tariff_id int
|
25
|
+
tariff_id int not null,
|
26
26
|
start_date date not null,
|
27
27
|
amount integer(11) default null,
|
28
28
|
primary key (tariff_id, start_date)
|
29
|
-
)
|
29
|
+
);
|
30
30
|
|
31
31
|
create table product_tariffs (
|
32
|
-
product_id int
|
33
|
-
tariff_id int
|
32
|
+
product_id int not null,
|
33
|
+
tariff_id int not null,
|
34
34
|
tariff_start_date date not null,
|
35
35
|
primary key (product_id, tariff_id, tariff_start_date)
|
36
|
-
)
|
36
|
+
);
|
37
37
|
|
38
38
|
create table suburbs (
|
39
|
-
city_id int
|
40
|
-
suburb_id int
|
39
|
+
city_id int not null,
|
40
|
+
suburb_id int not null,
|
41
41
|
name varchar(50) not null,
|
42
42
|
primary key (city_id, suburb_id)
|
43
|
-
)
|
43
|
+
);
|
44
44
|
|
45
45
|
create table streets (
|
46
|
-
id int
|
47
|
-
city_id int
|
48
|
-
suburb_id int
|
46
|
+
id int not null auto_increment,
|
47
|
+
city_id int not null,
|
48
|
+
suburb_id int not null,
|
49
49
|
name varchar(50) not null,
|
50
50
|
primary key (id)
|
51
|
-
)
|
51
|
+
);
|
52
52
|
|
53
53
|
create table users (
|
54
|
-
id int
|
54
|
+
id int not null auto_increment,
|
55
55
|
name varchar(50) not null,
|
56
56
|
primary key (id)
|
57
|
-
)
|
57
|
+
);
|
58
58
|
|
59
59
|
create table articles (
|
60
|
-
id int
|
60
|
+
id int not null auto_increment,
|
61
61
|
name varchar(50) not null,
|
62
62
|
primary key (id)
|
63
|
-
)
|
63
|
+
);
|
64
64
|
|
65
65
|
create table readings (
|
66
|
-
id int
|
67
|
-
user_id int
|
68
|
-
article_id int
|
69
|
-
rating int
|
66
|
+
id int not null auto_increment,
|
67
|
+
user_id int not null,
|
68
|
+
article_id int not null,
|
69
|
+
rating int not null,
|
70
70
|
primary key (id)
|
71
|
-
)
|
71
|
+
);
|
72
72
|
|
73
73
|
create table groups (
|
74
|
-
id int
|
74
|
+
id int not null auto_increment,
|
75
75
|
name varchar(50) not null,
|
76
76
|
primary key (id)
|
77
|
-
)
|
77
|
+
);
|
78
78
|
|
79
79
|
create table memberships (
|
80
|
-
user_id int
|
81
|
-
group_id int
|
80
|
+
user_id int not null,
|
81
|
+
group_id int not null,
|
82
82
|
primary key (user_id,group_id)
|
83
|
-
)
|
83
|
+
);
|
84
84
|
|
85
85
|
create table membership_statuses (
|
86
|
-
id int
|
87
|
-
user_id int
|
88
|
-
group_id int
|
86
|
+
id int not null auto_increment,
|
87
|
+
user_id int not null,
|
88
|
+
group_id int not null,
|
89
89
|
status varchar(50) not null,
|
90
90
|
primary key (id)
|
91
|
-
)
|
91
|
+
);
|
92
92
|
|
93
93
|
create table departments (
|
94
|
-
department_id int
|
95
|
-
location_id int
|
94
|
+
department_id int not null,
|
95
|
+
location_id int not null,
|
96
96
|
primary key (department_id, location_id)
|
97
|
-
)
|
97
|
+
);
|
98
98
|
|
99
99
|
create table employees (
|
100
|
-
id int
|
101
|
-
department_id int
|
102
|
-
location_id int
|
100
|
+
id int not null auto_increment,
|
101
|
+
department_id int default null,
|
102
|
+
location_id int default null,
|
103
103
|
primary key (id)
|
104
|
-
)
|
104
|
+
);
|
105
105
|
|
106
106
|
create table comments (
|
107
|
-
id int
|
108
|
-
person_id int
|
107
|
+
id int not null auto_increment,
|
108
|
+
person_id int default null,
|
109
109
|
person_type varchar(100) default null,
|
110
|
-
hack_id int
|
110
|
+
hack_id int default null,
|
111
111
|
primary key (id)
|
112
|
-
)
|
112
|
+
);
|
113
113
|
|
114
114
|
create table hacks (
|
115
|
-
id int
|
115
|
+
id int not null auto_increment,
|
116
116
|
name varchar(50) not null,
|
117
117
|
primary key (id)
|
118
|
-
)
|
118
|
+
);
|
119
119
|
|
120
120
|
create table restaurants (
|
121
|
-
franchise_id int
|
122
|
-
store_id int
|
121
|
+
franchise_id int not null,
|
122
|
+
store_id int not null,
|
123
123
|
name varchar(100),
|
124
124
|
primary key (franchise_id, store_id)
|
125
|
-
)
|
125
|
+
);
|
126
126
|
|
127
127
|
create table restaurants_suburbs (
|
128
|
-
franchise_id int
|
129
|
-
store_id int
|
130
|
-
city_id int
|
131
|
-
suburb_id int
|
132
|
-
)
|
128
|
+
franchise_id int not null,
|
129
|
+
store_id int not null,
|
130
|
+
city_id int not null,
|
131
|
+
suburb_id int not null
|
132
|
+
);
|
133
133
|
|
134
134
|
create table dorms (
|
135
|
-
id int
|
135
|
+
id int not null auto_increment,
|
136
136
|
primary key(id)
|
137
|
-
)
|
137
|
+
);
|
138
138
|
|
139
139
|
create table rooms (
|
140
|
-
dorm_id int
|
141
|
-
room_id int
|
140
|
+
dorm_id int not null,
|
141
|
+
room_id int not null,
|
142
142
|
primary key (dorm_id, room_id)
|
143
|
-
)
|
143
|
+
);
|
144
144
|
|
145
145
|
create table room_attributes (
|
146
|
-
id int
|
146
|
+
id int not null auto_increment,
|
147
147
|
name varchar(50),
|
148
148
|
primary key(id)
|
149
|
-
)
|
149
|
+
);
|
150
150
|
|
151
151
|
create table room_attribute_assignments (
|
152
|
-
dorm_id int
|
153
|
-
room_id int
|
154
|
-
room_attribute_id int
|
155
|
-
)
|
152
|
+
dorm_id int not null,
|
153
|
+
room_id int not null,
|
154
|
+
room_attribute_id int not null
|
155
|
+
);
|
156
156
|
|
157
157
|
create table students (
|
158
|
-
id int
|
158
|
+
id int not null auto_increment,
|
159
159
|
primary key(id)
|
160
|
-
)
|
160
|
+
);
|
161
161
|
|
162
162
|
create table room_assignments (
|
163
|
-
student_id int
|
164
|
-
dorm_id int
|
165
|
-
room_id int
|
166
|
-
)
|
163
|
+
student_id int not null,
|
164
|
+
dorm_id int not null,
|
165
|
+
room_id int not null
|
166
|
+
);
|
167
167
|
|
168
168
|
create table seats (
|
169
|
-
flight_number int
|
170
|
-
seat int
|
169
|
+
flight_number int not null,
|
170
|
+
seat int not null,
|
171
171
|
customer int,
|
172
172
|
primary key (flight_number, seat)
|
173
|
-
)
|
173
|
+
);
|
174
174
|
|
175
175
|
create table capitols (
|
176
176
|
country varchar(100) default null,
|
177
177
|
city varchar(100) default null,
|
178
178
|
primary key (country, city)
|
179
|
-
)
|
179
|
+
);
|
180
180
|
|
181
181
|
create table products_restaurants (
|
182
|
-
product_id int
|
183
|
-
franchise_id int
|
184
|
-
store_id int
|
185
|
-
)
|
182
|
+
product_id int not null,
|
183
|
+
franchise_id int not null,
|
184
|
+
store_id int not null
|
185
|
+
);
|
186
186
|
|
data/test/fixtures/department.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Department < ActiveRecord::Base
|
2
|
-
|
2
|
+
self.primary_keys = :department_id, :location_id
|
3
3
|
has_many :employees, :foreign_key => [:department_id, :location_id]
|
4
4
|
has_one :head, :class_name => 'Employee', :foreign_key => [:department_id, :location_id], :dependent => :delete
|
5
5
|
end
|
data/test/fixtures/dorm.rb
CHANGED
data/test/fixtures/membership.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Membership < ActiveRecord::Base
|
2
|
-
#
|
3
|
-
|
2
|
+
# self.primary_keys = *keys - turns on composite key functionality
|
3
|
+
self.primary_keys = :user_id, :group_id
|
4
4
|
belongs_to :user
|
5
5
|
belongs_to :group
|
6
6
|
has_many :statuses, :class_name => 'MembershipStatus', :foreign_key => [:user_id, :group_id]
|
data/test/fixtures/product.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Product < ActiveRecord::Base
|
2
|
-
|
2
|
+
self.primary_keys = :id # redundant
|
3
3
|
has_many :product_tariffs, :foreign_key => :product_id, :dependent => :delete_all
|
4
4
|
has_many :tariffs, :through => :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
|
5
5
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class ProductTariff < ActiveRecord::Base
|
2
|
-
|
2
|
+
self.primary_keys = :product_id, :tariff_id, :tariff_start_date
|
3
3
|
belongs_to :product, :foreign_key => :product_id
|
4
4
|
belongs_to :tariff, :foreign_key => [:tariff_id, :tariff_start_date]
|
5
5
|
end
|
data/test/fixtures/restaurant.rb
CHANGED
data/test/fixtures/room.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Room < ActiveRecord::Base
|
2
|
-
|
2
|
+
self.primary_keys = :dorm_id, :room_id
|
3
3
|
belongs_to :dorm
|
4
4
|
has_many :room_assignments, :foreign_key => [:dorm_id, :room_id]
|
5
5
|
has_many :room_attribute_assignments, :foreign_key => [:dorm_id, :room_id]
|
data/test/fixtures/seat.rb
CHANGED
data/test/fixtures/suburb.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Suburb < ActiveRecord::Base
|
2
|
-
|
2
|
+
self.primary_keys = :city_id, :suburb_id
|
3
3
|
has_many :streets, :foreign_key => [:city_id, :suburb_id]
|
4
4
|
has_many :first_streets, :foreign_key => [:city_id, :suburb_id],
|
5
5
|
:class_name => 'Street', :conditions => "streets.name = 'First Street'"
|
data/test/fixtures/tariff.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class Tariff < ActiveRecord::Base
|
2
|
-
|
2
|
+
self.primary_keys = [:tariff_id, :start_date]
|
3
3
|
has_many :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
|
4
4
|
has_many :products, :through => :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
|
5
5
|
end
|
data/test/test_associations.rb
CHANGED
@@ -5,27 +5,6 @@ class TestAssociations < ActiveSupport::TestCase
|
|
5
5
|
:dorms, :rooms, :room_attributes, :room_attribute_assignments, :students, :room_assignments, :users, :readings,
|
6
6
|
:departments, :employees, :memberships, :membership_statuses
|
7
7
|
|
8
|
-
def test_count
|
9
|
-
assert_equal(3, Product.count(:include => :product_tariffs))
|
10
|
-
assert_equal(3, Tariff.count(:include => :product_tariffs))
|
11
|
-
|
12
|
-
expected = {Date.today => 2,
|
13
|
-
Date.today.next => 1}
|
14
|
-
|
15
|
-
assert_equal(expected, Tariff.count(:group => :start_date))
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_count_distinct
|
19
|
-
product = products(:first_product)
|
20
|
-
assert_equal(2, product.product_tariffs.count(:distinct => true))
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_count_includes
|
24
|
-
count = Dorm.count(:include => :rooms,
|
25
|
-
:conditions => ["rooms.room_id = ?", 2])
|
26
|
-
assert_equal(1, count)
|
27
|
-
end
|
28
|
-
|
29
8
|
def test_products
|
30
9
|
assert_not_nil products(:first_product).product_tariffs
|
31
10
|
assert_equal 2, products(:first_product).product_tariffs.length
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestCalculations < ActiveSupport::TestCase
|
4
|
+
fixtures :articles, :products, :tariffs, :product_tariffs, :suburbs, :streets, :restaurants,
|
5
|
+
:dorms, :rooms, :room_attributes, :room_attribute_assignments, :students, :room_assignments, :users, :readings,
|
6
|
+
:departments, :employees, :memberships, :membership_statuses
|
7
|
+
|
8
|
+
def test_count
|
9
|
+
assert_equal(3, Product.count(:include => :product_tariffs))
|
10
|
+
assert_equal(3, Tariff.count(:include => :product_tariffs))
|
11
|
+
|
12
|
+
expected = {Date.today => 2,
|
13
|
+
Date.today.next => 1}
|
14
|
+
|
15
|
+
assert_equal(expected, Tariff.count(:group => :start_date))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_count_distinct
|
19
|
+
product = products(:first_product)
|
20
|
+
assert_equal(2, product.product_tariffs.count(:distinct => true))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_count_includes
|
24
|
+
count = Dorm.count(:include => :rooms,
|
25
|
+
:conditions => ["rooms.room_id = ?", 2])
|
26
|
+
assert_equal(1, count)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_count_includes_dup_columns
|
30
|
+
count = Tariff.includes(:product_tariffs).where("product_tariffs.tariff_id = ?", 2).count
|
31
|
+
assert_equal(1, count)
|
32
|
+
end
|
33
|
+
end
|
data/test/test_exists.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path('../abstract_unit', __FILE__)
|
2
2
|
|
3
3
|
class TestExists < ActiveSupport::TestCase
|
4
|
-
fixtures :articles, :departments
|
4
|
+
fixtures :articles, :departments, :capitols
|
5
5
|
|
6
6
|
def test_id
|
7
7
|
assert(Article.exists?(1))
|
@@ -32,4 +32,9 @@ class TestExists < ActiveSupport::TestCase
|
|
32
32
|
assert(Department.exists?(['department_id = ? and location_id = ?', 1, 1]))
|
33
33
|
assert(!Department.exists?(['department_id = ? and location_id = ?', 1, -1]))
|
34
34
|
end
|
35
|
+
|
36
|
+
def test_cpk_array_string_id
|
37
|
+
assert(Capitol.exists?(['The Netherlands', 'Amsterdam']))
|
38
|
+
assert(!Capitol.exists?(['The Netherlands', 'Paris']))
|
39
|
+
end
|
35
40
|
end
|
data/test/test_find.rb
CHANGED
@@ -50,7 +50,13 @@ class TestFind < ActiveSupport::TestCase
|
|
50
50
|
error = assert_raise(::ActiveRecord::RecordNotFound) do
|
51
51
|
ReferenceCode.find(['999', '999'])
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
|
+
connection = ActiveRecord::Base.connection
|
55
|
+
ref_type_quoted = "#{connection.quote_table_name('reference_codes')}.#{connection.quote_column_name('reference_type_id')}"
|
56
|
+
ref_code_quoted = "#{connection.quote_table_name('reference_codes')}.#{connection.quote_column_name('reference_code')}"
|
57
|
+
expected = "Couldn't find ReferenceCode with ID=999,999 WHERE #{ref_type_quoted} = 999 AND #{ref_code_quoted} = 999"
|
58
|
+
|
59
|
+
assert_equal(with_quoted_identifiers(expected),
|
54
60
|
error.message)
|
55
61
|
end
|
56
62
|
|
data/test/test_miscellaneous.rb
CHANGED
data/test/test_predicates.rb
CHANGED
@@ -14,9 +14,12 @@ class TestEqual < ActiveSupport::TestCase
|
|
14
14
|
predicates << dep[:id].eq(i)
|
15
15
|
end
|
16
16
|
|
17
|
+
connection = ActiveRecord::Base.connection
|
18
|
+
quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
|
19
|
+
expected = "((#{quoted} = 0) OR (#{quoted} = 1) OR (#{quoted} = 2))"
|
20
|
+
|
17
21
|
pred = cpk_or_predicate(predicates)
|
18
|
-
assert_equal(with_quoted_identifiers(
|
19
|
-
pred)
|
22
|
+
assert_equal(with_quoted_identifiers(expected), pred.to_s)
|
20
23
|
end
|
21
24
|
|
22
25
|
def test_and
|
@@ -28,8 +31,11 @@ class TestEqual < ActiveSupport::TestCase
|
|
28
31
|
predicates << dep[:id].eq(i)
|
29
32
|
end
|
30
33
|
|
34
|
+
connection = ActiveRecord::Base.connection
|
35
|
+
quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
|
36
|
+
expected = "#{quoted} = 0 AND #{quoted} = 1 AND #{quoted} = 2"
|
37
|
+
|
31
38
|
pred = cpk_and_predicate(predicates)
|
32
|
-
assert_equal(with_quoted_identifiers(
|
33
|
-
pred.to_sql)
|
39
|
+
assert_equal(with_quoted_identifiers(expected), pred.to_sql)
|
34
40
|
end
|
35
41
|
end
|
data/test/test_suite.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composite_primary_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0.0
|
5
|
-
prerelease:
|
4
|
+
version: 5.0.0
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Dr Nic Williams
|
@@ -10,22 +10,21 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-02-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
17
|
-
requirement: &
|
17
|
+
requirement: &24424140 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 3.2.0
|
22
|
+
version: 3.2.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
26
|
-
description: Composite key support for ActiveRecord
|
27
|
-
email:
|
28
|
-
- drnicwilliams@gmail.com
|
25
|
+
version_requirements: *24424140
|
26
|
+
description: Composite key support for ActiveRecord
|
27
|
+
email:
|
29
28
|
executables: []
|
30
29
|
extensions: []
|
31
30
|
extra_rdoc_files: []
|
@@ -154,6 +153,7 @@ files:
|
|
154
153
|
- test/test_associations.rb
|
155
154
|
- test/test_attributes.rb
|
156
155
|
- test/test_attribute_methods.rb
|
156
|
+
- test/test_calculations.rb
|
157
157
|
- test/test_composite_arrays.rb
|
158
158
|
- test/test_create.rb
|
159
159
|
- test/test_delete.rb
|
@@ -172,7 +172,7 @@ files:
|
|
172
172
|
- test/test_tutorial_example.rb
|
173
173
|
- test/test_update.rb
|
174
174
|
- test/test_validations.rb
|
175
|
-
homepage:
|
175
|
+
homepage: https://github.com/drnic/composite_primary_keys
|
176
176
|
licenses: []
|
177
177
|
post_install_message:
|
178
178
|
rdoc_options: []
|
@@ -187,9 +187,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
188
|
none: false
|
189
189
|
requirements:
|
190
|
-
- - ! '
|
190
|
+
- - ! '>='
|
191
191
|
- !ruby/object:Gem::Version
|
192
|
-
version:
|
192
|
+
version: '0'
|
193
193
|
requirements: []
|
194
194
|
rubyforge_project: compositekeys
|
195
195
|
rubygems_version: 1.8.15
|
@@ -205,6 +205,7 @@ test_files:
|
|
205
205
|
- test/test_associations.rb
|
206
206
|
- test/test_attributes.rb
|
207
207
|
- test/test_attribute_methods.rb
|
208
|
+
- test/test_calculations.rb
|
208
209
|
- test/test_composite_arrays.rb
|
209
210
|
- test/test_create.rb
|
210
211
|
- test/test_delete.rb
|