activerecord-import 0.3.1 → 0.4.0

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/Brewfile +3 -0
  4. data/Gemfile +39 -0
  5. data/Rakefile +1 -24
  6. data/activerecord-import.gemspec +22 -0
  7. data/benchmarks/README +32 -0
  8. data/benchmarks/benchmark.rb +64 -0
  9. data/benchmarks/boot.rb +18 -0
  10. data/benchmarks/lib/base.rb +137 -0
  11. data/benchmarks/lib/cli_parser.rb +103 -0
  12. data/benchmarks/lib/float.rb +15 -0
  13. data/benchmarks/lib/mysql_benchmark.rb +22 -0
  14. data/benchmarks/lib/output_to_csv.rb +18 -0
  15. data/benchmarks/lib/output_to_html.rb +69 -0
  16. data/benchmarks/models/test_innodb.rb +3 -0
  17. data/benchmarks/models/test_memory.rb +3 -0
  18. data/benchmarks/models/test_myisam.rb +3 -0
  19. data/benchmarks/schema/mysql_schema.rb +16 -0
  20. data/gemfiles/3.1.gemfile +4 -0
  21. data/gemfiles/3.2.gemfile +4 -0
  22. data/gemfiles/4.0.gemfile +4 -0
  23. data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +0 -1
  24. data/lib/activerecord-import/active_record/adapters/em_mysql2_adapter.rb +8 -0
  25. data/lib/activerecord-import/adapters/abstract_adapter.rb +5 -58
  26. data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +5 -0
  27. data/lib/activerecord-import/adapters/mysql_adapter.rb +50 -3
  28. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +28 -3
  29. data/lib/activerecord-import/base.rb +3 -2
  30. data/lib/activerecord-import/em_mysql2.rb +7 -0
  31. data/lib/activerecord-import/import.rb +29 -29
  32. data/lib/activerecord-import/synchronize.rb +11 -10
  33. data/lib/activerecord-import/value_sets_parser.rb +54 -0
  34. data/lib/activerecord-import/version.rb +5 -0
  35. data/test/adapters/em_mysql2.rb +1 -0
  36. data/test/adapters/jdbcmysql.rb +1 -0
  37. data/test/adapters/mysql.rb +1 -0
  38. data/test/adapters/mysql2.rb +1 -0
  39. data/test/adapters/mysql2spatial.rb +1 -0
  40. data/test/adapters/mysqlspatial.rb +1 -0
  41. data/test/adapters/postgis.rb +1 -0
  42. data/test/adapters/postgresql.rb +1 -0
  43. data/test/adapters/seamless_database_pool.rb +1 -0
  44. data/test/adapters/spatialite.rb +1 -0
  45. data/test/adapters/sqlite3.rb +1 -0
  46. data/test/database.yml.sample +57 -0
  47. data/test/em_mysql2/import_test.rb +6 -0
  48. data/test/import_test.rb +350 -0
  49. data/test/jdbcmysql/import_test.rb +6 -0
  50. data/test/models/book.rb +3 -0
  51. data/test/models/group.rb +3 -0
  52. data/test/models/topic.rb +7 -0
  53. data/test/models/widget.rb +7 -0
  54. data/test/mysql/import_test.rb +6 -0
  55. data/test/mysql2/import_test.rb +6 -0
  56. data/test/mysqlspatial/import_test.rb +6 -0
  57. data/test/mysqlspatial2/import_test.rb +6 -0
  58. data/test/postgis/import_test.rb +4 -0
  59. data/test/postgresql/import_test.rb +4 -0
  60. data/test/schema/generic_schema.rb +104 -0
  61. data/test/schema/mysql_schema.rb +17 -0
  62. data/test/schema/version.rb +10 -0
  63. data/test/sqlite3/import_test.rb +52 -0
  64. data/test/support/active_support/test_case_extensions.rb +67 -0
  65. data/test/support/factories.rb +19 -0
  66. data/test/support/generate.rb +29 -0
  67. data/test/support/mysql/assertions.rb +55 -0
  68. data/test/support/mysql/import_examples.rb +147 -0
  69. data/test/support/postgresql/import_examples.rb +21 -0
  70. data/test/synchronize_test.rb +22 -0
  71. data/test/test_helper.rb +48 -0
  72. data/test/value_sets_bytes_parser_test.rb +96 -0
  73. data/test/value_sets_records_parser_test.rb +32 -0
  74. metadata +120 -58
  75. data/VERSION +0 -1
