composite_primary_keys 12.0.0 → 12.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/History.rdoc +44 -3
  3. data/README.rdoc +3 -2
  4. data/lib/composite_primary_keys.rb +57 -57
  5. data/lib/composite_primary_keys/active_model/attribute_assignment.rb +19 -0
  6. data/lib/composite_primary_keys/arel/sqlserver.rb +1 -3
  7. data/lib/composite_primary_keys/associations/through_association.rb +2 -1
  8. data/lib/composite_primary_keys/attribute_methods.rb +2 -2
  9. data/lib/composite_primary_keys/attribute_methods/primary_key.rb +13 -0
  10. data/lib/composite_primary_keys/base.rb +12 -1
  11. data/lib/composite_primary_keys/composite_arrays.rb +49 -14
  12. data/lib/composite_primary_keys/connection_adapters/abstract/database_statements.rb +8 -3
  13. data/lib/composite_primary_keys/connection_adapters/abstract_adapter.rb +1 -1
  14. data/lib/composite_primary_keys/connection_adapters/mysql/database_statements.rb +24 -0
  15. data/lib/composite_primary_keys/connection_adapters/sqlserver/database_statements.rb +33 -12
  16. data/lib/composite_primary_keys/core.rb +1 -1
  17. data/lib/composite_primary_keys/persistence.rb +2 -2
  18. data/lib/composite_primary_keys/relation.rb +100 -25
  19. data/lib/composite_primary_keys/relation/finder_methods.rb +6 -6
  20. data/lib/composite_primary_keys/relation/predicate_builder/association_query_value.rb +1 -1
  21. data/lib/composite_primary_keys/validations/uniqueness.rb +1 -1
  22. data/lib/composite_primary_keys/version.rb +1 -1
  23. data/test/abstract_unit.rb +3 -5
  24. data/test/fixtures/article.rb +4 -0
  25. data/test/fixtures/articles.yml +4 -3
  26. data/test/fixtures/comment.rb +1 -3
  27. data/test/fixtures/comments.yml +10 -9
  28. data/test/fixtures/db_definitions/db2-create-tables.sql +0 -14
  29. data/test/fixtures/db_definitions/db2-drop-tables.sql +1 -3
  30. data/test/fixtures/db_definitions/mysql.sql +7 -44
  31. data/test/fixtures/db_definitions/oracle.drop.sql +3 -9
  32. data/test/fixtures/db_definitions/oracle.sql +12 -48
  33. data/test/fixtures/db_definitions/postgresql.sql +7 -44
  34. data/test/fixtures/db_definitions/sqlite.sql +6 -42
  35. data/test/fixtures/db_definitions/sqlserver.sql +5 -41
  36. data/test/fixtures/department.rb +8 -3
  37. data/test/fixtures/departments.yml +4 -4
  38. data/test/fixtures/readings.yml +2 -2
  39. data/test/fixtures/restaurants_suburbs.yml +1 -1
  40. data/test/fixtures/streets.yml +2 -2
  41. data/test/fixtures/suburbs.yml +2 -2
  42. data/test/fixtures/user.rb +3 -2
  43. data/test/test_associations.rb +30 -23
  44. data/test/test_composite_arrays.rb +14 -0
  45. data/test/test_create.rb +15 -18
  46. data/test/test_delete.rb +3 -3
  47. data/test/test_exists.rb +5 -5
  48. data/test/test_find.rb +22 -2
  49. data/test/test_habtm.rb +2 -2
  50. data/test/test_ids.rb +5 -6
  51. data/test/test_nested_attributes.rb +0 -57
  52. data/test/test_polymorphic.rb +29 -13
  53. data/test/test_preload.rb +4 -3
  54. data/test/test_serialize.rb +2 -2
  55. data/test/test_update.rb +19 -1
  56. metadata +6 -64
  57. data/test/fixtures/hack.rb +0 -5
  58. data/test/fixtures/hacks.yml +0 -3
  59. data/test/fixtures/pk_called_id.rb +0 -5
  60. data/test/fixtures/pk_called_ids.yml +0 -11
  61. data/test/fixtures/reference_code_using_composite_key_alias.rb +0 -8
  62. data/test/fixtures/reference_code_using_simple_key_alias.rb +0 -8
  63. data/test/fixtures/seat.rb +0 -5
  64. data/test/fixtures/seats.yml +0 -9
  65. data/test/fixtures/topic.rb +0 -6
  66. data/test/fixtures/topic_source.rb +0 -7
  67. data/test/mkmf.log +0 -592
  68. data/test/test_aliases.rb +0 -18
  69. data/test/test_enum.rb +0 -21
  70. data/test/test_suite.rb +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69bb7bf55e5c40834cb9f38c6978cc7ad2564bc7e2884cc0181d7894f9ebba40
