Empact-activerecord-import 0.3.5 → 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.
data/README.markdown CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  activerecord-import is a library for bulk inserting data using ActiveRecord.
4
4
 
5
- For more information on activerecord-import please see its wiki: http://wiki.github.com/zdennis/activerecord-import/
5
+ For more information on activerecord-import please see its wiki: https://github.com/zdennis/activerecord-import/wiki
6
6
 
7
7
  # License
8
8
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.5
1
+ 0.4.0
@@ -2,15 +2,15 @@ class ActiveRecord::Base
2
2
  class << self
3
3
  def establish_connection_with_activerecord_import(*args)
4
4
  establish_connection_without_activerecord_import(*args)
5
- ActiveSupport.run_load_hooks(:active_record_connection_established, connection)
5
+ ActiveSupport.run_load_hooks(:active_record_connection_established, connection_pool)
6
6
  end
7
7
  alias_method_chain :establish_connection, :activerecord_import
8
8
  end
9
9
  end
10
10
 
11
- ActiveSupport.on_load(:active_record_connection_established) do |connection|
12
- if !ActiveRecord.const_defined?(:Import) || !ActiveRecord::Import.respond_to?(:load_from_connection)
11
+ ActiveSupport.on_load(:active_record_connection_established) do |connection_pool|
12
+ if !ActiveRecord.const_defined?(:Import) || !ActiveRecord::Import.respond_to?(:load_from_connection_pool)
13
13
  require File.join File.dirname(__FILE__), "activerecord-import/base"
14
14
  end
15
- ActiveRecord::Import.load_from_connection connection
15
+ ActiveRecord::Import.require_adapter connection_pool.spec.config[:adapter]
16
16
  end
@@ -2,5 +2,5 @@ require "active_record/connection_adapters/mysql2_adapter"
2
2
  require "activerecord-import/adapters/mysql_adapter"
3
3
 
4
4
  class ActiveRecord::ConnectionAdapters::Mysql2Adapter
5
- include ActiveRecord::Import::MysqlAdapter::InstanceMethods
6
- end
5
+ include ActiveRecord::Import::MysqlAdapter
6
+ end
@@ -2,5 +2,5 @@ require "active_record/connection_adapters/mysql_adapter"
2
2
  require "activerecord-import/adapters/mysql_adapter"
3
3
 
4
4
  class ActiveRecord::ConnectionAdapters::MysqlAdapter
5
- include ActiveRecord::Import::MysqlAdapter::InstanceMethods
6
- end
5
+ include ActiveRecord::Import::MysqlAdapter
6
+ end
@@ -2,6 +2,6 @@ require "active_record/connection_adapters/postgresql_adapter"
2
2
  require "activerecord-import/adapters/postgresql_adapter"
3
3
 
4
4
  class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
5
- include ActiveRecord::Import::PostgreSQLAdapter::InstanceMethods
5
+ include ActiveRecord::Import::PostgreSQLAdapter
6
6
  end
7
7
 
@@ -2,6 +2,6 @@ require "active_record/connection_adapters/sqlite3_adapter"
2
2
  require "activerecord-import/adapters/sqlite3_adapter"
3
3
 
4
4
  class ActiveRecord::ConnectionAdapters::Sqlite3Adapter
5
- include ActiveRecord::Import::Sqlite3Adapter::InstanceMethods
5
+ include ActiveRecord::Import::Sqlite3Adapter
6
6
  end
7
7
 
@@ -45,7 +45,7 @@ module ActiveRecord::Import::AbstractAdapter
45
45
  sql_size = QUERY_OVERHEAD + base_sql.size + post_sql.size
46
46
 
47
47
  # the number of bytes the requested insert statement values will take up
48
- values_in_bytes = values.sum {|value| value.size }
48
+ values_in_bytes = values.sum {|value| value.bytesize }
49
49
 
50
50
  # the number of bytes (commas) it will take to comma separate our values
51
51
  comma_separated_bytes = values.size-1
@@ -1,59 +1,53 @@
1
1
  module ActiveRecord::Import::MysqlAdapter