@@ -0,0 +1,15 @@
1
+ # Taken from http://www.programmingishard.com/posts/show/128
2
+ # Posted by rbates
3
+ class Float
4
+ def round_to(x)
5
+ (self * 10**x).round.to_f / 10**x
6
+ end
7
+
8
+ def ceil_to(x)
9
+ (self * 10**x).ceil.to_f / 10**x
10
+ end
11
+
12
+ def floor_to(x)
13
+ (self * 10**x).floor.to_f / 10**x
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ class MysqlBenchmark < 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
22
+
@@ -0,0 +1,18 @@
1
+ require 'fastercsv'
2
+
3
+ module OutputToCSV
4
+ def self.output_results( filename, results )
5
+ FasterCSV.open( filename, 'w' ) do |csv|
6
+ # Iterate over each result set, which contains many results
7
+ results.each do |result_set|
8
+ columns, times = [], []
9
+ result_set.each do |result|
10
+ columns << result.description
11
+ times << result.tms.real
12
+ end
13
+ csv << columns
14
+ csv << times
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,69 @@
1
+ require 'erb'
2
+
3
+ module OutputToHTML
4
+
5
+ TEMPLATE_HEADER =<<"EOT"
6
+ <div>
7
+ All times are rounded to the nearest thousandth for display purposes. Speedups next to each time are computed
8
+ before any rounding occurs. Also, all speedup calculations are computed by comparing a given time against
9
+ the very first column (which is always the default ActiveRecord::Base.create method.
10
+ </div>
11
+ EOT
12
+
13
+ TEMPLATE =<<"EOT"
14
+ <style>
15
+ td#benchmarkTitle {
16
+ border: 1px solid black;
17
+ padding: 2px;
18
+ font-size: 0.8em;
19
+ background-color: black;
20
+ color: white;
21
+ }
22
+ td#benchmarkCell {
23
+ border: 1px solid black;
24
+ padding: 2px;
25
+ font-size: 0.8em;
26
+ }
27
+ </style>
28
+ <table>
29
+ <tr>
30
+ <% columns.each do |col| %>
31
+ <td id="benchmarkTitle"><%= col %></td>
32
+ <% end %>
33
+ </tr>
34
+ <tr>
35
+ <% times.each do |time| %>
36
+ <td id="benchmarkCell"><%= time %></td>
37
+ <% end %>
38
+ </tr>
39
+ <tr><td>&nbsp;</td></tr>
40
+ </table>
41
+ EOT
42
+
43
+ def self.output_results( filename, results )
44
+ html = ''
45
+ results.each do |result_set|
46
+ columns, times = [], []
47
+ result_set.each do |result|
48
+ columns << result.description
49
+ if result.failed
50
+ times << "failed"
51
+ else
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
60
+ end
61
+ end
62
+
63
+ template = ERB.new( TEMPLATE, 0, "%<>")
64
+ html << template.result( binding )
65
+ end
66
+
67
+ File.open( filename, 'w' ){ |file| file.write( TEMPLATE_HEADER + html ) }
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ class TestInnoDb < ActiveRecord::Base
2
+ set_table_name 'test_innodb'
3
+ end
@@ -0,0 +1,3 @@
1
+ class TestMemory < ActiveRecord::Base
2
+ set_table_name 'test_memory'
3
+ end
@@ -0,0 +1,3 @@
1
+ class TestMyISAM < ActiveRecord::Base
2
+ set_table_name 'test_myisam'
3
+ end
@@ -0,0 +1,16 @@
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
4
+ t.column :description, :string
5
+ end
6
+
7
+ create_table :test_innodb, :options=>'ENGINE=InnoDb', :force=>true do |t|
8
+ t.column :my_name, :string, :null=>false
9
+ t.column :description, :string
10
+ end
11
+
12
+ create_table :test_memory, :options=>'ENGINE=Memory', :force=>true do |t|
13
+ t.column :my_name, :string, :null=>false
14
+ t.column :description, :string
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ platforms :ruby do
2
+ gem 'mysql', '~> 2.8.1'
3
+ gem 'activerecord', '~> 3.1.0'
4
+ end
@@ -0,0 +1,4 @@
1
+ platforms :ruby do
2
+ gem 'mysql', '~> 2.8.1'
3
+ gem 'activerecord', '~> 3.2.0'
4
+ end
@@ -0,0 +1,4 @@
1
+ platforms :ruby do
2
+ gem 'mysql', '~> 2.9'
3
+ gem 'activerecord', '~> 4.0.0.rc2'
4
+ end
@@ -3,7 +3,6 @@ require "activerecord-import/adapters/abstract_adapter"
3
3
  module ActiveRecord # :nodoc:
