composite_primary_keys 7.0.12 → 7.0.13
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 +12 -0
- data/README.rdoc +4 -0
- data/lib/composite_primary_keys.rb +2 -0
- data/lib/composite_primary_keys/locking/optimistic.rb +55 -0
- data/lib/composite_primary_keys/nested_attributes.rb +1 -1
- data/lib/composite_primary_keys/version.rb +1 -1
- data/test/fixtures/db_definitions/db2-create-tables.sql +15 -0
- data/test/fixtures/db_definitions/db2-drop-tables.sql +2 -0
- data/test/fixtures/db_definitions/mysql.sql +15 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +3 -0
- data/test/fixtures/db_definitions/oracle.sql +15 -0
- data/test/fixtures/db_definitions/postgresql.sql +15 -0
- data/test/fixtures/db_definitions/sqlite.sql +15 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +6 -0
- data/test/fixtures/db_definitions/sqlserver.sql +17 -2
- data/test/fixtures/product_tariffs.yml +2 -2
- data/test/fixtures/reference_code.rb +2 -2
- data/test/fixtures/topic.rb +6 -0
- data/test/fixtures/topic_source.rb +7 -0
- data/test/fixtures/topic_sources.yml +4 -0
- data/test/fixtures/topics.yml +9 -0
- data/test/test_nested_attributes.rb +58 -0
- data/test/test_optimistic.rb +18 -0
- data/test/test_suite.rb +1 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11bd0689a2d8973f43dc85cb073ad159ff3bf928
|
4
|
+
data.tar.gz: f522a924cbcf3133266412edbc199578d04de126
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35ab53ffeda373c7cbd67e9b44aa59176bda538d02be516e10d5d8aca2e36ebf96f56458c318689df792672cd06dcc3110057bcc8eb3fe2a1673705b13649679
|
7
|
+
data.tar.gz: 85cf61a48776def558c3ac4ec34f59402faa00979552dc6e64bd46fdd0f0712955ce5e83761422f656174a5894a7eb622efb8fc1d3037afe46b365a3e41288c1
|
data/History.rdoc
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 7.0.13 (2015-01-24)
|
2
|
+
|
3
|
+
* Support optimistic lock and lock_version added to existing fixtures (Kirika)
|
4
|
+
* README change to convey finding available versions (Aaron Bartell)
|
5
|
+
* Fixes indentation in product_tariffs (Zaldabus)
|
6
|
+
|
1
7
|
== 7.0.12 (2014-11-09)
|
2
8
|
|
3
9
|
* ActiveRecord 4.1.7 support (Tom Hughes)
|
@@ -84,6 +90,12 @@ The first one no longer works. It was removed because it made the internal code
|
|
84
90
|
and makes the intention of the code clearer (especially when finding multiple records).
|
85
91
|
If this change causes too much pain then please submit a ticket on Github.
|
86
92
|
|
93
|
+
== 6.0.08 (2015-01-24)
|
94
|
+
|
95
|
+
* Fix habtm association #delete_records (Uros Jurglic)
|
96
|
+
* Support optimistic locking (Toshio Maki)
|
97
|
+
* Remove singleton classes on CPK relations (Nicolás Hock Isaza)
|
98
|
+
|
87
99
|
== 6.0.7 (2014-10-06)
|
88
100
|
|
89
101
|
* Support Rails 4.0.6 (Tom Hughes)
|
data/README.rdoc
CHANGED
@@ -25,6 +25,10 @@ things straight, here is the mapping:
|
|
25
25
|
Version 5.x is designed to work with ActiveRecord 3.2.x
|
26
26
|
Version 4.x is designed to work with ActiveRecord 3.1.x
|
27
27
|
|
28
|
+
Run the following command to list available versions:
|
29
|
+
|
30
|
+
gem list composite_primary_keys -ra
|
31
|
+
|
28
32
|
== The basics
|
29
33
|
|
30
34
|
A model with composite primary keys is defined like this:
|
@@ -52,6 +52,7 @@ require 'active_record/attribute_methods/primary_key'
|
|
52
52
|
require 'active_record/attribute_methods/dirty'
|
53
53
|
require 'active_record/attribute_methods/read'
|
54
54
|
require 'active_record/attribute_methods/write'
|
55
|
+
require 'active_record/locking/optimistic'
|
55
56
|
require 'active_record/nested_attributes'
|
56
57
|
|
57
58
|
require 'active_record/connection_adapters/abstract_adapter'
|
@@ -92,6 +93,7 @@ require 'composite_primary_keys/attribute_methods/primary_key'
|
|
92
93
|
require 'composite_primary_keys/attribute_methods/dirty'
|
93
94
|
require 'composite_primary_keys/attribute_methods/read'
|
94
95
|
require 'composite_primary_keys/attribute_methods/write'
|
96
|
+
require 'composite_primary_keys/locking/optimistic'
|
95
97
|
require 'composite_primary_keys/nested_attributes'
|
96
98
|
|
97
99
|
require 'composite_primary_keys/connection_adapters/abstract_adapter'
|
@@ -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
|
@@ -51,7 +51,6 @@ module ActiveRecord
|
|
51
51
|
|
52
52
|
attributes_collection.each do |attributes|
|
53
53
|
attributes = attributes.with_indifferent_access
|
54
|
-
|
55
54
|
if attributes['id'].blank?
|
56
55
|
unless reject_new_record?(association_name, attributes)
|
57
56
|
association.build(attributes.except(*UNASSIGNABLE_KEYS))
|
@@ -62,6 +61,7 @@ module ActiveRecord
|
|
62
61
|
# proxy_target array (either by finding it, or adding it if not found)
|
63
62
|
# Take into account that the proxy_target may have changed due to callbacks
|
64
63
|
target_record = cpk_detect_record(attributes['id'], association.target)
|
64
|
+
|
65
65
|
if target_record
|
66
66
|
existing_record = target_record
|
67
67
|
else
|
@@ -1,3 +1,17 @@
|
|
1
|
+
CREATE TABLE topics (
|
2
|
+
id integer NOT NULL,
|
3
|
+
name varchar(50) default NULL,
|
4
|
+
feed_size integer default NULL,
|
5
|
+
PRIMARY KEY (id)
|
6
|
+
);
|
7
|
+
|
8
|
+
CREATE TABLE topic_sources (
|
9
|
+
topic_id integer NOT NULL,
|
10
|
+
platform varchar(50) NOT NULL,
|
11
|
+
keywords varchar(50) default NULL,
|
12
|
+
PRIMARY KEY (topic_id,platform)
|
13
|
+
);
|
14
|
+
|
1
15
|
CREATE TABLE reference_types (
|
2
16
|
reference_type_id integer NOT NULL generated by default as identity (start with 100, increment by 1, no cache),
|
3
17
|
type_label varchar(50) default NULL,
|
@@ -94,6 +108,7 @@ create table restaurants (
|
|
94
108
|
franchise_id integer not null,
|
95
109
|
store_id integer not null,
|
96
110
|
name varchar(100),
|
111
|
+
lock_version integer default 0,
|
97
112
|
primary key (franchise_id, store_id)
|
98
113
|
);
|
99
114
|
|
@@ -1,3 +1,17 @@
|
|
1
|
+
create table topics (
|
2
|
+
id int not null auto_increment,
|
3
|
+
name varchar(50) default null,
|
4
|
+
feed_size int default null,
|
5
|
+
primary key (id)
|
6
|
+
);
|
7
|
+
|
8
|
+
create table topic_sources (
|
9
|
+
topic_id int not null,
|
10
|
+
platform varchar(50) not null,
|
11
|
+
keywords varchar(50) default null,
|
12
|
+
primary key (topic_id,platform)
|
13
|
+
);
|
14
|
+
|
1
15
|
create table reference_types (
|
2
16
|
reference_type_id int not null auto_increment,
|
3
17
|
type_label varchar(50) default null,
|
@@ -124,6 +138,7 @@ create table restaurants (
|
|
124
138
|
franchise_id int not null,
|
125
139
|
store_id int not null,
|
126
140
|
name varchar(100),
|
141
|
+
lock_version int default 0,
|
127
142
|
primary key (franchise_id, store_id)
|
128
143
|
);
|
129
144
|
|
@@ -1,3 +1,17 @@
|
|
1
|
+
create sequence topics_seq start with 1000;
|
2
|
+
|
3
|
+
create table topics (
|
4
|
+
id number(11) primary key,
|
5
|
+
name varchar(50) default null,
|
6
|
+
feed_size number(11) default null,
|
7
|
+
);
|
8
|
+
|
9
|
+
create table topic_sources (
|
10
|
+
topic_id number(11),
|
11
|
+
platform varchar(50),
|
12
|
+
keywords varchar(50) default null,
|
13
|
+
);
|
14
|
+
|
1
15
|
create sequence reference_types_seq start with 1000;
|
2
16
|
|
3
17
|
create table reference_types (
|
@@ -132,6 +146,7 @@ create table restaurants (
|
|
132
146
|
franchise_id number(11) not null,
|
133
147
|
store_id number(11) not null,
|
134
148
|
name varchar(100),
|
149
|
+
lock_version number(11) default 0,
|
135
150
|
constraint restaurants_pk primary key (franchise_id, store_id)
|
136
151
|
);
|
137
152
|
|
@@ -1,3 +1,17 @@
|
|
1
|
+
create table topics (
|
2
|
+
id serial not null,
|
3
|
+
name varchar(50) default null,
|
4
|
+
feed_size int default null,
|
5
|
+
primary key (id)
|
6
|
+
);
|
7
|
+
|
8
|
+
create table topic_sources (
|
9
|
+
topic_id int not null,
|
10
|
+
platform varchar(50) not null,
|
11
|
+
keywords varchar(50) default null,
|
12
|
+
primary key (topic_id,platform)
|
13
|
+
);
|
14
|
+
|
1
15
|
create table reference_types (
|
2
16
|
reference_type_id serial not null,
|
3
17
|
type_label varchar(50) default null,
|
@@ -126,6 +140,7 @@ create table restaurants (
|
|
126
140
|
franchise_id int not null,
|
127
141
|
store_id int not null,
|
128
142
|
name varchar(100),
|
143
|
+
lock_version int default 0,
|
129
144
|
primary key (franchise_id, store_id)
|
130
145
|
);
|
131
146
|
|
@@ -1,3 +1,17 @@
|
|
1
|
+
create table topics (
|
2
|
+
id int not null,
|
3
|
+
name varchar(50) default null,
|
4
|
+
feed_size int default null,
|
5
|
+
primary key (id)
|
6
|
+
);
|
7
|
+
|
8
|
+
create table topic_sources (
|
9
|
+
topic_id int not null,
|
10
|
+
platform varchar(50) not null,
|
11
|
+
keywords varchar(50) default null,
|
12
|
+
primary key (topic_id,platform)
|
13
|
+
);
|
14
|
+
|
1
15
|
create table reference_types (
|
2
16
|
reference_type_id integer primary key,
|
3
17
|
type_label varchar(50) default null,
|
@@ -115,6 +129,7 @@ create table restaurants (
|
|
115
129
|
franchise_id integer not null,
|
116
130
|
store_id integer not null,
|
117
131
|
name varchar(100),
|
132
|
+
lock_version integer default 0,
|
118
133
|
primary key (franchise_id, store_id)
|
119
134
|
);
|
120
135
|
|
@@ -1,6 +1,20 @@
|
|
1
1
|
USE [composite_primary_keys_unittest];
|
2
2
|
go
|
3
3
|
|
4
|
+
CREATE TABLE topics (
|
5
|
+
id [int] IDENTITY(1000,1) NOT NULL,
|
6
|
+
name [varchar](50) default NULL,
|
7
|
+
feed_size [int] default NULL
|
8
|
+
);
|
9
|
+
go
|
10
|
+
|
11
|
+
CREATE TABLE topic_sources (
|
12
|
+
topic_id [int] NOT NULL,
|
13
|
+
platform [varchar](50) NOT NULL,
|
14
|
+
keywords [varchar](50) default NULL,
|
15
|
+
);
|
16
|
+
go
|
17
|
+
|
4
18
|
CREATE TABLE reference_types (
|
5
19
|
reference_type_id [int] IDENTITY(1000,1) NOT NULL,
|
6
20
|
type_label [varchar](50) NULL,
|
@@ -134,7 +148,8 @@ go
|
|
134
148
|
CREATE TABLE restaurants (
|
135
149
|
franchise_id [int] NOT NULL,
|
136
150
|
store_id [int] NOT NULL,
|
137
|
-
name [varchar](100)
|
151
|
+
name [varchar](100),
|
152
|
+
lock_version [int] DEFAULT 0
|
138
153
|
CONSTRAINT [restaurants_pk] PRIMARY KEY CLUSTERED
|
139
154
|
( [franchise_id], [store_id] )
|
140
155
|
);
|
@@ -208,4 +223,4 @@ CREATE TABLE products_restaurants (
|
|
208
223
|
franchise_id [int] NOT NULL,
|
209
224
|
store_id [int] NOT NULL
|
210
225
|
);
|
211
|
-
go
|
226
|
+
go
|
@@ -33,6 +33,7 @@ class TestNestedAttributes < ActiveSupport::TestCase
|
|
33
33
|
:code_label => 'AAA',
|
34
34
|
:abbreviation => 'Aaa'
|
35
35
|
}]
|
36
|
+
|
36
37
|
reference_code = ReferenceCode.find_by_reference_code(code_id)
|
37
38
|
assert_kind_of(ReferenceCode, reference_code)
|
38
39
|
assert_equal(reference_code.code_label, 'AAA')
|
@@ -63,4 +64,61 @@ class TestNestedAttributes < ActiveSupport::TestCase
|
|
63
64
|
assert_equal(reference_code.code_label, 'XX')
|
64
65
|
assert_equal(reference_code.abbreviation, 'Xx')
|
65
66
|
end
|
67
|
+
|
68
|
+
fixtures :topics, :topic_sources
|
69
|
+
|
70
|
+
def test_nested_attributes_create_with_string_in_primary_key
|
71
|
+
platform = 'instagram'
|
72
|
+
|
73
|
+
topic = topics(:music)
|
74
|
+
topic.update_attribute :topic_sources_attributes, [{
|
75
|
+
:platform => platform,
|
76
|
+
:keywords => 'funk'
|
77
|
+
}]
|
78
|
+
assert_not_nil TopicSource.find_by_platform(platform)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_nested_attributes_update_with_string_in_primary_key
|
82
|
+
platform = 'instagram'
|
83
|
+
|
84
|
+
topic = topics(:music)
|
85
|
+
topic.update_attribute :topic_sources_attributes, [{
|
86
|
+
:platform => platform,
|
87
|
+
:keywords => 'funk'
|
88
|
+
}]
|
89
|
+
assert_not_nil TopicSource.find_by_platform(platform)
|
90
|
+
|
91
|
+
topic_source = TopicSource.find_by_platform(platform)
|
92
|
+
cpk = CompositePrimaryKeys::CompositeKeys[topic.id, platform]
|
93
|
+
topic.update_attribute :topic_sources_attributes, [{
|
94
|
+
:id => cpk,
|
95
|
+
:keywords => 'jazz'
|
96
|
+
}]
|
97
|
+
|
98
|
+
topic_source = TopicSource.find_by_platform(platform)
|
99
|
+
assert_kind_of(TopicSource, topic_source)
|
100
|
+
assert_equal(topic_source.keywords, 'jazz')
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_nested_attributes_update_with_string_in_primary_key_2
|
104
|
+
topic = topics(:music)
|
105
|
+
topic_source = topic_sources(:music_source)
|
106
|
+
|
107
|
+
topic.update_attributes(:topic_sources_attributes => [{:id => topic_source.id,
|
108
|
+
:keywords => 'classical, jazz'}])
|
109
|
+
|
110
|
+
topic_source.reload
|
111
|
+
assert_equal(topic_source.keywords, 'classical, jazz')
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_nested_attributes_update_with_string_in_primary_key_3
|
115
|
+
topic = topics(:music)
|
116
|
+
topic_source = topic_sources(:music_source)
|
117
|
+
|
118
|
+
topic.update_attributes(:topic_sources_attributes => [{:id => topic_source.id.to_s,
|
119
|
+
:keywords => 'classical, jazz'}])
|
120
|
+
|
121
|
+
topic_source.reload
|
122
|
+
assert_equal(topic_source.keywords, 'classical, jazz')
|
123
|
+
end
|
66
124
|
end
|
@@ -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
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: 7.0.
|
4
|
+
version: 7.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Savage
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- lib/composite_primary_keys/core.rb
|
61
61
|
- lib/composite_primary_keys/dirty.rb
|
62
62
|
- lib/composite_primary_keys/fixtures.rb
|
63
|
+
- lib/composite_primary_keys/locking/optimistic.rb
|
63
64
|
- lib/composite_primary_keys/model_schema.rb
|
64
65
|
- lib/composite_primary_keys/nested_attributes.rb
|
65
66
|
- lib/composite_primary_keys/persistence.rb
|
@@ -158,6 +159,10 @@ files:
|
|
158
159
|
- test/fixtures/suburbs.yml
|
159
160
|
- test/fixtures/tariff.rb
|
160
161
|
- test/fixtures/tariffs.yml
|
162
|
+
- test/fixtures/topic.rb
|
163
|
+
- test/fixtures/topic_source.rb
|
164
|
+
- test/fixtures/topic_sources.yml
|
165
|
+
- test/fixtures/topics.yml
|
161
166
|
- test/fixtures/user.rb
|
162
167
|
- test/fixtures/users.yml
|
163
168
|
- test/plugins/pagination.rb
|
@@ -184,6 +189,7 @@ files:
|
|
184
189
|
- test/test_ids.rb
|
185
190
|
- test/test_miscellaneous.rb
|
186
191
|
- test/test_nested_attributes.rb
|
192
|
+
- test/test_optimistic.rb
|
187
193
|
- test/test_pagination.rb
|
188
194
|
- test/test_polymorphic.rb
|
189
195
|
- test/test_predicates.rb
|
@@ -214,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
214
220
|
version: '0'
|
215
221
|
requirements: []
|
216
222
|
rubyforge_project:
|
217
|
-
rubygems_version: 2.4.
|
223
|
+
rubygems_version: 2.4.5
|
218
224
|
signing_key:
|
219
225
|
specification_version: 4
|
220
226
|
summary: Composite key support for ActiveRecord
|
@@ -244,6 +250,7 @@ test_files:
|
|
244
250
|
- test/test_ids.rb
|
245
251
|
- test/test_miscellaneous.rb
|
246
252
|
- test/test_nested_attributes.rb
|
253
|
+
- test/test_optimistic.rb
|
247
254
|
- test/test_pagination.rb
|
248
255
|
- test/test_polymorphic.rb
|
249
256
|
- test/test_predicates.rb
|