2
- module InstanceMethods
3
- def self.included(klass)
4
- klass.instance_eval do
5
- include ActiveRecord::Import::ImportSupport
6
- include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
7
- end
8
- end
9
-
10
- # Returns the maximum number of bytes that the server will allow
11
- # in a single packet
12
- def max_allowed_packet # :nodoc:
13
- result = execute( "SHOW VARIABLES like 'max_allowed_packet';" )
14
- # original Mysql gem responds to #fetch_row while Mysql2 responds to #first
15
- val = result.respond_to?(:fetch_row) ? result.fetch_row[1] : result.first[1]
16
- val.to_i
17
- end
18
-
19
- # Returns a generated ON DUPLICATE KEY UPDATE statement given the passed
20
- # in +args+.
21
- def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
22
- sql = ' ON DUPLICATE KEY UPDATE '
23
- arg = args.first
24
- if arg.is_a?( Array )
25
- sql << sql_for_on_duplicate_key_update_as_array( table_name, arg )
26
- elsif arg.is_a?( Hash )
27
- sql << sql_for_on_duplicate_key_update_as_hash( table_name, arg )
28
- elsif arg.is_a?( String )
29
- sql << arg
30
- else
31
- raise ArgumentError.new( "Expected Array or Hash" )
32
- end
33
- sql
34
- end
2
+ include ActiveRecord::Import::ImportSupport
3
+ include ActiveRecord::Import::OnDuplicateKeyUpdateSupport
4
+
5
+ # Returns the maximum number of bytes that the server will allow
6
+ # in a single packet
7
+ def max_allowed_packet # :nodoc:
8
+ result = execute( "SHOW VARIABLES like 'max_allowed_packet';" )
9
+ # original Mysql gem responds to #fetch_row while Mysql2 responds to #first
10
+ val = result.respond_to?(:fetch_row) ? result.fetch_row[1] : result.first[1]
11
+ val.to_i
12
+ end
35
13
 
36
- def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
37
- results = arr.map do |column|
38
- qc = quote_column_name( column )
39
- "#{table_name}.#{qc}=VALUES(#{qc})"
40
- end
41
- results.join( ',' )
14
+ # Returns a generated ON DUPLICATE KEY UPDATE statement given the passed
15
+ # in +args+.
16
+ def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
17
+ sql = ' ON DUPLICATE KEY UPDATE '
18
+ arg = args.first
19
+ if arg.is_a?( Array )
20
+ sql << sql_for_on_duplicate_key_update_as_array( table_name, arg )
21
+ elsif arg.is_a?( Hash )
22
+ sql << sql_for_on_duplicate_key_update_as_hash( table_name, arg )
23
+ elsif arg.is_a?( String )
24
+ sql << arg
25
+ else
26
+ raise ArgumentError.new( "Expected Array or Hash" )
42
27
  end
43
-
44
- def sql_for_on_duplicate_key_update_as_hash( table_name, hsh ) # :nodoc:
45
- sql = ' ON DUPLICATE KEY UPDATE '
46
- results = hsh.map do |column1, column2|
47
- qc1 = quote_column_name( column1 )
48
- qc2 = quote_column_name( column2 )
49
- "#{table_name}.#{qc1}=VALUES( #{qc2} )"
50
- end
51
- results.join( ',')
28
+ sql
29
+ end
30
+
31
+ def sql_for_on_duplicate_key_update_as_array( table_name, arr ) # :nodoc:
32
+ results = arr.map do |column|
33
+ qc = quote_column_name( column )
34
+ "#{table_name}.#{qc}=VALUES(#{qc})"
52
35
  end
36
+ results.join( ',' )
37
+ end
53
38
 
54
- #return true if the statement is a duplicate key record error
55
- def duplicate_key_update_error?(exception)# :nodoc:
56
- exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
39
+ def sql_for_on_duplicate_key_update_as_hash( table_name, hsh ) # :nodoc:
40
+ sql = ' ON DUPLICATE KEY UPDATE '
41
+ results = hsh.map do |column1, column2|
42
+ qc1 = quote_column_name( column1 )
43
+ qc2 = quote_column_name( column2 )
44
+ "#{table_name}.#{qc1}=VALUES( #{qc2} )"
57
45
  end