4
4
  module ConnectionAdapters # :nodoc:
5
5
  class AbstractAdapter # :nodoc:
6
- extend ActiveRecord::Import::AbstractAdapter::ClassMethods
7
6
  include ActiveRecord::Import::AbstractAdapter::InstanceMethods
8
7
  end
9
8
  end
@@ -0,0 +1,8 @@
1
+ require "em-synchrony"
2
+ require "em-synchrony/mysql2"
3
+ require "em-synchrony/activerecord"
4
+ require "activerecord-import/adapters/em_mysql2_adapter"
5
+
6
+ class ActiveRecord::ConnectionAdapters::EMMysql2Adapter
7
+ include ActiveRecord::Import::EMMysql2Adapter
8
+ end
@@ -1,73 +1,20 @@
1
1
  module ActiveRecord::Import::AbstractAdapter
2
- NO_MAX_PACKET = 0
3
- QUERY_OVERHEAD = 8 #This was shown to be true for MySQL, but it's not clear where the overhead is from.
4
-
5
- module ClassMethods
6
- def get_insert_value_sets( values, sql_size, max_bytes ) # :nodoc:
7
- value_sets = []
8
- arr, current_arr_values_size, current_size = [], 0, 0
9
- values.each_with_index do |val,i|
10
- comma_bytes = arr.size
11
- sql_size_thus_far = sql_size + current_size + val.bytesize + comma_bytes
12
- if NO_MAX_PACKET == max_bytes or sql_size_thus_far <= max_bytes
13
- current_size += val.bytesize
14
- arr << val
15
- else
16
- value_sets << arr
17
- arr = [ val ]
18
- current_size = val.bytesize
19
- end
20
-
21
- # if we're on the last iteration push whatever we have in arr to value_sets
22
- value_sets << arr if i == (values.size-1)
23
- end
24
- [ *value_sets ]
25
- end
26
- end
27
-
28
2
  module InstanceMethods
29
3
  def next_value_for_sequence(sequence_name)
