activerecord-import 1.0.0 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +17 -14
- data/CHANGELOG.md +65 -0
- data/Gemfile +4 -1
- data/LICENSE +21 -56
- data/README.markdown +54 -59
- data/activerecord-import.gemspec +2 -2
- data/gemfiles/6.0.gemfile +1 -0
- data/gemfiles/6.1.gemfile +1 -0
- data/lib/activerecord-import/adapters/abstract_adapter.rb +8 -2
- data/lib/activerecord-import/adapters/mysql_adapter.rb +4 -5
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +11 -12
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +15 -20
- data/lib/activerecord-import/base.rb +8 -1
- data/lib/activerecord-import/import.rb +41 -36
- data/lib/activerecord-import/synchronize.rb +1 -1
- data/lib/activerecord-import/version.rb +1 -1
- data/test/import_test.rb +5 -0
- data/test/schema/postgresql_schema.rb +16 -0
- data/test/support/postgresql/import_examples.rb +44 -0
- data/test/support/shared_examples/on_duplicate_key_update.rb +10 -0
- data/test/support/shared_examples/recursive_import.rb +38 -0
- data/test/support/sqlite3/import_examples.rb +2 -15
- metadata +7 -6
data/activerecord-import.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.summary = "Bulk insert extension for ActiveRecord"
|
8
8
|
gem.description = "A library for bulk inserting data using ActiveRecord."
|
9
9
|
gem.homepage = "http://github.com/zdennis/activerecord-import"
|
10
|
-
gem.license = "
|
10
|
+
gem.license = "MIT"
|
11
11
|
|
12
12
|
gem.files = `git ls-files`.split($\)
|
13
13
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.require_paths = ["lib"]
|
17
17
|
gem.version = ActiveRecord::Import::VERSION
|
18
18
|
|
19
|
-
gem.required_ruby_version = ">=
|
19
|
+
gem.required_ruby_version = ">= 2.0.0"
|
20
20
|
|
21
21
|
gem.add_runtime_dependency "activerecord", ">= 3.2"
|
22
22
|
gem.add_development_dependency "rake"
|
@@ -0,0 +1 @@
|
|
1
|
+
gem 'activerecord', '~> 6.0.0'
|
@@ -0,0 +1 @@
|
|
1
|
+
gem 'activerecord', '~> 6.1.0.alpha', github: "rails/rails"
|
@@ -46,7 +46,7 @@ module ActiveRecord::Import::AbstractAdapter
|
|
46
46
|
|
47
47
|
if supports_on_duplicate_key_update? && options[:on_duplicate_key_update]
|
48
48
|
post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:primary_key], options[:locking_column] )
|
49
|
-
elsif options[:on_duplicate_key_update]
|
49
|
+
elsif logger && options[:on_duplicate_key_update]
|
50
50
|
logger.warn "Ignoring on_duplicate_key_update because it is not supported by the database."
|
51
51
|
end
|
52
52
|
|
@@ -59,8 +59,14 @@ module ActiveRecord::Import::AbstractAdapter
|
|
59
59
|
post_sql_statements
|
60
60
|
end
|
61
61
|
|
62
|
+
def increment_locking_column!(table_name, results, locking_column)
|
63
|
+
if locking_column.present?
|
64
|
+
results << "\"#{locking_column}\"=#{table_name}.\"#{locking_column}\"+1"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
62
68
|
def supports_on_duplicate_key_update?
|
63
|
-
|
69
|
+
true
|
64
70
|
end
|
65
71
|
end
|
66
72
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ActiveRecord::Import::MysqlAdapter
|
2
2
|
include ActiveRecord::Import::ImportSupport
|
3
|
-
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
4
3
|
|
5
4
|
NO_MAX_PACKET = 0
|
6
5
|
QUERY_OVERHEAD = 8 # This was shown to be true for MySQL, but it's not clear where the overhead is from.
|
@@ -102,7 +101,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
102
101
|
qc = quote_column_name( column )
|
103
102
|
"#{table_name}.#{qc}=VALUES(#{qc})"
|
104
103
|
end
|
105
|
-
increment_locking_column!(
|
104
|
+
increment_locking_column!(table_name, results, locking_column)
|
106
105
|
results.join( ',' )
|
107
106
|
end
|
108
107
|
|
@@ -112,7 +111,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
112
111
|
qc2 = quote_column_name( column2 )
|
113
112
|
"#{table_name}.#{qc1}=VALUES( #{qc2} )"
|
114
113
|
end
|
115
|
-
increment_locking_column!(
|
114
|
+
increment_locking_column!(table_name, results, locking_column)
|
116
115
|
results.join( ',')
|
117
116
|
end
|
118
117
|
|
@@ -121,9 +120,9 @@ module ActiveRecord::Import::MysqlAdapter
|
|
121
120
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
|
122
121
|
end
|
123
122
|
|
124
|
-
def increment_locking_column!(
|
123
|
+
def increment_locking_column!(table_name, results, locking_column)
|
125
124
|
if locking_column.present?
|
126
|
-
results << "
|
125
|
+
results << "`#{locking_column}`=#{table_name}.`#{locking_column}`+1"
|
127
126
|
end
|
128
127
|
end
|
129
128
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ActiveRecord::Import::PostgreSQLAdapter
|
2
2
|
include ActiveRecord::Import::ImportSupport
|
3
|
-
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
4
3
|
|
5
4
|
MIN_VERSION_FOR_UPSERT = 90_500
|
6
5
|
|
@@ -19,7 +18,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
19
18
|
sql2insert = base_sql + values.join( ',' ) + post_sql
|
20
19
|
|
21
20
|
columns = returning_columns(options)
|
22
|
-
if columns.blank? || options[:no_returning]
|
21
|
+
if columns.blank? || (options[:no_returning] && !options[:recursive])
|
23
22
|
insert( sql2insert, *args )
|
24
23
|
else
|
25
24
|
returned_values = if columns.size > 1
|
@@ -73,14 +72,14 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
73
72
|
if (options[:ignore] || options[:on_duplicate_key_ignore]) && !options[:on_duplicate_key_update] && !options[:recursive]
|
74
73
|
sql << sql_for_on_duplicate_key_ignore( table_name, options[:on_duplicate_key_ignore] )
|
75
74
|
end
|
76
|
-
elsif options[:on_duplicate_key_ignore] && !options[:on_duplicate_key_update]
|
75
|
+
elsif logger && options[:on_duplicate_key_ignore] && !options[:on_duplicate_key_update]
|
77
76
|
logger.warn "Ignoring on_duplicate_key_ignore because it is not supported by the database."
|
78
77
|
end
|
79
78
|
|
80
79
|
sql += super(table_name, options)
|
81
80
|
|
82
81
|
columns = returning_columns(options)
|
83
|
-
unless columns.blank? || options[:no_returning]
|
82
|
+
unless columns.blank? || (options[:no_returning] && !options[:recursive])
|
84
83
|
sql << " RETURNING \"#{columns.join('", "')}\""
|
85
84
|
end
|
86
85
|
|
@@ -158,7 +157,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
158
157
|
qc = quote_column_name( column )
|
159
158
|
"#{qc}=EXCLUDED.#{qc}"
|
160
159
|
end
|
161
|
-
increment_locking_column!(results, locking_column)
|
160
|
+
increment_locking_column!(table_name, results, locking_column)
|
162
161
|
results.join( ',' )
|
163
162
|
end
|
164
163
|
|
@@ -168,7 +167,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
168
167
|
qc2 = quote_column_name( column2 )
|
169
168
|
"#{qc1}=EXCLUDED.#{qc2}"
|
170
169
|
end
|
171
|
-
increment_locking_column!(results, locking_column)
|
170
|
+
increment_locking_column!(table_name, results, locking_column)
|
172
171
|
results.join( ',' )
|
173
172
|
end
|
174
173
|
|
@@ -195,17 +194,17 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
195
194
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('duplicate key')
|
196
195
|
end
|
197
196
|
|
198
|
-
def supports_on_duplicate_key_update?
|
199
|
-
|
197
|
+
def supports_on_duplicate_key_update?
|
198
|
+
database_version >= MIN_VERSION_FOR_UPSERT
|
200
199
|
end
|
201
200
|
|
202
201
|
def supports_setting_primary_key_of_imported_objects?
|
203
202
|
true
|
204
203
|
end
|
205
204
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
205
|
+
private
|
206
|
+
|
207
|
+
def database_version
|
208
|
+
defined?(postgresql_version) ? postgresql_version : super
|
210
209
|
end
|
211
210
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module ActiveRecord::Import::SQLite3Adapter
|
2
2
|
include ActiveRecord::Import::ImportSupport
|
3
|
-
include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
|
4
3
|
|
5
4
|
MIN_VERSION_FOR_IMPORT = "3.7.11".freeze
|
6
5
|
MIN_VERSION_FOR_UPSERT = "3.24.0".freeze
|
@@ -9,16 +8,12 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
9
8
|
# Override our conformance to ActiveRecord::Import::ImportSupport interface
|
10
9
|
# to ensure that we only support import in supported version of SQLite.
|
11
10
|
# Which INSERT statements with multiple value sets was introduced in 3.7.11.
|
12
|
-
def supports_import?
|
13
|
-
|
14
|
-
true
|
15
|
-
else
|
16
|
-
false
|
17
|
-
end
|
11
|
+
def supports_import?
|
12
|
+
database_version >= MIN_VERSION_FOR_IMPORT
|
18
13
|
end
|
19
14
|
|
20
|
-
def supports_on_duplicate_key_update?
|
21
|
-
|
15
|
+
def supports_on_duplicate_key_update?
|
16
|
+
database_version >= MIN_VERSION_FOR_UPSERT
|
22
17
|
end
|
23
18
|
|
24
19
|
# +sql+ can be a single string or an array. If it is an array all
|
@@ -96,7 +91,7 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
96
91
|
|
97
92
|
# Returns a generated ON CONFLICT DO UPDATE statement given the passed
|
98
93
|
# in +args+.
|
99
|
-
def sql_for_on_duplicate_key_update(
|
94
|
+
def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
|
100
95
|
arg, primary_key, locking_column = args
|
101
96
|
arg = { columns: arg } if arg.is_a?( Array ) || arg.is_a?( String )
|
102
97
|
return unless arg.is_a?( Hash )
|
@@ -117,9 +112,9 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
117
112
|
|
118
113
|
sql << "#{conflict_target}DO UPDATE SET "
|
119
114
|
if columns.is_a?( Array )
|
120
|
-
sql << sql_for_on_duplicate_key_update_as_array( locking_column, columns )
|
115
|
+
sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, columns )
|
121
116
|
elsif columns.is_a?( Hash )
|
122
|
-
sql << sql_for_on_duplicate_key_update_as_hash( locking_column, columns )
|
117
|
+
sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, columns )
|
123
118
|
elsif columns.is_a?( String )
|
124
119
|
sql << columns
|
125
120
|
else
|
@@ -131,22 +126,22 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
131
126
|
sql
|
132
127
|
end
|
133
128
|
|
134
|
-
def sql_for_on_duplicate_key_update_as_array( locking_column, arr ) # :nodoc:
|
129
|
+
def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
|
135
130
|
results = arr.map do |column|
|
136
131
|
qc = quote_column_name( column )
|
137
132
|
"#{qc}=EXCLUDED.#{qc}"
|
138
133
|
end
|
139
|
-
increment_locking_column!(results, locking_column)
|
134
|
+
increment_locking_column!(table_name, results, locking_column)
|
140
135
|
results.join( ',' )
|
141
136
|
end
|
142
137
|
|
143
|
-
def sql_for_on_duplicate_key_update_as_hash( locking_column, hsh ) # :nodoc:
|
138
|
+
def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
|
144
139
|
results = hsh.map do |column1, column2|
|
145
140
|
qc1 = quote_column_name( column1 )
|
146
141
|
qc2 = quote_column_name( column2 )
|
147
142
|
"#{qc1}=EXCLUDED.#{qc2}"
|
148
143
|
end
|
149
|
-
increment_locking_column!(results, locking_column)
|
144
|
+
increment_locking_column!(table_name, results, locking_column)
|
150
145
|
results.join( ',' )
|
151
146
|
end
|
152
147
|
|
@@ -170,9 +165,9 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
170
165
|
exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('duplicate key')
|
171
166
|
end
|
172
167
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
168
|
+
private
|
169
|
+
|
170
|
+
def database_version
|
171
|
+
defined?(sqlite_version) ? sqlite_version : super
|
177
172
|
end
|
178
173
|
end
|
@@ -13,6 +13,7 @@ module ActiveRecord::Import
|
|
13
13
|
when 'postgresql_makara' then 'postgresql'
|
14
14
|
when 'makara_postgis' then 'postgresql'
|
15
15
|
when 'postgis' then 'postgresql'
|
16
|
+
when 'cockroachdb' then 'postgresql'
|
16
17
|
else adapter
|
17
18
|
end
|
18
19
|
end
|
@@ -26,7 +27,13 @@ module ActiveRecord::Import
|
|
26
27
|
|
27
28
|
# Loads the import functionality for the passed in ActiveRecord connection
|
28
29
|
def self.load_from_connection_pool(connection_pool)
|
29
|
-
|
30
|
+
adapter =
|
31
|
+
if connection_pool.respond_to?(:db_config) # ActiveRecord >= 6.1
|
32
|
+
connection_pool.db_config.adapter
|
33
|
+
else
|
34
|
+
connection_pool.spec.config[:adapter]
|
35
|
+
end
|
36
|
+
require_adapter adapter
|
30
37
|
end
|
31
38
|
end
|
32
39
|
|
@@ -11,12 +11,6 @@ module ActiveRecord::Import #:nodoc:
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
module OnDuplicateKeyUpdateSupport #:nodoc:
|
15
|
-
def supports_on_duplicate_key_update? #:nodoc:
|
16
|
-
true
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
14
|
class MissingColumnError < StandardError
|
21
15
|
def initialize(name, index)
|
22
16
|
super "Missing column for value <#{name}> at index #{index}"
|
@@ -26,6 +20,7 @@ module ActiveRecord::Import #:nodoc:
|
|
26
20
|
class Validator
|
27
21
|
def initialize(klass, options = {})
|
28
22
|
@options = options
|
23
|
+
@validator_class = klass
|
29
24
|
init_validations(klass)
|
30
25
|
end
|
31
26
|
|
@@ -70,6 +65,8 @@ module ActiveRecord::Import #:nodoc:
|
|
70
65
|
end
|
71
66
|
|
72
67
|
def valid_model?(model)
|
68
|
+
init_validations(model.class) unless model.class == @validator_class
|
69
|
+
|
73
70
|
validation_context = @options[:validate_with_context]
|
74
71
|
validation_context ||= (model.new_record? ? :create : :update)
|
75
72
|
current_context = model.send(:validation_context)
|
@@ -242,16 +239,17 @@ class ActiveRecord::Associations::CollectionAssociation
|
|
242
239
|
alias import bulk_import unless respond_to? :import
|
243
240
|
end
|
244
241
|
|
242
|
+
module ActiveRecord::Import::Connection
|
243
|
+
def establish_connection(args = nil)
|
244
|
+
conn = super(args)
|
245
|
+
ActiveRecord::Import.load_from_connection_pool connection_pool
|
246
|
+
conn
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
245
250
|
class ActiveRecord::Base
|
246
251
|
class << self
|
247
|
-
|
248
|
-
conn = establish_connection_without_activerecord_import(*args)
|
249
|
-
ActiveRecord::Import.load_from_connection_pool connection_pool
|
250
|
-
conn
|
251
|
-
end
|
252
|
-
|
253
|
-
alias establish_connection_without_activerecord_import establish_connection
|
254
|
-
alias establish_connection establish_connection_with_activerecord_import
|
252
|
+
prepend ActiveRecord::Import::Connection
|
255
253
|
|
256
254
|
# Returns true if the current database connection adapter
|
257
255
|
# supports import functionality, otherwise returns false.
|
@@ -528,7 +526,7 @@ class ActiveRecord::Base
|
|
528
526
|
import_helper(*args)
|
529
527
|
end
|
530
528
|
end
|
531
|
-
alias import bulk_import unless respond_to? :import
|
529
|
+
alias import bulk_import unless ActiveRecord::Base.respond_to? :import
|
532
530
|
|
533
531
|
# Imports a collection of values if all values are valid. Import fails at the
|
534
532
|
# first encountered validation error and raises ActiveRecord::RecordInvalid
|
@@ -540,7 +538,7 @@ class ActiveRecord::Base
|
|
540
538
|
|
541
539
|
bulk_import(*args, options)
|
542
540
|
end
|
543
|
-
alias import! bulk_import! unless respond_to? :import!
|
541
|
+
alias import! bulk_import! unless ActiveRecord::Base.respond_to? :import!
|
544
542
|
|
545
543
|
def import_helper( *args )
|
546
544
|
options = { validate: true, timestamps: true }
|
@@ -574,15 +572,6 @@ class ActiveRecord::Base
|
|
574
572
|
end
|
575
573
|
end
|
576
574
|
|
577
|
-
default_values = column_defaults
|
578
|
-
stored_attrs = respond_to?(:stored_attributes) ? stored_attributes : {}
|
579
|
-
serialized_attrs = if defined?(ActiveRecord::Type::Serialized)
|
580
|
-
attrs = column_names.select { |c| type_for_attribute(c.to_s).class == ActiveRecord::Type::Serialized }
|
581
|
-
Hash[attrs.map { |a| [a, nil] }]
|
582
|
-
else
|
583
|
-
serialized_attributes
|
584
|
-
end
|
585
|
-
|
586
575
|
update_attrs = if record_timestamps && options[:timestamps]
|
587
576
|
if respond_to?(:timestamp_attributes_for_update, true)
|
588
577
|
send(:timestamp_attributes_for_update).map(&:to_sym)
|
@@ -608,12 +597,8 @@ class ActiveRecord::Base
|
|
608
597
|
update_attrs && update_attrs.include?(name.to_sym) &&
|
609
598
|
!model.send("#{name}_changed?")
|
610
599
|
nil
|
611
|
-
elsif stored_attrs.key?(name.to_sym) ||
|
612
|
-
serialized_attrs.key?(name.to_s) ||
|
613
|
-
default_values[name.to_s]
|
614
|
-
model.read_attribute(name.to_s)
|
615
600
|
else
|
616
|
-
model.
|
601
|
+
model.read_attribute(name.to_s)
|
617
602
|
end
|
618
603
|
end
|
619
604
|
end
|
@@ -640,7 +625,7 @@ class ActiveRecord::Base
|
|
640
625
|
end
|
641
626
|
# supports empty array
|
642
627
|
elsif args.last.is_a?( Array ) && args.last.empty?
|
643
|
-
return ActiveRecord::Import::Result.new([], 0, [])
|
628
|
+
return ActiveRecord::Import::Result.new([], 0, [], [])
|
644
629
|
# supports 2-element array and array
|
645
630
|
elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
|
646
631
|
|
@@ -851,6 +836,19 @@ class ActiveRecord::Base
|
|
851
836
|
end
|
852
837
|
end
|
853
838
|
|
839
|
+
deserialize_value = lambda do |column, value|
|
840
|
+
column = columns_hash[column]
|
841
|
+
return value unless column
|
842
|
+
if respond_to?(:type_caster)
|
843
|
+
type = type_for_attribute(column.name)
|
844
|
+
type.deserialize(value)
|
845
|
+
elsif column.respond_to?(:type_cast_from_database)
|
846
|
+
column.type_cast_from_database(value)
|
847
|
+
else
|
848
|
+
value
|
849
|
+
end
|
850
|
+
end
|
851
|
+
|
854
852
|
if models.size == import_result.results.size
|
855
853
|
columns = Array(options[:returning])
|
856
854
|
single_column = "#{columns.first}=" if columns.size == 1
|
@@ -858,10 +856,12 @@ class ActiveRecord::Base
|
|
858
856
|
model = models[index]
|
859
857
|
|
860
858
|
if single_column
|
861
|
-
|
859
|
+
val = deserialize_value.call(columns.first, result)
|
860
|
+
model.send(single_column, val)
|
862
861
|
else
|
863
862
|
columns.each_with_index do |column, col_index|
|
864
|
-
|
863
|
+
val = deserialize_value.call(column, result[col_index])
|
864
|
+
model.send("#{column}=", val)
|
865
865
|
end
|
866
866
|
end
|
867
867
|
end
|
@@ -882,10 +882,12 @@ class ActiveRecord::Base
|
|
882
882
|
|
883
883
|
# Sync belongs_to association ids with foreign key field
|
884
884
|
def load_association_ids(model)
|
885
|
+
changed_columns = model.changed
|
885
886
|
association_reflections = model.class.reflect_on_all_associations(:belongs_to)
|
886
887
|
association_reflections.each do |association_reflection|
|
887
888
|
column_name = association_reflection.foreign_key
|
888
889
|
next if association_reflection.options[:polymorphic]
|
890
|
+
next if changed_columns.include?(column_name)
|
889
891
|
association = model.association(association_reflection.name)
|
890
892
|
association = association.target
|
891
893
|
next if association.blank? || model.public_send(column_name).present?
|
@@ -904,8 +906,9 @@ class ActiveRecord::Base
|
|
904
906
|
associated_objects_by_class = {}
|
905
907
|
models.each { |model| find_associated_objects_for_import(associated_objects_by_class, model) }
|
906
908
|
|
907
|
-
# :on_duplicate_key_update not supported for associations
|
909
|
+
# :on_duplicate_key_update and :returning not supported for associations
|
908
910
|
options.delete(:on_duplicate_key_update)
|
911
|
+
options.delete(:returning)
|
909
912
|
|
910
913
|
associated_objects_by_class.each_value do |associations|
|
911
914
|
associations.each_value do |associated_records|
|
@@ -964,7 +967,7 @@ class ActiveRecord::Base
|
|
964
967
|
elsif column
|
965
968
|
if respond_to?(:type_caster) # Rails 5.0 and higher
|
966
969
|
type = type_for_attribute(column.name)
|
967
|
-
val = type.type == :boolean ? type.cast(val) : type.serialize(val)
|
970
|
+
val = !type.respond_to?(:subtype) && type.type == :boolean ? type.cast(val) : type.serialize(val)
|
968
971
|
connection_memo.quote(val)
|
969
972
|
elsif column.respond_to?(:type_cast_from_user) # Rails 4.2
|
970
973
|
connection_memo.quote(column.type_cast_from_user(val), column)
|
@@ -973,9 +976,11 @@ class ActiveRecord::Base
|
|
973
976
|
val = serialized_attributes[column.name].dump(val)
|
974
977
|
end
|
975
978
|
# Fixes #443 to support binary (i.e. bytea) columns on PG
|
976
|
-
val = column.type_cast(val) unless column.type.to_sym == :binary
|
979
|
+
val = column.type_cast(val) unless column.type && column.type.to_sym == :binary
|
977
980
|
connection_memo.quote(val, column)
|
978
981
|
end
|
982
|
+
else
|
983
|
+
raise ArgumentError, "Number of values (#{arr.length}) exceeds number of columns (#{columns.length})"
|
979
984
|
end
|
980
985
|
end
|
981
986
|
"(#{my_values.join(',')})"
|