46
+ results.join( ',')
47
+ end
48
+
49
+ #return true if the statement is a duplicate key record error
50
+ def duplicate_key_update_error?(exception)# :nodoc:
51
+ exception.is_a?(ActiveRecord::StatementInvalid) && exception.to_s.include?('Duplicate entry')
58
52
  end
59
- end
53
+ end
@@ -1,13 +1,7 @@
1
1
  module ActiveRecord::Import::PostgreSQLAdapter
2
- module InstanceMethods
3
- def self.included(klass)
4
- klass.instance_eval do
5
- include ActiveRecord::Import::ImportSupport
6
- end
7
- end
2
+ include ActiveRecord::Import::ImportSupport
8
3
 
9
- def next_value_for_sequence(sequence_name)
10
- %{nextval('#{sequence_name}')}
11
- end
4
+ def next_value_for_sequence(sequence_name)
5
+ %{nextval('#{sequence_name}')}
12
6
  end
13
7
  end
@@ -1,7 +1,5 @@
1
1
  module ActiveRecord::Import::Sqlite3Adapter
2
- module InstanceMethods
3
- def next_value_for_sequence(sequence_name)
4
- %{nextval('#{sequence_name}')}
5
- end
2
+ def next_value_for_sequence(sequence_name)
3
+ %{nextval('#{sequence_name}')}
6
4
  end
7
5
  end
@@ -1,28 +1,24 @@
1
- require "pathname"
2
- require "active_record"
3
- require "active_record/version"
4
-
5
1
  module ActiveRecord::Import
6
- AdapterPath = File.join File.expand_path(File.dirname(__FILE__)), "/active_record/adapters"
2
+ AdapterPath = File.join File.expand_path(File.dirname(__FILE__)), "active_record/adapters"
7
3
 
8
- # Loads the import functionality for a specific database adapter
9
- def self.require_adapter(adapter)
10
- require File.join(AdapterPath,"/abstract_adapter")
11
- require File.join(AdapterPath,"/#{adapter}_adapter")
4
+ def self.base_adapter(adapter)
5
+ case adapter
6
+ when 'mysqlspatial' then 'mysql'
7
+ when 'spatialite' then 'sqlite3'
8
+ when 'postgis' then 'postgresql'
9
+ else adapter
10
+ end
12
11
  end
13
12
 
14
- # Loads the import functionality for the passed in ActiveRecord connection
15
- def self.load_from_connection(connection)
16
- import_adapter = "ActiveRecord::Import::#{connection.class.name.demodulize}::InstanceMethods"
17
- unless connection.class.ancestors.map(&:name).include?(import_adapter)
18
- config = connection.instance_variable_get :@config
19
- require_adapter config[:adapter]
20
- end
13
+ # Loads the import functionality for a specific database adapter
14
+ def self.require_adapter(adapter)
15
+ require File.join(AdapterPath, "abstract_adapter")
16
+ require File.join(AdapterPath, "#{base_adapter(adapter)}_adapter")
21
17
  end
22
18
  end
23
19
 
24
20
 
25
- this_dir = Pathname.new File.dirname(__FILE__)
26
- require this_dir.join("import").to_s
27
- require this_dir.join("active_record/adapters/abstract_adapter").to_s
28
- require this_dir.join("synchronize").to_s
21
+ this_dir = File.dirname(__FILE__)
22
+ require File.join(this_dir, "import")
23
+ require File.join(this_dir, "active_record/adapters/abstract_adapter")
24
+ require File.join(this_dir, "synchronize")
@@ -1,17 +1,28 @@
1
- require "ostruct"
2
-
3
1
  module ActiveRecord::Import::ConnectionAdapters ; end
4
2
 
5
3
  module ActiveRecord::Import #:nodoc:
6
4
  class Result < Struct.new(:failed_instances, :num_inserts)
7
5
  end
8
6
 
7
+ # use tz as set in ActiveRecord::Base
8
+ tproc = lambda do
9
+ ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
10
+ end
11
+
12
+ TIME_COLUMNS = {
13
+ :create => { "created_on" => tproc ,
14
+ "created_at" => tproc },
15
+ :update => { "updated_on" => tproc ,
16
+ "updated_at" => tproc }
17
+ }
18
+ TIME_COLUMN_NAMES = TIME_COLUMNS[:create].keys + TIME_COLUMNS[:update].keys
19
+
9
20
  module ImportSupport #:nodoc:
10
21
  def supports_import? #:nodoc:
11
22
  true
12
23
  end
13
24
  end
14
-
25
+
15
26
  module OnDuplicateKeyUpdateSupport #:nodoc:
16
27
  def supports_on_duplicate_key_update? #:nodoc:
17
28
  true
@@ -21,44 +32,28 @@ end
21
32
 
22
33
  class ActiveRecord::Base
23
34
  class << self
24
-
25
- # use tz as set in ActiveRecord::Base
26
- tproc = lambda do
27
- ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
28
- end
29
-
30
- AREXT_RAILS_COLUMNS = {
31
- :create => { "created_on" => tproc ,
32
- "created_at" => tproc },
33
- :update => { "updated_on" => tproc ,
34
- "updated_at" => tproc }
35
- }
36
- AREXT_RAILS_COLUMN_NAMES = AREXT_RAILS_COLUMNS[:create].keys + AREXT_RAILS_COLUMNS[:update].keys
37
-
38
35
  # Returns true if the current database connection adapter
39
36
  # supports import functionality, otherwise returns false.
40
37
  def supports_import?
41
- connection.supports_import?
42
- rescue NoMethodError
43
- false
38
+ connection.respond_to?(:supports_import?) \
39
+ && connection.supports_import?
44
40
  end
45
41
 
46
42
  # Returns true if the current database connection adapter
47
43
  # supports on duplicate key update functionality, otherwise
48
44
  # returns false.
49
45
  def supports_on_duplicate_key_update?
50
- connection.supports_on_duplicate_key_update?
51
- rescue NoMethodError
52
- false
46
+ connection.respond_to?(:supports_on_duplicate_key_update?) \
47
+ && connection.supports_on_duplicate_key_update?
53
48
  end
54
-
55
- # Imports a collection of values to the database.
49
+
50
+ # Imports a collection of values to the database.
56
51
  #
57
52
  # This is more efficient than using ActiveRecord::Base#create or
58
53
  # ActiveRecord::Base#save multiple times. This method works well if
59
54
  # you want to create more than one record at a time and do not care
60
55
  # about having ActiveRecord objects returned for each record
61
- # inserted.
56
+ # inserted.
62
57
  #
63
58
  # This can be used with or without validations. It does not utilize
64
59
  # the ActiveRecord::Callbacks during creation/modification while
@@ -68,9 +63,9 @@ class ActiveRecord::Base
68
63
  # Model.import array_of_models
69
64
  # Model.import column_names, array_of_values
70
65
  # Model.import column_names, array_of_values, options
71
- #
66
+ #
72
67
  # ==== Model.import array_of_models
73
- #
68
+ #
74
69
  # With this form you can call _import_ passing in an array of model
75
70
  # objects that you want updated.
76
71
  #
@@ -102,9 +97,9 @@ class ActiveRecord::Base
102
97
  # * +timestamps+ - true|false, tells import to not add timestamps \
103
98
  # (if false) even if record timestamps is disabled in ActiveRecord::Base
104
99
  #
105
- # == Examples
100
+ # == Examples
106
101
  # class BlogPost < ActiveRecord::Base ; end
107
- #
102
+ #
108
103
  # # Example using array of model objects
109
104
  # posts = [ BlogPost.new :author_name=>'Zach Dennis', :title=>'AREXT',
110
105
  # BlogPost.new :author_name=>'Zach Dennis', :title=>'AREXT2',
@@ -114,7 +109,7 @@ class ActiveRecord::Base
114
109
  # # Example using column_names and array_of_values
115
110
  # columns = [ :author_name, :title ]
116
111
  # values = [ [ 'zdennis', 'test post' ], [ 'jdoe', 'another test post' ] ]
117
- # BlogPost.import columns, values
112
+ # BlogPost.import columns, values
118
113
  #
119
114
  # # Example using column_names, array_of_value and options
120
115
  # columns = [ :author_name, :title ]
@@ -136,8 +131,8 @@ class ActiveRecord::Base
136
131
  #
137
132
  # == On Duplicate Key Update (MySQL only)
138
133
  #