4
- data.tar.gz: 31b2aa1fedc849533cbdebfbee1f2cd434a0a2ec37085a92b5592004d7a0ff4a
3
+ metadata.gz: b2a0ca9aa38fb1dfdca5c0974049eec9faf2c5703666a8e8de2ad28f6c78c7bc
4
+ data.tar.gz: 6384ddd8291fbd65e074965bfb70b8945c4ac6b556537973cc62561a86a0c609
5
5
  SHA512:
6
- metadata.gz: 3b12c996e4d31037a31560dc6b69cd15ef422abfb6355c1331902b40ce1dff9e4faf59f36537c293b978571a09df875ee6628a94d6a24735fea20f84c370a2f3
7
- data.tar.gz: eea6437fa46aab688e1b721e0cc3352b95ad318e1385d068399f30a111729fb0879a71071a3e94c56b652e8817e768651bd26f1f6a2a02066d2a0ece5b2e2f25
6
+ metadata.gz: 3c8a87f9676da79d514cd3dd2b21d7c1b523ddde1e13a2b37484e69ed4d93556e94fd725bc41642117338de66679932b69aff077c90c6c45d2026792439f4d5a
7
+ data.tar.gz: 5e393c7b725a757bef1a5b99efb9ef62612e3d11b7aa8dec15399684221a6a75f1b34908434b1471a0bc86a67814e7e387905d6e92885f7dddefb521668a7f9b
@@ -1,6 +1,47 @@
1
- == 12.0.0 (?)
2
- * Update to ActiveRecord 6.0 (Hiroshi Kajisha, Alexandru Anca, Charlie Savage)
3
- * Update travis setup (Olle Jonsson)
1
+ == 12.0.5 (2020-12-31)
2
+ * Finally issue with SQLServer when tables are marked as exclude_output_inserted. See #535. (Charlie Savage)
3
+
4
+ == 12.0.4 (2020-12-30)
5
+ * Fix compatibility with Ruby Ruby 2.6 and below (ta1kt0me)
6
+ * Finally get SQLServer mass updates and deletes working (Charlie Savage)
7
+ * Fix MySQL mass updates and deletes that were broken by 12.0.3 (Charlie Savage)
8
+
9
+ == 12.0.3 (2020-11-11)
10
+ * Prevents infinite loops with gems which modify the 'attributes' method (Nicholas Guarino)
11
+ * Improve delete_all and update_all queries (Charlie Savage)
12
+ * Improve Oracle support (Charlie Savage)
13
+ * Improve SQL Server support. Note delete_all and update_all queries still do not work due to
14
+ quirks in SQL Server syntax (Charlie Savage)
15
+ * Improve support for polymorphic associations (Charlie Savage)
16
+ * Update fixtures and tests to include a model that uses an :id column as part of a composite
17
+ key (Charlie Savage)
18
+ * Fixed bug where id values were not correctly mapped between primary and foreign keys in associations (Charlie Savage)
19
+ * Cleanup how the gem is loaded (Charlie Savage)
20
+ * Remove older, unused or minimally used fixtures (Charlie Savage)
21
+
22
+ == 12.0.2 (2020-05-19)
23
+ * Remove deprecation warning for Ruby 2.7 due to keyword parameters (Alexandru Anca )
24
+ * Use sqlite for default in tests (Charlie Savage)
25
+ * Modernize gem tests by using Bundler (Charlie Savage)
26
+ * Update travis for ruby 2.7 (Charlie Savage)
27
+ * Port "Fix create record where one or more of the primary keys has a default value" from ar 5.2 branch (Charlie Savage)
28
+ * Remove extra argument from sql_for_insert for SqlServer (tohae)
29
+
30
+ == 12.0.1 (2019-11-25)
31
+ * Convert attribute names to strings before checking for them in has_attribute? (Daniel de Haas)
32
+ * Update the comment referring to the overridden Rails code (Daniel de Haas)
33
+
34
+ == 12.0.0 (2019-09-03)
35
+ * Update to ActiveRecord 6.0 (Hiroshi Kajisha, Alexandru Anca, Charlie Savage, Sammy Larbi)
36
+ * Update travis setup (Olle Jonsson, Charlie Savage)
37
+
38
+ ==11.3.1 (2020-04-01)¶ ↑
39
+ * Fix overriding AbstractReflection for activerecord 5.2.4 (Sergey Semyonov)
40
+ * Fix handling CPK with fields containing comma (Sergey Semyonov)
41
+ * Fixed incorrect SQL condition for joining by CPK (Sergey Semyonov)
42
+ * Update travis.yml file (Sergey Semyonov)
43
+ * Add tests for composite keys with default values (Daniel Wiklund)
44
+ * Fix create record where one or more of the primary keys has a default value (Daniel Wiklund)
4
45
 