30
4
  %{#{sequence_name}.nextval}
31
5
  end
32
-
33
- # +sql+ can be a single string or an array. If it is an array all
34
- # elements that are in position >= 1 will be appended to the final SQL.
6
+
35
7
  def insert_many( sql, values, *args ) # :nodoc:
36
- # the number of inserts default
37
- number_of_inserts = 0
38
-
8
+ number_of_inserts = 1
9
+
39
10
  base_sql,post_sql = if sql.is_a?( String )
40
11
  [ sql, '' ]
41
12
  elsif sql.is_a?( Array )
42
13
  [ sql.shift, sql.join( ' ' ) ]
43
14
  end
44
-
45
- sql_size = QUERY_OVERHEAD + base_sql.size + post_sql.size
46
15
 
47
- # the number of bytes the requested insert statement values will take up
48
- values_in_bytes = values.sum {|value| value.bytesize }
49
-
50
- # the number of bytes (commas) it will take to comma separate our values
51
- comma_separated_bytes = values.size-1
52
-
53
- # the total number of bytes required if this statement is one statement
54
- total_bytes = sql_size + values_in_bytes + comma_separated_bytes
55
-
56
- max = max_allowed_packet
57
-
58
- # if we can insert it all as one statement
59
- if NO_MAX_PACKET == max or total_bytes < max
60
- number_of_inserts += 1
61
- sql2insert = base_sql + values.join( ',' ) + post_sql
62
- insert( sql2insert, *args )
63
- else
64
- value_sets = self.class.get_insert_value_sets( values, sql_size, max )
65
- value_sets.each do |values|
66
- number_of_inserts += 1
67
- sql2insert = base_sql + values.join( ',' ) + post_sql
68
- insert( sql2insert, *args )
69
- end
70
- end
16
+ sql2insert = base_sql + values.join( ',' ) + post_sql
17
+ insert( sql2insert, *args )
71
18
 
72
19
  number_of_inserts
73
20
  end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + "/mysql_adapter"
2
+
3
+ module ActiveRecord::Import::EMMysql2Adapter
4
+ include ActiveRecord::Import::MysqlAdapter
5
+ end
@@ -1,7 +1,54 @@
1
1
  module ActiveRecord::Import::MysqlAdapter
2
- include ActiveRecord::Import::ImportSupport
2
+ include ActiveRecord::Import::ImportSupport
3
3
  include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
4
4
 
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.
7
+
8
+ # +sql+ can be a single string or an array. If it is an array all
9
+ # elements that are in position >= 1 will be appended to the final SQL.
10
+ def insert_many( sql, values, *args ) # :nodoc:
11
+ # the number of inserts default
12
+ number_of_inserts = 0
13
+
14
+ base_sql,post_sql = if sql.is_a?( String )
15
+ [ sql, '' ]
16
+ elsif sql.is_a?( Array )
17
+ [ sql.shift, sql.join( ' ' ) ]
18
+ end
19
+
20
+ sql_size = QUERY_OVERHEAD + base_sql.size + post_sql.size
21
+
22
+ # the number of bytes the requested insert statement values will take up
23
+ values_in_bytes = values.sum {|value| value.bytesize }
24
+
25
+ # the number of bytes (commas) it will take to comma separate our values
26
+ comma_separated_bytes = values.size-1
27
+
28
+ # the total number of bytes required if this statement is one statement
29
+ total_bytes = sql_size + values_in_bytes + comma_separated_bytes
30
+
31
+ max = max_allowed_packet
32
+
33
+ # if we can insert it all as one statement
34
+ if NO_MAX_PACKET == max or total_bytes < max
35
+ number_of_inserts += 1
36
+ sql2insert = base_sql + values.join( ',' ) + post_sql
37
+ insert( sql2insert, *args )
38
+ else
39
+ value_sets = ::ActiveRecord::Import::ValueSetsBytesParser.parse(values,
40
+ :reserved_bytes => sql_size,
41
+ :max_bytes => max)
42
+ value_sets.each do |values|
43
+ number_of_inserts += 1
44
+ sql2insert = base_sql + values.join( ',' ) + post_sql
45
+ insert( sql2insert, *args )
46
+ end
47
+ end
48
+
49
+ number_of_inserts
50
+ end
51
+
5
52
  # Returns the maximum number of bytes that the server will allow
6
53
  # in a single packet
7
54
  def max_allowed_packet # :nodoc:
@@ -12,9 +59,9 @@ module ActiveRecord::Import::MysqlAdapter
12
59
  val.to_i
13
60
  end
14
61
  end
15
-
62
+
16
63
  # Returns a generated ON DUPLICATE KEY UPDATE statement given the passed
17
- # in +args+.
64
+ # in +args+.
18
65
  def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
19
66
  sql = ' ON DUPLICATE KEY UPDATE '
20
67
  arg = args.first
@@ -1,18 +1,43 @@
1
+ require 'debugger'
1
2
  module ActiveRecord::Import::SQLite3Adapter
2
3
  include ActiveRecord::Import::ImportSupport
3
4
 
5
+ MIN_VERSION_FOR_IMPORT = "3.7.11"
6
+ SQLITE_LIMIT_COMPOUND_SELECT = 500
7
+
4
8
  # Override our conformance to ActiveRecord::Import::ImportSupport interface
5
9
  # to ensure that we only support import in supported version of SQLite.
6
- # Which INSERT statements with multiple value sets was introduced in 3.2.11.
10
+ # Which INSERT statements with multiple value sets was introduced in 3.7.11.
7
11
  def supports_import?(current_version=self.sqlite_version)
8
- minimum_supported_version = "3.2.11"
9
- if current_version >= minimum_supported_version
12
+ if current_version >= MIN_VERSION_FOR_IMPORT
10
13
  true
11
14
  else
12
15
  false
13
16
  end
14
17
  end
15
18
 
19
+ # +sql+ can be a single string or an array. If it is an array all
20
+ # elements that are in position >= 1 will be appended to the final SQL.
21
+ def insert_many(sql, values, *args) # :nodoc:
22
+ number_of_inserts = 0
23
+ base_sql,post_sql = if sql.is_a?( String )
24
+ [ sql, '' ]
25
+ elsif sql.is_a?( Array )
26
+ [ sql.shift, sql.join( ' ' ) ]
27
+ end
28
+
29
+ value_sets = ::ActiveRecord::Import::ValueSetsRecordsParser.parse(values,
30
+ :max_records => SQLITE_LIMIT_COMPOUND_SELECT)
31
+
32
+ value_sets.each do |values|
33
+ number_of_inserts += 1
34
+ sql2insert = base_sql + values.join( ',' ) + post_sql
35
+ insert( sql2insert, *args )
36
+ end
37
+
38
+ number_of_inserts
39
+ end
40
+
16
41
  def next_value_for_sequence(sequence_name)
17
42
  %{nextval('#{sequence_name}')}
18
43
  end
@@ -14,7 +14,7 @@ module ActiveRecord::Import
14
14
  else adapter
15
15
  end
16
16
  end
17
-
17
+
18
18
  # Loads the import functionality for a specific database adapter
19
19
  def self.require_adapter(adapter)
20
20
  require File.join(AdapterPath,"/abstract_adapter")
@@ -31,4 +31,5 @@ end
31
31
  this_dir = Pathname.new File.dirname(__FILE__)
32
32
  require this_dir.join("import").to_s
33
33
  require this_dir.join("active_record/adapters/abstract_adapter").to_s
34
- require this_dir.join("synchronize").to_s
34
+ require this_dir.join("synchronize").to_s
35
+ require this_dir.join("value_sets_parser").to_s
@@ -0,0 +1,7 @@
1
+ warn <<-MSG
2
+ [DEPRECATION] loading activerecord-import via 'require "activerecord-import/<adapter-name>"'
3
+ is deprecated. Update to autorequire using 'require "activerecord-import"'. See
4
+ http://github.com/zdennis/activerecord-import/wiki/Requiring for more information
5
+ MSG
6
+
7
+ require File.expand_path(File.join(File.dirname(__FILE__), "/../activerecord-import"))
@@ -11,7 +11,7 @@ module ActiveRecord::Import #:nodoc:
11
11
  true
12
12
  end
13
13
  end
14
-
14
+
15
15
  module OnDuplicateKeyUpdateSupport #:nodoc:
16
16
  def supports_on_duplicate_key_update? #:nodoc:
17
17
  true
@@ -32,7 +32,7 @@ class ActiveRecord::Base
32
32
  tproc = lambda do
33
33
  ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
34
34
  end
35
-
35
+
36
36
  AREXT_RAILS_COLUMNS = {
37
37
  :create => { "created_on" => tproc ,
38
38
  "created_at" => tproc },
@@ -40,7 +40,7 @@ class ActiveRecord::Base
40
40
  "updated_at" => tproc }
41
41
  }
