composite_primary_keys 7.0.12 → 7.0.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 65cb7db711192f8ae6b531e8c5cc5fa316554806
4
- data.tar.gz: ce079278064acfc94b691592c804047c6b0a4dd5
3
+ metadata.gz: 11bd0689a2d8973f43dc85cb073ad159ff3bf928
4
+ data.tar.gz: f522a924cbcf3133266412edbc199578d04de126
5
5
  SHA512:
6
- metadata.gz: f927ff29273325bc1034c2981382403fc568709f6f400db40e9d33c0933dc2016b222a9ae67cc85ad414b1e8b0e5186441ca534039f9c61c0bf35fe27c87c284
7
- data.tar.gz: c0f88b9953c629c61b2bb001b0ff9375878c196b9b13f6d60e92705514ff04971b5a5ed4add442c55eebd169aded609f159d5a30ee0bd326a4b370f1d595a787
6
+ metadata.gz: 35ab53ffeda373c7cbd67e9b44aa59176bda538d02be516e10d5d8aca2e36ebf96f56458c318689df792672cd06dcc3110057bcc8eb3fe2a1673705b13649679
7
+ data.tar.gz: 85cf61a48776def558c3ac4ec34f59402faa00979552dc6e64bd46fdd0f0712955ce5e83761422f656174a5894a7eb622efb8fc1d3037afe46b365a3e41288c1
@@ -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)
@@ -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
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION
3
3
  MAJOR = 7
4
4
  MINOR = 0
5
- TINY = 12
5
+ TINY = 13
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
@@ -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
 
@@ -15,3 +15,5 @@ drop table KITCHEN_SINK;
15
15
  drop table RESTAURANTS;
16
16
  drop table RESTAURANTS_SUBURBS;
17
17
  drop table PRODUCTS_RESTAURANTS;
18
+ drop table TOPICS;
19
+ drop table TOPIC_SOURCES;
@@ -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,6 @@
1
+ drop table topics;
2
+ drop sequence topics_seq;
3
+ drop table topic_sources;
1
4
  drop table reference_types;
2
5
  drop sequence reference_types_seq;
3
6
  drop table reference_codes;
@@ -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,12 @@
1
1
  USE [composite_primary_keys_unittest];
2
2
  go
3
3
 
4
+ DROP TABLE topics;
5
+ go
6
+
7
+ DROP TABLE topic_sources;
8
+ go
9
+
4
10
  DROP TABLE reference_types;
5
11
  go
6
12
 
@@ -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
@@ -3,11 +3,11 @@ first_flat:
3
3
  tariff_id: 1
4
4
  tariff_start_date: <%= Date.today.to_s(:db) %>
5
5
 
6
- first_free:
6
+ first_free:
7
7
  product_id: 1
8
8
  tariff_id: 2
9
9
  tariff_start_date: <%= Date.today.to_s(:db) %>
10
-
10
+
11
11
  second_free:
12
12
  product_id: 2
13
13
  tariff_id: 2
@@ -1,7 +1,7 @@
1
1
  class ReferenceCode < ActiveRecord::Base
2
2
  self.primary_keys = :reference_type_id, :reference_code
3
-
3
+
4
4
  belongs_to :reference_type, :foreign_key => "reference_type_id"
5
-
5
+
6
6
  validates_presence_of :reference_code, :code_label, :abbreviation
7
7
  end
@@ -0,0 +1,6 @@
1
+ class Topic < ActiveRecord::Base
2
+ has_many :topic_sources, dependent: :destroy
3
+ accepts_nested_attributes_for :topic_sources
4
+
5
+ validates :name, :feed_size, presence: true
6
+ end
@@ -0,0 +1,7 @@
1
+ class TopicSource < ActiveRecord::Base
2
+ self.primary_keys = :topic_id, :platform
3
+
4
+ belongs_to :topic, inverse_of: :topic_sources
5
+
6
+ validates :platform, presence: true
7
+ end
@@ -0,0 +1,4 @@
1
+ music_source:
2
+ topic_id: 1
3
+ platform: 'twitter'
4
+ keywords: 'classical'
@@ -0,0 +1,9 @@
1
+ music:
2
+ id: 1
3
+ name: Guitar
4
+ feed_size: 500
5
+
6
+ iphone:
7
+ id: 2
8
+ name: iPhone
9
+ feed_size: 500
@@ -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
@@ -19,6 +19,7 @@
19
19
  test_ids
20
20
  test_miscellaneous
21
21
  test_nested_attributes
22
+ test_optimistic
22
23
  test_pagination
23
24
  test_polymorphic
24
25
  test_predicates
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.12
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: 2014-11-09 00:00:00.000000000 Z
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.1
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