5
46
  == 11.2.0 (2019-03-16)
6
47
  * When creating new records, honor composite key autoincrementing fields if possible (Antti Pitkänen)
@@ -113,7 +113,8 @@ divided into the following bundler groups:
113
113
  Since it is likely you do not have all the above databases installed on your computer, you want to install just the
114
114
  gems for your database. For example, to test postgresql you would install the appropriate gems like this:
115
115
 
116
- bundler install --without "mysql oracle sqlite sqlserver"
116
+ bundler config set --local without "mysql oracle sqlite sqlserver"
117
+ bundler install
117
118
 
118
119
  Once you have installed the appropriate gems, the next step is to create the test database. There is a rake
119
120
  command for each database. Using our example:
@@ -132,7 +133,7 @@ Finally, to run tests:
132
133
 
133
134
  rake postgresql:test
134
135
 
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
+ 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]
136
137
 
137
138
  === DB2
138
139
 
@@ -21,16 +21,17 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
- $:.unshift(File.dirname(__FILE__)) unless
25
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
26
-
27
24
  unless defined?(ActiveRecord)
28
25
  require 'rubygems'
29
- gem 'activerecord', '6.0.0'
26
+ gem 'activerecord', '~>6.0.0'
30
27
  require 'active_record'
31
28
  end
32
29
 
33
- # AR files we override
30
+ # ActiveModel files we override
31
+ # _write_attribute
32
+ require 'active_model/attribute_assignment'
33
+
34
+ # ActiveRecord files we override
34
35
  require 'active_record/attribute_methods'
35
36
  require 'active_record/autosave_association'
36
37
  require 'active_record/counter_cache'
@@ -64,55 +65,54 @@ require 'active_record/connection_adapters/postgresql/database_statements'
64
65
 
65
66
  require 'active_record/relation/where_clause'
66
67
 
