Empact-activerecord-import 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +1 -1
- data/VERSION +1 -1
- data/lib/activerecord-import.rb +4 -4
- data/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb +2 -2
- data/lib/activerecord-import/active_record/adapters/mysql_adapter.rb +2 -2
- data/lib/activerecord-import/active_record/adapters/postgresql_adapter.rb +1 -1
- data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +1 -1
- data/lib/activerecord-import/adapters/abstract_adapter.rb +1 -1
- data/lib/activerecord-import/adapters/mysql_adapter.rb +46 -52
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +3 -9
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +2 -4
- data/lib/activerecord-import/base.rb +16 -20
- data/lib/activerecord-import/import.rb +69 -70
- data/lib/activerecord-import/synchronize.rb +7 -7
- metadata +16 -16
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:
|
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.
|
1
|
+
0.4.0
|
data/lib/activerecord-import.rb
CHANGED
@@ -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,
|
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 |
|
12
|
-
if !ActiveRecord.const_defined?(:Import) || !ActiveRecord::Import.respond_to?(:
|
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.
|
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
|
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
|
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
|
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
|
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.
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
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
|
-
|
10
|
-
|
11
|
-
end
|
4
|
+
def next_value_for_sequence(sequence_name)
|
5
|
+
%{nextval('#{sequence_name}')}
|
12
6
|
end
|
13
7
|
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__)), "
|
2
|
+
AdapterPath = File.join File.expand_path(File.dirname(__FILE__)), "active_record/adapters"
|
7
3
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
15
|
-
def self.
|
16
|
-
|
17
|
-
|
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 =
|
26
|
-
require
|
27
|
-
require
|
28
|
-
require
|
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
|
-
|
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
|
-
|
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
|
-
|
171
|
-
|
172
|
-
|
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
|
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(
|
286
|
-
|
287
|
-
|
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
|
-
|
301
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
337
|
-
|
338
|
-
options[:on_duplicate_key_update]
|
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.
|
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:
|
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: &
|
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
|
22
|
+
version: '3.0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70265403670100
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rake
|
28
|
-
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: *
|
36
|
+
version_requirements: *70265403669060
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: jeweler
|
39
|
-
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: *
|
47
|
+
version_requirements: *70265403667660
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: activerecord
|
50
|
-
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
|
55
|
+
version: '3.0'
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
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:
|
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.
|
107
|
+
rubygems_version: 1.8.11
|
108
108
|
signing_key:
|
109
109
|
specification_version: 3
|
110
110
|
summary: Bulk-loading extension for ActiveRecord
|