composite_primary_keys 6.0.7 → 6.0.8
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 +6 -0
- data/lib/composite_primary_keys.rb +6 -0
- data/lib/composite_primary_keys/associations/has_and_belongs_to_many_association.rb +2 -1
- data/lib/composite_primary_keys/attribute_methods/primary_key.rb +17 -0
- data/lib/composite_primary_keys/base.rb +1 -0
- data/lib/composite_primary_keys/composite_relation.rb +44 -0
- data/lib/composite_primary_keys/locking/optimistic.rb +51 -0
- data/lib/composite_primary_keys/relation.rb +9 -55
- data/lib/composite_primary_keys/version.rb +1 -1
- data/test/abstract_unit.rb +8 -7
- data/test/fixtures/db_definitions/db2-create-tables.sql +20 -13
- data/test/fixtures/db_definitions/db2-drop-tables.sql +14 -13
- data/test/fixtures/db_definitions/mysql.sql +7 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +1 -0
- data/test/fixtures/db_definitions/oracle.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.sql +7 -0
- data/test/fixtures/db_definitions/sqlite.sql +30 -24
- data/test/fixtures/db_definitions/sqlserver.drop.sql +4 -1
- data/test/fixtures/db_definitions/sqlserver.sql +16 -7
- data/test/fixtures/dorm.rb +2 -2
- data/test/fixtures/model_with_callback.rb +39 -0
- data/test/fixtures/model_with_callbacks.yml +3 -0
- data/test/fixtures/suburb.rb +3 -3
- data/test/test_callbacks.rb +36 -0
- data/test/test_delete.rb +5 -3
- data/test/test_dumpable.rb +15 -0
- data/test/test_equal.rb +1 -1
- data/test/test_optimistic.rb +18 -0
- data/test/test_suite.rb +1 -0
- metadata +28 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0407c008d66e10820394e98a97bb7a507d0226a
|
4
|
+
data.tar.gz: 25d4c43eb87731e104c3ec486e94a20b9568f0bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 007219da8c4b82d562742f361516772b7f74d4f97e6d065ef01b526dbb9b6047e18b2445dcf3054070d7ff129da0d7a29f5ff78fc55ef49f22503080fa894a42
|
7
|
+
data.tar.gz: b712e6fb1b0d39c530b6c54c9e6dddd81bcf6552989f95b12160612379aaa27ee671ae6d1fc85a40d698c933ff2fc65eba2777b1e060ac94380f3c7ce6a603cb
|
data/History.rdoc
CHANGED
@@ -52,8 +52,10 @@ require 'active_record/associations/preloader/has_and_belongs_to_many'
|
|
52
52
|
require 'active_model/dirty'
|
53
53
|
|
54
54
|
require 'active_record/attribute_methods/dirty'
|
55
|
+
require 'active_record/attribute_methods/primary_key'
|
55
56
|
require 'active_record/attribute_methods/read'
|
56
57
|
require 'active_record/attribute_methods/write'
|
58
|
+
require 'active_record/locking/optimistic'
|
57
59
|
require 'active_record/nested_attributes'
|
58
60
|
|
59
61
|
require 'active_record/connection_adapters/abstract_adapter'
|
@@ -68,6 +70,7 @@ require 'active_record/validations/uniqueness'
|
|
68
70
|
|
69
71
|
# CPK files
|
70
72
|
require 'composite_primary_keys/persistence'
|
73
|
+
require 'composite_primary_keys/locking/optimistic'
|
71
74
|
require 'composite_primary_keys/active_record_overides'
|
72
75
|
require 'composite_primary_keys/base'
|
73
76
|
require 'composite_primary_keys/core'
|
@@ -92,6 +95,7 @@ require 'composite_primary_keys/associations/preloader/has_and_belongs_to_many'
|
|
92
95
|
require 'composite_primary_keys/dirty'
|
93
96
|
|
94
97
|
require 'composite_primary_keys/attribute_methods/dirty'
|
98
|
+
require 'composite_primary_keys/attribute_methods/primary_key'
|
95
99
|
require 'composite_primary_keys/attribute_methods/read'
|
96
100
|
require 'composite_primary_keys/attribute_methods/write'
|
97
101
|
require 'composite_primary_keys/nested_attributes'
|
@@ -105,3 +109,5 @@ require 'composite_primary_keys/relation/finder_methods'
|
|
105
109
|
require 'composite_primary_keys/relation/query_methods'
|
106
110
|
|
107
111
|
require 'composite_primary_keys/validations/uniqueness'
|
112
|
+
|
113
|
+
require 'composite_primary_keys/composite_relation'
|
@@ -49,7 +49,8 @@ module ActiveRecord
|
|
49
49
|
|
50
50
|
predicate1 = cpk_id_predicate(relation, Array(reflection.foreign_key), Array(owner.id))
|
51
51
|
predicate2 = cpk_in_predicate(relation, Array(reflection.association_foreign_key), records.map { |x| x.id }) unless records == :all
|
52
|
-
|
52
|
+
conds = predicate2.nil?? predicate1 : predicate1.and(predicate2)
|
53
|
+
stmt = relation.where(conds).compile_delete
|
53
54
|
|
54
55
|
owner.class.connection.delete stmt.to_sql
|
55
56
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module PrimaryKey
|
4
|
+
def id_was
|
5
|
+
sync_with_transaction_state
|
6
|
+
|
7
|
+
if self.composite?
|
8
|
+
self.class.primary_keys.map do |key_attr|
|
9
|
+
attribute_changed?(key_attr) ? changed_attributes[key_attr] : self.ids_hash[key_attr]
|
10
|
+
end
|
11
|
+
else
|
12
|
+
attribute_was(self.class.primary_key)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -4,6 +4,7 @@ module ActiveRecord
|
|
4
4
|
|
5
5
|
class Base
|
6
6
|
include CompositePrimaryKeys::ActiveRecord::Persistence
|
7
|
+
include CompositePrimaryKeys::ActiveRecord::Locking::Optimistic
|
7
8
|
|
8
9
|
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
9
10
|
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module CompositeRelation
|
3
|
+
include CompositePrimaryKeys::ActiveRecord::Batches
|
4
|
+
include CompositePrimaryKeys::ActiveRecord::Calculations
|
5
|
+
include CompositePrimaryKeys::ActiveRecord::FinderMethods
|
6
|
+
include CompositePrimaryKeys::ActiveRecord::QueryMethods
|
7
|
+
|
8
|
+
def delete(id_or_array)
|
9
|
+
# Without CPK:
|
10
|
+
# where(primary_key => id_or_array).delete_all
|
11
|
+
|
12
|
+
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
13
|
+
[id_or_array]
|
14
|
+
else
|
15
|
+
Array(id_or_array)
|
16
|
+
end
|
17
|
+
|
18
|
+
id_or_array.each do |id|
|
19
|
+
where(cpk_id_predicate(table, self.primary_key, id)).delete_all
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy(id_or_array)
|
24
|
+
# Without CPK:
|
25
|
+
#if id.is_a?(Array)
|
26
|
+
# id.map { |one_id| destroy(one_id) }
|
27
|
+
#else
|
28
|
+
# find(id).destroy
|
29
|
+
#end
|
30
|
+
|
31
|
+
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
32
|
+
[id_or_array]
|
33
|
+
else
|
34
|
+
Array(id_or_array)
|
35
|
+
end
|
36
|
+
|
37
|
+
id_or_array.each do |id|
|
38
|
+
where(cpk_id_predicate(table, self.primary_key, id)).each do |record|
|
39
|
+
record.destroy
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CompositePrimaryKeys
|
2
|
+
module ActiveRecord
|
3
|
+
module Locking
|
4
|
+
module Optimistic
|
5
|
+
private
|
6
|
+
def _update_record(attribute_names = @attributes.keys) #:nodoc:
|
7
|
+
return super unless locking_enabled?
|
8
|
+
return 0 if attribute_names.empty?
|
9
|
+
|
10
|
+
lock_col = self.class.locking_column
|
11
|
+
previous_lock_value = send(lock_col).to_i
|
12
|
+
increment_lock
|
13
|
+
|
14
|
+
attribute_names += [lock_col]
|
15
|
+
attribute_names.uniq!
|
16
|
+
|
17
|
+
begin
|
18
|
+
relation = self.class.unscoped
|
19
|
+
|
20
|
+
if self.composite?
|
21
|
+
stmt = relation.where(
|
22
|
+
relation.cpk_id_predicate(relation.table, self.class.primary_key, id_was).and(
|
23
|
+
relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
|
24
|
+
)
|
25
|
+
).arel.compile_update(arel_attributes_with_values_for_update(attribute_names))
|
26
|
+
else
|
27
|
+
stmt = relation.where(
|
28
|
+
relation.table[self.class.primary_key].eq(id).and(
|
29
|
+
relation.table[lock_col].eq(self.class.quote_value(previous_lock_value, column_for_attribute(lock_col)))
|
30
|
+
)
|
31
|
+
).arel.compile_update(arel_attributes_with_values_for_update(attribute_names))
|
32
|
+
end
|
33
|
+
|
34
|
+
affected_rows = self.class.connection.update stmt
|
35
|
+
|
36
|
+
unless affected_rows == 1
|
37
|
+
raise ::ActiveRecord::StaleObjectError.new(self, "update")
|
38
|
+
end
|
39
|
+
|
40
|
+
affected_rows
|
41
|
+
|
42
|
+
# If something went wrong, revert the version.
|
43
|
+
rescue Exception
|
44
|
+
send(lock_col + '=', previous_lock_value)
|
45
|
+
raise
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,71 +1,25 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
class Relation
|
3
3
|
def add_cpk_support
|
4
|
-
|
5
|
-
include CompositePrimaryKeys::ActiveRecord::Batches
|
6
|
-
include CompositePrimaryKeys::ActiveRecord::Calculations
|
7
|
-
include CompositePrimaryKeys::ActiveRecord::FinderMethods
|
8
|
-
include CompositePrimaryKeys::ActiveRecord::QueryMethods
|
9
|
-
|
10
|
-
|
11
|
-
def delete(id_or_array)
|
12
|
-
# Without CPK:
|
13
|
-
# where(primary_key => id_or_array).delete_all
|
14
|
-
|
15
|
-
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
16
|
-
[id_or_array]
|
17
|
-
else
|
18
|
-
Array(id_or_array)
|
19
|
-
end
|
20
|
-
|
21
|
-
id_or_array.each do |id|
|
22
|
-
where(cpk_id_predicate(table, self.primary_key, id)).delete_all
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def destroy(id_or_array)
|
27
|
-
# Without CPK:
|
28
|
-
#if id.is_a?(Array)
|
29
|
-
# id.map { |one_id| destroy(one_id) }
|
30
|
-
#else
|
31
|
-
# find(id).destroy
|
32
|
-
#end
|
33
|
-
|
34
|
-
id_or_array = if id_or_array.kind_of?(CompositePrimaryKeys::CompositeKeys)
|
35
|
-
[id_or_array]
|
36
|
-
else
|
37
|
-
Array(id_or_array)
|
38
|
-
end
|
39
|
-
|
40
|
-
id_or_array.each do |id|
|
41
|
-
where(cpk_id_predicate(table, self.primary_key, id)).each do |record|
|
42
|
-
record.destroy
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
4
|
+
extend CompositePrimaryKeys::CompositeRelation
|
47
5
|
end
|
48
6
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
nodes_from_and = with_default_scope.where_values.grep(Arel::Nodes::And).map {|and_node| and_node.children.grep(Arel::Nodes::Equality) }.flatten
|
7
|
+
alias :where_values_hash_without_cpk :where_values_hash
|
8
|
+
def where_values_hash(relation_table_name = table_name)
|
9
|
+
# CPK adds this so that it finds the Equality nodes beneath the And node:
|
10
|
+
nodes_from_and = with_default_scope.where_values.grep(Arel::Nodes::And).map {|and_node| and_node.children.grep(Arel::Nodes::Equality) }.flatten
|
54
11
|
|
55
|
-
|
56
|
-
|
57
|
-
|
12
|
+
equalities = (nodes_from_and + with_default_scope.where_values.grep(Arel::Nodes::Equality)).find_all { |node|
|
13
|
+
node.left.relation.name == relation_table_name
|
14
|
+
}
|
58
15
|
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
16
|
+
Hash[equalities.map { |where| [where.left.name, where.right] }]
|
62
17
|
end
|
63
18
|
|
64
19
|
alias :initialize_without_cpk :initialize
|
65
20
|
def initialize(klass, table, values = {})
|
66
21
|
initialize_without_cpk(klass, table, values)
|
67
22
|
add_cpk_support if klass && klass.composite?
|
68
|
-
add_cpk_where_values_hash
|
69
23
|
end
|
70
24
|
|
71
25
|
alias :initialize_copy_without_cpk :initialize_copy
|
data/test/abstract_unit.rb
CHANGED
@@ -6,6 +6,7 @@ require 'composite_primary_keys'
|
|
6
6
|
|
7
7
|
require 'active_support/test_case'
|
8
8
|
require 'minitest/autorun'
|
9
|
+
require 'mocha/mini_test'
|
9
10
|
|
10
11
|
# Now load the connection spec
|
11
12
|
require File.join(PROJECT_ROOT, "test", "connections", "connection_spec")
|
@@ -27,13 +28,13 @@ I18n.config.enforce_available_locales = true
|
|
27
28
|
|
28
29
|
class ActiveSupport::TestCase
|
29
30
|
include ActiveRecord::TestFixtures
|
30
|
-
|
31
|
+
|
31
32
|
self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
32
33
|
self.use_instantiated_fixtures = false
|
33
34
|
self.use_transactional_fixtures = true
|
34
35
|
|
35
36
|
def assert_date_from_db(expected, actual, message = nil)
|
36
|
-
# SQL Server doesn't have a separate column type just for dates,
|
37
|
+
# SQL Server doesn't have a separate column type just for dates,
|
37
38
|
# so the time is in the string and incorrectly formatted
|
38
39
|
if current_adapter?(:SQLServerAdapter)
|
39
40
|
assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
|
@@ -60,11 +61,11 @@ class ActiveSupport::TestCase
|
|
60
61
|
def assert_no_queries(&block)
|
61
62
|
assert_queries(0, &block)
|
62
63
|
end
|
63
|
-
|
64
|
+
|
64
65
|
cattr_accessor :classes
|
65
66
|
|
66
67
|
protected
|
67
|
-
|
68
|
+
|
68
69
|
def testing_with(&block)
|
69
70
|
classes.keys.each do |key_test|
|
70
71
|
@key_test = key_test
|
@@ -75,15 +76,15 @@ class ActiveSupport::TestCase
|
|
75
76
|
yield
|
76
77
|
end
|
77
78
|
end
|
78
|
-
|
79
|
+
|
79
80
|
def first_id
|
80
81
|
ids = (1..@primary_keys.length).map {|num| 1}
|
81
82
|
composite? ? ids.to_composite_ids : ids.first
|
82
83
|
end
|
83
|
-
|
84
|
+
|
84
85
|
def composite?
|
85
86
|
@key_test != :single
|
86
|
-
end
|
87
|
+
end
|
87
88
|
|
88
89
|
# Oracle metadata is in all caps.
|
89
90
|
def with_quoted_identifiers(s)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
CREATE TABLE reference_types (
|
2
|
-
reference_type_id integer NOT NULL generated by default as identity (start with 100, increment by 1, no cache),
|
3
|
-
type_label varchar(50) default NULL,
|
4
|
-
abbreviation varchar(50) default NULL,
|
5
|
-
description varchar(50) default NULL,
|
2
|
+
reference_type_id integer NOT NULL generated by default as identity (start with 100, increment by 1, no cache),
|
3
|
+
type_label varchar(50) default NULL,
|
4
|
+
abbreviation varchar(50) default NULL,
|
5
|
+
description varchar(50) default NULL,
|
6
6
|
PRIMARY KEY (reference_type_id)
|
7
7
|
);
|
8
8
|
|
@@ -74,7 +74,7 @@ CREATE TABLE groups (
|
|
74
74
|
id integer NOT NULL ,
|
75
75
|
name varchar(50) NOT NULL,
|
76
76
|
PRIMARY KEY (id)
|
77
|
-
);
|
77
|
+
);
|
78
78
|
|
79
79
|
CREATE TABLE memberships (
|
80
80
|
user_id integer NOT NULL,
|
@@ -91,17 +91,18 @@ CREATE TABLE membership_statuses (
|
|
91
91
|
);
|
92
92
|
|
93
93
|
create table restaurants (
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
franchise_id integer not null,
|
95
|
+
store_id integer not null,
|
96
|
+
name varchar(100),
|
97
|
+
lock_version integer default 0,
|
98
|
+
primary key (franchise_id, store_id)
|
98
99
|
);
|
99
100
|
|
100
101
|
create table restaurants_suburbs (
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
franchise_id integer not null,
|
103
|
+
store_id integer not null,
|
104
|
+
city_id integer not null,
|
105
|
+
suburb_id integer not null
|
105
106
|
);
|
106
107
|
|
107
108
|
create table products_restaurants (
|
@@ -109,3 +110,9 @@ create table products_restaurants (
|
|
109
110
|
franchise_id integer not null,
|
110
111
|
store_id integer not null
|
111
112
|
);
|
113
|
+
|
114
|
+
create table model_with_callbacks (
|
115
|
+
reference_type_id integer,
|
116
|
+
reference_code integer NOT NULL,
|
117
|
+
PRIMARY KEY (reference_type_id,reference_code)
|
118
|
+
);
|
@@ -1,17 +1,18 @@
|
|
1
|
-
drop table MEMBERSHIPS;
|
2
|
-
drop table REFERENCE_CODES;
|
3
|
-
drop table TARIFFS;
|
4
|
-
drop table ARTICLES;
|
5
|
-
drop table GROUPS;
|
6
|
-
drop table MEMBERSHIP_STATUSES;
|
7
|
-
drop table READINGS;
|
8
|
-
drop table REFERENCE_TYPES;
|
9
|
-
drop table STREETS;
|
10
|
-
drop table PRODUCTS;
|
11
|
-
drop table USERS;
|
12
|
-
drop table SUBURBS;
|
13
|
-
drop table PRODUCT_TARIFFS;
|
1
|
+
drop table MEMBERSHIPS;
|
2
|
+
drop table REFERENCE_CODES;
|
3
|
+
drop table TARIFFS;
|
4
|
+
drop table ARTICLES;
|
5
|
+
drop table GROUPS;
|
6
|
+
drop table MEMBERSHIP_STATUSES;
|
7
|
+
drop table READINGS;
|
8
|
+
drop table REFERENCE_TYPES;
|
9
|
+
drop table STREETS;
|
10
|
+
drop table PRODUCTS;
|
11
|
+
drop table USERS;
|
12
|
+
drop table SUBURBS;
|
13
|
+
drop table PRODUCT_TARIFFS;
|
14
14
|
drop table KITCHEN_SINK;
|
15
15
|
drop table RESTAURANTS;
|
16
16
|
drop table RESTAURANTS_SUBURBS;
|
17
17
|
drop table PRODUCTS_RESTAURANTS;
|
18
|
+
drop table MODEL_WITH_CALLBACKS;
|
@@ -123,6 +123,7 @@ create table restaurants (
|
|
123
123
|
franchise_id int not null,
|
124
124
|
store_id int not null,
|
125
125
|
name varchar(100),
|
126
|
+
lock_version int default 0,
|
126
127
|
primary key (franchise_id, store_id)
|
127
128
|
);
|
128
129
|
|
@@ -190,3 +191,9 @@ create table employees_groups (
|
|
190
191
|
employee_id int not null,
|
191
192
|
group_id int not null
|
192
193
|
);
|
194
|
+
|
195
|
+
create table model_with_callbacks (
|
196
|
+
reference_type_id int not null,
|
197
|
+
reference_code int not null,
|
198
|
+
primary key (reference_type_id, reference_code)
|
199
|
+
);
|
@@ -131,6 +131,7 @@ create table restaurants (
|
|
131
131
|
franchise_id number(11) not null,
|
132
132
|
store_id number(11) not null,
|
133
133
|
name varchar(100),
|
134
|
+
lock_version number(11) default 0,
|
134
135
|
constraint restaurants_pk primary key (franchise_id, store_id)
|
135
136
|
);
|
136
137
|
|
@@ -205,3 +206,8 @@ create table employees_groups (
|
|
205
206
|
group_id int not null
|
206
207
|
);
|
207
208
|
|
209
|
+
create table model_with_callbacks(
|
210
|
+
reference_type_id number(11),
|
211
|
+
reference_code number(11),
|
212
|
+
constraint model_with_callbacks_pk primary key (reference_type_id, reference_code)
|
213
|
+
);
|
@@ -125,6 +125,7 @@ create table restaurants (
|
|
125
125
|
franchise_id int not null,
|
126
126
|
store_id int not null,
|
127
127
|
name varchar(100),
|
128
|
+
lock_version int default 0,
|
128
129
|
primary key (franchise_id, store_id)
|
129
130
|
);
|
130
131
|
|
@@ -192,3 +193,9 @@ create table employees_groups (
|
|
192
193
|
employee_id int not null,
|
193
194
|
group_id int not null
|
194
195
|
);
|
196
|
+
|
197
|
+
create table model_with_callbacks(
|
198
|
+
reference_type_id int,
|
199
|
+
reference_code int not null,
|
200
|
+
primary key (reference_type_id, reference_code)
|
201
|
+
);
|
@@ -83,7 +83,7 @@ create table membership_statuses (
|
|
83
83
|
id integer not null primary key autoincrement,
|
84
84
|
user_id int not null,
|
85
85
|
group_id int not null,
|
86
|
-
|
86
|
+
status varchar(50) not null
|
87
87
|
);
|
88
88
|
|
89
89
|
create table departments (
|
@@ -111,48 +111,49 @@ create table hacks (
|
|
111
111
|
);
|
112
112
|
|
113
113
|
create table restaurants (
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
114
|
+
franchise_id integer not null,
|
115
|
+
store_id integer not null,
|
116
|
+
name varchar(100),
|
117
|
+
lock_version integer default 0,
|
118
|
+
primary key (franchise_id, store_id)
|
118
119
|
);
|
119
120
|
|
120
121
|
create table restaurants_suburbs (
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
122
|
+
franchise_id integer not null,
|
123
|
+
store_id integer not null,
|
124
|
+
city_id integer not null,
|
125
|
+
suburb_id integer not null
|
125
126
|
);
|
126
127
|
|
127
128
|
create table dorms (
|
128
|
-
|
129
|
+
id integer not null primary key autoincrement
|
129
130
|
);
|
130
131
|
|
131
132
|
create table rooms (
|
132
|
-
|
133
|
-
|
134
|
-
|
133
|
+
dorm_id integer not null,
|
134
|
+
room_id integer not null,
|
135
|
+
primary key (dorm_id, room_id)
|
135
136
|
);
|
136
137
|
|
137
138
|
create table room_attributes (
|
138
|
-
|
139
|
-
|
139
|
+
id integer not null primary key autoincrement,
|
140
|
+
name varchar(50)
|
140
141
|
);
|
141
142
|
|
142
143
|
create table room_attribute_assignments (
|
143
|
-
|
144
|
-
|
145
|
-
|
144
|
+
dorm_id integer not null,
|
145
|
+
room_id integer not null,
|
146
|
+
room_attribute_id integer not null
|
146
147
|
);
|
147
148
|
|
148
149
|
create table students (
|
149
|
-
|
150
|
+
id integer not null primary key autoincrement
|
150
151
|
);
|
151
152
|
|
152
153
|
create table room_assignments (
|
153
|
-
|
154
|
-
|
155
|
-
|
154
|
+
student_id integer not null,
|
155
|
+
dorm_id integer not null,
|
156
|
+
room_id integer not null
|
156
157
|
);
|
157
158
|
|
158
159
|
create table seats (
|
@@ -170,8 +171,8 @@ create table capitols (
|
|
170
171
|
|
171
172
|
create table products_restaurants (
|
172
173
|
product_id integer not null,
|
173
|
-
|
174
|
-
|
174
|
+
franchise_id integer not null,
|
175
|
+
store_id integer not null
|
175
176
|
);
|
176
177
|
|
177
178
|
create table employees_groups (
|
@@ -179,3 +180,8 @@ create table employees_groups (
|
|
179
180
|
group_id integer not null
|
180
181
|
);
|
181
182
|
|
183
|
+
create table model_with_callbacks(
|
184
|
+
reference_type_id int(11),
|
185
|
+
reference_code int(11) not null,
|
186
|
+
primary key (reference_type_id, reference_code)
|
187
|
+
);
|
@@ -28,7 +28,7 @@ CREATE TABLE tariffs (
|
|
28
28
|
[tariff_id] [int],
|
29
29
|
[start_date] [date],
|
30
30
|
[amount] [int] NULL
|
31
|
-
CONSTRAINT [tariffs_pk] PRIMARY KEY
|
31
|
+
CONSTRAINT [tariffs_pk] PRIMARY KEY
|
32
32
|
( [tariff_id], [start_date] )
|
33
33
|
);
|
34
34
|
go
|
@@ -88,7 +88,7 @@ go
|
|
88
88
|
CREATE TABLE memberships (
|
89
89
|
user_id [int] NOT NULL,
|
90
90
|
group_id [int] NOT NULL
|
91
|
-
CONSTRAINT [memberships_pk] PRIMARY KEY
|
91
|
+
CONSTRAINT [memberships_pk] PRIMARY KEY
|
92
92
|
( [user_id], [group_id] )
|
93
93
|
);
|
94
94
|
go
|
@@ -133,8 +133,9 @@ go
|
|
133
133
|
CREATE TABLE restaurants (
|
134
134
|
franchise_id [int] NOT NULL,
|
135
135
|
store_id [int] NOT NULL,
|
136
|
-
name [varchar](100)
|
137
|
-
|
136
|
+
name [varchar](100),
|
137
|
+
lock_version [int] DEFAULT 0
|
138
|
+
CONSTRAINT [restaurants_pk] PRIMARY KEY CLUSTERED
|
138
139
|
( [franchise_id], [store_id] )
|
139
140
|
);
|
140
141
|
go
|
@@ -155,7 +156,7 @@ go
|
|
155
156
|
CREATE TABLE rooms (
|
156
157
|
dorm_id [int] NOT NULL,
|
157
158
|
room_id [int] NOT NULL,
|
158
|
-
CONSTRAINT [rooms_pk] PRIMARY KEY CLUSTERED
|
159
|
+
CONSTRAINT [rooms_pk] PRIMARY KEY CLUSTERED
|
159
160
|
( [dorm_id], [room_id] )
|
160
161
|
);
|
161
162
|
go
|
@@ -197,7 +198,7 @@ go
|
|
197
198
|
CREATE TABLE capitols (
|
198
199
|
country varchar(450) NOT NULL,
|
199
200
|
city varchar(450) NOT NULL
|
200
|
-
CONSTRAINT [capitols_pk] PRIMARY KEY
|
201
|
+
CONSTRAINT [capitols_pk] PRIMARY KEY
|
201
202
|
( [country], [city] )
|
202
203
|
);
|
203
204
|
go
|
@@ -207,4 +208,12 @@ CREATE TABLE products_restaurants (
|
|
207
208
|
franchise_id [int] NOT NULL,
|
208
209
|
store_id [int] NOT NULL
|
209
210
|
);
|
210
|
-
go
|
211
|
+
go
|
212
|
+
|
213
|
+
CREATE TABLE model_with_callbacks (
|
214
|
+
reference_type_id [int],
|
215
|
+
reference_code [int],
|
216
|
+
CONSTRAINT [model_with_callbacks_pk] PRIMARY KEY
|
217
|
+
( [reference_type_id], [reference_code] )
|
218
|
+
);
|
219
|
+
go
|
data/test/fixtures/dorm.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
class Dorm < ActiveRecord::Base
|
2
|
-
has_many :rooms,
|
3
|
-
end
|
2
|
+
has_many :rooms, -> { includes(:room_attributes) }, :primary_key => [:id]
|
3
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class ModelWithCallback < ActiveRecord::Base
|
2
|
+
after_save :after_save_method
|
3
|
+
before_save :before_save_method
|
4
|
+
around_save :around_save_method
|
5
|
+
|
6
|
+
after_create :after_create_method
|
7
|
+
before_create :before_create_method
|
8
|
+
around_create :around_create_method
|
9
|
+
|
10
|
+
after_update :after_update_method
|
11
|
+
before_update :before_update_method
|
12
|
+
around_update :around_update_method
|
13
|
+
|
14
|
+
after_destroy :after_destroy_method
|
15
|
+
before_destroy :before_destroy_method
|
16
|
+
around_destroy :around_destroy_method
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# Save callbacks
|
21
|
+
def after_save_method ; end
|
22
|
+
def before_save_method ; end
|
23
|
+
def around_save_method ; yield ; end
|
24
|
+
|
25
|
+
# Create callbacks
|
26
|
+
def after_create_method ; end
|
27
|
+
def before_create_method ; end
|
28
|
+
def around_create_method ; yield ;end
|
29
|
+
|
30
|
+
# Update callbacks
|
31
|
+
def after_update_method ; end
|
32
|
+
def before_update_method ; end
|
33
|
+
def around_update_method ; yield ; end
|
34
|
+
|
35
|
+
# Destroy callbacks
|
36
|
+
def after_destroy_method ; end
|
37
|
+
def before_destroy_method ; end
|
38
|
+
def around_destroy_method ; yield ; end
|
39
|
+
end
|
data/test/fixtures/suburb.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
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
|
-
has_many :first_streets,
|
5
|
-
|
6
|
-
end
|
4
|
+
has_many :first_streets, -> { where "streets.name = 'First Street'" },
|
5
|
+
:foreign_key => [:city_id, :suburb_id], :class_name => 'Street'
|
6
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
def has_callbacks(obj, action, options = {})
|
4
|
+
obj.expects(:"before_#{action}_method")
|
5
|
+
obj.expects(:"after_#{action}_method")
|
6
|
+
obj.expects(:"around_#{action}_method")
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestCallbacks < ActiveSupport::TestCase
|
10
|
+
fixtures :model_with_callbacks
|
11
|
+
|
12
|
+
def test_save_callbacks
|
13
|
+
obj = ModelWithCallback.first
|
14
|
+
has_callbacks(obj, :save)
|
15
|
+
obj.save
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_create_callbacks
|
19
|
+
obj = ModelWithCallback.new
|
20
|
+
has_callbacks(obj, :create)
|
21
|
+
obj.save!
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_update_callbacks
|
25
|
+
obj = ModelWithCallback.first
|
26
|
+
has_callbacks(obj, :update)
|
27
|
+
obj.reference_code = 4
|
28
|
+
obj.save!
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_destroy_callbacks
|
32
|
+
obj = ModelWithCallback.first
|
33
|
+
has_callbacks(obj, :destroy)
|
34
|
+
obj.destroy
|
35
|
+
end
|
36
|
+
end
|
data/test/test_delete.rb
CHANGED
@@ -90,11 +90,13 @@ class TestDelete < ActiveSupport::TestCase
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def test_destroy_has_and_belongs_to_many_on_non_cpk
|
93
|
-
steve = employees(:steve)
|
94
93
|
records_before = ActiveRecord::Base.connection.execute("select * from employees_groups").count
|
95
|
-
|
94
|
+
employee = Employee.create
|
95
|
+
employee.groups << Group.create(name: 'test')
|
96
|
+
employees_groups_count = employee.groups.count
|
97
|
+
employee.destroy!
|
96
98
|
records_after = ActiveRecord::Base.connection.execute("select * from employees_groups").count
|
97
|
-
assert_equal
|
99
|
+
assert_equal records_before, records_after
|
98
100
|
end
|
99
101
|
|
100
102
|
def test_delete_not_destroy_on_cpk
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path('../abstract_unit', __FILE__)
|
2
|
+
|
3
|
+
class TestDumpable < ActiveSupport::TestCase
|
4
|
+
fixtures :articles, :readings, :users
|
5
|
+
|
6
|
+
def test_marshal_with_simple_preload
|
7
|
+
articles = Article.preload(:readings).where(id: 1).to_a
|
8
|
+
assert_equal(Marshal.load(Marshal.dump(articles)), articles)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_marshal_with_comples_preload
|
12
|
+
articles = Article.preload({ readings: :user }).where(id: 1).to_a
|
13
|
+
assert_equal(Marshal.load(Marshal.dump(articles)), articles)
|
14
|
+
end
|
15
|
+
end
|
data/test/test_equal.rb
CHANGED
@@ -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,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: composite_primary_keys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.
|
4
|
+
version: 6.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dr Nic Williams
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-01-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -25,6 +25,20 @@ dependencies:
|
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: 4.0.6
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: mocha
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.1.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.1.0
|
28
42
|
description: Composite key support for ActiveRecord
|
29
43
|
email:
|
30
44
|
executables: []
|
@@ -50,17 +64,20 @@ files:
|
|
50
64
|
- lib/composite_primary_keys/associations/preloader/belongs_to.rb
|
51
65
|
- lib/composite_primary_keys/associations/preloader/has_and_belongs_to_many.rb
|
52
66
|
- lib/composite_primary_keys/attribute_methods/dirty.rb
|
67
|
+
- lib/composite_primary_keys/attribute_methods/primary_key.rb
|
53
68
|
- lib/composite_primary_keys/attribute_methods/read.rb
|
54
69
|
- lib/composite_primary_keys/attribute_methods/write.rb
|
55
70
|
- lib/composite_primary_keys/base.rb
|
56
71
|
- lib/composite_primary_keys/composite_arrays.rb
|
57
72
|
- lib/composite_primary_keys/composite_predicates.rb
|
73
|
+
- lib/composite_primary_keys/composite_relation.rb
|
58
74
|
- lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb
|
59
75
|
- lib/composite_primary_keys/connection_adapters/abstract_adapter.rb
|
60
76
|
- lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb
|
61
77
|
- lib/composite_primary_keys/core.rb
|
62
78
|
- lib/composite_primary_keys/dirty.rb
|
63
79
|
- lib/composite_primary_keys/fixtures.rb
|
80
|
+
- lib/composite_primary_keys/locking/optimistic.rb
|
64
81
|
- lib/composite_primary_keys/nested_attributes.rb
|
65
82
|
- lib/composite_primary_keys/persistence.rb
|
66
83
|
- lib/composite_primary_keys/relation.rb
|
@@ -123,6 +140,8 @@ files:
|
|
123
140
|
- test/fixtures/membership_status.rb
|
124
141
|
- test/fixtures/membership_statuses.yml
|
125
142
|
- test/fixtures/memberships.yml
|
143
|
+
- test/fixtures/model_with_callback.rb
|
144
|
+
- test/fixtures/model_with_callbacks.yml
|
126
145
|
- test/fixtures/product.rb
|
127
146
|
- test/fixtures/product_tariff.rb
|
128
147
|
- test/fixtures/product_tariffs.yml
|
@@ -166,10 +185,12 @@ files:
|
|
166
185
|
- test/test_attribute_methods.rb
|
167
186
|
- test/test_attributes.rb
|
168
187
|
- test/test_calculations.rb
|
188
|
+
- test/test_callbacks.rb
|
169
189
|
- test/test_composite_arrays.rb
|
170
190
|
- test/test_counter_cache.rb
|
171
191
|
- test/test_create.rb
|
172
192
|
- test/test_delete.rb
|
193
|
+
- test/test_dumpable.rb
|
173
194
|
- test/test_dup.rb
|
174
195
|
- test/test_equal.rb
|
175
196
|
- test/test_exists.rb
|
@@ -178,6 +199,7 @@ files:
|
|
178
199
|
- test/test_ids.rb
|
179
200
|
- test/test_miscellaneous.rb
|
180
201
|
- test/test_nested_attributes.rb
|
202
|
+
- test/test_optimistic.rb
|
181
203
|
- test/test_pagination.rb
|
182
204
|
- test/test_polymorphic.rb
|
183
205
|
- test/test_predicates.rb
|
@@ -207,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
229
|
version: '0'
|
208
230
|
requirements: []
|
209
231
|
rubyforge_project: compositekeys
|
210
|
-
rubygems_version: 2.4.
|
232
|
+
rubygems_version: 2.4.5
|
211
233
|
signing_key:
|
212
234
|
specification_version: 4
|
213
235
|
summary: Composite key support for ActiveRecord
|
@@ -221,10 +243,12 @@ test_files:
|
|
221
243
|
- test/test_attributes.rb
|
222
244
|
- test/test_attribute_methods.rb
|
223
245
|
- test/test_calculations.rb
|
246
|
+
- test/test_callbacks.rb
|
224
247
|
- test/test_composite_arrays.rb
|
225
248
|
- test/test_counter_cache.rb
|
226
249
|
- test/test_create.rb
|
227
250
|
- test/test_delete.rb
|
251
|
+
- test/test_dumpable.rb
|
228
252
|
- test/test_dup.rb
|
229
253
|
- test/test_equal.rb
|
230
254
|
- test/test_exists.rb
|
@@ -233,6 +257,7 @@ test_files:
|
|
233
257
|
- test/test_ids.rb
|
234
258
|
- test/test_miscellaneous.rb
|
235
259
|
- test/test_nested_attributes.rb
|
260
|
+
- test/test_optimistic.rb
|
236
261
|
- test/test_pagination.rb
|
237
262
|
- test/test_polymorphic.rb
|
238
263
|
- test/test_predicates.rb
|