activerecord-import 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +49 -0
  3. data/.rubocop_todo.yml +36 -0
  4. data/.travis.yml +31 -7
  5. data/CHANGELOG.md +19 -0
  6. data/Gemfile +5 -2
  7. data/README.markdown +6 -1
  8. data/Rakefile +5 -2
  9. data/activerecord-import.gemspec +1 -1
  10. data/benchmarks/benchmark.rb +67 -68
  11. data/benchmarks/lib/base.rb +136 -137
  12. data/benchmarks/lib/cli_parser.rb +106 -107
  13. data/benchmarks/lib/mysql2_benchmark.rb +19 -21
  14. data/benchmarks/lib/output_to_csv.rb +2 -1
  15. data/benchmarks/lib/output_to_html.rb +8 -13
  16. data/benchmarks/schema/mysql_schema.rb +8 -8
  17. data/gemfiles/4.0.gemfile +1 -1
  18. data/gemfiles/4.1.gemfile +1 -1
  19. data/gemfiles/4.2.gemfile +1 -1
  20. data/gemfiles/5.0.gemfile +1 -1
  21. data/lib/activerecord-import.rb +2 -0
  22. data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +0 -1
  23. data/lib/activerecord-import/adapters/abstract_adapter.rb +9 -9
  24. data/lib/activerecord-import/adapters/mysql_adapter.rb +17 -17
  25. data/lib/activerecord-import/adapters/postgresql_adapter.rb +20 -22
  26. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +9 -9
  27. data/lib/activerecord-import/base.rb +3 -3
  28. data/lib/activerecord-import/import.rb +152 -131
  29. data/lib/activerecord-import/synchronize.rb +20 -20
  30. data/lib/activerecord-import/value_sets_parser.rb +7 -6
  31. data/lib/activerecord-import/version.rb +1 -1
  32. data/test/adapters/mysql2spatial.rb +1 -1
  33. data/test/adapters/postgis.rb +1 -1
  34. data/test/adapters/postgresql.rb +1 -1
  35. data/test/adapters/spatialite.rb +1 -1
  36. data/test/adapters/sqlite3.rb +1 -1
  37. data/test/import_test.rb +121 -70
  38. data/test/models/book.rb +5 -6
  39. data/test/models/chapter.rb +2 -2
  40. data/test/models/discount.rb +3 -0
  41. data/test/models/end_note.rb +2 -2
  42. data/test/models/promotion.rb +1 -1
  43. data/test/models/question.rb +1 -1
  44. data/test/models/rule.rb +2 -2
  45. data/test/models/topic.rb +3 -3
  46. data/test/models/widget.rb +1 -1
  47. data/test/postgis/import_test.rb +1 -1
  48. data/test/schema/generic_schema.rb +100 -96
  49. data/test/schema/mysql_schema.rb +5 -7
  50. data/test/sqlite3/import_test.rb +0 -2
  51. data/test/support/active_support/test_case_extensions.rb +12 -15
  52. data/test/support/assertions.rb +1 -1
  53. data/test/support/factories.rb +15 -16
  54. data/test/support/generate.rb +4 -4
  55. data/test/support/mysql/import_examples.rb +21 -21
  56. data/test/support/postgresql/import_examples.rb +83 -55
  57. data/test/support/shared_examples/on_duplicate_key_update.rb +23 -23
  58. data/test/synchronize_test.rb +2 -2
  59. data/test/test_helper.rb +6 -8
  60. data/test/value_sets_bytes_parser_test.rb +14 -17
  61. data/test/value_sets_records_parser_test.rb +6 -6
  62. metadata +7 -4
  63. data/test/travis/build.sh +0 -34