67
- # CPK files
68
- require 'composite_primary_keys/attribute_methods'
69
- require 'composite_primary_keys/autosave_association'
70
- require 'composite_primary_keys/persistence'
71
- require 'composite_primary_keys/base'
72
- require 'composite_primary_keys/core'
73
- require 'composite_primary_keys/composite_arrays'
74
- require 'composite_primary_keys/composite_predicates'
75
- require 'composite_primary_keys/counter_cache'
76
- require 'composite_primary_keys/fixtures'
77
- require 'composite_primary_keys/reflection'
78
- require 'composite_primary_keys/relation'
79
- require 'composite_primary_keys/sanitization'
80
- require 'composite_primary_keys/transactions'
81
- require 'composite_primary_keys/version'
82
-
83
- require 'composite_primary_keys/associations/association'
84
- require 'composite_primary_keys/associations/association_scope'
85
- require 'composite_primary_keys/associations/foreign_association'
86
- require 'composite_primary_keys/associations/has_many_association'
87
- require 'composite_primary_keys/associations/has_many_through_association'
88
- require 'composite_primary_keys/associations/join_dependency'
89
- require 'composite_primary_keys/associations/preloader/association'
90
- require 'composite_primary_keys/associations/collection_association'
91
- require 'composite_primary_keys/associations/through_association'
92
-
93
- require 'composite_primary_keys/attribute_methods/primary_key'
94
- require 'composite_primary_keys/attribute_methods/read'
95
- require 'composite_primary_keys/attribute_methods/write'
96
- require 'composite_primary_keys/nested_attributes'
97
-
98
- require 'composite_primary_keys/connection_adapters/abstract/database_statements'
99
- require 'composite_primary_keys/connection_adapters/abstract_adapter'
100
- require 'composite_primary_keys/connection_adapters/postgresql/database_statements'
101
- require 'composite_primary_keys/connection_adapters/sqlserver/database_statements'
102
-
103
- require 'composite_primary_keys/relation/batches'
104
- require 'composite_primary_keys/relation/where_clause'
105
- require 'composite_primary_keys/relation/calculations'
106
- require 'composite_primary_keys/relation/finder_methods'
107
- require 'composite_primary_keys/relation/predicate_builder/association_query_value'
108
- require 'composite_primary_keys/relation/query_methods'
109
-
110
- require 'composite_primary_keys/validations/uniqueness'
111
-
112
- require 'composite_primary_keys/composite_relation'
113
-
114
- require 'composite_primary_keys/arel/to_sql'
115
-
116
- # SQL Servers Support - uncomment these lines
117
- #require 'activerecord-sqlserver-adapter/arel/visitors/sqlserver'
118
- #require 'composite_primary_keys/arel/sqlserver'
68
+ # CPK overrides
69
+ require_relative 'composite_primary_keys/active_model/attribute_assignment'
70
+ require_relative 'composite_primary_keys/attribute_methods'
71
+ require_relative 'composite_primary_keys/autosave_association'
72
+ require_relative 'composite_primary_keys/persistence'
73
+ require_relative 'composite_primary_keys/base'
74
+ require_relative 'composite_primary_keys/core'
75
+ require_relative 'composite_primary_keys/composite_arrays'
76
+ require_relative 'composite_primary_keys/composite_predicates'
77
+ require_relative 'composite_primary_keys/counter_cache'
78
+ require_relative 'composite_primary_keys/fixtures'
79
+ require_relative 'composite_primary_keys/reflection'
80
+ require_relative 'composite_primary_keys/relation'
81
+ require_relative 'composite_primary_keys/sanitization'
82
+ require_relative 'composite_primary_keys/transactions'
83
+ require_relative 'composite_primary_keys/version'
84
+
85
+ require_relative 'composite_primary_keys/associations/association'
86
+ require_relative 'composite_primary_keys/associations/association_scope'
87
+ require_relative 'composite_primary_keys/associations/foreign_association'
88
+ require_relative 'composite_primary_keys/associations/has_many_association'
89
+ require_relative 'composite_primary_keys/associations/has_many_through_association'
90
+ require_relative 'composite_primary_keys/associations/join_dependency'
91
+ require_relative 'composite_primary_keys/associations/preloader/association'
92
+ require_relative 'composite_primary_keys/associations/collection_association'
93
+ require_relative 'composite_primary_keys/associations/through_association'
94
+
95
+ require_relative 'composite_primary_keys/attribute_methods/primary_key'
96
+ require_relative 'composite_primary_keys/attribute_methods/read'
97
+ require_relative 'composite_primary_keys/attribute_methods/write'
98
+ require_relative 'composite_primary_keys/nested_attributes'
99
+
100
+ require_relative 'composite_primary_keys/connection_adapters/abstract/database_statements'
101
+ require_relative 'composite_primary_keys/connection_adapters/abstract_adapter'
102
+ require_relative 'composite_primary_keys/connection_adapters/mysql/database_statements'
103
+ require_relative 'composite_primary_keys/connection_adapters/postgresql/database_statements'
104
+ require_relative 'composite_primary_keys/connection_adapters/sqlserver/database_statements'
105
+
106
+ require_relative 'composite_primary_keys/relation/batches'
107
+ require_relative 'composite_primary_keys/relation/where_clause'
108
+ require_relative 'composite_primary_keys/relation/calculations'
109
+ require_relative 'composite_primary_keys/relation/finder_methods'
110
+ require_relative 'composite_primary_keys/relation/predicate_builder/association_query_value'
111
+ require_relative 'composite_primary_keys/relation/query_methods'
112
+
113
+ require_relative 'composite_primary_keys/validations/uniqueness'
114
+
115
+ require_relative 'composite_primary_keys/composite_relation'
116
+
117
+ require_relative 'composite_primary_keys/arel/to_sql'
118
+ require_relative 'composite_primary_keys/arel/sqlserver'
@@ -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' && 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
@@ -5,7 +5,8 @@ module ActiveRecord
5
5
 
