composite_primary_keys 5.0.0.rc1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|