composite_primary_keys 11.1.0 → 11.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.rdoc +7 -0
- data/lib/composite_primary_keys.rb +4 -4
- data/lib/composite_primary_keys/associations/has_many_through_association.rb +0 -59
- data/lib/composite_primary_keys/associations/preloader/association.rb +1 -1
- data/lib/composite_primary_keys/associations/through_association.rb +24 -0
- data/lib/composite_primary_keys/connection_adapters/abstract/database_statements.rb +17 -0
- data/lib/composite_primary_keys/persistence.rb +20 -0
- data/lib/composite_primary_keys/relation/batches.rb +24 -4
- data/lib/composite_primary_keys/version.rb +1 -1
- data/test/fixtures/db_definitions/postgresql.sql +2 -2
- data/test/fixtures/db_definitions/sqlite.sql +13 -13
- data/test/test_associations.rb +14 -0
- data/test/test_create.rb +11 -0
- data/test/test_delete.rb +13 -0
- data/test/test_preload.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76e658e30475707dc7495c8f5f5647c18ad0a67edc3cc5787a312a1785418524
|
4
|
+
data.tar.gz: f824d0c22fb21ec5d7d8311047433a6661cb5c134549ee46460e6c693b0cbe4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0721b3f2dcb649fd585baf7facf0747d73edf8929e1f7c2ef9b4522ce3824b23d94cec7caafd810d7ea77e03043ee3cc31abfd6dca16eb012556be147c634fe0
|
7
|
+
data.tar.gz: 40282b497748d0a9eda0cc461c38c4dc91714560022fa37e7466e085a65ea2bd53b85f50cd5845560a2ab43e0c24544b76faf493457f9f9f166ce3761b420285
|
data/History.rdoc
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 11.2.0 (2019-03-16)
|
2
|
+
* When creating new records, honor composite key autoincrementing fields if possible (Antti Pitkänen)
|
3
|
+
* Update Association#run to more closely match ActiveRecord (Fabian Mersch)
|
4
|
+
* Updates needed due to changes in ActiveRecord (Sammy Larbi)
|
5
|
+
* Fix construct_join_attributes method (Brad Slaughter)
|
6
|
+
* Fix destroy_all on HABTM (Brad Slaughter)
|
7
|
+
|
1
8
|
== 11.1.0 (2018-11-14)
|
2
9
|
* Support ActiveRecord 5.2.1 (S1Artem Tselovalnikov, Caleb Buxton, Charlie Savage)
|
3
10
|
* Fix counter cache (Tomonori Murakami)
|
@@ -50,21 +50,19 @@ require 'active_record/associations/join_dependency'
|
|
50
50
|
require 'active_record/associations/preloader/association'
|
51
51
|
require 'active_record/associations/singular_association'
|
52
52
|
require 'active_record/associations/collection_association'
|
53
|
+
require 'active_record/associations/through_association'
|
53
54
|
|
54
55
|
require 'active_record/attribute_methods/primary_key'
|
55
56
|
require 'active_record/attribute_methods/read'
|
56
57
|
require 'active_record/attribute_methods/write'
|
57
58
|
require 'active_record/nested_attributes'
|
58
59
|
|
60
|
+
require 'active_record/connection_adapters/abstract/database_statements'
|
59
61
|
require 'active_record/connection_adapters/abstract_adapter'
|
60
62
|
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
61
63
|
require 'active_record/connection_adapters/postgresql/database_statements'
|
62
64
|
|
63
|
-
require 'active_record/relation/batches'
|
64
65
|
require 'active_record/relation/where_clause'
|
65
|
-
require 'active_record/relation/calculations'
|
66
|
-
require 'active_record/relation/finder_methods'
|
67
|
-
require 'active_record/relation/query_methods'
|
68
66
|
require 'active_record/relation/predicate_builder/association_query_value'
|
69
67
|
|
70
68
|
require 'active_record/validations/uniqueness'
|
@@ -92,12 +90,14 @@ require 'composite_primary_keys/associations/has_many_through_association'
|
|
92
90
|
require 'composite_primary_keys/associations/join_dependency'
|
93
91
|
require 'composite_primary_keys/associations/preloader/association'
|
94
92
|
require 'composite_primary_keys/associations/collection_association'
|
93
|
+
require 'composite_primary_keys/associations/through_association'
|
95
94
|
|
96
95
|
require 'composite_primary_keys/attribute_methods/primary_key'
|
97
96
|
require 'composite_primary_keys/attribute_methods/read'
|
98
97
|
require 'composite_primary_keys/attribute_methods/write'
|
99
98
|
require 'composite_primary_keys/nested_attributes'
|
100
99
|
|
100
|
+
require 'composite_primary_keys/connection_adapters/abstract/database_statements'
|
101
101
|
require 'composite_primary_keys/connection_adapters/abstract_adapter'
|
102
102
|
require 'composite_primary_keys/connection_adapters/abstract_mysql_adapter'
|
103
103
|
require 'composite_primary_keys/connection_adapters/postgresql/database_statements'
|
@@ -1,66 +1,7 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class HasManyThroughAssociation
|
4
|
-
def cpk_join_through_predicate(*records)
|
5
|
-
ensure_mutable
|
6
4
|
|
7
|
-
ids = records.map do |record|
|
8
|
-
source_reflection.association_primary_key(reflection.klass).map do |key|
|
9
|
-
record.send(key)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
cpk_in_predicate(through_association.scope.klass.arel_table, source_reflection.foreign_key, ids)
|
14
|
-
end
|
15
|
-
|
16
|
-
def delete_records(records, method)
|
17
|
-
ensure_not_nested
|
18
|
-
|
19
|
-
scope = through_association.scope
|
20
|
-
# CPK
|
21
|
-
# scope.where! construct_join_attributes(*records)
|
22
|
-
if source_reflection.klass.composite?
|
23
|
-
scope.where! cpk_join_through_predicate(*records)
|
24
|
-
else
|
25
|
-
scope.where! construct_join_attributes(*records)
|
26
|
-
end
|
27
|
-
|
28
|
-
case method
|
29
|
-
when :destroy
|
30
|
-
if scope.klass.primary_key
|
31
|
-
count = scope.destroy_all.length
|
32
|
-
else
|
33
|
-
scope.to_a.each do |record|
|
34
|
-
record.run_callbacks :destroy
|
35
|
-
end
|
36
|
-
|
37
|
-
arel = scope.arel
|
38
|
-
|
39
|
-
stmt = Arel::DeleteManager.new arel.engine
|
40
|
-
stmt.from scope.klass.arel_table
|
41
|
-
stmt.wheres = arel.constraints
|
42
|
-
|
43
|
-
count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
|
44
|
-
end
|
45
|
-
when :nullify
|
46
|
-
count = scope.update_all(source_reflection.foreign_key => nil)
|
47
|
-
else
|
48
|
-
count = scope.delete_all
|
49
|
-
end
|
50
|
-
|
51
|
-
delete_through_records(records)
|
52
|
-
|
53
|
-
if source_reflection.options[:counter_cache] && method != :destroy
|
54
|
-
counter = source_reflection.counter_cache_column
|
55
|
-
klass.decrement_counter counter, records.map(&:id)
|
56
|
-
end
|
57
|
-
|
58
|
-
if through_reflection.collection? && update_through_counter?(method)
|
59
|
-
update_counter(-count, through_reflection)
|
60
|
-
end
|
61
|
-
|
62
|
-
update_counter(-count)
|
63
|
-
end
|
64
5
|
|
65
6
|
def through_records_for(record)
|
66
7
|
# CPK
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
module ThroughAssociation
|
4
|
+
alias :original_construct_join_attributes :construct_join_attributes
|
5
|
+
|
6
|
+
def construct_join_attributes(*records)
|
7
|
+
# CPK
|
8
|
+
if source_reflection.klass.composite?
|
9
|
+
ensure_mutable
|
10
|
+
|
11
|
+
ids = records.map do |record|
|
12
|
+
source_reflection.association_primary_key(reflection.klass).map do |key|
|
13
|
+
record.send(key)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
cpk_in_predicate(through_association.scope.klass.arel_table, source_reflection.foreign_key, ids)
|
18
|
+
else
|
19
|
+
original_construct_join_attributes(*records)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module DatabaseStatements
|
4
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
5
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
6
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
7
|
+
|
8
|
+
# CPK
|
9
|
+
if value && pk.is_a?(Array)
|
10
|
+
id_value || value.rows.first
|
11
|
+
else
|
12
|
+
id_value || last_inserted_id(value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -56,5 +56,25 @@ module ActiveRecord
|
|
56
56
|
connection.delete(dm, "#{self} Destroy")
|
57
57
|
end
|
58
58
|
end
|
59
|
+
|
60
|
+
def _create_record(attribute_names = self.attribute_names)
|
61
|
+
attribute_names &= self.class.column_names
|
62
|
+
attributes_values = attributes_with_values_for_create(attribute_names)
|
63
|
+
|
64
|
+
new_id = self.class._insert_record(attributes_values)
|
65
|
+
|
66
|
+
# CPK
|
67
|
+
if self.composite? && self.id.compact.empty?
|
68
|
+
self.id = new_id
|
69
|
+
else
|
70
|
+
self.id ||= new_id if self.class.primary_key
|
71
|
+
end
|
72
|
+
|
73
|
+
@new_record = false
|
74
|
+
|
75
|
+
yield(self) if block_given?
|
76
|
+
|
77
|
+
id
|
78
|
+
end
|
59
79
|
end
|
60
80
|
end
|
@@ -7,12 +7,19 @@ module CompositePrimaryKeys
|
|
7
7
|
return BatchEnumerator.new(of: of, start: start, finish: finish, relation: self)
|
8
8
|
end
|
9
9
|
|
10
|
-
if arel.orders.present?
|
11
|
-
|
10
|
+
if arel.orders.present?
|
11
|
+
act_on_ignored_order(error_on_ignore)
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
batch_limit = of
|
15
|
+
if limit_value
|
16
|
+
remaining = limit_value
|
17
|
+
batch_limit = remaining if remaining < batch_limit
|
18
|
+
end
|
19
|
+
|
20
|
+
relation = relation.reorder(batch_order).limit(batch_limit)
|
15
21
|
relation = apply_limits(relation, start, finish)
|
22
|
+
relation.skip_query_cache! # Retaining the results in the query cache would undermine the point of batching
|
16
23
|
batch_relation = relation
|
17
24
|
|
18
25
|
loop do
|
@@ -39,7 +46,20 @@ module CompositePrimaryKeys
|
|
39
46
|
|
40
47
|
yield yielded_relation
|
41
48
|
|
42
|
-
break if ids.length <
|
49
|
+
break if ids.length < batch_limit
|
50
|
+
|
51
|
+
if limit_value
|
52
|
+
remaining -= ids.length
|
53
|
+
|
54
|
+
if remaining == 0
|
55
|
+
# Saves a useless iteration when the limit is a multiple of the
|
56
|
+
# batch size.
|
57
|
+
break
|
58
|
+
elsif remaining < batch_limit
|
59
|
+
relation = relation.limit(remaining)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
43
63
|
# CPK
|
44
64
|
# batch_relation = relation.where(arel_attribute(primary_key).gt(primary_key_offset))
|
45
65
|
batch_relation = if composite?
|
@@ -20,8 +20,8 @@ create table reference_types (
|
|
20
20
|
);
|
21
21
|
|
22
22
|
create table reference_codes (
|
23
|
-
reference_type_id int
|
24
|
-
reference_code int
|
23
|
+
reference_type_id int,
|
24
|
+
reference_code int not null,
|
25
25
|
code_label varchar(50) default null,
|
26
26
|
abbreviation varchar(50) default null,
|
27
27
|
description varchar(50) default null,
|
@@ -29,14 +29,14 @@ create table reference_codes (
|
|
29
29
|
);
|
30
30
|
|
31
31
|
create table products (
|
32
|
-
id int
|
32
|
+
id int not null primary key,
|
33
33
|
name varchar(50) default null,
|
34
34
|
created_at TIMESTAMP,
|
35
35
|
updated_at TIMESTAMP
|
36
36
|
);
|
37
37
|
|
38
38
|
create table tariffs (
|
39
|
-
tariff_id int
|
39
|
+
tariff_id int not null,
|
40
40
|
start_date date not null,
|
41
41
|
amount integer(11) default null,
|
42
42
|
created_at TIMESTAMP,
|
@@ -45,23 +45,23 @@ create table tariffs (
|
|
45
45
|
);
|
46
46
|
|
47
47
|
create table product_tariffs (
|
48
|
-
product_id int
|
49
|
-
tariff_id int
|
48
|
+
product_id int not null,
|
49
|
+
tariff_id int not null,
|
50
50
|
tariff_start_date date not null,
|
51
51
|
primary key (product_id, tariff_id, tariff_start_date)
|
52
52
|
);
|
53
53
|
|
54
54
|
create table suburbs (
|
55
|
-
city_id int(
|
56
|
-
suburb_id int(
|
55
|
+
city_id int identity(1,1) not null,
|
56
|
+
suburb_id int identity(1,1) not null,
|
57
57
|
name varchar(50) not null,
|
58
58
|
primary key (city_id, suburb_id)
|
59
59
|
);
|
60
60
|
|
61
61
|
create table streets (
|
62
62
|
id integer not null primary key autoincrement,
|
63
|
-
city_id int
|
64
|
-
suburb_id int
|
63
|
+
city_id int not null,
|
64
|
+
suburb_id int not null,
|
65
65
|
name varchar(50) not null
|
66
66
|
);
|
67
67
|
|
@@ -77,9 +77,9 @@ create table articles (
|
|
77
77
|
|
78
78
|
create table readings (
|
79
79
|
id integer not null primary key autoincrement,
|
80
|
-
user_id int
|
81
|
-
article_id int
|
82
|
-
rating int
|
80
|
+
user_id int not null,
|
81
|
+
article_id int not null,
|
82
|
+
rating int not null
|
83
83
|
);
|
84
84
|
|
85
85
|
create table groups (
|
data/test/test_associations.rb
CHANGED
@@ -33,6 +33,11 @@ class TestAssociations < ActiveSupport::TestCase
|
|
33
33
|
assert_equal(3, products.inject(0) {|sum, product| sum + product.product_tariffs.length})
|
34
34
|
end
|
35
35
|
|
36
|
+
def test_find_includes_2
|
37
|
+
products = ProductTariff.where(:tariff_id => 2).order('product_id, tariff_id').includes(:tariff)
|
38
|
+
assert_equal(2, products.length)
|
39
|
+
end
|
40
|
+
|
36
41
|
def test_find_includes_eager_loading
|
37
42
|
product = products(:second_product)
|
38
43
|
product_tarrif = product_tariffs(:second_free)
|
@@ -59,6 +64,15 @@ class TestAssociations < ActiveSupport::TestCase
|
|
59
64
|
assert_equal(3, tariffs.inject(0) {|sum, tariff| sum + tariff.product_tariffs.length})
|
60
65
|
end
|
61
66
|
|
67
|
+
def test_find_each_does_not_throw_error
|
68
|
+
tariffs = Tariff.includes(:product_tariffs)
|
69
|
+
worked = false
|
70
|
+
tariffs.first.product_tariffs.order(:tariff_id).find_each do |pt|
|
71
|
+
worked = true
|
72
|
+
end
|
73
|
+
assert worked
|
74
|
+
end
|
75
|
+
|
62
76
|
def test_association_with_composite_primary_key_can_be_autosaved
|
63
77
|
room = Room.new(dorm_id: 1000, room_id: 1001)
|
64
78
|
room_assignment = RoomAssignment.new(student_id: 1000)
|
data/test/test_create.rb
CHANGED
@@ -48,6 +48,17 @@ class TestCreate < ActiveSupport::TestCase
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
def test_create_generated_keys
|
52
|
+
# Not all databases support columns with multiple identity fields
|
53
|
+
if defined?(ActiveRecord::ConnectionAdapters::PostgreSQL) ||
|
54
|
+
defined?(ActiveRecord::ConnectionAdapters::SQLite3)
|
55
|
+
|
56
|
+
suburb = Suburb.create!(:name => 'Capitol Hill')
|
57
|
+
refute_nil(suburb.city_id)
|
58
|
+
refute_nil(suburb.suburb_id)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
51
62
|
def test_create_on_association
|
52
63
|
suburb = Suburb.first
|
53
64
|
suburb.streets.create(:name => "my street")
|
data/test/test_delete.rb
CHANGED
@@ -116,6 +116,19 @@ class TestDelete < ActiveSupport::TestCase
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
|
+
def test_create_destroy_all_has_and_belongs_to_many_on_non_cpk
|
120
|
+
records_before = ActiveRecord::Base.connection.execute('select * from employees_groups')
|
121
|
+
employee = Employee.create!(department_id: 3, location_id: 2, name: 'Jon')
|
122
|
+
employee.groups << Group.create(name: 'test')
|
123
|
+
employee.groups.destroy_all
|
124
|
+
records_after = ActiveRecord::Base.connection.execute('select * from employees_groups')
|
125
|
+
if records_before.respond_to?(:count)
|
126
|
+
assert_equal records_before.count, records_after.count
|
127
|
+
elsif records_before.respond_to?(:row_count) # OCI8:Cursor for oracle adapter
|
128
|
+
assert_equal records_before.row_count, records_after.row_count
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
119
132
|
def test_delete_not_destroy_on_cpk
|
120
133
|
tariff = Tariff.where(tariff_id: 2).first
|
121
134
|
tariff.delete
|
data/test/test_preload.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path('../abstract_unit', __FILE__)
|
2
2
|
|
3
3
|
class TestPreload < ActiveSupport::TestCase
|
4
|
-
fixtures :comments, :users, :employees, :groups, :hacks
|
4
|
+
fixtures :comments, :users, :employees, :groups, :hacks, :readings
|
5
5
|
|
6
6
|
class UserForPreload < User
|
7
7
|
has_many :comments_with_include_condition, -> { where('person_type = ?', 'User')},
|
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: 11.
|
4
|
+
version: 11.2.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:
|
11
|
+
date: 2019-03-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -100,6 +100,7 @@ files:
|
|
100
100
|
- lib/composite_primary_keys/associations/has_many_through_association.rb
|
101
101
|
- lib/composite_primary_keys/associations/join_dependency.rb
|
102
102
|
- lib/composite_primary_keys/associations/preloader/association.rb
|
103
|
+
- lib/composite_primary_keys/associations/through_association.rb
|
103
104
|
- lib/composite_primary_keys/attribute_methods.rb
|
104
105
|
- lib/composite_primary_keys/attribute_methods/primary_key.rb
|
105
106
|
- lib/composite_primary_keys/attribute_methods/read.rb
|
@@ -109,6 +110,7 @@ files:
|
|
109
110
|
- lib/composite_primary_keys/composite_arrays.rb
|
110
111
|
- lib/composite_primary_keys/composite_predicates.rb
|
111
112
|
- lib/composite_primary_keys/composite_relation.rb
|
113
|
+
- lib/composite_primary_keys/connection_adapters/abstract/database_statements.rb
|
112
114
|
- lib/composite_primary_keys/connection_adapters/abstract_adapter.rb
|
113
115
|
- lib/composite_primary_keys/connection_adapters/abstract_mysql_adapter.rb
|
114
116
|
- lib/composite_primary_keys/connection_adapters/postgresql/database_statements.rb
|
@@ -270,8 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
270
272
|
- !ruby/object:Gem::Version
|
271
273
|
version: '0'
|
272
274
|
requirements: []
|
273
|
-
|
274
|
-
rubygems_version: 2.7.6
|
275
|
+
rubygems_version: 3.0.2
|
275
276
|
signing_key:
|
276
277
|
specification_version: 4
|
277
278
|
summary: Composite key support for ActiveRecord
|