42
42
  AREXT_RAILS_COLUMN_NAMES = AREXT_RAILS_COLUMNS[:create].keys + AREXT_RAILS_COLUMNS[:update].keys
43
-
43
+
44
44
  # Returns true if the current database connection adapter
45
45
  # supports import functionality, otherwise returns false.
46
46
  def supports_import?(*args)
@@ -57,14 +57,14 @@ class ActiveRecord::Base
57
57
  rescue NoMethodError
58
58
  false
59
59
  end
60
-
61
- # Imports a collection of values to the database.
60
+
61
+ # Imports a collection of values to the database.
62
62
  #
63
63
  # This is more efficient than using ActiveRecord::Base#create or
64
64
  # ActiveRecord::Base#save multiple times. This method works well if
65
65
  # you want to create more than one record at a time and do not care
66
66
  # about having ActiveRecord objects returned for each record
67
- # inserted.
67
+ # inserted.
68
68
  #
69
69
  # This can be used with or without validations. It does not utilize
70
70
  # the ActiveRecord::Callbacks during creation/modification while
@@ -74,9 +74,9 @@ class ActiveRecord::Base
74
74
  # Model.import array_of_models
75
75
  # Model.import column_names, array_of_values
76
76
  # Model.import column_names, array_of_values, options
77
- #
77
+ #
78
78
  # ==== Model.import array_of_models