6
6
  def construct_join_attributes(*records)
7
7
  # CPK
8
- if source_reflection.klass.composite?
8
+ is_composite = self.source_reflection.polymorphic? ? source_reflection.active_record.composite? : source_reflection.klass.composite?
9
+ if is_composite
9
10
  ensure_mutable
10
11
 
11
12
  ids = records.map do |record|
@@ -2,8 +2,8 @@ module ActiveRecord
2
2
  module AttributeMethods
3
3
  def has_attribute?(attr_name)
4
4
  # CPK
5
- # attributes.key?(attr_name)
6
- Array(attr_name).all? {|single_attr| attributes.key?(single_attr) }
5
+ # @attributes.key?(attr_name.to_s)
6
+ Array(attr_name).all? {|single_attr| @attributes.key?(single_attr.to_s) }
7
7
  end
8
8
  end
9
9
  end
@@ -1,6 +1,19 @@
1
1
  module ActiveRecord
2
2
  module AttributeMethods
3
3
  module PrimaryKey
4
+ module ClassMethods
5
+ def suppress_composite_primary_key(pk)
6
+ pk
7
+ # return pk unless pk.is_a?(Array)
8
+ #
9
+ # warn <<~WARNING
10
+ # WARNING: Active Record does not support composite primary key.
11
+ #
12
+ # #{table_name} has composite primary key. Composite primary key is ignored.
13
+ # WARNING
14
+ end
15
+ end
16
+
4
17
  # Returns the primary key previous value.
5
18
  def id_was
6
19
  sync_with_transaction_state
@@ -89,6 +89,17 @@ module ActiveRecord
89
89
  end
90
90
  alias_method :ids, :id
91
91
 
92
+ # This is overridden purely for json serialization support. If the model is composite
93
+ # and one of the keys is id, then we don't want to call the id method, instead we want
94
+ # to get the id attribute value
95
+ def read_attribute_for_serialization(attribute)
96
+ if self.composite? && attribute == 'id'
97
+ read_attribute(attribute)
98
+ else
99
+ send(attribute)
100
+ end
101
+ end
102
+
92
103
  def ids_hash
93
104
  self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
94
105
  hash[key] = value
@@ -123,7 +134,7 @@ module ActiveRecord
123
134
  end
124
135
 
125
136
  def to_param
126
- persisted? ? to_key.join(CompositePrimaryKeys::ID_SEP) : nil
137
+ persisted? ? to_key.to_composite_keys.to_s : nil
127
138
  end
128
139
  end
129
140
  end
@@ -1,6 +1,7 @@
1
1
  module CompositePrimaryKeys
2
2
  ID_SEP = ','
3
3
  ID_SET_SEP = ';'
4
+ ESCAPE_CHAR = '^'
4
5
 
5
6
  module ArrayExtension
6
7
  def to_composite_keys
@@ -8,12 +9,27 @@ module CompositePrimaryKeys
8
9
  end
9
10
  end
10
11
 
11
- def self.normalize(ids)
12
+ # Convert mixed representation of CPKs (by strings or arrays) to normalized
13
+ # representation (just by arrays).
14
+ #
15
+ # `ids` is Array that may contain:
16
+ # 1. A CPK represented by an array or a string.
17
+ # 2. An array of CPKs represented by arrays or strings.
18
+ #
19
+ # There is an issue. Let `ids` contain an array with serveral strings. We can't distinguish case 1
20
+ # from case 2 there in general. E.g. the item can be an array containing appropriate number of strings,
21
+ # and each string can contain appropriate number of commas. We consider case 2 to win there.
22
+ def self.normalize(ids, cpk_size)
12
23
  ids.map do |id|
13
- if id.is_a?(Array)
14
- normalize(id)
15
- elsif id.is_a?(String) && id.index(ID_SEP)
16
- id.split(ID_SEP)
24
+ if Utils.cpk_as_array?(id, cpk_size) && id.any? { |item| !Utils.cpk_as_string?(item, cpk_size) }
25
+ # CPK as an array - case 1
26
+ id
27
+ elsif id.is_a?(Array)
28
+ # An array of CPKs - case 2
29
+ normalize(id, cpk_size)
30
+ elsif id.is_a?(String)
31
+ # CPK as a string - case 1
32
+ CompositeKeys.parse(id)
17
33
  else
