composite_primary_keys 8.1.6 → 9.0.10
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 +5 -5
- data/History.rdoc +59 -7
- data/README.rdoc +62 -1
- data/Rakefile +4 -1
- data/lib/composite_primary_keys/arel/in.rb +6 -0
- data/lib/composite_primary_keys/arel/sqlserver.rb +36 -0
- data/lib/composite_primary_keys/arel/to_sql.rb +26 -0
- data/lib/composite_primary_keys/associations/association.rb +14 -12
- data/lib/composite_primary_keys/associations/association_scope.rb +22 -27
- data/lib/composite_primary_keys/associations/collection_association.rb +39 -8
- data/lib/composite_primary_keys/associations/has_many_association.rb +17 -40
- data/lib/composite_primary_keys/associations/has_many_through_association.rb +58 -58
- data/lib/composite_primary_keys/associations/join_dependency/join_association.rb +13 -11
- data/lib/composite_primary_keys/associations/join_dependency.rb +73 -56
- data/lib/composite_primary_keys/associations/preloader/association.rb +75 -73
- data/lib/composite_primary_keys/attribute_methods/primary_key.rb +13 -11
- data/lib/composite_primary_keys/attribute_methods/read.rb +18 -15
- data/lib/composite_primary_keys/attribute_methods/write.rb +21 -19
- data/lib/composite_primary_keys/attribute_methods.rb +6 -4
- data/lib/composite_primary_keys/autosave_association.rb +19 -54
- data/lib/composite_primary_keys/base.rb +18 -82
- data/lib/composite_primary_keys/composite_arrays.rb +9 -1
- data/lib/composite_primary_keys/composite_predicates.rb +1 -0
- data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +10 -10
- data/lib/composite_primary_keys/connection_adapters/abstract_mysql_adapter.rb +5 -6
- data/lib/composite_primary_keys/connection_adapters/sqlite3_adapter.rb +23 -0
- data/lib/composite_primary_keys/core.rb +46 -45
- data/lib/composite_primary_keys/fixtures.rb +19 -17
- data/lib/composite_primary_keys/locking/optimistic.rb +53 -49
- data/lib/composite_primary_keys/nested_attributes.rb +60 -53
- data/lib/composite_primary_keys/persistence.rb +49 -41
- data/lib/composite_primary_keys/relation/batches.rb +35 -32
- data/lib/composite_primary_keys/relation/calculations.rb +3 -7
- data/lib/composite_primary_keys/relation/finder_methods.rb +122 -55
- data/lib/composite_primary_keys/relation/predicate_builder.rb +18 -29
- data/lib/composite_primary_keys/relation/query_methods.rb +25 -36
- data/lib/composite_primary_keys/relation/where_clause.rb +33 -0
- data/lib/composite_primary_keys/relation.rb +96 -43
- data/lib/composite_primary_keys/sanitization.rb +6 -15
- data/lib/composite_primary_keys/version.rb +3 -3
- data/lib/composite_primary_keys.rb +10 -19
- data/scripts/console.rb +48 -48
- data/scripts/txt2html +76 -76
- data/scripts/txt2js +65 -65
- data/tasks/databases/mysql.rake +17 -19
- data/tasks/databases/oracle.rake +29 -15
- data/tasks/databases/postgresql.rake +20 -29
- data/tasks/databases/sqlite.rake +25 -0
- data/tasks/databases/sqlserver.rake +32 -16
- data/tasks/website.rake +18 -18
- data/test/README_tests.rdoc +56 -56
- data/test/abstract_unit.rb +24 -18
- data/test/connections/connection_spec.rb +11 -2
- data/test/connections/databases.ci.yml +5 -4
- data/test/connections/databases.example.yml +19 -4
- data/test/connections/databases.yml +40 -30
- data/test/db_test.rb +52 -52
- data/test/fixtures/article.rb +1 -0
- data/test/fixtures/articles.yml +6 -6
- data/test/fixtures/capitol.rb +3 -3
- data/test/fixtures/capitols.yml +16 -16
- data/test/fixtures/comments.yml +15 -15
- data/test/fixtures/db_definitions/mysql.sql +16 -17
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +26 -17
- data/test/fixtures/db_definitions/postgresql.sql +2 -3
- data/test/fixtures/db_definitions/sqlite.sql +0 -1
- data/test/fixtures/db_definitions/sqlserver.sql +20 -35
- data/test/fixtures/department.rb +5 -5
- data/test/fixtures/departments.yml +15 -15
- data/test/fixtures/dorms.yml +4 -4
- data/test/fixtures/employee.rb +5 -7
- data/test/fixtures/employees.yml +1 -5
- data/test/fixtures/group.rb +2 -2
- data/test/fixtures/groups.yml +6 -6
- data/test/fixtures/hack.rb +4 -4
- data/test/fixtures/hacks.yml +2 -2
- data/test/fixtures/membership_status.rb +2 -2
- data/test/fixtures/product.rb +9 -9
- data/test/fixtures/product_tariff.rb +5 -5
- data/test/fixtures/products.yml +11 -11
- data/test/fixtures/reading.rb +4 -4
- data/test/fixtures/readings.yml +10 -10
- data/test/fixtures/reference_code_using_composite_key_alias.rb +8 -8
- data/test/fixtures/reference_code_using_simple_key_alias.rb +8 -8
- data/test/fixtures/reference_codes.yml +28 -28
- data/test/fixtures/reference_type.rb +1 -1
- data/test/fixtures/reference_types.yml +9 -9
- data/test/fixtures/restaurant.rb +9 -9
- data/test/fixtures/restaurants.yml +14 -14
- data/test/fixtures/restaurants_suburbs.yml +10 -10
- data/test/fixtures/room.rb +11 -11
- data/test/fixtures/room_assignment.rb +13 -13
- data/test/fixtures/room_assignments.yml +24 -24
- data/test/fixtures/room_attribute.rb +2 -2
- data/test/fixtures/room_attribute_assignment.rb +4 -4
- data/test/fixtures/room_attribute_assignments.yml +4 -4
- data/test/fixtures/room_attributes.yml +2 -2
- data/test/fixtures/rooms.yml +12 -12
- data/test/fixtures/seat.rb +5 -5
- data/test/fixtures/seats.yml +8 -8
- data/test/fixtures/street.rb +2 -2
- data/test/fixtures/streets.yml +16 -16
- data/test/fixtures/student.rb +3 -3
- data/test/fixtures/students.yml +15 -15
- data/test/fixtures/suburbs.yml +14 -14
- data/test/fixtures/tariff.rb +1 -1
- data/test/fixtures/tariffs.yml +14 -14
- data/test/fixtures/user.rb +0 -1
- data/test/plugins/pagination.rb +405 -405
- data/test/plugins/pagination_helper.rb +135 -135
- data/test/setup.rb +50 -50
- data/test/test_aliases.rb +18 -18
- data/test/test_associations.rb +18 -17
- data/test/test_composite_arrays.rb +24 -24
- data/test/test_counter_cache.rb +30 -30
- data/test/test_create.rb +14 -6
- data/test/test_delete.rb +36 -34
- data/test/test_dup.rb +37 -37
- data/test/test_exists.rb +39 -39
- data/test/test_find.rb +16 -4
- data/test/test_habtm.rb +27 -3
- data/test/test_miscellaneous.rb +32 -32
- data/test/test_nested_attributes.rb +6 -6
- data/test/test_pagination.rb +35 -35
- data/test/test_polymorphic.rb +0 -7
- data/test/test_predicates.rb +20 -20
- data/test/test_preload.rb +94 -0
- data/test/test_suite.rb +1 -1
- data/test/test_update.rb +10 -7
- data/test/test_validations.rb +13 -13
- metadata +30 -39
- data/README_DB2.rdoc +0 -33
- data/lib/composite_primary_keys/arel/visitors/to_sql.rb +0 -36
- data/lib/composite_primary_keys/associations/singular_association.rb +0 -18
- data/lib/composite_primary_keys/attribute_methods/dirty.rb +0 -29
- data/lib/composite_primary_keys/attribute_set/builder.rb +0 -20
- data/lib/composite_primary_keys/connection_adapters/abstract/connection_specification_changes.rb +0 -70
- data/lib/composite_primary_keys/connection_adapters/postgresql_adapter.rb +0 -19
- data/lib/composite_primary_keys/dirty.rb +0 -19
- data/lib/composite_primary_keys/validations/uniqueness.rb +0 -41
- data/tasks/databases/oracle_enhanced.rake +0 -27
- data/tasks/databases/sqlite3.rake +0 -27
- data/test/connections/native_ibm_db/connection.rb +0 -19
- data/test/connections/native_mysql/connection.rb +0 -17
- data/test/connections/native_oracle/connection.rb +0 -11
- data/test/connections/native_oracle_enhanced/connection.rb +0 -16
- data/test/connections/native_postgresql/connection.rb +0 -13
- data/test/connections/native_sqlite3/connection.rb +0 -9
- data/test/connections/native_sqlserver/connection.rb +0 -11
- data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -92
- data/test/test_delete_all.rb +0 -35
- data/test/test_find_in_batches.rb +0 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 133a4025b9fe7ee82617de7c3c34373d8f52d38d5e88c03ab742ebd954bf6064
|
|
4
|
+
data.tar.gz: 579e4d9e564e4c9e40f976d0d56b76533296c8f7e5b5ba925d7244141604fb08
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 334933952b9a84db67746c48c074c38d197215fa607640e134bf7aedd564e122a0c809318fab4529e0ad5bd181081baa792395419b25a4b19149066122cdfdfc
|
|
7
|
+
data.tar.gz: 2820381f390429bbdf61b0a04434c0432faa88d2cffdb04c5cd74f9dfc26682893809531b2d4dc14b03620614bec0ce1a69e128624b6a511b5718b19e24c9970
|
data/History.rdoc
CHANGED
|
@@ -1,11 +1,62 @@
|
|
|
1
|
-
==
|
|
1
|
+
== 9.0.10 (2018-06-24)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Fix
|
|
8
|
-
|
|
3
|
+
* Fix AR 5.0.7 (Jordan Owens)
|
|
4
|
+
|
|
5
|
+
== 9.0.9 (2018-03-06)
|
|
6
|
+
|
|
7
|
+
* Fix update statements that incorrectly pass NULL values for the primary key components (Sean Linsley)
|
|
8
|
+
|
|
9
|
+
== 9.0.8 (2017-10-11)
|
|
10
|
+
|
|
11
|
+
* Fix Paper Trail compatibility (Sean Linsley)
|
|
12
|
+
|
|
13
|
+
== 9.0.7 (2017-05-22)
|
|
14
|
+
|
|
15
|
+
* Update sqlite3 to support deletes and updates (Charlie Savage)
|
|
16
|
+
* Specify version for sql server gem so it works with Rails 5.0 (Charlie Savage)
|
|
17
|
+
* Use `datetime` datatype to address Invalid default value for updated_at (Yasuo Honda)
|
|
18
|
+
* Fix ORA-00900 error when it attempts to execute blank statement (pustomytnyk)
|
|
19
|
+
* Override ActiveRecord::Associations::CollectionAssociation#ids_reader (pustomytnyk)
|
|
20
|
+
* Only define #primary_keys if #primary_keys=(value) is called (Charlie Savage)
|
|
21
|
+
* Change `timestamp` to `datetime` for MySQL as ActiveRecord timestamps type does (Oriol Collel)
|
|
22
|
+
* Fix incorrect case statement to get PK for SQLServer (Oriol Collel)
|
|
23
|
+
* Fixes random failures in test_preload_of_polymorphic_association (Boris Peterbarg)
|
|
24
|
+
|
|
25
|
+
== 9.0.6 (2017-01-08)
|
|
26
|
+
|
|
27
|
+
* Uncomment tests (Sammy Larbi)
|
|
28
|
+
* Update readme (Charlie Savage)
|
|
29
|
+
|
|
30
|
+
== 9.0.5 (2017-01-02)
|
|
31
|
+
|
|
32
|
+
* Don't nest PK twice when looking up id, fixes #319 (Kerey Roper)
|
|
33
|
+
* Simplify database setup for tests (Charlie Savage)
|
|
34
|
+
* Revamp gem management (Charlie Savage)
|
|
35
|
+
* Add support for Relation#update_all when using joins (Charlie Savage)
|
|
36
|
+
* Add erb support to test database.yml files (Charlie Savage)
|
|
37
|
+
* Sqlserver fixes for ordering (Charlie Savage)
|
|
38
|
+
* Sqlserver refresh (Charlie Savage)
|
|
39
|
+
* Oracle refresh (Charlie Savage)
|
|
40
|
+
* Fix delete_all for MySql (Charlie Savage)
|
|
41
|
+
* Added test cases for preloading associations with and without conditions (Martin Körner)
|
|
42
|
+
* Revamp single association handling to correctly setup SQL binds (Charlie Savage)
|
|
43
|
+
* Remove references to ActiveModel - #352 (Charlie Savage)
|
|
44
|
+
* Fixes for #232, #359, #367 and #371 (Charlie Savage)
|
|
45
|
+
|
|
46
|
+
== 9.0.4 (2016-08-17)
|
|
47
|
+
* Do not set associations to readonly. See https://github.com/rails/rails/issues/24093 (Charlie Savage)
|
|
48
|
+
|
|
49
|
+
== 9.0.2 (2016-08-10)
|
|
50
|
+
* Fix delete_all when used with a join (Charlie Savage)
|
|
51
|
+
|
|
52
|
+
== 9.0.1 (2016-07-27)
|
|
53
|
+
* Create OR predicates in a nicely balanced tree fixing #320 (Nathan Samson)
|
|
54
|
+
|
|
55
|
+
== 9.0.0 (2016-07-06)
|
|
56
|
+
* Support connection_specification_name in rails5.0.0.rc1 (pocari)
|
|
57
|
+
|
|
58
|
+
== 9.0.0.beta1 (2016-04-16)
|
|
59
|
+
* Rails 5 beta support (Sammy Larbi)
|
|
9
60
|
|
|
10
61
|
== 8.1.5 (2017-01-01)
|
|
11
62
|
|
|
@@ -38,6 +89,7 @@ Extend approach from #344 to fix autosave for has_one associations as well (Came
|
|
|
38
89
|
* Remove call to verify_active_connections! which was removed from AR 4.1 (Steve Pletcher)
|
|
39
90
|
* Aligned the establish connection paramater handling to be similar to latest version of rails (Harish Shetty)
|
|
40
91
|
|
|
92
|
+
|
|
41
93
|
== 8.1.0 (2014-03-23)
|
|
42
94
|
|
|
43
95
|
* ActiveRecord 4.2.1 support (Charlie Savage)
|
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 9.x is designed to work with ActiveRecord 5.0.x
|
|
23
24
|
Version 8.x is designed to work with ActiveRecord 4.2.x
|
|
24
25
|
Version 7.x is designed to work with ActiveRecord 4.1.x
|
|
25
26
|
Version 6.x is designed to work with ActiveRecord 4.0.x
|
|
@@ -97,9 +98,69 @@ CPK supports the following databases:
|
|
|
97
98
|
|
|
98
99
|
== Tests
|
|
99
100
|
|
|
101
|
+
To run tests you first need to install the appropriate gems for the database you want to test. Database gems are
|
|
102
|
+
divided into the following bundler groups:
|
|
103
|
+
|
|
104
|
+
* mysql
|
|
105
|
+
* oracle
|
|
106
|
+
* postgresql
|
|
107
|
+
* sqlite
|
|
108
|
+
* sqlserver
|
|
109
|
+
|
|
110
|
+
Since it is likely you do not have all the above databases installed on your computer, you want to install just the
|
|
111
|
+
gems for your database. For example, to test postgresql you would install the appropriate gems like this:
|
|
112
|
+
|
|
113
|
+
bundler install --without "mysql oracle sqlite sqlserver"
|
|
114
|
+
|
|
115
|
+
Once you have installed the appropriate gems, the next step is to create the test database. There is a rake
|
|
116
|
+
command for each database. Using our example:
|
|
117
|
+
|
|
118
|
+
rake postgresql:build_database
|
|
119
|
+
|
|
120
|
+
You can also rebuild the database if it already exists using this command:
|
|
121
|
+
|
|
122
|
+
rake postgresql:rebuild_database
|
|
123
|
+
|
|
124
|
+
To get a list of commands for your database use:
|
|
125
|
+
|
|
126
|
+
Rake -T
|
|
127
|
+
|
|
128
|
+
Finally, to run tests:
|
|
129
|
+
|
|
130
|
+
rake postgresql:test
|
|
131
|
+
|
|
100
132
|
Travis build status: {<img src="https://travis-ci.org/composite-primary-keys/composite_primary_keys.svg" alt="Build Status" />}[https://travis-ci.org/composite-primary-keys/composite_primary_keys]
|
|
101
133
|
|
|
102
|
-
|
|
134
|
+
=== DB2
|
|
135
|
+
|
|
136
|
+
DB2 is no longer supported due to difficulties in getting the ibm_db2 gem to build. Thus tests
|
|
137
|
+
have not been run against db2.
|
|
138
|
+
|
|
139
|
+
=== MariaDb (mysql)
|
|
140
|
+
|
|
141
|
+
MariaDb is fully supported with all tests passing.
|
|
142
|
+
|
|
143
|
+
=== Oracle
|
|
144
|
+
|
|
145
|
+
Oracle is fully supported with all tests passing.
|
|
146
|
+
|
|
147
|
+
=== Postgresql
|
|
148
|
+
|
|
149
|
+
Postgresql is fully supported with all tests passing.
|
|
150
|
+
|
|
151
|
+
=== Sqlite 3
|
|
152
|
+
|
|
153
|
+
The sqlite database is created at the path composite_primary_keys/db. Note you must *first* create the database using the
|
|
154
|
+
built-in rake task before running tests:
|
|
155
|
+
|
|
156
|
+
rake sqlite:build_database
|
|
157
|
+
|
|
158
|
+
Note not all tests currently pass on sqlite3. These failures happen when trying to DELETE records where the query
|
|
159
|
+
includes a JOIN.
|
|
160
|
+
|
|
161
|
+
=== SqlServer
|
|
162
|
+
|
|
163
|
+
SqlServer is partially supported. There are a number of failing tests - patches welcomed.
|
|
103
164
|
|
|
104
165
|
== Questions, Discussion and Contributions
|
|
105
166
|
|
data/Rakefile
CHANGED
|
@@ -8,6 +8,9 @@ require 'rubygems/package_task'
|
|
|
8
8
|
::PROJECT_ROOT = File.expand_path(".")
|
|
9
9
|
::GEM_NAME = 'composite_primary_keys'
|
|
10
10
|
|
|
11
|
+
require File.join(PROJECT_ROOT, 'lib', 'composite_primary_keys')
|
|
12
|
+
require File.join(PROJECT_ROOT, 'test', 'connections', 'connection_spec')
|
|
13
|
+
|
|
11
14
|
# Read the spec file
|
|
12
15
|
spec = Gem::Specification.load("#{GEM_NAME}.gemspec")
|
|
13
16
|
|
|
@@ -20,7 +23,7 @@ Dir.glob('tasks/**/*.rake').each do |rake_file|
|
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
# Set up test tasks for each supported connection adapter
|
|
23
|
-
%w(mysql
|
|
26
|
+
%w(mysql sqlite oracle oracle_enhanced postgresql ibm_db sqlserver).each do |adapter|
|
|
24
27
|
namespace adapter do
|
|
25
28
|
desc "Run tests using the #{adapter} adapter"
|
|
26
29
|
task "test" do
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Arel
|
|
2
|
+
module Visitors
|
|
3
|
+
class SQLServer
|
|
4
|
+
def make_Fetch_Possible_And_Deterministic o
|
|
5
|
+
return if o.limit.nil? && o.offset.nil?
|
|
6
|
+
t = table_From_Statement o
|
|
7
|
+
pk = primary_Key_From_Table t
|
|
8
|
+
return unless pk
|
|
9
|
+
if o.orders.empty?
|
|
10
|
+
# Prefer deterministic vs a simple `(SELECT NULL)` expr.
|
|
11
|
+
# CPK
|
|
12
|
+
#o.orders = [pk.asc]
|
|
13
|
+
o.orders = pk.map {|a_pk| a_pk.asc}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def primary_Key_From_Table t
|
|
18
|
+
return unless t
|
|
19
|
+
column_name = schema_cache.primary_keys(t.name) || column_cache(t.name).first.second.try(:name)
|
|
20
|
+
|
|
21
|
+
# CPK
|
|
22
|
+
# column_name ? t[column_name] : nil
|
|
23
|
+
case column_name
|
|
24
|
+
when Array
|
|
25
|
+
column_name.map do |name|
|
|
26
|
+
t[name]
|
|
27
|
+
end
|
|
28
|
+
when NilClass
|
|
29
|
+
nil
|
|
30
|
+
else
|
|
31
|
+
[t[column_name]]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Arel
|
|
2
|
+
module Visitors
|
|
3
|
+
class ToSql
|
|
4
|
+
def visit_CompositePrimaryKeys_Nodes_In o, collector
|
|
5
|
+
collector << "("
|
|
6
|
+
visit(o.left, collector)
|
|
7
|
+
collector << ")"
|
|
8
|
+
collector << " IN ("
|
|
9
|
+
visit(o.right, collector) << ")"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def visit_CompositePrimaryKeys_CompositeKeys o, collector
|
|
13
|
+
values = o.map do |key|
|
|
14
|
+
case key
|
|
15
|
+
when Arel::Attributes::Attribute
|
|
16
|
+
"#{key.relation.name}.#{key.name}"
|
|
17
|
+
else
|
|
18
|
+
key
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
collector << "#{values.join(', ')}"
|
|
22
|
+
collector
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
module ActiveRecord
|
|
2
2
|
module Associations
|
|
3
3
|
class Association
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
silence_warnings do
|
|
5
|
+
def creation_attributes
|
|
6
|
+
attributes = {}
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
if (reflection.has_one? || reflection.collection?) && !options[:through]
|
|
9
|
+
# CPK
|
|
10
|
+
# attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
|
|
11
|
+
Array(reflection.foreign_key).zip(Array(reflection.active_record_primary_key)).each do |key1, key2|
|
|
12
|
+
attributes[key1] = owner[key2]
|
|
13
|
+
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
if reflection.options[:as]
|
|
16
|
+
attributes[reflection.type] = owner.class.base_class.name
|
|
17
|
+
end
|
|
16
18
|
end
|
|
17
|
-
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
attributes
|
|
21
|
+
end
|
|
20
22
|
end
|
|
21
23
|
end
|
|
22
24
|
end
|
|
@@ -23,49 +23,44 @@ module ActiveRecord
|
|
|
23
23
|
binds
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def
|
|
27
|
-
join_keys = reflection.join_keys(
|
|
26
|
+
def last_chain_scope(scope, table, reflection, owner, association_klass)
|
|
27
|
+
join_keys = reflection.join_keys(association_klass)
|
|
28
28
|
key = join_keys.key
|
|
29
29
|
foreign_key = join_keys.foreign_key
|
|
30
30
|
|
|
31
31
|
# CPK
|
|
32
|
-
#
|
|
33
|
-
|
|
32
|
+
#value = transform_value(owner[foreign_key])
|
|
33
|
+
#scope = scope.where(table.name => { key => value })
|
|
34
|
+
mappings = Array(key).zip(Array(foreign_key))
|
|
35
|
+
joins = mappings.reduce(Hash.new) do |hash, mapping|
|
|
36
|
+
hash[mapping.first] = transform_value(owner[mapping.last])
|
|
37
|
+
hash
|
|
38
|
+
end
|
|
39
|
+
scope = scope.where(table.name => joins)
|
|
34
40
|
|
|
35
41
|
if reflection.type
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
scope = scope.where(table[reflection.type].eq(bind_val))
|
|
42
|
+
polymorphic_type = transform_value(owner.class.base_class.name)
|
|
43
|
+
scope = scope.where(table.name => { reflection.type => polymorphic_type })
|
|
39
44
|
end
|
|
40
45
|
|
|
41
|
-
scope
|
|
46
|
+
scope
|
|
42
47
|
end
|
|
43
48
|
|
|
44
|
-
def
|
|
45
|
-
join_keys = reflection.join_keys(
|
|
49
|
+
def next_chain_scope(scope, table, reflection, association_klass, foreign_table, next_reflection)
|
|
50
|
+
join_keys = reflection.join_keys(association_klass)
|
|
46
51
|
key = join_keys.key
|
|
47
52
|
foreign_key = join_keys.foreign_key
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
key.zip(foreign_key).map do |k, fk|
|
|
53
|
-
bind_val = bind scope, table.table_name, k.to_s, owner[fk], tracker
|
|
54
|
-
scope = scope.where(table[k].eq(bind_val))
|
|
55
|
-
end
|
|
56
|
-
else
|
|
57
|
-
bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key], tracker
|
|
58
|
-
scope = scope.where(table[key].eq(bind_val))
|
|
59
|
-
end
|
|
54
|
+
# CPK
|
|
55
|
+
# constraint = table[key].eq(foreign_table[foreign_key])
|
|
56
|
+
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
|
60
57
|
|
|
61
58
|
if reflection.type
|
|
62
|
-
value
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
scope.where(table[reflection.type].eq(bind_val))
|
|
66
|
-
else
|
|
67
|
-
scope
|
|
59
|
+
value = transform_value(next_reflection.klass.base_class.name)
|
|
60
|
+
scope = scope.where(table.name => { reflection.type => value })
|
|
68
61
|
end
|
|
62
|
+
|
|
63
|
+
scope = scope.joins(join(foreign_table, constraint))
|
|
69
64
|
end
|
|
70
65
|
end
|
|
71
66
|
end
|
|
@@ -1,15 +1,46 @@
|
|
|
1
1
|
module CompositePrimaryKeys
|
|
2
2
|
module CollectionAssociation
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
def get_records
|
|
4
|
+
cpk_applies = target.try(:composite?) || owner.try(:composite?)
|
|
5
|
+
return scope.to_a if cpk_applies
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def ids_reader
|
|
10
|
+
if loaded?
|
|
11
|
+
load_target.map do |record|
|
|
12
|
+
if reflection.association_primary_key.is_a?(Array)
|
|
13
|
+
reflection.association_primary_key.map { |key| record.send(key) }
|
|
14
|
+
else
|
|
15
|
+
record.send(reflection.association_primary_key)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
else
|
|
19
|
+
@association_ids ||= (
|
|
20
|
+
column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
|
|
21
|
+
scope.pluck(column)
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ids_writer(ids)
|
|
27
|
+
pk_type = reflection.primary_key_type
|
|
28
|
+
ids = Array(ids).reject(&:blank?)
|
|
29
|
+
ids.map! { |i| pk_type.cast(i) }
|
|
30
|
+
# CPK
|
|
31
|
+
if reflection.association_primary_key.is_a?(Array)
|
|
32
|
+
predicate = Class.new.extend(CompositePrimaryKeys::Predicates).cpk_in_predicate(klass.arel_table, reflection.association_primary_key, ids)
|
|
33
|
+
records = klass.where(predicate).index_by do |r|
|
|
34
|
+
reflection.association_primary_key.map{ |k| r.send(k) }
|
|
35
|
+
end.values_at(*ids)
|
|
36
|
+
else
|
|
37
|
+
records = klass.where(reflection.association_primary_key => ids).index_by do |r|
|
|
38
|
+
r.send(reflection.association_primary_key)
|
|
39
|
+
end.values_at(*ids)
|
|
9
40
|
end
|
|
10
|
-
|
|
41
|
+
replace(records)
|
|
11
42
|
end
|
|
12
43
|
end
|
|
13
44
|
end
|
|
14
45
|
|
|
15
|
-
ActiveRecord::Associations::CollectionAssociation.
|
|
46
|
+
ActiveRecord::Associations::CollectionAssociation.prepend CompositePrimaryKeys::CollectionAssociation
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
module ActiveRecord
|
|
2
2
|
module Associations
|
|
3
3
|
class HasManyAssociation
|
|
4
|
+
include CompositePrimaryKeys::Predicates
|
|
5
|
+
|
|
6
|
+
def delete_records(records, method)
|
|
7
|
+
if method == :destroy
|
|
8
|
+
records.each(&:destroy!)
|
|
9
|
+
update_counter(-records.length) unless reflection.inverse_updates_counter_cache?
|
|
10
|
+
return
|
|
11
|
+
# Zerista
|
|
12
|
+
elsif self.reflection.klass.composite?
|
|
13
|
+
predicate = cpk_in_predicate(self.scope.table, self.reflection.klass.primary_keys, records.map(&:id))
|
|
14
|
+
scope = self.scope.where(predicate)
|
|
15
|
+
else
|
|
16
|
+
scope = self.scope.where(reflection.klass.primary_key => records)
|
|
17
|
+
end
|
|
18
|
+
update_counter(-delete_count(method, scope))
|
|
19
|
+
end
|
|
20
|
+
|
|
4
21
|
def delete_count(method, scope)
|
|
5
22
|
if method == :delete_all
|
|
6
23
|
scope.delete_all
|
|
@@ -15,46 +32,6 @@ module ActiveRecord
|
|
|
15
32
|
end
|
|
16
33
|
end
|
|
17
34
|
|
|
18
|
-
def delete_records(records, method)
|
|
19
|
-
if method == :destroy
|
|
20
|
-
records.each(&:destroy!)
|
|
21
|
-
update_counter(-records.length) unless inverse_updates_counter_cache?
|
|
22
|
-
else
|
|
23
|
-
if records == :all || !reflection.klass.primary_key
|
|
24
|
-
scope = self.scope
|
|
25
|
-
else
|
|
26
|
-
# CPK
|
|
27
|
-
# scope = self.scope.where(reflection.klass.primary_key => records)
|
|
28
|
-
table = Arel::Table.new(reflection.table_name)
|
|
29
|
-
and_conditions = records.map do |record|
|
|
30
|
-
eq_conditions = Array(reflection.association_primary_key).map do |name|
|
|
31
|
-
table[name].eq(record[name])
|
|
32
|
-
end
|
|
33
|
-
Arel::Nodes::And.new(eq_conditions)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
condition = and_conditions.shift
|
|
37
|
-
and_conditions.each do |and_condition|
|
|
38
|
-
condition = condition.or(and_condition)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
scope = self.scope.where(condition)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
if method == :delete_all
|
|
45
|
-
update_counter(-scope.delete_all)
|
|
46
|
-
else
|
|
47
|
-
# CPK
|
|
48
|
-
# update_counter(-scope.update_all(reflection.foreign_key => nil))
|
|
49
|
-
update_hash = Array(reflection.foreign_key).inject(Hash.new) do |hash, key|
|
|
50
|
-
hash[key] = nil
|
|
51
|
-
hash
|
|
52
|
-
end
|
|
53
|
-
update_counter(-scope.update_all(update_hash))
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
35
|
def foreign_key_present?
|
|
59
36
|
if reflection.klass.primary_key
|
|
60
37
|
# CPK
|
|
@@ -13,79 +13,79 @@ module ActiveRecord
|
|
|
13
13
|
cpk_in_predicate(through_association.scope.klass.arel_table, source_reflection.foreign_key, ids)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
silence_warnings do
|
|
17
|
+
def delete_records(records, method)
|
|
18
|
+
ensure_not_nested
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
scope.where! cpk_join_through_predicate(*records)
|
|
25
|
-
else
|
|
26
|
-
scope.where! construct_join_attributes(*records)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
case method
|
|
30
|
-
when :destroy
|
|
31
|
-
if scope.klass.primary_key
|
|
32
|
-
count = scope.destroy_all.length
|
|
20
|
+
scope = through_association.scope
|
|
21
|
+
# CPK
|
|
22
|
+
# scope.where! construct_join_attributes(*records)
|
|
23
|
+
if source_reflection.klass.composite?
|
|
24
|
+
scope.where! cpk_join_through_predicate(*records)
|
|
33
25
|
else
|
|
34
|
-
scope.
|
|
35
|
-
|
|
36
|
-
end
|
|
26
|
+
scope.where! construct_join_attributes(*records)
|
|
27
|
+
end
|
|
37
28
|
|
|
38
|
-
|
|
29
|
+
case method
|
|
30
|
+
when :destroy
|
|
31
|
+
if scope.klass.primary_key
|
|
32
|
+
count = scope.destroy_all.length
|
|
33
|
+
else
|
|
34
|
+
scope.to_a.each do |record|
|
|
35
|
+
record.run_callbacks :destroy
|
|
36
|
+
end
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
stmt.from scope.klass.arel_table
|
|
42
|
-
stmt.wheres = arel.constraints
|
|
38
|
+
arel = scope.arel
|
|
43
39
|
|
|
44
|
-
|
|
40
|
+
stmt = Arel::DeleteManager.new arel.engine
|
|
41
|
+
stmt.from scope.klass.arel_table
|
|
42
|
+
stmt.wheres = arel.constraints
|
|
43
|
+
|
|
44
|
+
count = scope.klass.connection.delete(stmt, 'SQL', scope.bind_values)
|
|
45
|
+
end
|
|
46
|
+
when :nullify
|
|
47
|
+
count = scope.update_all(source_reflection.foreign_key => nil)
|
|
48
|
+
else
|
|
49
|
+
count = scope.delete_all
|
|
45
50
|
end
|
|
46
|
-
when :nullify
|
|
47
|
-
count = scope.update_all(source_reflection.foreign_key => nil)
|
|
48
|
-
else
|
|
49
|
-
count = scope.delete_all
|
|
50
|
-
end
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
delete_through_records(records)
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
if source_reflection.options[:counter_cache] && method != :destroy
|
|
55
|
+
counter = source_reflection.counter_cache_column
|
|
56
|
+
klass.decrement_counter counter, records.map(&:id)
|
|
57
|
+
end
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
if through_reflection.collection? && update_through_counter?(method)
|
|
60
|
+
update_counter(-count, through_reflection)
|
|
61
|
+
end
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
update_counter(-count)
|
|
64
|
+
end
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
66
|
+
def through_records_for(record)
|
|
67
|
+
# CPK
|
|
68
|
+
# attributes = construct_join_attributes(record)
|
|
69
|
+
# candidates = Array.wrap(through_association.target)
|
|
70
|
+
# candidates.find_all do |c|
|
|
71
|
+
# attributes.all? do |key, value|
|
|
72
|
+
# c.public_send(key) == value
|
|
73
|
+
# end
|
|
74
|
+
# end
|
|
75
|
+
if record.composite?
|
|
76
|
+
candidates = Array.wrap(through_association.target)
|
|
77
|
+
candidates.find_all { |c| c.attributes.slice(*source_reflection.association_primary_key) == record.ids_hash }
|
|
78
|
+
else
|
|
79
|
+
attributes = construct_join_attributes(record)
|
|
80
|
+
candidates = Array.wrap(through_association.target)
|
|
81
|
+
candidates.find_all do |c|
|
|
82
|
+
attributes.all? do |key, value|
|
|
83
|
+
c.public_send(key) == value
|
|
84
|
+
end
|
|
84
85
|
end
|
|
85
86
|
end
|
|
86
87
|
end
|
|
87
88
|
end
|
|
88
|
-
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
end
|
|
@@ -2,19 +2,21 @@ module ActiveRecord
|
|
|
2
2
|
module Associations
|
|
3
3
|
class JoinDependency
|
|
4
4
|
class JoinAssociation
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
silence_warnings do
|
|
6
|
+
def build_constraint(klass, table, key, foreign_table, foreign_key)
|
|
7
|
+
# CPK
|
|
8
|
+
# constraint = table[key].eq(foreign_table[foreign_key])
|
|
9
|
+
constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
if klass.finder_needs_type_condition?
|
|
12
|
+
constraint = table.create_and([
|
|
13
|
+
constraint,
|
|
14
|
+
klass.send(:type_condition, table)
|
|
15
|
+
])
|
|
16
|
+
end
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
constraint
|
|
19
|
+
end
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
end
|