79
- #
79
+ #
80
80
  # With this form you can call _import_ passing in an array of model
81
81
  # objects that you want updated.
82
82
  #
@@ -108,9 +108,9 @@ class ActiveRecord::Base
108
108
  # * +timestamps+ - true|false, tells import to not add timestamps \
109
109
  # (if false) even if record timestamps is disabled in ActiveRecord::Base
110
110
  #
111
- # == Examples
111
+ # == Examples
112
112
  # class BlogPost < ActiveRecord::Base ; end
113
- #
113
+ #
114
114
  # # Example using array of model objects
115
115
  # posts = [ BlogPost.new :author_name=>'Zach Dennis', :title=>'AREXT',
116
116
  # BlogPost.new :author_name=>'Zach Dennis', :title=>'AREXT2',
@@ -128,7 +128,7 @@ class ActiveRecord::Base
128
128
  # BlogPost.import( columns, values, :validate => false )
129
129
  #
130
130
  # # Example synchronizing existing instances in memory
131
- # post = BlogPost.find_by_author_name( 'zdennis' )
131
+ # post = BlogPost.where(author_name: 'zdennis').first
132
132
  # puts post.author_name # => 'zdennis'
133
133
  # columns = [ :author_name, :title ]
134
134
  # values = [ [ 'yoda', 'test post' ] ]
@@ -143,7 +143,7 @@ class ActiveRecord::Base
143
143
  # == On Duplicate Key Update (MySQL only)
144
144
  #
145
145
  # The :on_duplicate_key_update option can be either an Array or a Hash.
146
- #
146
+ #
147
147
  # ==== Using an Array
148
148
  #
149
149
  # The :on_duplicate_key_update option can be an array of column
@@ -158,9 +158,9 @@ class ActiveRecord::Base
158
158
  # to model attribute name mappings. This gives you finer grained
159
159
  # control over what fields are updated with what attributes on your
160
160
  # model. Below is an example:
161
- #
162
- # BlogPost.import columns, attributes, :on_duplicate_key_update=>{ :title => :title }
163
- #
161
+ #
162
+ # BlogPost.import columns, attributes, :on_duplicate_key_update=>{ :title => :title }
163
+ #
164
164
  # = Returns
165
165
  # This returns an object which responds to +failed_instances+ and +num_inserts+.
166
166
  # * failed_instances - an array of objects that fails validation and were not committed to the database. An empty array if no validation is performed.
@@ -180,7 +180,7 @@ class ActiveRecord::Base
180
180
  models = args.first
181
181
  column_names = self.column_names.dup
182
182
  end
