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 +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
|