139
- # The :on_duplicate_key_update option can be either an Array or a Hash.
140
- #
134
+ # The :on_duplicate_key_update option can be either an Array or a Hash.
135
+ #
141
136
  # ==== Using an Array
142
137
  #
143
138
  # The :on_duplicate_key_update option can be an array of column
@@ -152,9 +147,9 @@ class ActiveRecord::Base
152
147
  # to model attribute name mappings. This gives you finer grained
153
148
  # control over what fields are updated with what attributes on your
154
149
  # model. Below is an example:
155
- #
156
- # BlogPost.import columns, attributes, :on_duplicate_key_update=>{ :title => :title }
157
- #
150
+ #
151
+ # BlogPost.import columns, attributes, :on_duplicate_key_update=>{ :title => :title }
152
+ #
158
153
  # = Returns
159
154
  # This returns an object which responds to +failed_instances+ and +num_inserts+.
160
155
  # * failed_instances - an array of objects that fails validation and were not committed to the database. An empty array if no validation is performed.
@@ -167,14 +162,9 @@ class ActiveRecord::Base
167
162
 
168
163
  # assume array of model objects
169
164
  if args.last.is_a?( Array ) and args.last.first.is_a? ActiveRecord::Base
170
- if args.length == 2
171
- models = args.last
172
- column_names = args.first
173
- else
174
- models = args.first
175
- column_names = self.column_names.dup
176
- end
177
-
165
+ models = args.pop
166
+ column_names = args.first || self.column_names.dup
167
+
178
168
  array_of_attributes = models.map do |model|
179
169
  # this next line breaks sqlite.so with a segmentation fault
180
170
  # if model.new_record? || options[:on_duplicate_key_update]
@@ -221,26 +211,27 @@ class ActiveRecord::Base
221
211
  synchronize( options[:synchronize], sync_keys)
222
212
  end
223
213
 
224
- return_obj.num_inserts = 0 if return_obj.num_inserts.nil?
214
+ return_obj.num_inserts ||= 0
225
215
  return_obj
226
216
  end
227
-
228
- # TODO import_from_table needs to be implemented.
217
+
218
+ # TODO import_from_table needs to be implemented.
229
219
  def import_from_table( options ) # :nodoc:
220
+ raise NotImplementedError, 'import_from_table needs to be implemented'
230
221
  end
231
-
222
+
232
223
  # Imports the passed in +column_names+ and +array_of_attributes+
233
224
  # given the passed in +options+ Hash with validations. Returns an
234
- # object with the methods +failed_instances+ and +num_inserts+.
235
- # +failed_instances+ is an array of instances that failed validations.
225
+ # object with the methods +failed_instances+ and +num_inserts+.
226
+ # +failed_instances+ is an array of instances that failed validations.
236
227
  # +num_inserts+ is the number of inserts it took to import the data. See
237
228
  # ActiveRecord::Base.import for more information on
238
229
  # +column_names+, +array_of_attributes+ and +options+.
239
230
  def import_with_validations( column_names, array_of_attributes, options={} )
240
231
  failed_instances = []
241
-
232
+
242
233
  # create instances for each of our column/value sets
243
- arr = validations_array_for_column_names_and_attributes( column_names, array_of_attributes )
234
+ arr = validations_array_for_column_names_and_attributes( column_names, array_of_attributes )
244
235
 
245
236
  # keep track of the instance and the position it is currently at. if this fails
246
237
  # validation we'll use the index to remove it from the array_of_attributes
@@ -251,14 +242,14 @@ class ActiveRecord::Base
251
242
  if not instance.valid?
252
243
  array_of_attributes[ i ] = nil
253
244
  failed_instances << instance
254
- end
245
+ end
255
246
  end
256
247
  array_of_attributes.compact!
257
-
248
+
258
249
  num_inserts = array_of_attributes.empty? ? 0 : import_without_validations_or_callbacks( column_names, array_of_attributes, options )
259
250
  ActiveRecord::Import::Result.new(failed_instances, num_inserts)
260
251
  end
261
-
252
+
262
253
  # Imports the passed in +column_names+ and +array_of_attributes+
263
254
  # given the passed in +options+ Hash. This will return the number
264
255
  # of insert operations it took to create these records without
@@ -280,11 +271,13 @@ class ActiveRecord::Base
280
271
  else