183
-
183
+
184
184
  array_of_attributes = models.map do |model|
185
185
  # this next line breaks sqlite.so with a segmentation fault
186
186
  # if model.new_record? || options[:on_duplicate_key_update]
@@ -230,23 +230,23 @@ class ActiveRecord::Base
230
230
  return_obj.num_inserts = 0 if return_obj.num_inserts.nil?
231
231
  return_obj
232
232
  end
233
-
234
- # TODO import_from_table needs to be implemented.
233
+
234
+ # TODO import_from_table needs to be implemented.
235
235
  def import_from_table( options ) # :nodoc:
236
236
  end
237
-
237
+
238
238
  # Imports the passed in +column_names+ and +array_of_attributes+
239
239
  # given the passed in +options+ Hash with validations. Returns an
240
- # object with the methods +failed_instances+ and +num_inserts+.
241
- # +failed_instances+ is an array of instances that failed validations.
240
+ # object with the methods +failed_instances+ and +num_inserts+.
241
+ # +failed_instances+ is an array of instances that failed validations.
242
242
  # +num_inserts+ is the number of inserts it took to import the data. See
243
243
  # ActiveRecord::Base.import for more information on
244
244
  # +column_names+, +array_of_attributes+ and +options+.
245
245
  def import_with_validations( column_names, array_of_attributes, options={} )
246
246
  failed_instances = []
247
-
247
+
248
248
  # create instances for each of our column/value sets
249
- arr = validations_array_for_column_names_and_attributes( column_names, array_of_attributes )
249
+ arr = validations_array_for_column_names_and_attributes( column_names, array_of_attributes )
250
250
 
251
251
  # keep track of the instance and the position it is currently at. if this fails
252
252
  # validation we'll use the index to remove it from the array_of_attributes
@@ -257,7 +257,7 @@ class ActiveRecord::Base
257
257
  if not instance.valid?
258
258
  array_of_attributes[ i ] = nil
259
259
  failed_instances << instance
260
- end
260
+ end
261
261
  end
262
262
  array_of_attributes.compact!
263
263
 
@@ -268,7 +268,7 @@ class ActiveRecord::Base
268
268
  end
269
269
  ActiveRecord::Import::Result.new(failed_instances, num_inserts)
270
270
  end
271
-
271
+
272
272
  # Imports the passed in +column_names+ and +array_of_attributes+
273
273
  # given the passed in +options+ Hash. This will return the number
274
274
  # of insert operations it took to create these records without
@@ -309,7 +309,7 @@ class ActiveRecord::Base
309
309
  post_sql_statements = connection.post_sql_statements( quoted_table_name, options )
310
310
 
311
311
  # perform the inserts
312
- number_inserted = connection.insert_many( [ insert_sql, post_sql_statements ].flatten,
312
+ number_inserted = connection.insert_many( [ insert_sql, post_sql_statements ].flatten,
313
313
  values_sql,
314
314
  "#{self.class.name} Create Many Without Validations Or Callbacks" )
315
315
  end
@@ -367,7 +367,7 @@ class ActiveRecord::Base
367
367
  column_names << key
368
368
  array_of_attributes.each { |arr| arr << value }
369
369
  end
370
-
370
+
371
371
  if supports_on_duplicate_key_update?
372
372
  if options[:on_duplicate_key_update]
373
373
  options[:on_duplicate_key_update] << key.to_sym if options[:on_duplicate_key_update].is_a?(Array)
@@ -379,13 +379,13 @@ class ActiveRecord::Base
379
379
  end
380
380
  end
381
381
  end
382
-
382
+
383
383
  # Returns an Array of Hashes for the passed in +column_names+ and +array_of_attributes+.
384
384
  def validations_array_for_column_names_and_attributes( column_names, array_of_attributes ) # :nodoc:
385
385
  array_of_attributes.map do |attributes|
386
386
  Hash[attributes.each_with_index.map {|attr, c| [column_names[c], attr] }]
387
387
  end
388
388
  end
389
-
389
+
390
390
  end
391
391
  end