@@ -1,107 +1,106 @@
1
- require 'optparse'
2
- require 'ostruct'
3
-
4
- #
5
- # == PARAMETERS
6
- # * a - database adapter. ie: mysql, postgresql, oracle, etc.
7
- # * n - number of objects to test with. ie: 1, 100, 1000, etc.
8
- # * t - the table types to test. ie: myisam, innodb, memory, temporary, etc.
9
- #
10
- module BenchmarkOptionParser
11
- BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options."
12
-
13
- def self.print_banner
14
- puts BANNER
15
- end
16
-
17
- def self.print_banner!
18
- print_banner
19
- exit
20
- end
21
-
22
- def self.print_options( options )
23
- puts "Benchmarking the following options:"
24
- puts " Database adapter: #{options.adapter}"
25
- puts " Number of objects: #{options.number_of_objects}"
26
- puts " Table types:"
27
- print_valid_table_types( options, :prefix=>" " )
28
- end
29
-
30
- # TODO IMPLEMENT THIS
31
- def self.print_valid_table_types( options, hsh={:prefix=>''} )
32
- if options.table_types.keys.size > 0
33
- options.table_types.keys.sort.each{ |type| puts hsh[:prefix].to_s + type.to_s }
34
- else
35
- puts 'No table types defined.'
36
- end
37
- end
38
-
39
- def self.parse( args )
40
- options = OpenStruct.new(
41
- :adapter => 'mysql2',
42
- :table_types => {},
43
- :delete_on_finish => true,
44
- :number_of_objects => [],
45
- :outputs => [] )
46
-
47
- opts = OptionParser.new do |opts|
48
- opts.banner = BANNER
49
-
50
- # parse the database adapter
51
- opts.on( "a", "--adapter [String]",
52
- "The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
53
- options.adapter = arg
54
- end
55
-
56
- # parse do_not_delete flag
57
- opts.on( "d", "--do-not-delete",
58
- "By default all records in the benchmark tables will be deleted at the end of the benchmark. " +
59
- "This flag indicates not to delete the benchmark data." ) do |arg|
60
- options.delete_on_finish = false
61
- end
62
-
63
- # parse the number of row objects to test
64
- opts.on( "n", "--num [Integer]",
65
- "The number of objects to benchmark." ) do |arg|
66
- options.number_of_objects << arg.to_i
67
- end
68
-
69
- # parse the table types to test
70
- opts.on( "t", "--table-type [String]",
71
- "The table type to test. This can be used multiple times." ) do |arg|
72
- if arg =~ /^all$/
73
- options.table_types['all'] = options.benchmark_all_types = true
74
- else
75
- options.table_types[arg] = true
76
- end
77
- end
78
-
79
- # print results in CSV format
80
- opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
81
- options.outputs << OpenStruct.new( :format=>'csv', :filename=>filename)
82
- end
83
-
84
- # print results in HTML format
85
- opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
86
- options.outputs << OpenStruct.new( :format=>'html', :filename=>filename )
87
- end
88
- end #end opt.parse!
89
-
90
- begin
91
- opts.parse!( args )
92
- if options.table_types.size == 0
93
- options.table_types['all'] = options.benchmark_all_types = true
94
- end
95
- rescue Exception => ex
96
- print_banner!
97
- end
98
-
99
- options.number_of_objects = [1000] if options.number_of_objects.empty?
100
- options.outputs = [ OpenStruct.new( :format => 'html', :filename => 'benchmark.html')] if options.outputs.empty?
101
-
102
- print_options( options )
103
-
104
- options
105
- end
106
-
107
- end
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ #
5
+ # == PARAMETERS
6
+ # * a - database adapter. ie: mysql, postgresql, oracle, etc.
7
+ # * n - number of objects to test with. ie: 1, 100, 1000, etc.
8
+ # * t - the table types to test. ie: myisam, innodb, memory, temporary, etc.
9
+ #
10
+ module BenchmarkOptionParser
11
+ BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options.".freeze
12
+
13
+ def self.print_banner
14
+ puts BANNER
15
+ end
16
+
17
+ def self.print_banner!
18
+ print_banner
19
+ exit
20
+ end
21
+
22
+ def self.print_options( options )
23
+ puts "Benchmarking the following options:"
24
+ puts " Database adapter: #{options.adapter}"
25
+ puts " Number of objects: #{options.number_of_objects}"
26
+ puts " Table types:"
27
+ print_valid_table_types( options, prefix: " " )
28
+ end
29
+
30
+ # TODO IMPLEMENT THIS
31
+ def self.print_valid_table_types( options, hsh = { prefix: '' } )
32
+ if !options.table_types.keys.empty?
33
+ options.table_types.keys.sort.each { |type| puts hsh[:prefix].to_s + type.to_s }
34
+ else
35
+ puts 'No table types defined.'
36
+ end
37
+ end
38
+
39
+ def self.parse( args )
40
+ options = OpenStruct.new(
41
+ adapter: 'mysql2',
42
+ table_types: {},
43
+ delete_on_finish: true,
44
+ number_of_objects: [],
45
+ outputs: [] )
46
+
47
+ opt_parser = OptionParser.new do |opts|
48
+ opts.banner = BANNER
49
+
50
+ # parse the database adapter
51
+ opts.on( "a", "--adapter [String]",
52
+ "The database adapter to use. IE: mysql, postgresql, oracle" ) do |arg|
53
+ options.adapter = arg
54
+ end
55
+
56
+ # parse do_not_delete flag
57
+ opts.on( "d", "--do-not-delete",
58
+ "By default all records in the benchmark tables will be deleted at the end of the benchmark. " \
59
+ "This flag indicates not to delete the benchmark data." ) do |_|
60
+ options.delete_on_finish = false
61
+ end
62
+
63
+ # parse the number of row objects to test
64
+ opts.on( "n", "--num [Integer]",
65
+ "The number of objects to benchmark." ) do |arg|
66
+ options.number_of_objects << arg.to_i
67
+ end
68
+
69
+ # parse the table types to test
70
+ opts.on( "t", "--table-type [String]",
71
+ "The table type to test. This can be used multiple times." ) do |arg|
72
+ if arg =~ /^all$/
73
+ options.table_types['all'] = options.benchmark_all_types = true
74
+ else
75
+ options.table_types[arg] = true
76
+ end
77
+ end
78
+
79
+ # print results in CSV format
80
+ opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
81
+ options.outputs << OpenStruct.new( format: 'csv', filename: filename)
82
+ end
83
+
84
+ # print results in HTML format
85
+ opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
86
+ options.outputs << OpenStruct.new( format: 'html', filename: filename )
87
+ end
88
+ end # end opt.parse!
89
+
90
+ begin
91
+ opt_parser.parse!( args )
92
+ if options.table_types.empty?
93
+ options.table_types['all'] = options.benchmark_all_types = true
94
+ end
95
+ rescue Exception
96
+ print_banner!
97
+ end
98
+
99
+ options.number_of_objects = [1000] if options.number_of_objects.empty?
100
+ options.outputs = [OpenStruct.new( format: 'html', filename: 'benchmark.html')] if options.outputs.empty?
101
+
102
+ print_options( options )
103
+
104
+ options
105
+ end
106
+ end
@@ -1,21 +1,19 @@
1
- class Mysql2Benchmark < BenchmarkBase
2
-
3
- def benchmark_all( array_of_cols_and_vals )
4
- methods = self.methods.find_all { |m| m =~ /benchmark_/ }
5
- methods.delete_if{ |m| m =~ /benchmark_(all|model)/ }
6
- methods.each { |method| self.send( method, array_of_cols_and_vals ) }
7
- end
8
-
9
- def benchmark_myisam( array_of_cols_and_vals )
10
- bm_model( TestMyISAM, array_of_cols_and_vals )
11
- end
12
-
13
- def benchmark_innodb( array_of_cols_and_vals )
14
- bm_model( TestInnoDb, array_of_cols_and_vals )
15
- end
16
-
17
- def benchmark_memory( array_of_cols_and_vals )
18
- bm_model( TestMemory, array_of_cols_and_vals )
19
- end
20
-
21
- end
1
+ class Mysql2Benchmark < BenchmarkBase
2
+ def benchmark_all( array_of_cols_and_vals )
3
+ methods = self.methods.find_all { |m| m =~ /benchmark_/ }
4
+ methods.delete_if { |m| m =~ /benchmark_(all|model)/ }
5
+ methods.each { |method| send( method, array_of_cols_and_vals ) }
6
+ end
7
+
8
+ def benchmark_myisam( array_of_cols_and_vals )
9
+ bm_model( TestMyISAM, array_of_cols_and_vals )
10
+ end
11
+
12
+ def benchmark_innodb( array_of_cols_and_vals )
13
+ bm_model( TestInnoDb, array_of_cols_and_vals )
14
+ end
15
+
16
+ def benchmark_memory( array_of_cols_and_vals )
17
+ bm_model( TestMemory, array_of_cols_and_vals )
18
+ end
19
+ end
@@ -5,7 +5,8 @@ module OutputToCSV
5
5
  CSV.open( filename, 'w' ) do |csv|
6
6
  # Iterate over each result set, which contains many results
7
7
  results.each do |result_set|
8
- columns, times = [], []
8
+ columns = []
9
+ times = []
9
10
  result_set.each do |result|
10
11
  columns << result.description
11
12
  times << result.tms.real
@@ -1,8 +1,7 @@
1
1
  require 'erb'
2
2
 
3
3
  module OutputToHTML
4
-
5
- TEMPLATE_HEADER =<<"EOT"
4
+ TEMPLATE_HEADER = <<"EOT".freeze
6
5
  <div>
7
6
  All times are rounded to the nearest thousandth for display purposes. Speedups next to each time are computed
8
7
  before any rounding occurs. Also, all speedup calculations are computed by comparing a given time against
@@ -10,7 +9,7 @@ TEMPLATE_HEADER =<<"EOT"
10
9
  </div>
11
10
  EOT
12
11
 
13
- TEMPLATE =<<"EOT"
12
+ TEMPLATE = <<"EOT".freeze
14
13
  <style>
15
14
  td#benchmarkTitle {
16
15
  border: 1px solid black;
@@ -43,27 +42,23 @@ EOT
43
42
  def self.output_results( filename, results )
44
43
  html = ''
45
44
  results.each do |result_set|
46
- columns, times = [], []
45
+ columns = []
46
+ times = []
47
47
  result_set.each do |result|
48
48
  columns << result.description
49
49
  if result.failed
50
50
  times << "failed"
51
51
  else
52
52
  time = result.tms.real.round_to( 3 )
53
- speedup = ( result_set.first.tms.real / result.tms.real ).round
54
-
55
- if result == result_set.first
56
- times << "#{time}"
57
- else
58
- times << "#{time} (#{speedup}x speedup)"
59
- end
53
+ speedup = ( result_set.first.tms.real / result.tms.real ).round
54
+ times << result == result_set.first ? time.to_s : "#{time} (#{speedup}x speedup)"
60
55
  end
61
56
  end
62
57
 
63
58
  template = ERB.new( TEMPLATE, 0, "%<>")
64
59
  html << template.result( binding )
65
60
  end
66
-
67
- File.open( filename, 'w' ){ |file| file.write( TEMPLATE_HEADER + html ) }
61
+
62
+ File.open( filename, 'w' ) { |file| file.write( TEMPLATE_HEADER + html ) }
68
63
  end
69
64
  end
@@ -1,16 +1,16 @@
1
1
  ActiveRecord::Schema.define do
2
- create_table :test_myisam, :options=>'ENGINE=MyISAM', :force=>true do |t|
3
- t.column :my_name, :string, :null=>false
2
+ create_table :test_myisam, options: 'ENGINE=MyISAM', force: true do |t|
3
+ t.column :my_name, :string, null: false
4
4
  t.column :description, :string
5
5
  end
6
-
7
- create_table :test_innodb, :options=>'ENGINE=InnoDb', :force=>true do |t|
8
- t.column :my_name, :string, :null=>false
6
+
7
+ create_table :test_innodb, options: 'ENGINE=InnoDb', force: true do |t|
8
+ t.column :my_name, :string, null: false
9
9
  t.column :description, :string
10
10
  end
11
11
 
12
- create_table :test_memory, :options=>'ENGINE=Memory', :force=>true do |t|
13
- t.column :my_name, :string, :null=>false
12
+ create_table :test_memory, options: 'ENGINE=Memory', force: true do |t|
13
+ t.column :my_name, :string, null: false
14
14
  t.column :description, :string
15
15
  end
16
- end
16
+ end
@@ -1,3 +1,3 @@
1
1
  platforms :ruby do
2
- gem 'activerecord', '~> 4.0'
2
+ gem 'activerecord', '~> 4.0.0'
3
3
  end
@@ -1,3 +1,3 @@
1
1
  platforms :ruby do
2
- gem 'activerecord', '~> 4.1'
2
+ gem 'activerecord', '~> 4.1.0'
3
3
  end
@@ -1,3 +1,3 @@
1
1
  platforms :ruby do
2
- gem 'activerecord', '~> 4.2'
2
+ gem 'activerecord', '~> 4.2.0'
3
3
  end
@@ -1,3 +1,3 @@
1
1
  platforms :ruby do
2
- gem 'activerecord', '~> 5.0.0.beta1'
2
+ gem 'activerecord', '~> 5.0.0.beta3'
3
3
  end
@@ -1,3 +1,5 @@
1
+ # rubocop:disable Style/FileName
2
+
1
3
  ActiveSupport.on_load(:active_record) do
2
4
  class ActiveRecord::Base
3
5
  class << self
@@ -4,4 +4,3 @@ require "activerecord-import/adapters/sqlite3_adapter"
4
4
  class ActiveRecord::ConnectionAdapters::SQLite3Adapter
5
5
  include ActiveRecord::Import::SQLite3Adapter
6
6
  end
7
-
@@ -1,22 +1,22 @@
1
1
  module ActiveRecord::Import::AbstractAdapter
2
2
  module InstanceMethods
3
3
  def next_value_for_sequence(sequence_name)
4
- %{#{sequence_name}.nextval}
4
+ %(#{sequence_name}.nextval)
5
5
  end
6
6
 
7
7
  def insert_many( sql, values, *args ) # :nodoc:
8
8
  number_of_inserts = 1
9
9
 
10
- base_sql,post_sql = if sql.is_a?( String )
11
- [ sql, '' ]
10
+ base_sql, post_sql = if sql.is_a?( String )
11
+ [sql, '']
12
12
  elsif sql.is_a?( Array )
13
- [ sql.shift, sql.join( ' ' ) ]
13
+ [sql.shift, sql.join( ' ' )]
14
14
  end
15
15
 
16
16
  sql2insert = base_sql + values.join( ',' ) + post_sql
17
17
  insert( sql2insert, *args )
18
18
 
19
- [number_of_inserts,[]]
19
+ [number_of_inserts, []]
20
20
  end
21
21
 
22
22
  def pre_sql_statements(options)
@@ -25,7 +25,7 @@ module ActiveRecord::Import::AbstractAdapter
25
25
  sql << options[:command] if options[:command]
26
26
  sql << "IGNORE" if options[:ignore]
27
27
 
28
- #add keywords like IGNORE or DELAYED
28
+ # add keywords like IGNORE or DELAYED
29
29
  if options[:keywords].is_a?(Array)
30
30
  sql.concat(options[:keywords])
31
31
  elsif options[:keywords]
@@ -38,7 +38,7 @@ module ActiveRecord::Import::AbstractAdapter
38
38
  # Synchronizes the passed in ActiveRecord instances with the records in
39
39
  # the database by calling +reload+ on each instance.
40
40
  def after_import_synchronize( instances )
41
- instances.each { |e| e.reload }
41
+ instances.each(&:reload)
42
42
  end
43
43
 
44
44
  # Returns an array of post SQL statements given the passed in options.
@@ -53,10 +53,10 @@ module ActiveRecord::Import::AbstractAdapter
53
53
  end
54
54
  end
55
55
 
56
- #custom user post_sql
56
+ # custom user post_sql
57
57
  post_sql_statements << options[:post_sql] if options[:post_sql]
58
58
 
59
- #with rollup
59
+ # with rollup
60
60
  post_sql_statements << rollup_sql if options[:rollup]
61
61
 
62
62
  post_sql_statements
@@ -3,7 +3,7 @@ module ActiveRecord::Import::MysqlAdapter
3
3
  include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
4
4
 
5
5
  NO_MAX_PACKET = 0
6
- QUERY_OVERHEAD = 8 #This was shown to be true for MySQL, but it's not clear where the overhead is from.
6
+ QUERY_OVERHEAD = 8 # This was shown to be true for MySQL, but it's not clear where the overhead is from.
7
7
 
8
8
  # +sql+ can be a single string or an array. If it is an array all
9
9
  # elements that are in position >= 1 will be appended to the final SQL.
@@ -11,19 +11,19 @@ module ActiveRecord::Import::MysqlAdapter
11
11
  # the number of inserts default
12
12
  number_of_inserts = 0
13
13
 
14
- base_sql,post_sql = if sql.is_a?( String )
15
- [ sql, '' ]
14
+ base_sql, post_sql = if sql.is_a?( String )
15
+ [sql, '']
16
16
  elsif sql.is_a?( Array )
17
- [ sql.shift, sql.join( ' ' ) ]
17
+ [sql.shift, sql.join( ' ' )]
18
18
  end
19
19
 
20
20
  sql_size = QUERY_OVERHEAD + base_sql.size + post_sql.size
21
21
 
22
22
  # the number of bytes the requested insert statement values will take up
23
- values_in_bytes = values.sum {|value| value.bytesize }
23
+ values_in_bytes = values.sum(&:bytesize)
24
24
 
25
25
  # the number of bytes (commas) it will take to comma separate our values
26
- comma_separated_bytes = values.size-1
26
+ comma_separated_bytes = values.size - 1
27
27
 
28
28
  # the total number of bytes required if this statement is one statement
29
29
  total_bytes = sql_size + values_in_bytes + comma_separated_bytes
@@ -31,22 +31,22 @@ module ActiveRecord::Import::MysqlAdapter
31
31
  max = max_allowed_packet
32
32
 
33
33
  # if we can insert it all as one statement
34
- if NO_MAX_PACKET == max or total_bytes < max
34
+ if NO_MAX_PACKET == max || total_bytes < max
35
35
  number_of_inserts += 1
36
36
  sql2insert = base_sql + values.join( ',' ) + post_sql
37
37
  insert( sql2insert, *args )
38
38
  else
39
39
  value_sets = ::ActiveRecord::Import::ValueSetsBytesParser.parse(values,
40
- :reserved_bytes => sql_size,
41
- :max_bytes => max)
42
- value_sets.each do |values|
40
+ reserved_bytes: sql_size,
41
+ max_bytes: max)
42
+ value_sets.each do |value_set|
43
43
  number_of_inserts += 1
44
- sql2insert = base_sql + values.join( ',' ) + post_sql
44
+ sql2insert = base_sql + value_set.join( ',' ) + post_sql
45
45
  insert( sql2insert, *args )
46
46
  end
47
47
  end
48
48
 
49
- [number_of_inserts,[]]
49
+ [number_of_inserts, []]
50
50
  end
51
51
 
52
52
  # Returns the maximum number of bytes that the server will allow
@@ -61,7 +61,7 @@ module ActiveRecord::Import::MysqlAdapter
61
61
  end
62
62
 
63
63
  # Add a column to be updated on duplicate key update
64
- def add_column_for_on_duplicate_key_update( column, options={} ) # :nodoc:
64
+ def add_column_for_on_duplicate_key_update( column, options = {} ) # :nodoc:
65
65
  if options.include?(:on_duplicate_key_update)
66
66
  columns = options[:on_duplicate_key_update]
67
67
  case columns
@@ -69,7 +69,7 @@ module ActiveRecord::Import::MysqlAdapter
69
69
  when Hash then columns[column.to_sym] = column.to_sym
70
70
  end
71
71
  else
72
- options[:on_duplicate_key_update] = [ column.to_sym ]
72
+ options[:on_duplicate_key_update] = [column.to_sym]
73
73
  end
74
74
  end
75
75
 
@@ -85,12 +85,12 @@ module ActiveRecord::Import::MysqlAdapter
85
85
  elsif arg.is_a?( String )
86
86
  sql << arg
87
87
  else
88
- raise ArgumentError.new( "Expected Array or Hash" )
88
+ raise ArgumentError, "Expected Array or Hash"
89
89
  end
90
90
  sql
91
91
  end
92
92
 
93
- def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
93
+ def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
94
94
  results = arr.map do |column|
95
95
  qc = quote_column_name( column )
96
96
  "#{table_name}.#{qc}=VALUES(#{qc})"
@@ -108,7 +108,7 @@ module ActiveRecord::Import::MysqlAdapter
108
108
  end
109
109
 
110
110
  # Return true if the statement is a duplicate key record error
111
- def duplicate_key_update_error?(exception)# :nodoc:
111
+ def duplicate_key_update_error?(exception) # :nodoc:
112
112
  exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
113
113
  end
114
114
  end