18
34
  id
19
35
  end
@@ -27,25 +43,44 @@ module CompositePrimaryKeys
27
43
  when Array
28
44
  value.to_composite_keys
29
45
  when String
30
- self.new(value.split(ID_SEP))
46
+ value.split(ID_SEP).map { |key| Utils.unescape_string_key(key) }.to_composite_keys
31
47
  else
32
48
  raise(ArgumentError, "Unsupported type: #{value}")
33
49
  end
34
50
  end
35
51
 
36
- def in(other)
37
- case other
38
- when Arel::SelectManager
39
- Arel::Nodes::In.new(self, other.ast)
40
- end
52
+ def to_s
53
+ # Doing this makes it easier to parse Base#[](attr_name)
54
+ map { |key| Utils.escape_string_key(key.to_s) }.join(ID_SEP)
41
55
  end
56
+ end
42
57
 
58
+ module Utils
59
+ class << self
60
+ def escape_string_key(key)
61
+ key.gsub(Regexp.union(ESCAPE_CHAR, ID_SEP)) do |unsafe|
62
+ "#{ESCAPE_CHAR}#{unsafe.ord.to_s(16).upcase}"
63
+ end
64
+ end
43
65
 
44
- def to_s
45
- # Doing this makes it easier to parse Base#[](attr_name)
46
- join(ID_SEP)
66
+ def unescape_string_key(key)
67
+ key.gsub(/#{Regexp.escape(ESCAPE_CHAR)}[0-9a-fA-F]{2}/) do |escaped|
68
+ char = escaped.slice(1, 2).hex.chr
69
+ (char == ESCAPE_CHAR || char == ID_SEP) ? char : escaped
70
+ end
71
+ end
72
+
73
+ def cpk_as_array?(value, pk_size)
74
+ # We don't permit Array to be an element of CPK.
75
+ value.is_a?(Array) && value.size == pk_size && value.none? { |item| item.is_a?(Array) }
76
+ end
77
+
78
+ def cpk_as_string?(value, pk_size)
79
+ value.is_a?(String) && value.count(ID_SEP) == pk_size - 1
80
+ end
47
81
  end
48
82
  end
83
+ private_constant :Utils
49
84
  end
50
85
 
51
86
  Array.send(:include, CompositePrimaryKeys::ArrayExtension)
@@ -5,9 +5,14 @@ module ActiveRecord
5
5
  sql, binds = to_sql_and_binds(arel, binds)
6
6
  value = exec_insert(sql, name, binds, pk, sequence_name)
7
7
 
8
- # CPK
9
- if value && pk.is_a?(Array)
10
- id_value || value.rows.first
8
+ if pk.is_a?(Array) && !value.empty?
9
+ # This is a CPK model and the query result is not empty. Thus we can figure out the new ids for each
10
+ # auto incremented field
11
+ id_value || pk.map {|key| value.first[key]}
12
+ elsif pk.is_a?(Array)
13
+ # This is CPK, but we don't know what autoincremented fields were updated. So return nil, which means
14
+ # the existing id_value of the model will be used.
15
+ id_value || Array.new(pk.size)
11
16
  else
12
17
  id_value || last_inserted_id(value)
13
18
  end
@@ -4,7 +4,7 @@ module ActiveRecord
4
4
  def quote_column_names(name)
5
5
  Array(name).map do |col|
6
6
  quote_column_name(col.to_s)
7
- end.join(CompositePrimaryKeys::ID_SEP)
7
+ end.to_composite_keys.to_s
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module MySQL
6
+ module DatabaseStatements
7
+ def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
8
+ sql, binds = to_sql_and_binds(arel, binds)
9
+ value = exec_insert(sql, name, binds, pk, sequence_name)
10
+
11
+ # CPK
12
+ if pk.is_a?(Array)
13
+ pk.map do |key|
14
+ column = column_for(arel.ast.relation.name, key)
15
+ column.auto_increment? ? last_inserted_id(value) : nil
16
+ end
17
+ else
18
+ id_value || last_inserted_id(value)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end