composite_primary_keys 12.0.2 → 12.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/History.rdoc +880 -841
  3. data/README.rdoc +180 -179
  4. data/lib/composite_primary_keys/active_model/attribute_assignment.rb +19 -0
  5. data/lib/composite_primary_keys/arel/sqlserver.rb +1 -3
  6. data/lib/composite_primary_keys/associations/association_scope.rb +68 -68
  7. data/lib/composite_primary_keys/associations/join_dependency.rb +103 -103
  8. data/lib/composite_primary_keys/associations/through_association.rb +2 -1
  9. data/lib/composite_primary_keys/attribute_methods/primary_key.rb +13 -0
  10. data/lib/composite_primary_keys/attribute_methods/read.rb +30 -30
  11. data/lib/composite_primary_keys/attribute_methods/write.rb +35 -35
  12. data/lib/composite_primary_keys/attribute_methods.rb +9 -9
  13. data/lib/composite_primary_keys/base.rb +141 -130
  14. data/lib/composite_primary_keys/composite_arrays.rb +0 -8
  15. data/lib/composite_primary_keys/connection_adapters/abstract/database_statements.rb +37 -17
  16. data/lib/composite_primary_keys/connection_adapters/sqlserver/database_statements.rb +44 -23
  17. data/lib/composite_primary_keys/core.rb +48 -48
  18. data/lib/composite_primary_keys/persistence.rb +82 -81
  19. data/lib/composite_primary_keys/reflection.rb +29 -29
  20. data/lib/composite_primary_keys/relation/batches.rb +1 -1
  21. data/lib/composite_primary_keys/relation/calculations.rb +81 -81
  22. data/lib/composite_primary_keys/relation/finder_methods.rb +235 -235
  23. data/lib/composite_primary_keys/relation/predicate_builder/association_query_value.rb +20 -20
  24. data/lib/composite_primary_keys/relation/query_methods.rb +42 -42
  25. data/lib/composite_primary_keys/relation/where_clause.rb +23 -23
  26. data/lib/composite_primary_keys/relation.rb +193 -118
  27. data/lib/composite_primary_keys/version.rb +8 -8
  28. data/lib/composite_primary_keys.rb +117 -118
  29. data/test/abstract_unit.rb +114 -113
  30. data/test/connections/databases.ci.yml +22 -19
  31. data/test/fixtures/article.rb +4 -0
  32. data/test/fixtures/articles.yml +4 -3
  33. data/test/fixtures/comment.rb +1 -3
  34. data/test/fixtures/comments.yml +10 -9
  35. data/test/fixtures/db_definitions/db2-create-tables.sql +112 -126
  36. data/test/fixtures/db_definitions/db2-drop-tables.sql +17 -19
  37. data/test/fixtures/db_definitions/mysql.sql +180 -217
  38. data/test/fixtures/db_definitions/oracle.drop.sql +42 -48
  39. data/test/fixtures/db_definitions/oracle.sql +200 -236
  40. data/test/fixtures/db_definitions/postgresql.sql +183 -220
  41. data/test/fixtures/db_definitions/sqlite.sql +170 -206
  42. data/test/fixtures/db_definitions/sqlserver.sql +176 -212
  43. data/test/fixtures/department.rb +16 -11
  44. data/test/fixtures/departments.yml +15 -15
  45. data/test/fixtures/employees.yml +27 -27
  46. data/test/fixtures/readings.yml +2 -2
  47. data/test/fixtures/restaurants_suburbs.yml +11 -11
  48. data/test/fixtures/streets.yml +16 -16
  49. data/test/fixtures/suburbs.yml +14 -14
  50. data/test/fixtures/user.rb +11 -10
  51. data/test/test_associations.rb +358 -351
  52. data/test/test_attributes.rb +60 -60
  53. data/test/test_calculations.rb +42 -42
  54. data/test/test_create.rb +218 -183
  55. data/test/test_delete.rb +182 -179
  56. data/test/test_exists.rb +39 -39
  57. data/test/test_find.rb +164 -145
  58. data/test/test_habtm.rb +2 -2
  59. data/test/test_ids.rb +112 -116
  60. data/test/test_nested_attributes.rb +67 -124
  61. data/test/test_polymorphic.rb +29 -13
  62. data/test/test_preload.rb +4 -3
  63. data/test/test_serialize.rb +2 -2
  64. data/test/test_update.rb +96 -78
  65. metadata +4 -19
  66. data/test/fixtures/hack.rb +0 -5
  67. data/test/fixtures/hacks.yml +0 -3
  68. data/test/fixtures/pk_called_id.rb +0 -5
  69. data/test/fixtures/pk_called_ids.yml +0 -11
  70. data/test/fixtures/reference_code_using_composite_key_alias.rb +0 -8
  71. data/test/fixtures/reference_code_using_simple_key_alias.rb +0 -8
  72. data/test/fixtures/seat.rb +0 -5
  73. data/test/fixtures/seats.yml +0 -9
  74. data/test/fixtures/topic.rb +0 -6
  75. data/test/fixtures/topic_source.rb +0 -7
  76. data/test/test_aliases.rb +0 -18
  77. data/test/test_enum.rb +0 -21
  78. data/test/test_suite.rb +0 -35