281
272
  # generate the sql
282
273
  post_sql_statements = connection.post_sql_statements( quoted_table_name, options )
283
-
274
+
284
275
  # perform the inserts
285
- number_inserted = connection.insert_many( [ insert_sql, post_sql_statements ].flatten,
286
- values_sql,
287
- "#{self.class.name} Create Many Without Validations Or Callbacks" )
276
+ number_inserted = connection.insert_many(
277
+ [ insert_sql, post_sql_statements ].flatten,
278
+ values_sql,
279
+ "#{self.class.name} Create Many Without Validations Or Callbacks"
280
+ )
288
281
  end
289
282
  number_inserted
290
283
  end
@@ -294,13 +287,17 @@ class ActiveRecord::Base
294
287
  # Returns SQL the VALUES for an INSERT statement given the passed in +columns+
295
288
  # and +array_of_attributes+.
296
289
  def values_sql_for_columns_and_attributes(columns, array_of_attributes) # :nodoc:
290
+ # connection gets called a *lot* in this high intensity loop.
291
+ # Reuse the same one w/in the loop, otherwise it would keep being re-retreived (= lots of time for large imports)
292
+ connection_memo = connection
297
293
  array_of_attributes.map do |arr|
298
294
  my_values = arr.each_with_index.map do |val,j|
299
295
  column = columns[j]
300
- if !sequence_name.blank? && column.name == primary_key && val.nil?
301
- connection.next_value_for_sequence(sequence_name)
296
+ # be sure to query sequence_name *last*, only if cheaper tests fail, because it's costly
297
+ if val.nil? && column.name == primary_key && !sequence_name.blank?
298
+ connection_memo.next_value_for_sequence(sequence_name)
302
299
  else
303
- connection.quote(column.type_cast(val), column)
300
+ connection_memo.quote(val, column) # no need for column.type_cast(val) - quote already does type casting
304
301
  end
305
302
  end
306
303
  "(#{my_values.join(',')})"
@@ -308,7 +305,7 @@ class ActiveRecord::Base
308
305
  end
309
306
 
310
307
  def add_special_rails_stamps( column_names, array_of_attributes, options )
311
- AREXT_RAILS_COLUMNS[:create].each_pair do |key, blk|
308
+ ActiveRecord::Import::TIME_COLUMNS[:create].each_pair do |key, blk|
312
309
  if self.column_names.include?(key)
313
310
  value = blk.call
314
311
  if index=column_names.index(key)
@@ -321,7 +318,7 @@ class ActiveRecord::Base
321
318
  end
322
319
  end
323
320
 
324
- AREXT_RAILS_COLUMNS[:update].each_pair do |key, blk|
321
+ ActiveRecord::Import::TIME_COLUMNS[:update].each_pair do |key, blk|
325
322
  if self.column_names.include?(key)
326
323
  value = blk.call
327
324
  if index=column_names.index(key)
@@ -331,11 +328,13 @@ class ActiveRecord::Base
331
328
  column_names << key
332
329
  array_of_attributes.each { |arr| arr << value }
333
330
  end
334
-
331
+
335
332
  if supports_on_duplicate_key_update?
336
- if options[:on_duplicate_key_update]
337
- options[:on_duplicate_key_update] << key.to_sym if options[:on_duplicate_key_update].is_a?(Array)
338
- options[:on_duplicate_key_update][key.to_sym] = key.to_sym if options[:on_duplicate_key_update].is_a?(Hash)
333
+ case options[:on_duplicate_key_update]
334
+ when Array
335
+ options[:on_duplicate_key_update] << key.to_sym
336
+ when Hash
337
+ options[:on_duplicate_key_update][key.to_sym] = key.to_sym
339
338
  else
340
339
  options[:on_duplicate_key_update] = [ key.to_sym ]
341
340
  end
@@ -343,13 +342,13 @@ class ActiveRecord::Base
343
342
  end
344
343
  end
345
344
  end
346
-
345
+
347
346
  # Returns an Array of Hashes for the passed in +column_names+ and +array_of_attributes+.
348
347
  def validations_array_for_column_names_and_attributes( column_names, array_of_attributes ) # :nodoc:
349
348
  array_of_attributes.map do |attributes|
