composite_primary_keys 8.0.0 → 8.1.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.
- checksums.yaml +4 -4
- data/History.rdoc +26 -1
- data/README.rdoc +1 -0
- data/lib/composite_primary_keys.rb +3 -1
- data/lib/composite_primary_keys/associations/singular_association.rb +5 -2
- data/lib/composite_primary_keys/attribute_methods/read.rb +12 -7
- data/lib/composite_primary_keys/composite_arrays.rb +14 -1
- data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +3 -0
- data/lib/composite_primary_keys/connection_adapters/sqlserver_adapter.rb +17 -0
- data/lib/composite_primary_keys/core.rb +37 -45
- data/lib/composite_primary_keys/locking/optimistic.rb +55 -0
- data/lib/composite_primary_keys/relation/finder_methods.rb +12 -8
- data/lib/composite_primary_keys/version.rb +1 -1
- data/test/connections/databases.example.yml +7 -0
- data/test/fixtures/db_definitions/db2-create-tables.sql +1 -0
- data/test/fixtures/db_definitions/mysql.sql +11 -0
- data/test/fixtures/db_definitions/oracle.sql +1 -0
- data/test/fixtures/db_definitions/postgresql.sql +11 -0
- data/test/fixtures/db_definitions/sqlite.sql +10 -0
- data/test/fixtures/db_definitions/sqlserver.sql +3 -2
- data/test/fixtures/employee.rb +6 -0
- data/test/fixtures/salary.rb +5 -0
- data/test/test_associations.rb +45 -0
- data/test/test_attributes.rb +2 -2
- data/test/test_create.rb +46 -1
- data/test/test_delete.rb +10 -0
- data/test/test_optimistic.rb +18 -0
- data/test/test_suite.rb +1 -0
- data/test/test_tutorial_example.rb +8 -4
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbf168474ed65f8ab1b123eec93d3e63fa218e8a
|
4
|
+
data.tar.gz: 4e3168853f10d4bd5fd564e6beb27972dbee0588
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e486302769c4f5fab7270a6f3ca684bfdbf1826aa7ae16d9a11b0d4883ab97d93361bb22dff69389c1f2eabc133a201b4f1a4b1150b371f73d4bb16f5d32cb4
|
7
|
+
data.tar.gz: 2d740b4e57d3f206956b202cfbde77b0acb550da97c14d717369c06666c1dfa9098ad8a5159bfa40826f124161c637870b3a61d624a68d5e83ae7276571e3d73
|
data/History.rdoc
CHANGED
@@ -1,7 +1,26 @@
|
|
1
|
-
== 8.
|
1
|
+
== 8.1.0 (2014-03-23)
|
2
|
+
|
3
|
+
* ActiveRecord 4.2.1 support (Charlie Savage)
|
4
|
+
* Change parsing of composite ids to fix #290 (Charlie Savage)
|
5
|
+
* Add sqlserver setting for test suite (Joachim Herb)
|
6
|
+
* Fix sqlserver adapater, isse #224 (Joachim Herb)
|
7
|
+
* Update readme file to include version 8.* information (David Silva)
|
8
|
+
|
9
|
+
|
10
|
+
== 8.0.1 (2014-01-24)
|
11
|
+
|
12
|
+
* Support optimistic lock and lock_version added to existing fixtures (Kirika)
|
13
|
+
|
14
|
+
== 8.0.0 (2014-01-10)
|
2
15
|
|
3
16
|
* ActiveRecord 4.2.* support (Sammy Larbi)
|
4
17
|
|
18
|
+
== 7.0.13 (2015-01-24)
|
19
|
+
|
20
|
+
* Support optimistic lock and lock_version added to existing fixtures (Kirika)
|
21
|
+
* README change to convey finding available versions (Aaron Bartell)
|
22
|
+
* Fixes indentation in product_tariffs (Zaldabus)
|
23
|
+
|
5
24
|
== 7.0.12 (2014-11-09)
|
6
25
|
|
7
26
|
* ActiveRecord 4.1.7 support (Tom Hughes)
|
@@ -88,6 +107,12 @@ The first one no longer works. It was removed because it made the internal code
|
|
88
107
|
and makes the intention of the code clearer (especially when finding multiple records).
|
89
108
|
If this change causes too much pain then please submit a ticket on Github.
|
90
109
|
|
110
|
+
== 6.0.08 (2015-01-24)
|
111
|
+
|
112
|
+
* Fix habtm association #delete_records (Uros Jurglic)
|
113
|
+
* Support optimistic locking (Toshio Maki)
|
114
|
+
* Remove singleton classes on CPK relations (Nicolás Hock Isaza)
|
115
|
+
|
91
116
|
== 6.0.7 (2014-10-06)
|
92
117
|
|
93
118
|
* Support Rails 4.0.6 (Tom Hughes)
|
data/README.rdoc
CHANGED
@@ -20,6 +20,7 @@ Every major version of ActiveRecord has included numerous internal changes. As
|
|
20
20
|
CPK has to be rewritten for each version of ActiveRecord. To help keep
|
21
21
|
things straight, here is the mapping:
|
22
22
|
|
23
|
+
Version 8.x is designed to work with ActiveRecord 4.2.x
|
23
24
|
Version 7.x is designed to work with ActiveRecord 4.1.x
|
24
25
|
Version 6.x is designed to work with ActiveRecord 4.0.x
|
25
26
|
Version 5.x is designed to work with ActiveRecord 3.2.x
|
@@ -26,7 +26,7 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
26
26
|
|
27
27
|
unless defined?(ActiveRecord)
|
28
28
|
require 'rubygems'
|
29
|
-
gem 'activerecord', '4.2.0'
|
29
|
+
gem 'activerecord', '~>4.2.0'
|
30
30
|
require 'active_record'
|
31
31
|
end
|
32
32
|
|
@@ -54,6 +54,7 @@ require 'active_record/attribute_set/builder'
|
|
54
54
|
require 'active_record/attribute_methods/primary_key'
|
55
55
|
require 'active_record/attribute_methods/read'
|
56
56
|
require 'active_record/attribute_methods/write'
|
57
|
+
require 'active_record/locking/optimistic'
|
57
58
|
require 'active_record/nested_attributes'
|
58
59
|
|
59
60
|
require 'active_record/connection_adapters/abstract_adapter'
|
@@ -97,6 +98,7 @@ require 'composite_primary_keys/attribute_methods/primary_key'
|
|
97
98
|
require 'composite_primary_keys/attribute_methods/dirty'
|
98
99
|
require 'composite_primary_keys/attribute_methods/read'
|
99
100
|
require 'composite_primary_keys/attribute_methods/write'
|
101
|
+
require 'composite_primary_keys/locking/optimistic'
|
100
102
|
require 'composite_primary_keys/nested_attributes'
|
101
103
|
|
102
104
|
require 'composite_primary_keys/connection_adapters/abstract_adapter'
|
@@ -3,7 +3,10 @@ module CompositePrimaryKeys
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
included do
|
5
5
|
def get_records_with_cpk_support
|
6
|
-
cpk_applies = (target && target.composite?) ||
|
6
|
+
cpk_applies = (target && target.composite?) ||
|
7
|
+
(owner && owner.composite?) ||
|
8
|
+
(options[:primary_key] && options[:primary_key].kind_of?(Array)) ||
|
9
|
+
(options[:foreign_key] && options[:foreign_key].kind_of?(Array))
|
7
10
|
return scope.limit(1).to_a if cpk_applies
|
8
11
|
get_records_without_cpk_support
|
9
12
|
end
|
@@ -12,4 +15,4 @@ module CompositePrimaryKeys
|
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
|
-
ActiveRecord::Associations::SingularAssociation.send(:include, CompositePrimaryKeys::SingularAssociation)
|
18
|
+
ActiveRecord::Associations::SingularAssociation.send(:include, CompositePrimaryKeys::SingularAssociation)
|
@@ -3,16 +3,21 @@ module ActiveRecord
|
|
3
3
|
module Read
|
4
4
|
def read_attribute(attr_name, &block)
|
5
5
|
# CPK
|
6
|
-
# name = attr_name.to_s
|
7
|
-
# name = self.class.primary_key if name == 'id'
|
8
|
-
# @attributes.fetch_value(name, &block)
|
9
|
-
|
10
6
|
if attr_name.kind_of?(Array)
|
11
|
-
attr_name
|
7
|
+
_read_attribute(attr_name, &block)
|
12
8
|
else
|
13
9
|
name = attr_name.to_s
|
14
|
-
name = self.class.primary_key if name == 'id'
|
15
|
-
|
10
|
+
name = self.class.primary_key if name == 'id'
|
11
|
+
_read_attribute(name, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def _read_attribute(attr_name)
|
16
|
+
# CPK
|
17
|
+
if attr_name.kind_of?(Array)
|
18
|
+
attr_name.map {|name| @attributes.fetch_value(name.to_s)}
|
19
|
+
else
|
20
|
+
@attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? }
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|
@@ -8,8 +8,21 @@ module CompositePrimaryKeys
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
+
def self.normalize(ids)
|
12
|
+
ids.map do |id|
|
13
|
+
if id.is_a?(Array)
|
14
|
+
normalize(id)
|
15
|
+
elsif id.is_a?(String) && id.index(ID_SEP)
|
16
|
+
id.split(ID_SEP)
|
17
|
+
else
|
18
|
+
id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
11
23
|
class CompositeKeys < Array
|
12
|
-
|
24
|
+
|
25
|
+
def self.parse(value)
|
13
26
|
case value
|
14
27
|
when Array
|
15
28
|
value.to_composite_keys
|
data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb
CHANGED
@@ -4,6 +4,9 @@ module ActiveRecord
|
|
4
4
|
if (adapter.to_s =~ /postgresql/) or (adapter.to_s =~ /postgis/)
|
5
5
|
require "composite_primary_keys/connection_adapters/postgresql_adapter.rb"
|
6
6
|
end
|
7
|
+
if (adapter.to_s =~ /sqlserver/)
|
8
|
+
require "composite_primary_keys/connection_adapters/sqlserver_adapter.rb"
|
9
|
+
end
|
7
10
|
end
|
8
11
|
|
9
12
|
def self.establish_connection(spec = ENV["DATABASE_URL"])
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class SQLServerAdapter
|
4
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
5
|
+
sql = if pk && self.class.use_output_inserted
|
6
|
+
# support composite primary keys consisting of more than one column name
|
7
|
+
quoted_pks = [pk].flatten.map {|pk| "INSERTED.#{SQLServer::Utils.extract_identifiers(pk).quoted}"}
|
8
|
+
sql.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT #{quoted_pks.join(", ")}"
|
9
|
+
# p sql
|
10
|
+
else
|
11
|
+
"#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
|
12
|
+
end
|
13
|
+
[sql, binds]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -16,54 +16,46 @@ module ActiveRecord
|
|
16
16
|
|
17
17
|
super
|
18
18
|
end
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
module CompositePrimaryKeys
|
26
|
-
module ActiveRecordCoreConcernIncludedExtension
|
27
|
-
extend ActiveSupport::Concern
|
28
19
|
|
29
|
-
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
20
|
+
module ClassMethods
|
21
|
+
def find(*ids) # :nodoc:
|
22
|
+
# We don't have cache keys for this stuff yet
|
23
|
+
return super unless ids.length == 1
|
24
|
+
# Allow symbols to super to maintain compatibility for deprecated finders until Rails 5
|
25
|
+
return super if ids.first.kind_of?(Symbol)
|
26
|
+
return super if block_given? ||
|
27
|
+
primary_key.nil? ||
|
28
|
+
default_scopes.any? ||
|
29
|
+
current_scope ||
|
30
|
+
columns_hash.include?(inheritance_column) ||
|
31
|
+
ids.first.kind_of?(Array)
|
32
|
+
|
33
|
+
# CPK
|
34
|
+
return super if self.composite?
|
35
|
+
|
36
|
+
id = ids.first
|
37
|
+
if ActiveRecord::Base === id
|
38
|
+
id = id.id
|
39
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
40
|
+
You are passing an instance of ActiveRecord::Base to `find`.
|
41
|
+
Please pass the id of the object by calling `.id`
|
42
|
+
MSG
|
35
43
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
result << [id]
|
47
|
-
end
|
48
|
-
elsif id.is_a?(Array) && id.count > 1 && id.first.to_s.index(",")
|
49
|
-
result << id.map{|subid| subid.split(",")}
|
50
|
-
else
|
51
|
-
result << [id]
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
copy_to_find_depth, depth = result.dup, -1
|
56
|
-
|
57
|
-
until copy_to_find_depth == result.flatten
|
58
|
-
depth += 1
|
59
|
-
copy_to_find_depth = copy_to_find_depth.flatten(1)
|
44
|
+
key = primary_key
|
45
|
+
|
46
|
+
s = find_by_statement_cache[key] || find_by_statement_cache.synchronize {
|
47
|
+
find_by_statement_cache[key] ||= StatementCache.create(connection) { |params|
|
48
|
+
where(key => params.bind).limit(1)
|
49
|
+
}
|
50
|
+
}
|
51
|
+
record = s.execute([id], self, connection).first
|
52
|
+
unless record
|
53
|
+
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
|
60
54
|
end
|
61
|
-
|
62
|
-
|
63
|
-
|
55
|
+
record
|
56
|
+
rescue RangeError
|
57
|
+
raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
|
64
58
|
end
|
65
59
|
end
|
66
60
|
end
|
67
|
-
end
|
68
|
-
|
69
|
-
ActiveRecord::Base.send(:include, CompositePrimaryKeys::ActiveRecordCoreConcernIncludedExtension)
|
61
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Locking
|
3
|
+
module Optimistic
|
4
|
+
private
|
5
|
+
def _update_record(attribute_names = @attributes.keys) #:nodoc:
|
6
|
+
return super unless locking_enabled?
|
7
|
+
return 0 if attribute_names.empty?
|
8
|
+
|
9
|
+
lock_col = self.class.locking_column
|
10
|
+
previous_lock_value = send(lock_col).to_i
|
11
|
+
increment_lock
|
12
|
+
|
13
|
+
attribute_names += [lock_col]
|
14
|
+
attribute_names.uniq!
|
15
|
+
|
16
|
+
begin
|
17
|
+
relation = self.class.unscoped
|
18
|
+
|
19
|
+
if self.composite?
|
20
|
+
stmt = relation.where(
|
21
|
+
relation.cpk_id_predicate(relation.table, self.class.primary_key, id_was).and(
|
22
|
+
relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
|
23
|
+
)
|
24
|
+
).arel.compile_update(
|
25
|
+
arel_attributes_with_values_for_update(attribute_names),
|
26
|
+
self.class.primary_key
|
27
|
+
)
|
28
|
+
else
|
29
|
+
stmt = relation.where(
|
30
|
+
relation.table[self.class.primary_key].eq(id).and(
|
31
|
+
relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
|
32
|
+
)
|
33
|
+
).arel.compile_update(
|
34
|
+
arel_attributes_with_values_for_update(attribute_names),
|
35
|
+
self.class.primary_key
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
affected_rows = self.class.connection.update stmt
|
40
|
+
|
41
|
+
unless affected_rows == 1
|
42
|
+
raise ActiveRecord::StaleObjectError.new(self, "update")
|
43
|
+
end
|
44
|
+
|
45
|
+
affected_rows
|
46
|
+
|
47
|
+
# If something went wrong, revert the version.
|
48
|
+
rescue Exception
|
49
|
+
send(lock_col + '=', previous_lock_value)
|
50
|
+
raise
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -75,28 +75,32 @@ module CompositePrimaryKeys
|
|
75
75
|
|
76
76
|
connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
def find_with_ids(*ids)
|
80
|
-
# CPK handle strings that come w/ calling to_param on CPK-enabled models
|
81
|
-
ids = cpk_parse_ids(ids)
|
82
80
|
raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
|
83
81
|
|
84
|
-
|
82
|
+
# CPK
|
83
|
+
#expects_array = ids.first.kind_of?(Array)
|
84
|
+
ids = CompositePrimaryKeys.normalize(ids)
|
85
|
+
expects_array = ids.flatten != ids.flatten(1)
|
86
|
+
|
85
87
|
return ids.first if expects_array && ids.first.empty?
|
86
88
|
|
87
|
-
# CPK
|
89
|
+
# CPK
|
88
90
|
#ids = ids.flatten.compact.uniq
|
91
|
+
ids = expects_array ? ids.first : ids
|
92
|
+
|
89
93
|
case ids.size
|
90
94
|
when 0
|
91
95
|
raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
|
92
96
|
when 1
|
93
97
|
result = find_one(ids.first)
|
94
|
-
|
95
|
-
# expects_array ? [ result ] : result
|
96
|
-
result
|
98
|
+
expects_array ? [ result ] : result
|
97
99
|
else
|
98
100
|
find_some(ids)
|
99
101
|
end
|
102
|
+
rescue RangeError
|
103
|
+
raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
|
100
104
|
end
|
101
105
|
|
102
106
|
def find_one(id)
|
@@ -119,6 +119,16 @@ create table employees (
|
|
119
119
|
primary key (id)
|
120
120
|
);
|
121
121
|
|
122
|
+
create table salaries (
|
123
|
+
id int not null auto_increment,
|
124
|
+
employee_id int,
|
125
|
+
location_id int,
|
126
|
+
year int not null,
|
127
|
+
month int not null,
|
128
|
+
value int default null,
|
129
|
+
primary key (id)
|
130
|
+
);
|
131
|
+
|
122
132
|
create table comments (
|
123
133
|
id int not null auto_increment,
|
124
134
|
person_id int default null,
|
@@ -138,6 +148,7 @@ create table restaurants (
|
|
138
148
|
franchise_id int not null,
|
139
149
|
store_id int not null,
|
140
150
|
name varchar(100),
|
151
|
+
lock_version int default 0,
|
141
152
|
primary key (franchise_id, store_id)
|
142
153
|
);
|
143
154
|
|
@@ -121,6 +121,16 @@ create table employees (
|
|
121
121
|
primary key (id)
|
122
122
|
);
|
123
123
|
|
124
|
+
create table salaries (
|
125
|
+
id serial not null,
|
126
|
+
employee_id int,
|
127
|
+
location_id int,
|
128
|
+
year int not null,
|
129
|
+
month int not null,
|
130
|
+
value int default null,
|
131
|
+
primary key (id)
|
132
|
+
);
|
133
|
+
|
124
134
|
create table comments (
|
125
135
|
id serial not null,
|
126
136
|
person_id int default null,
|
@@ -140,6 +150,7 @@ create table restaurants (
|
|
140
150
|
franchise_id int not null,
|
141
151
|
store_id int not null,
|
142
152
|
name varchar(100),
|
153
|
+
lock_version int default 0,
|
143
154
|
primary key (franchise_id, store_id)
|
144
155
|
);
|
145
156
|
|
@@ -112,6 +112,15 @@ create table employees (
|
|
112
112
|
location_id integer null
|
113
113
|
);
|
114
114
|
|
115
|
+
create table salaries (
|
116
|
+
id integer not null primary key autoincrement,
|
117
|
+
employee_id integer,
|
118
|
+
location_id integer,
|
119
|
+
year int not null,
|
120
|
+
month int not null,
|
121
|
+
value int default null
|
122
|
+
);
|
123
|
+
|
115
124
|
create table comments (
|
116
125
|
id integer not null primary key autoincrement,
|
117
126
|
person_id int null,
|
@@ -129,6 +138,7 @@ create table restaurants (
|
|
129
138
|
franchise_id integer not null,
|
130
139
|
store_id integer not null,
|
131
140
|
name varchar(100),
|
141
|
+
lock_version integer default 0,
|
132
142
|
primary key (franchise_id, store_id)
|
133
143
|
);
|
134
144
|
|
@@ -148,7 +148,8 @@ go
|
|
148
148
|
CREATE TABLE restaurants (
|
149
149
|
franchise_id [int] NOT NULL,
|
150
150
|
store_id [int] NOT NULL,
|
151
|
-
name [varchar](100)
|
151
|
+
name [varchar](100),
|
152
|
+
lock_version [int] DEFAULT 0
|
152
153
|
CONSTRAINT [restaurants_pk] PRIMARY KEY CLUSTERED
|
153
154
|
( [franchise_id], [store_id] )
|
154
155
|
);
|
@@ -222,4 +223,4 @@ CREATE TABLE products_restaurants (
|
|
222
223
|
franchise_id [int] NOT NULL,
|
223
224
|
store_id [int] NOT NULL
|
224
225
|
);
|
225
|
-
go
|
226
|
+
go
|
data/test/fixtures/employee.rb
CHANGED
@@ -2,4 +2,10 @@ class Employee < ActiveRecord::Base
|
|
2
2
|
belongs_to :department, :foreign_key => [:department_id, :location_id]
|
3
3
|
has_many :comments, :as => :person
|
4
4
|
has_and_belongs_to_many :groups
|
5
|
+
has_many :salaries,
|
6
|
+
:primary_key => [:id, :location_id],
|
7
|
+
:foreign_key => [:employee_id, :location_id]
|
8
|
+
has_one :one_salary, :class_name => "Salary",
|
9
|
+
:primary_key => [:id, :location_id],
|
10
|
+
:foreign_key => [:employee_id, :location_id]
|
5
11
|
end
|
data/test/test_associations.rb
CHANGED
@@ -81,6 +81,21 @@ class TestAssociations < ActiveSupport::TestCase
|
|
81
81
|
refute_equal accounting_head, engineering_head
|
82
82
|
end
|
83
83
|
|
84
|
+
def test_has_one_association_primary_key_and_foreign_key_are_present
|
85
|
+
steve = employees(:steve)
|
86
|
+
steve_salary = steve.create_one_salary(year: "2015", month: "1")
|
87
|
+
|
88
|
+
jill = employees(:jill)
|
89
|
+
jill_salary = jill.create_one_salary(year: "2015", month: "1")
|
90
|
+
|
91
|
+
steve_salary.reload
|
92
|
+
jill_salary.reload
|
93
|
+
assert_equal(steve.id, steve_salary.employee_id)
|
94
|
+
assert_equal(1, steve_salary.location_id)
|
95
|
+
assert_equal(jill.id, jill_salary.employee_id)
|
96
|
+
assert_equal(1, jill_salary.location_id)
|
97
|
+
end
|
98
|
+
|
84
99
|
def test_has_many_association_is_not_cached_to_where_it_returns_the_wrong_ones
|
85
100
|
engineering = departments(:engineering)
|
86
101
|
engineering_employees = engineering.employees
|
@@ -91,6 +106,36 @@ class TestAssociations < ActiveSupport::TestCase
|
|
91
106
|
refute_equal accounting_employees, engineering_employees
|
92
107
|
end
|
93
108
|
|
109
|
+
def test_has_many_association_primary_key_and_foreign_key_are_present
|
110
|
+
steve = employees(:steve)
|
111
|
+
steve_salary = steve.salaries.create(year: 2015, month: 1)
|
112
|
+
|
113
|
+
jill = employees(:jill)
|
114
|
+
jill_salary = jill.salaries.create(year: 2015, month: 1)
|
115
|
+
|
116
|
+
steve_salary.reload
|
117
|
+
jill_salary.reload
|
118
|
+
assert_equal(steve.id, steve_salary.employee_id)
|
119
|
+
assert_equal(1, steve_salary.location_id)
|
120
|
+
assert_equal(jill.id, jill_salary.employee_id)
|
121
|
+
assert_equal(1, jill_salary.location_id)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_belongs_to_association_primary_key_and_foreign_key_are_present
|
125
|
+
salary_01 = Salary.new(year: 2015, month: 1, employee_id: 5, location_id: 1)
|
126
|
+
employee_01 = salary_01.create_employee
|
127
|
+
salary_02 = Salary.new(year: 2015, month: 1, employee_id: 6, location_id: 1)
|
128
|
+
employee_02 = salary_02.create_employee
|
129
|
+
|
130
|
+
employee_01.reload
|
131
|
+
employee_02.reload
|
132
|
+
|
133
|
+
assert_equal(5, employee_01.id)
|
134
|
+
assert_equal(1, employee_01.location_id)
|
135
|
+
assert_equal(6, employee_02.id)
|
136
|
+
assert_equal(1, employee_02.location_id)
|
137
|
+
end
|
138
|
+
|
94
139
|
def test_find_includes_product_tariffs_product
|
95
140
|
# Old style
|
96
141
|
product_tariffs = ProductTariff.includes(:product)
|
data/test/test_attributes.rb
CHANGED
@@ -42,13 +42,13 @@ class TestAttributes < ActiveSupport::TestCase
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
def test_brackets_foreign_key_assignment
|
47
47
|
tarrif = tariffs(:flat)
|
48
48
|
product_tariff = product_tariffs(:first_flat)
|
49
49
|
compare_indexes(tarrif, tarrif.class.primary_key, product_tariff, [:tariff_id, :tariff_start_date])
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
private
|
53
53
|
|
54
54
|
def compare_indexes(obj1, indexes1, obj2, indexes2)
|
data/test/test_create.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path('../abstract_unit', __FILE__)
|
2
2
|
|
3
3
|
class TestCreate < ActiveSupport::TestCase
|
4
|
-
fixtures :reference_types, :reference_codes, :streets, :suburbs
|
4
|
+
fixtures :students, :dorms, :rooms, :room_assignments, :reference_types, :reference_codes, :streets, :suburbs
|
5
5
|
|
6
6
|
CLASSES = {
|
7
7
|
:single => {
|
@@ -109,4 +109,49 @@ class TestCreate < ActiveSupport::TestCase
|
|
109
109
|
assert_equal(25, suburb.suburb_id)
|
110
110
|
assert_equal("My Suburb", suburb.name)
|
111
111
|
end
|
112
|
+
|
113
|
+
def test_has_many_ids_1
|
114
|
+
dorm = dorms(:toyon)
|
115
|
+
room = Room.new(:dorm_id => dorm.id, :room_id => 5)
|
116
|
+
room.save!
|
117
|
+
|
118
|
+
student1 = students(:kelly)
|
119
|
+
student2 = students(:jordan)
|
120
|
+
|
121
|
+
RoomAssignment.delete_all
|
122
|
+
|
123
|
+
assignment1 = RoomAssignment.new(:student_id => student1.id, :dorm_id => room.dorm_id, :room_id => room.room_id)
|
124
|
+
assignment1.save!
|
125
|
+
|
126
|
+
room.room_assignment_ids = [[assignment1.student_id, assignment1.dorm_id, assignment1.room_id]]
|
127
|
+
room.save!
|
128
|
+
|
129
|
+
assert_equal(1, room.room_assignments.length)
|
130
|
+
assert_equal(assignment1, room.room_assignments.first)
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_has_many_ids_2
|
134
|
+
dorm = dorms(:toyon)
|
135
|
+
room = Room.new(:dorm_id => dorm.id, :room_id => 5)
|
136
|
+
room.save!
|
137
|
+
|
138
|
+
student1 = students(:kelly)
|
139
|
+
student2 = students(:jordan)
|
140
|
+
|
141
|
+
RoomAssignment.delete_all
|
142
|
+
|
143
|
+
assignment1 = RoomAssignment.new(:student_id => student1.id, :dorm_id => room.dorm_id, :room_id => room.room_id)
|
144
|
+
assignment1.save!
|
145
|
+
|
146
|
+
assignment2 = RoomAssignment.new(:student_id => student2.id, :dorm_id => room.dorm_id, :room_id => room.room_id)
|
147
|
+
assignment2.save!
|
148
|
+
|
149
|
+
room.room_assignment_ids = [[assignment1.student_id, assignment1.dorm_id, assignment1.room_id],
|
150
|
+
[assignment2.student_id, assignment2.dorm_id, assignment2.room_id]]
|
151
|
+
room.save!
|
152
|
+
|
153
|
+
assert_equal(2, room.room_assignments.length)
|
154
|
+
assert_equal(assignment1, room.room_assignments[0])
|
155
|
+
assert_equal(assignment2, room.room_assignments[1])
|
156
|
+
end
|
112
157
|
end
|
data/test/test_delete.rb
CHANGED
@@ -97,6 +97,16 @@ class TestDelete < ActiveSupport::TestCase
|
|
97
97
|
assert_equal records_after, records_before - steve.groups.count
|
98
98
|
end
|
99
99
|
|
100
|
+
def test_destroy_has_and_belongs_to_many_on_non_cpk
|
101
|
+
records_before = ActiveRecord::Base.connection.execute("select * from employees_groups").count
|
102
|
+
employee = Employee.create
|
103
|
+
employee.groups << Group.create(name: 'test')
|
104
|
+
employees_groups_count = employee.groups.count
|
105
|
+
employee.destroy!
|
106
|
+
records_after = ActiveRecord::Base.connection.execute("select * from employees_groups").count
|
107
|
+
assert_equal records_before, records_after
|
108
|
+
end
|
109
|
+
|
100
110
|
def test_delete_not_destroy_on_cpk
|
101
111
|
tariff = Tariff.where(tariff_id: 2).first
|
102
112
|
tariff.delete
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestOptimisitic < ActiveSupport::TestCase
|
4
|
+
fixtures :restaurants
|
5
|
+
|
6
|
+
def test_update_with_stale_error
|
7
|
+
restaurant_1 = Restaurant.find([1, 1])
|
8
|
+
restaurant_1['name'] = "McDonalds renamed"
|
9
|
+
|
10
|
+
restaurant_2 = Restaurant.find([1, 1])
|
11
|
+
restaurant_2['name'] = "McDonalds renamed 2"
|
12
|
+
|
13
|
+
assert(restaurant_1.save)
|
14
|
+
assert_raise ActiveRecord::StaleObjectError do
|
15
|
+
restaurant_2.save
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/test/test_suite.rb
CHANGED
@@ -4,19 +4,23 @@ class TestTutorialExample < ActiveSupport::TestCase
|
|
4
4
|
fixtures :users, :groups, :memberships, :membership_statuses
|
5
5
|
|
6
6
|
def test_membership
|
7
|
-
|
7
|
+
membership = Membership.find([1, 1])
|
8
|
+
assert(membership, "Cannot find a membership")
|
8
9
|
assert(membership.user)
|
9
10
|
assert(membership.group)
|
10
11
|
end
|
11
12
|
|
12
13
|
def test_status
|
13
|
-
|
14
|
-
|
14
|
+
membership = Membership.find([1, 1])
|
15
|
+
statuses = membership.statuses
|
16
|
+
assert(membership, "Cannot find a membership")
|
17
|
+
assert(statuses, "No has_many association to status")
|
15
18
|
assert_equal(membership, statuses.first.membership)
|
16
19
|
end
|
17
20
|
|
18
21
|
def test_count
|
19
|
-
|
22
|
+
membership = Membership.find([1, 1])
|
23
|
+
assert(membership, "Cannot find a membership")
|
20
24
|
assert_equal(1, membership.statuses.count)
|
21
25
|
end
|
22
26
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composite_primary_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.
|
4
|
+
version: 8.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Savage
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -58,9 +58,11 @@ files:
|
|
58
58
|
- lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb
|
59
59
|
- lib/composite_primary_keys/connection_adapters/abstract_adapter.rb
|
60
60
|
- lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
|
61
|
+
- lib/composite_primary_keys/connection_adapters/sqlserver_adapter.rb
|
61
62
|
- lib/composite_primary_keys/core.rb
|
62
63
|
- lib/composite_primary_keys/dirty.rb
|
63
64
|
- lib/composite_primary_keys/fixtures.rb
|
65
|
+
- lib/composite_primary_keys/locking/optimistic.rb
|
64
66
|
- lib/composite_primary_keys/model_schema.rb
|
65
67
|
- lib/composite_primary_keys/nested_attributes.rb
|
66
68
|
- lib/composite_primary_keys/persistence.rb
|
@@ -149,6 +151,7 @@ files:
|
|
149
151
|
- test/fixtures/room_attribute_assignments.yml
|
150
152
|
- test/fixtures/room_attributes.yml
|
151
153
|
- test/fixtures/rooms.yml
|
154
|
+
- test/fixtures/salary.rb
|
152
155
|
- test/fixtures/seat.rb
|
153
156
|
- test/fixtures/seats.yml
|
154
157
|
- test/fixtures/street.rb
|
@@ -189,6 +192,7 @@ files:
|
|
189
192
|
- test/test_ids.rb
|
190
193
|
- test/test_miscellaneous.rb
|
191
194
|
- test/test_nested_attributes.rb
|
195
|
+
- test/test_optimistic.rb
|
192
196
|
- test/test_pagination.rb
|
193
197
|
- test/test_polymorphic.rb
|
194
198
|
- test/test_predicates.rb
|
@@ -249,6 +253,7 @@ test_files:
|
|
249
253
|
- test/test_ids.rb
|
250
254
|
- test/test_miscellaneous.rb
|
251
255
|
- test/test_nested_attributes.rb
|
256
|
+
- test/test_optimistic.rb
|
252
257
|
- test/test_pagination.rb
|
253
258
|
- test/test_polymorphic.rb
|
254
259
|
- test/test_predicates.rb
|