data/README.rdoc CHANGED
@@ -1,179 +1,180 @@
1
- = Composite Primary Keys for ActiveRecords
2
-
3
- == Summary
4
-
5
- ActiveRecords infamously doesn't support composite primary keys.
6
- This gem, composite_primary_keys, or CPK for short, extends ActiveRecord
7
- to support composite keys.
8
-
9
- == Installation
10
-
11
- gem install composite_primary_keys
12
-
13
- If you are using Rails add the following to your Gemfile:
14
-
15
- gem 'composite_primary_keys', '=x.x.x' (see next section about what version to use)
16
-
17
- == Versions
18
-
19
- Every major version of ActiveRecord has included numerous internal changes. As a result,
20
- CPK has to be rewritten for each version of ActiveRecord. To help keep
21
- things straight, here is the mapping:
22
-
23
- Version 12.x is designed to work with ActiveRecord 6.0.x
24
- Version 11.x is designed to work with ActiveRecord 5.2.x
25
- Version 10.x is designed to work with ActiveRecord 5.1.x
26
- Version 9.x is designed to work with ActiveRecord 5.0.x
27
- Version 8.x is designed to work with ActiveRecord 4.2.x
28
- Version 7.x is designed to work with ActiveRecord 4.1.x
29
- Version 6.x is designed to work with ActiveRecord 4.0.x
30
- Version 5.x is designed to work with ActiveRecord 3.2.x
31
- Version 4.x is designed to work with ActiveRecord 3.1.x
32
-
33
- Run the following command to list available versions:
34
-
35
- gem list composite_primary_keys -ra
36
-
37
- == The basics
38
-
39
- A model with composite primary keys is defined like this:
40
-
41
- class Membership < ActiveRecord::Base
42
- self.primary_keys = :user_id, :group_id
43
- belongs_to :user
44
- belongs_to :group
45
- has_many :statuses, :class_name => 'MembershipStatus', :foreign_key => [:user_id, :group_id]
46
- end
47
-
48
- Note the addition of the line:
49
-
50
- self.primary_keys = :user_id, :group_id
51
-
52
-
53
- A model associated with a composite key model is defined like this:
54
-
55
- class MembershipStatus < ActiveRecord::Base
56
- belongs_to :membership, :foreign_key => [:user_id, :group_id]
57
- end
58
-
59
- That is, associations can include composite keys too. All Rails association types are supported. Nice.
60
-
61
- == Usage
62
-
63
- Once you’ve created your models to specify composite primary keys (such as the Membership class)
64
- and associations (such as MembershipStatus#membership), you can use them like any normal model
65
- with associations.
66
-
67
- But first, lets check out our primary keys.
68
-
69
- MembershipStatus.primary_key # => "id" # normal single key
70
- Membership.primary_key # => [:user_id, :group_id] # composite keys
71
- Membership.primary_key.to_s # => "user_id,group_id"
72
-
73
- Now we want to be able to find instances using the same syntax we always use for ActiveRecords…
74
-
75
- MembershipStatus.find(1) # single id returns single instance
76
- => <MembershipStatus:0x392a8c8 @attributes={"id"=>"1", "status"=>"Active"}>
77
-
78
- Membership.find([1,1]) # composite ids returns single instance
79
- => <Membership:0x39218b0 @attributes={"user_id"=>"1", "group_id"=>"1"}>
80
-
81
- Notice the use of an array to specify the composite key values.
82
-
83
- NOTE - API CHANGE. CPK Version 6.x and earlier used to allow composite keys to be listed out
84
- like this:
85
-
86
- Membership.find(1,1)
87
-
88
- This usage is no longer supported.
89
-
90
- == Databases
91
-
92
- CPK supports the following databases:
93
-
94
- * PostgreSQL
95
- * MySQL
96
- * MariaDB
97
- * Oracle
98
- * DB2
99
- * SQLite
100
- * SQLServer
101
-
102
- == Tests
103
-
104
- To run tests you first need to install the appropriate gems for the database you want to test. Database gems are
105
- divided into the following bundler groups:
106
-
107
- * mysql
108
- * oracle
109
- * postgresql
110
- * sqlite
111
- * sqlserver
112
-
113
- Since it is likely you do not have all the above databases installed on your computer, you want to install just the
114
- gems for your database. For example, to test postgresql you would install the appropriate gems like this:
115
-
116
- bundler install --without "mysql oracle sqlite sqlserver"
117
-
118
- Once you have installed the appropriate gems, the next step is to create the test database. There is a rake
119
- command for each database. Using our example:
120
-
121
- rake postgresql:build_database
122
-
123
- You can also rebuild the database if it already exists using this command:
124
-
125
- rake postgresql:rebuild_database
126
-
127
- To get a list of commands for your database use:
128
-
129
- Rake -T
130
-
131
- Finally, to run tests:
132
-
133
- rake postgresql:test
134
-
135
- 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]
136
-
137
- === DB2
138
-
139
- DB2 is no longer supported due to difficulties in getting the ibm_db2 gem to build. Thus tests
140
- have not been run against db2.
141
-
142
- === MariaDb (mysql)
143
-
144
- MariaDb is fully supported with all tests passing.
145
-
146
- === Oracle
147
-
148
- Oracle is fully supported with all tests passing.
149
-
150
- === Postgresql
151
-
152
- Postgresql is fully supported with all tests passing.
153
-
154
- === Sqlite 3
155
-
156
- The sqlite database is created at the path composite_primary_keys/db. Note you must *first* create the database using the
157
- built-in rake task before running tests:
158
-
159
- rake sqlite:build_database
160
-
161
- For sqlite3 to work correctly, you must manually require 'composite_primary_keys/connection_adapters/sqlite3_adapter' after
162
- loading the CPK gem.
163
-
164
- === SqlServer
165
-
166
- SqlServer is partially supported. There are a number of failing tests - patches welcomed.
167
-
168
- == Questions, Discussion and Contributions
169
-
170
- For help please visit https://github.com/composite-primary-keys/composite_primary_keys.
171
-
172
- == Author
173
-
174
- First version was written by Dr Nic Williams.
175
-
176
- Maintained by Charlie Savage
177
-
178
- Contributions by many!
179
-
1
+ = Composite Primary Keys for ActiveRecords
2
+
3
+ == Summary
4
+
5
+ ActiveRecords infamously doesn't support composite primary keys.
6
+ This gem, composite_primary_keys, or CPK for short, extends ActiveRecord
7
+ to support composite keys.
8
+
9
+ == Installation
10
+
11
+ gem install composite_primary_keys
12
+
13
+ If you are using Rails add the following to your Gemfile:
14
+
15
+ gem 'composite_primary_keys', '=x.x.x' (see next section about what version to use)
16
+
17
+ == Versions
18
+
19
+ Every major version of ActiveRecord has included numerous internal changes. As a result,
20
+ CPK has to be rewritten for each version of ActiveRecord. To help keep
21
+ things straight, here is the mapping:
22
+
23
+ Version 12.x is designed to work with ActiveRecord 6.0.x
24
+ Version 11.x is designed to work with ActiveRecord 5.2.x
25
+ Version 10.x is designed to work with ActiveRecord 5.1.x
26
+ Version 9.x is designed to work with ActiveRecord 5.0.x
27
+ Version 8.x is designed to work with ActiveRecord 4.2.x
28
+ Version 7.x is designed to work with ActiveRecord 4.1.x
29
+ Version 6.x is designed to work with ActiveRecord 4.0.x
30
+ Version 5.x is designed to work with ActiveRecord 3.2.x
31
+ Version 4.x is designed to work with ActiveRecord 3.1.x
32
+
33
+ Run the following command to list available versions:
34
+
35
+ gem list composite_primary_keys -ra
36
+
37
+ == The basics
38
+
39
+ A model with composite primary keys is defined like this:
40
+
41
+ class Membership < ActiveRecord::Base
42
+ self.primary_keys = :user_id, :group_id
43
+ belongs_to :user
44
+ belongs_to :group
45
+ has_many :statuses, :class_name => 'MembershipStatus', :foreign_key => [:user_id, :group_id]
46
+ end
47
+
48
+ Note the addition of the line:
49
+
50
+ self.primary_keys = :user_id, :group_id
51
+
52
+
53
+ A model associated with a composite key model is defined like this:
54
+
55
+ class MembershipStatus < ActiveRecord::Base
56
+ belongs_to :membership, :foreign_key => [:user_id, :group_id]
57
+ end
58
+
59
+ That is, associations can include composite keys too. All Rails association types are supported. Nice.
60
+
61
+ == Usage
62
+
63
+ Once you’ve created your models to specify composite primary keys (such as the Membership class)
64
+ and associations (such as MembershipStatus#membership), you can use them like any normal model
65
+ with associations.
66
+
67
+ But first, lets check out our primary keys.
68
+
69
+ MembershipStatus.primary_key # => "id" # normal single key
70
+ Membership.primary_key # => [:user_id, :group_id] # composite keys
71
+ Membership.primary_key.to_s # => "user_id,group_id"
72
+
73
+ Now we want to be able to find instances using the same syntax we always use for ActiveRecords…
74
+
75
+ MembershipStatus.find(1) # single id returns single instance
76
+ => <MembershipStatus:0x392a8c8 @attributes={"id"=>"1", "status"=>"Active"}>
77
+
78
+ Membership.find([1,1]) # composite ids returns single instance
79
+ => <Membership:0x39218b0 @attributes={"user_id"=>"1", "group_id"=>"1"}>
80
+
81
+ Notice the use of an array to specify the composite key values.
82
+
83
+ NOTE - API CHANGE. CPK Version 6.x and earlier used to allow composite keys to be listed out
84
+ like this:
85
+
86
+ Membership.find(1,1)
87
+
88
+ This usage is no longer supported.
89
+
90
+ == Databases
91
+
92
+ CPK supports the following databases:
93
+
94
+ * PostgreSQL
95
+ * MySQL
96
+ * MariaDB
97
+ * Oracle
98
+ * DB2
99
+ * SQLite
100
+ * SQLServer
101
+
102
+ == Tests
103
+
104
+ To run tests you first need to install the appropriate gems for the database you want to test. Database gems are
105
+ divided into the following bundler groups:
106
+
107
+ * mysql
108
+ * oracle
109
+ * postgresql
110
+ * sqlite
111
+ * sqlserver
112
+
113
+ Since it is likely you do not have all the above databases installed on your computer, you want to install just the
114
+ gems for your database. For example, to test postgresql you would install the appropriate gems like this:
115
+
116
+ bundler config set --local without "mysql oracle sqlite sqlserver"
117
+ bundler install
118
+
119
+ Once you have installed the appropriate gems, the next step is to create the test database. There is a rake
120
+ command for each database. Using our example:
121
+
122
+ rake postgresql:build_database
123
+
124
+ You can also rebuild the database if it already exists using this command:
125
+
126
+ rake postgresql:rebuild_database
127
+
128
+ To get a list of commands for your database use:
129
+
130
+ Rake -T
131
+
132
+ Finally, to run tests:
133
+
134
+ rake postgresql:test
135
+
136
+ Travis build status: {<img src="https://travis-ci.com/composite-primary-keys/composite_primary_keys.svg" alt="Build Status" />}[https://travis-ci.com/composite-primary-keys/composite_primary_keys]
137
+
138
+ === DB2
139
+
140
+ DB2 is no longer supported due to difficulties in getting the ibm_db2 gem to build. Thus tests
141
+ have not been run against db2.
142
+
143
+ === MariaDb (mysql)
144
+
145
+ MariaDb is fully supported with all tests passing.
146
+
147
+ === Oracle
148
+
149
+ Oracle is fully supported with all tests passing.
150
+
151
+ === Postgresql
152
+
153
+ Postgresql is fully supported with all tests passing.
154
+
155
+ === Sqlite 3
156
+
157
+ The sqlite database is created at the path composite_primary_keys/db. Note you must *first* create the database using the
158
+ built-in rake task before running tests:
159
+
160
+ rake sqlite:build_database
161
+
162
+ For sqlite3 to work correctly, you must manually require 'composite_primary_keys/connection_adapters/sqlite3_adapter' after
163
+ loading the CPK gem.
164
+
165
+ === SqlServer
166
+
167
+ SqlServer is partially supported. There are a number of failing tests - patches welcomed.
168
+
169
+ == Questions, Discussion and Contributions
170
+
171
+ For help please visit https://github.com/composite-primary-keys/composite_primary_keys.
172
+
173
+ == Author
174
+
175
+ First version was written by Dr Nic Williams.
176
+
177
+ Maintained by Charlie Savage
178
+
179
+ Contributions by many!
180
+
@@ -0,0 +1,19 @@
1
+ module ActiveModel
2
+ module AttributeAssignment
3
+ def _assign_attribute(k, v)
4
+ # CPK. This is super ugly, but if a table has a composite key where one of the fields is named :id we need
5
+ # to handle it as a single value. Otherwise, we would call the id=(value) method which is expecting
6
+ # and array of values.
7
+ if k == 'id' && !v.kind_of?(Array) && self.kind_of?(ActiveRecord::Base) && self.composite? && !self.column_for_attribute(k).null
8
+ self._write_attribute(k, v)
9
+ else
10
+ setter = :"#{k}="
11
+ if respond_to?(setter)
12
+ public_send(setter, v)
13
+ else
14
+ raise UnknownAttributeError.new(self, k)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,8 +1,6 @@
1
- require 'activerecord-sqlserver-adapter'
2
-
3
1
  module Arel
4
2
  module Visitors
5
- class SQLServer
3
+ class SQLServer < Arel::Visitors::ToSql
6
4
  def make_Fetch_Possible_And_Deterministic o
7
5
  return if o.limit.nil? && o.offset.nil?
8
6
  t = table_From_Statement o
@@ -1,69 +1,69 @@
1
- module ActiveRecord
2
- module Associations
3
- class AssociationScope
4
- def self.get_bind_values(owner, chain)
5
- binds = []
6
- last_reflection = chain.last
7
-
8
- # CPK
9
- # binds << last_reflection.join_id_for(owner)
10
- values = last_reflection.join_id_for(owner)
11
- binds += Array(values)
12
-
13
- if last_reflection.type
14
- binds << owner.class.polymorphic_name
15
- end
16
-
17
- chain.each_cons(2).each do |reflection, next_reflection|
18
- if reflection.type
19
- binds << next_reflection.klass.polymorphic_name
20
- end
21
- end
22
- binds
23
- end
24
-
25
- def last_chain_scope(scope, reflection, owner)
26
- join_keys = reflection.join_keys
27
- key = join_keys.key
28
- foreign_key = join_keys.foreign_key
29
-
30
- table = reflection.aliased_table
31
-
32
- # CPK
33
- # value = transform_value(owner[foreign_key])
34
- # scope = apply_scope(scope, table, key, value)
35
- Array(key).zip(Array(foreign_key)).each do |a_join_key, a_foreign_key|
36
- value = transform_value(owner[a_foreign_key])
37
- scope = apply_scope(scope, table, a_join_key, value)
38
- end
39
-
40
- if reflection.type
41
- polymorphic_type = transform_value(owner.class.polymorphic_name)
42
- scope = apply_scope(scope, table, reflection.type, polymorphic_type)
43
- end
44
-
45
- scope
46
- end
47
-
48
- def next_chain_scope(scope, reflection, next_reflection)
49
- join_keys = reflection.join_keys
50
- key = join_keys.key
51
- foreign_key = join_keys.foreign_key
52
-
53
- table = reflection.aliased_table
54
- foreign_table = next_reflection.aliased_table
55
-
56
- # CPK
57
- # constraint = table[key].eq(foreign_table[foreign_key])
58
- constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
59
-
60
- if reflection.type
61
- value = transform_value(next_reflection.klass.polymorphic_name)
62
- scope = apply_scope(scope, table, reflection.type, value)
63
- end
64
-
65
- scope.joins!(join(foreign_table, constraint))
66
- end
67
- end
68
- end
1
+ module ActiveRecord
2
+ module Associations
3
+ class AssociationScope
4
+ def self.get_bind_values(owner, chain)
5
+ binds = []
6
+ last_reflection = chain.last
7
+
8
+ # CPK
9
+ # binds << last_reflection.join_id_for(owner)
10
+ values = last_reflection.join_id_for(owner)
11
+ binds += Array(values)
12
+
13
+ if last_reflection.type
14
+ binds << owner.class.polymorphic_name
15
+ end
16
+
17
+ chain.each_cons(2).each do |reflection, next_reflection|
18
+ if reflection.type
19
+ binds << next_reflection.klass.polymorphic_name
20
+ end
21
+ end
22
+ binds
23
+ end
24
+
25
+ def last_chain_scope(scope, reflection, owner)
26
+ join_keys = reflection.join_keys
27
+ key = join_keys.key
28
+ foreign_key = join_keys.foreign_key
29
+
30
+ table = reflection.aliased_table
31
+
32
+ # CPK
33
+ # value = transform_value(owner[foreign_key])
34
+ # scope = apply_scope(scope, table, key, value)
35
+ Array(key).zip(Array(foreign_key)).each do |a_join_key, a_foreign_key|
36
+ value = transform_value(owner[a_foreign_key])
37
+ scope = apply_scope(scope, table, a_join_key, value)
38
+ end
39
+
40
+ if reflection.type
41
+ polymorphic_type = transform_value(owner.class.polymorphic_name)
42
+ scope = apply_scope(scope, table, reflection.type, polymorphic_type)
43
+ end
44
+
45
+ scope
46
+ end
47
+
48
+ def next_chain_scope(scope, reflection, next_reflection)
49
+ join_keys = reflection.join_keys
50
+ key = join_keys.key
51
+ foreign_key = join_keys.foreign_key
52
+
53
+ table = reflection.aliased_table
54
+ foreign_table = next_reflection.aliased_table
55
+
56
+ # CPK
57
+ # constraint = table[key].eq(foreign_table[foreign_key])
58
+ constraint = cpk_join_predicate(table, key, foreign_table, foreign_key)
59
+
60
+ if reflection.type
61
+ value = transform_value(next_reflection.klass.polymorphic_name)
62
+ scope = apply_scope(scope, table, reflection.type, value)
63
+ end
64
+
65
+ scope.joins!(join(foreign_table, constraint))
66
+ end
67
+ end
68
+ end
69
69
  end