350
349
  Hash[attributes.each_with_index.map {|attr, c| [column_names[c], attr] }]
351
350
  end
352
351
  end
353
-
352
+
354
353
  end
355
354
  end
@@ -1,10 +1,10 @@
1
1
  module ActiveRecord # :nodoc:
2
2
  class Base # :nodoc:
3
-
3
+
4
4
  # Synchronizes the passed in ActiveRecord instances with data
5
5
  # from the database. This is like calling reload on an individual
6
- # ActiveRecord instance but it is intended for use on multiple instances.
7
- #
6
+ # ActiveRecord instance but it is intended for use on multiple instances.
7
+ #
8
8
  # This uses one query for all instance updates and then updates existing
9
9
  # instances rather sending one query for each instance
10
10
  #
@@ -14,7 +14,7 @@ module ActiveRecord # :nodoc:
14
14
  # <.. out of system changes occur to change author name from Zach to Zachary..>
15
15
  # Post.synchronize posts
16
16
  # posts.first.author # => "Zachary" instead of Zach
17
- #
17
+ #
18
18
  # # Synchronizing using custom key fields
19
19
  # posts = Post.find_by_author("Zach")
20
20
  # <.. out of system changes occur to change the address of author 'Zach' to 1245 Foo Ln ..>
@@ -26,11 +26,11 @@ module ActiveRecord # :nodoc:
26
26
 
27
27
  conditions = {}
28
28
  order = ""
29
-
29
+
30
30
  key_values = keys.map { |key| instances.map(&"#{key}".to_sym) }
31
31
  keys.zip(key_values).each { |key, values| conditions[key] = values }
32
32
  order = keys.map{ |key| "#{key} ASC" }.join(",")
33
-
33
+
34
34
  klass = instances.first.class
35
35
 
36
36
  fresh_instances = klass.find( :all, :conditions=>conditions, :order=>order )
@@ -38,7 +38,7 @@ module ActiveRecord # :nodoc:
38
38
  matched_instance = fresh_instances.detect do |fresh_instance|
39
39
  keys.all?{ |key| fresh_instance.send(key) == instance.send(key) }
40
40
  end
41
-
41
+
42
42
  if matched_instance
43
43
  instance.clear_aggregation_cache
44
44
  instance.clear_association_cache
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Empact-activerecord-import
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,22 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-26 00:00:00.000000000Z
13
+ date: 2012-05-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
17
- requirement: &2151988300 !ruby/object:Gem::Requirement
17
+ requirement: &70265403670100 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
- - - ! '>='
20
+ - - ~>
21
21
  - !ruby/object:Gem::Version
22
- version: 3.0.0
22
+ version: '3.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2151988300
25
+ version_requirements: *70265403670100
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rake
28
- requirement: &2151971820 !ruby/object:Gem::Requirement
28
+ requirement: &70265403669060 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *2151971820
36
+ version_requirements: *70265403669060
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: jeweler
39
- requirement: &2151967900 !ruby/object:Gem::Requirement
39
+ requirement: &70265403667660 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,18 +44,18 @@ dependencies:
44
44
  version: 1.4.0
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *2151967900
47
+ version_requirements: *70265403667660
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: activerecord
50
- requirement: &2151962680 !ruby/object:Gem::Requirement
50
+ requirement: &70265403666900 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
- - - ! '>='
53
+ - - ~>
54
54
  - !ruby/object:Gem::Version
55
- version: 3.0.0
55
+ version: '3.0'
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *2151962680
58
+ version_requirements: *70265403666900
59
59
  description: Extraction of the ActiveRecord::Base#import functionality from ar-extensions
60
60
  for Rails 3 and beyond
61
61
  email: ben.woosley@gmail.com
@@ -95,7 +95,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
95
95
  version: '0'
96
96
  segments:
97
97
  - 0
98
- hash: -2232322125532575640
98
+ hash: 328182919252473110
99
99
  required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  none: false
101
101
  requirements:
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  version: '0'
105
105
  requirements: []
106
106
  rubyforge_project:
107
- rubygems_version: 1.8.8
107
+ rubygems_version: 1.8.11
108
108
  signing_key:
109
109
  specification_version: 3
110
110
  summary: Bulk-loading extension for ActiveRecord