activerecord-import 0.13.0 → 0.14.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.
- checksums.yaml +4 -4
- data/.travis.yml +9 -1
- data/CHANGELOG.md +23 -0
- data/Gemfile +1 -1
- data/Rakefile +13 -1
- data/activerecord-import.gemspec +1 -1
- data/benchmarks/lib/base.rb +3 -1
- data/benchmarks/lib/output_to_html.rb +1 -1
- data/lib/activerecord-import.rb +2 -1
- data/lib/activerecord-import/adapters/abstract_adapter.rb +4 -1
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +1 -1
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +10 -2
- data/lib/activerecord-import/base.rb +2 -0
- data/lib/activerecord-import/import.rb +42 -27
- data/lib/activerecord-import/synchronize.rb +1 -1
- data/lib/activerecord-import/version.rb +1 -1
- data/test/adapters/mysql2_makara.rb +1 -0
- data/test/adapters/postgresql_makara.rb +1 -0
- data/test/database.yml.sample +13 -6
- data/test/import_test.rb +40 -27
- data/test/mysql2_makara/import_test.rb +6 -0
- data/test/sqlite3/import_test.rb +2 -0
- data/test/support/factories.rb +5 -0
- data/test/support/postgresql/import_examples.rb +34 -133
- data/test/support/shared_examples/on_duplicate_key_update.rb +58 -47
- data/test/support/shared_examples/recursive_import.rb +122 -0
- data/test/travis/database.yml +25 -8
- metadata +13 -6
- data/gemfiles/3.1.gemfile +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f9f37b3a5f830a11ae96be25ce6f5c4b17a0644
|
4
|
+
data.tar.gz: 54a38cb34a3dcea2712144881922db6391dffb95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5711460969d86ad105727048bb1f86aa323f9bf9f48239b845ec7c2b95d5113e8bf0cf2e7bdafaca5d7a53dc5ce93b57e85e8468b69982c394e8d46d7dbadc5
|
7
|
+
data.tar.gz: 3877050ee37099c68deafb1f3532d781a4efbf3f50c049787e24676d7cc5131df70782e00f17abaef866766c30212b7cceceee41031cf7e2c834c20f18fbd381
|
data/.travis.yml
CHANGED
@@ -8,7 +8,6 @@ env:
|
|
8
8
|
# https://github.com/discourse/discourse/blob/master/.travis.yml
|
9
9
|
- RUBY_GC_MALLOC_LIMIT=50000000
|
10
10
|
matrix:
|
11
|
-
- AR_VERSION=3.1
|
12
11
|
- AR_VERSION=3.2
|
13
12
|
- AR_VERSION=4.0
|
14
13
|
- AR_VERSION=4.1
|
@@ -16,6 +15,13 @@ env:
|
|
16
15
|
- AR_VERSION=5.0
|
17
16
|
|
18
17
|
matrix:
|
18
|
+
include:
|
19
|
+
- rvm: jruby-9.0.5.0
|
20
|
+
env: AR_VERSION=4.2
|
21
|
+
script:
|
22
|
+
- bundle exec rake test:jdbcmysql
|
23
|
+
- bundle exec rake test:jdbcpostgresql
|
24
|
+
|
19
25
|
fast_finish: true
|
20
26
|
|
21
27
|
before_script:
|
@@ -33,9 +39,11 @@ addons:
|
|
33
39
|
|
34
40
|
script:
|
35
41
|
- bundle exec rake test:mysql2
|
42
|
+
- bundle exec rake test:mysql2_makara
|
36
43
|
- bundle exec rake test:mysql2spatial
|
37
44
|
- bundle exec rake test:postgis
|
38
45
|
- bundle exec rake test:postgresql
|
46
|
+
- bundle exec rake test:postgresql_makara
|
39
47
|
- bundle exec rake test:seamless_database_pool
|
40
48
|
- bundle exec rake test:spatialite
|
41
49
|
- bundle exec rake test:sqlite3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
## Changes in 0.14.0
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
|
5
|
+
* Support for ActiveRecord 3.1 has been dropped. Thanks to @sferik via \#254
|
6
|
+
* SQLite3 has learned the :recursive option. Thanks to @jkowens via \#281
|
7
|
+
* :on_duplicate_key_ignore will be ignored when imports are being done with :recursive. Thanks to @jkowens via \#268
|
8
|
+
* :activerecord-import learned how to tell PostgreSQL to return no data back from the import via the :no_returning boolean option. Thanks to @makaroni4 via \#276
|
9
|
+
|
10
|
+
### Fixes
|
11
|
+
|
12
|
+
* Polymorphic associations will not import the :type column. Thanks to @seanlinsley via \#282 and \#283
|
13
|
+
* ~2X speed increase for importing models with validations. Thanks to @jkowens via \#266
|
14
|
+
|
15
|
+
### Misc
|
16
|
+
|
17
|
+
* Benchmark HTML report has been fixed. Thanks to @jkowens via \#264
|
18
|
+
* seamless_database_pool has been updated to work with AR 5.0. Thanks to @jkowens via \#280
|
19
|
+
* Code cleanup, removal of redundant condition checks. Thanks to @pavlik4k via \#273
|
20
|
+
* Code cleanup, removal of deprecated `alias_method_chain`. Thanks to @codeodor via \#271
|
21
|
+
|
22
|
+
|
23
|
+
|
1
24
|
## Changes in 0.13.0
|
2
25
|
|
3
26
|
### New Features
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -13,7 +13,19 @@ namespace :display do
|
|
13
13
|
end
|
14
14
|
task default: ["display:notice"]
|
15
15
|
|
16
|
-
ADAPTERS = %w(
|
16
|
+
ADAPTERS = %w(
|
17
|
+
mysql2
|
18
|
+
mysql2_makara
|
19
|
+
mysql2spatial
|
20
|
+
jdbcmysql
|
21
|
+
jdbcpostgresql
|
22
|
+
postgresql
|
23
|
+
postgresql_makara
|
24
|
+
postgis
|
25
|
+
sqlite3
|
26
|
+
spatialite
|
27
|
+
seamless_database_pool
|
28
|
+
).freeze
|
17
29
|
ADAPTERS.each do |adapter|
|
18
30
|
namespace :test do
|
19
31
|
desc "Runs #{adapter} database tests."
|
data/activerecord-import.gemspec
CHANGED
data/benchmarks/lib/base.rb
CHANGED
@@ -126,7 +126,9 @@ class BenchmarkBase
|
|
126
126
|
# Deletes all records from all ActiveRecord subclasses
|
127
127
|
def delete_all
|
128
128
|
ActiveRecord::Base.send( :subclasses ).each do |subclass|
|
129
|
-
subclass.
|
129
|
+
if subclass.table_exists? && subclass.respond_to?(:delete_all)
|
130
|
+
subclass.delete_all
|
131
|
+
end
|
130
132
|
end
|
131
133
|
end
|
132
134
|
|
@@ -51,7 +51,7 @@ EOT
|
|
51
51
|
else
|
52
52
|
time = result.tms.real.round_to( 3 )
|
53
53
|
speedup = ( result_set.first.tms.real / result.tms.real ).round
|
54
|
-
times << result == result_set.first ? time.to_s : "#{time} (#{speedup}x speedup)"
|
54
|
+
times << (result == result_set.first ? time.to_s : "#{time} (#{speedup}x speedup)")
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
data/lib/activerecord-import.rb
CHANGED
@@ -12,7 +12,8 @@ ActiveSupport.on_load(:active_record) do
|
|
12
12
|
ActiveRecord::Import.load_from_connection_pool connection_pool
|
13
13
|
conn
|
14
14
|
end
|
15
|
-
|
15
|
+
alias establish_connection_without_activerecord_import establish_connection
|
16
|
+
alias establish_connection establish_connection_with_activerecord_import
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
@@ -47,7 +47,10 @@ module ActiveRecord::Import::AbstractAdapter
|
|
47
47
|
|
48
48
|
if supports_on_duplicate_key_update?
|
49
49
|
if options[:on_duplicate_key_ignore] && respond_to?(:sql_for_on_duplicate_key_ignore)
|
50
|
-
|
50
|
+
# Options :recursive and :on_duplicate_key_ignore are mutually exclusive
|
51
|
+
unless options[:recursive]
|
52
|
+
post_sql_statements << sql_for_on_duplicate_key_ignore( table_name, options[:on_duplicate_key_ignore] )
|
53
|
+
end
|
51
54
|
elsif options[:on_duplicate_key_update]
|
52
55
|
post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update] )
|
53
56
|
end
|
@@ -26,7 +26,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def post_sql_statements( table_name, options ) # :nodoc:
|
29
|
-
if options[:primary_key].blank?
|
29
|
+
if options[:no_returning] || options[:primary_key].blank?
|
30
30
|
super(table_name, options)
|
31
31
|
else
|
32
32
|
super(table_name, options) << "RETURNING #{options[:primary_key]}"
|
@@ -19,6 +19,8 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
19
19
|
# elements that are in position >= 1 will be appended to the final SQL.
|
20
20
|
def insert_many(sql, values, *args) # :nodoc:
|
21
21
|
number_of_inserts = 0
|
22
|
+
ids = []
|
23
|
+
|
22
24
|
base_sql, post_sql = if sql.is_a?( String )
|
23
25
|
[sql, '']
|
24
26
|
elsif sql.is_a?( Array )
|
@@ -31,13 +33,19 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
31
33
|
value_sets.each do |value_set|
|
32
34
|
number_of_inserts += 1
|
33
35
|
sql2insert = base_sql + value_set.join( ',' ) + post_sql
|
34
|
-
insert( sql2insert, *args )
|
36
|
+
first_insert_id = insert( sql2insert, *args )
|
37
|
+
last_insert_id = first_insert_id + value_set.size - 1
|
38
|
+
ids.concat((first_insert_id..last_insert_id).to_a)
|
35
39
|
end
|
36
40
|
|
37
|
-
[number_of_inserts,
|
41
|
+
[number_of_inserts, ids]
|
38
42
|
end
|
39
43
|
|
40
44
|
def next_value_for_sequence(sequence_name)
|
41
45
|
%{nextval('#{sequence_name}')}
|
42
46
|
end
|
47
|
+
|
48
|
+
def support_setting_primary_key_of_imported_objects?
|
49
|
+
true
|
50
|
+
end
|
43
51
|
end
|
@@ -7,8 +7,10 @@ module ActiveRecord::Import
|
|
7
7
|
|
8
8
|
def self.base_adapter(adapter)
|
9
9
|
case adapter
|
10
|
+
when 'mysql2_makara' then 'mysql2'
|
10
11
|
when 'mysql2spatial' then 'mysql2'
|
11
12
|
when 'spatialite' then 'sqlite3'
|
13
|
+
when 'postgresql_makara' then 'postgresql'
|
12
14
|
when 'postgis' then 'postgresql'
|
13
15
|
else adapter
|
14
16
|
end
|
@@ -61,13 +61,14 @@ class ActiveRecord::Associations::CollectionAssociation
|
|
61
61
|
|
62
62
|
models.each do |m|
|
63
63
|
m.public_send "#{symbolized_foreign_key}=", owner_primary_key_value
|
64
|
+
m.public_send "#{reflection.type}=", owner.class.name if reflection.type
|
64
65
|
end
|
65
66
|
|
66
67
|
return model_klass.import column_names, models, options
|
67
68
|
|
68
69
|
# supports empty array
|
69
70
|
elsif args.last.is_a?( Array ) && args.last.empty?
|
70
|
-
return ActiveRecord::Import::Result.new([], 0, [])
|
71
|
+
return ActiveRecord::Import::Result.new([], 0, [])
|
71
72
|
|
72
73
|
# supports 2-element array and array
|
73
74
|
elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
|
@@ -82,6 +83,11 @@ class ActiveRecord::Associations::CollectionAssociation
|
|
82
83
|
array_of_attributes.each { |attrs| attrs << owner_primary_key_value }
|
83
84
|
end
|
84
85
|
|
86
|
+
if reflection.type
|
87
|
+
column_names << reflection.type
|
88
|
+
array_of_attributes.each { |attrs| attrs << owner.class.name }
|
89
|
+
end
|
90
|
+
|
85
91
|
return model_klass.import column_names, array_of_attributes, options
|
86
92
|
else
|
87
93
|
raise ArgumentError, "Invalid arguments!"
|
@@ -168,7 +174,8 @@ class ActiveRecord::Base
|
|
168
174
|
# * +ignore+ - true|false, tells import to use MySQL's INSERT IGNORE
|
169
175
|
# to discard records that contain duplicate keys.
|
170
176
|
# * +on_duplicate_key_ignore+ - true|false, tells import to use
|
171
|
-
# Postgres 9.5+ ON CONFLICT DO NOTHING.
|
177
|
+
# Postgres 9.5+ ON CONFLICT DO NOTHING. Cannot be enabled on a
|
178
|
+
# recursive import.
|
172
179
|
# * +on_duplicate_key_update+ - an Array or Hash, tells import to
|
173
180
|
# use MySQL's ON DUPLICATE KEY UPDATE or Postgres 9.5+ ON CONFLICT
|
174
181
|
# DO UPDATE ability. See On Duplicate Key Update below.
|
@@ -350,18 +357,13 @@ class ActiveRecord::Base
|
|
350
357
|
# this next line breaks sqlite.so with a segmentation fault
|
351
358
|
# if model.new_record? || options[:on_duplicate_key_update]
|
352
359
|
column_names.map do |name|
|
353
|
-
name
|
354
|
-
if respond_to?(:defined_enums) && defined_enums.key?(name) # ActiveRecord 5
|
355
|
-
model.read_attribute(name)
|
356
|
-
else
|
357
|
-
model.read_attribute_before_type_cast(name)
|
358
|
-
end
|
360
|
+
model.read_attribute_before_type_cast(name.to_s)
|
359
361
|
end
|
360
362
|
# end
|
361
363
|
end
|
362
364
|
# supports empty array
|
363
365
|
elsif args.last.is_a?( Array ) && args.last.empty?
|
364
|
-
return ActiveRecord::Import::Result.new([], 0, [])
|
366
|
+
return ActiveRecord::Import::Result.new([], 0, [])
|
365
367
|
# supports 2-element array and array
|
366
368
|
elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
|
367
369
|
column_names, array_of_attributes = args
|
@@ -387,7 +389,19 @@ class ActiveRecord::Base
|
|
387
389
|
end
|
388
390
|
|
389
391
|
return_obj = if is_validating
|
390
|
-
|
392
|
+
if models
|
393
|
+
import_with_validations( column_names, array_of_attributes, options ) do |failed|
|
394
|
+
models.each_with_index do |model, i|
|
395
|
+
model = model.dup if options[:recursive]
|
396
|
+
next if model.valid?(options[:validate_with_context])
|
397
|
+
model.send(:raise_record_invalid) if options[:raise_error]
|
398
|
+
array_of_attributes[i] = nil
|
399
|
+
failed << model
|
400
|
+
end
|
401
|
+
end
|
402
|
+
else
|
403
|
+
import_with_validations( column_names, array_of_attributes, options )
|
404
|
+
end
|
391
405
|
else
|
392
406
|
(num_inserts, ids) = import_without_validations_or_callbacks( column_names, array_of_attributes, options )
|
393
407
|
ActiveRecord::Import::Result.new([], num_inserts, ids)
|
@@ -424,21 +438,24 @@ class ActiveRecord::Base
|
|
424
438
|
def import_with_validations( column_names, array_of_attributes, options = {} )
|
425
439
|
failed_instances = []
|
426
440
|
|
427
|
-
|
428
|
-
|
441
|
+
if block_given?
|
442
|
+
yield failed_instances
|
443
|
+
else
|
444
|
+
# create instances for each of our column/value sets
|
445
|
+
arr = validations_array_for_column_names_and_attributes( column_names, array_of_attributes )
|
429
446
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
447
|
+
# keep track of the instance and the position it is currently at. if this fails
|
448
|
+
# validation we'll use the index to remove it from the array_of_attributes
|
449
|
+
model = new
|
450
|
+
arr.each_with_index do |hsh, i|
|
434
451
|
hsh.each_pair { |k, v| model[k] = v }
|
452
|
+
next if model.valid?(options[:validate_with_context])
|
453
|
+
raise(ActiveRecord::RecordInvalid, model) if options[:raise_error]
|
454
|
+
array_of_attributes[i] = nil
|
455
|
+
failed_instances << model.dup
|
435
456
|
end
|
436
|
-
|
437
|
-
next if instance.valid?(options[:validate_with_context])
|
438
|
-
raise(ActiveRecord::RecordInvalid, instance) if options[:raise_error]
|
439
|
-
array_of_attributes[i] = nil
|
440
|
-
failed_instances << instance
|
441
457
|
end
|
458
|
+
|
442
459
|
array_of_attributes.compact!
|
443
460
|
|
444
461
|
num_inserts, ids = if array_of_attributes.empty? || options[:all_or_none] && failed_instances.any?
|
@@ -501,7 +518,7 @@ class ActiveRecord::Base
|
|
501
518
|
end
|
502
519
|
else
|
503
520
|
values_sql.each do |values|
|
504
|
-
connection.
|
521
|
+
ids << connection.insert(insert_sql + values)
|
505
522
|
number_inserted += 1
|
506
523
|
end
|
507
524
|
end
|
@@ -517,7 +534,7 @@ class ActiveRecord::Base
|
|
517
534
|
model.id = id.to_i
|
518
535
|
if model.respond_to?(:clear_changes_information) # Rails 4.0 and higher
|
519
536
|
model.clear_changes_information
|
520
|
-
else # Rails 3.
|
537
|
+
else # Rails 3.2
|
521
538
|
model.instance_variable_get(:@changed_attributes).clear
|
522
539
|
end
|
523
540
|
model.instance_variable_set(:@new_record, false)
|
@@ -590,7 +607,7 @@ class ActiveRecord::Base
|
|
590
607
|
connection_memo.quote(type_caster.type_cast_for_database(column.name, val))
|
591
608
|
elsif column.respond_to?(:type_cast_from_user) # Rails 4.2 and higher
|
592
609
|
connection_memo.quote(column.type_cast_from_user(val), column)
|
593
|
-
else # Rails 3.
|
610
|
+
else # Rails 3.2, 4.0 and 4.1
|
594
611
|
if serialized_attributes.include?(column.name)
|
595
612
|
val = serialized_attributes[column.name].dump(val)
|
596
613
|
end
|
@@ -636,9 +653,7 @@ class ActiveRecord::Base
|
|
636
653
|
|
637
654
|
# Returns an Array of Hashes for the passed in +column_names+ and +array_of_attributes+.
|
638
655
|
def validations_array_for_column_names_and_attributes( column_names, array_of_attributes ) # :nodoc:
|
639
|
-
array_of_attributes.map
|
640
|
-
Hash[attributes.each_with_index.map { |attr, c| [column_names[c], attr] }]
|
641
|
-
end
|
656
|
+
array_of_attributes.map { |values| Hash[column_names.zip(values)] }
|
642
657
|
end
|
643
658
|
end
|
644
659
|
end
|
@@ -47,7 +47,7 @@ module ActiveRecord # :nodoc:
|
|
47
47
|
instance.clear_changes_information # Rails 4.2 and higher
|
48
48
|
else
|
49
49
|
instance.instance_variable_set :@attributes_cache, {} # Rails 4.0, 4.1
|
50
|
-
instance.changed_attributes.clear # Rails 3.
|
50
|
+
instance.changed_attributes.clear # Rails 3.2
|
51
51
|
instance.previous_changes.clear
|
52
52
|
end
|
53
53
|
|
@@ -0,0 +1 @@
|
|
1
|
+
ENV["ARE_DB"] = "mysql2_makara"
|
@@ -0,0 +1 @@
|
|
1
|
+
ENV["ARE_DB"] = "postgresql"
|
data/test/database.yml.sample
CHANGED
@@ -12,12 +12,8 @@ mysql2: &mysql2
|
|
12
12
|
mysql2spatial:
|
13
13
|
<<: *mysql2
|
14
14
|
|
15
|
-
|
16
|
-
<<: *
|
17
|
-
adapter: seamless_database_pool
|
18
|
-
pool_adapter: mysql2
|
19
|
-
master:
|
20
|
-
host: localhost
|
15
|
+
mysql2_makara:
|
16
|
+
<<: *mysql2
|
21
17
|
|
22
18
|
postgresql: &postgresql
|
23
19
|
<<: *common
|
@@ -25,6 +21,9 @@ postgresql: &postgresql
|
|
25
21
|
adapter: postgresql
|
26
22
|
min_messages: warning
|
27
23
|
|
24
|
+
postresql_makara:
|
25
|
+
<<: *postgresql
|
26
|
+
|
28
27
|
postgis:
|
29
28
|
<<: *postgresql
|
30
29
|
|
@@ -33,6 +32,14 @@ oracle:
|
|
33
32
|
adapter: oracle
|
34
33
|
min_messages: debug
|
35
34
|
|
35
|
+
seamless_database_pool:
|
36
|
+
<<: *common
|
37
|
+
adapter: seamless_database_pool
|
38
|
+
prepared_statements: false
|
39
|
+
pool_adapter: mysql2
|
40
|
+
master:
|
41
|
+
host: localhost
|
42
|
+
|
36
43
|
sqlite:
|
37
44
|
adapter: sqlite
|
38
45
|
dbfile: test.db
|
data/test/import_test.rb
CHANGED
@@ -363,36 +363,30 @@ describe "#import" do
|
|
363
363
|
end
|
364
364
|
|
365
365
|
context "importing through an association scope" do
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
366
|
+
{ has_many: :chapters, polymorphic: :discounts }.each do |association_type, association|
|
367
|
+
let(:book) { FactoryGirl.create :book }
|
368
|
+
let(:scope) { book.public_send association }
|
369
|
+
let(:klass) { { chapters: Chapter, discounts: Discount }[association] }
|
370
|
+
let(:column) { { chapters: :title, discounts: :amount }[association] }
|
371
|
+
let(:val1) { { chapters: 'A', discounts: 5 }[association] }
|
372
|
+
let(:val2) { { chapters: 'B', discounts: 6 }[association] }
|
373
|
+
|
374
|
+
context "for #{association_type}" do
|
375
|
+
it "works importing models" do
|
376
|
+
scope.import [
|
377
|
+
klass.new(column => val1),
|
378
|
+
klass.new(column => val2)
|
379
|
+
]
|
380
|
+
|
381
|
+
assert_equal [val1, val2], scope.map(&column).sort
|
374
382
|
end
|
375
|
-
end
|
376
|
-
end
|
377
383
|
|
378
|
-
|
379
|
-
|
380
|
-
books = [
|
381
|
-
Book.new(author_name: "Author #1", title: "Book #1"),
|
382
|
-
Book.new(author_name: "Author #2", title: "Book #2"),
|
383
|
-
]
|
384
|
-
topic.books.import books
|
385
|
-
assert_equal 2, topic.books.count
|
386
|
-
assert topic.books.detect { |b| b.title == "Book #1" && b.author_name == "Author #1" }
|
387
|
-
assert topic.books.detect { |b| b.title == "Book #2" && b.author_name == "Author #2" }
|
388
|
-
end
|
384
|
+
it "works importing array of columns and values" do
|
385
|
+
scope.import [column], [[val1], [val2]]
|
389
386
|
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
assert_equal 2, topic.books.count
|
394
|
-
assert topic.books.detect { |b| b.title == "Book #1" && b.author_name == "Author #1" }
|
395
|
-
assert topic.books.detect { |b| b.title == "Book #2" && b.author_name == "Author #2" }
|
387
|
+
assert_equal [val1, val2], scope.map(&column).sort
|
388
|
+
end
|
389
|
+
end
|
396
390
|
end
|
397
391
|
end
|
398
392
|
|
@@ -451,6 +445,25 @@ describe "#import" do
|
|
451
445
|
end
|
452
446
|
end
|
453
447
|
|
448
|
+
context 'When importing arrays of values with Enum fields' do
|
449
|
+
let(:columns) { [:author_name, :title, :status] }
|
450
|
+
let(:values) { [['Author #1', 'Book #1', 0], ['Author #2', 'Book #2', 1]] }
|
451
|
+
|
452
|
+
it 'should be able to import enum fields' do
|
453
|
+
Book.delete_all if Book.count > 0
|
454
|
+
Book.import columns, values
|
455
|
+
assert_equal 2, Book.count
|
456
|
+
|
457
|
+
if ENV['AR_VERSION'].to_i >= 5.0
|
458
|
+
assert_equal 'draft', Book.first.read_attribute('status')
|
459
|
+
assert_equal 'published', Book.last.read_attribute('status')
|
460
|
+
else
|
461
|
+
assert_equal 0, Book.first.read_attribute('status')
|
462
|
+
assert_equal 1, Book.last.read_attribute('status')
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
454
467
|
describe "importing when model has default_scope" do
|
455
468
|
it "doesn't import the default scope values" do
|
456
469
|
assert_difference "Widget.unscoped.count", +2 do
|
@@ -0,0 +1,6 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
|
5
|
+
|
6
|
+
should_support_mysql_import_functionality
|
data/test/sqlite3/import_test.rb
CHANGED
data/test/support/factories.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
def should_support_postgresql_import_functionality
|
3
|
+
should_support_recursive_import
|
4
|
+
|
3
5
|
describe "#supports_imports?" do
|
4
6
|
it "should support import" do
|
5
7
|
assert ActiveRecord::Base.supports_import?
|
@@ -18,112 +20,6 @@ def should_support_postgresql_import_functionality
|
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
|
-
describe "importing objects with associations" do
|
22
|
-
let(:new_topics) { Build(num_topics, :topic_with_book) }
|
23
|
-
let(:new_topics_with_invalid_chapter) do
|
24
|
-
chapter = new_topics.first.books.first.chapters.first
|
25
|
-
chapter.title = nil
|
26
|
-
new_topics
|
27
|
-
end
|
28
|
-
let(:num_topics) { 3 }
|
29
|
-
let(:num_books) { 6 }
|
30
|
-
let(:num_chapters) { 18 }
|
31
|
-
let(:num_endnotes) { 24 }
|
32
|
-
|
33
|
-
let(:new_question_with_rule) { FactoryGirl.build :question, :with_rule }
|
34
|
-
|
35
|
-
it 'imports top level' do
|
36
|
-
assert_difference "Topic.count", +num_topics do
|
37
|
-
Topic.import new_topics, recursive: true
|
38
|
-
new_topics.each do |topic|
|
39
|
-
assert_not_nil topic.id
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'imports first level associations' do
|
45
|
-
assert_difference "Book.count", +num_books do
|
46
|
-
Topic.import new_topics, recursive: true
|
47
|
-
new_topics.each do |topic|
|
48
|
-
topic.books.each do |book|
|
49
|
-
assert_equal topic.id, book.topic_id
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'imports polymorphic associations' do
|
56
|
-
discounts = Array.new(1) { |i| Discount.new(amount: i) }
|
57
|
-
books = Array.new(1) { |i| Book.new(author_name: "Author ##{i}", title: "Book ##{i}") }
|
58
|
-
books.each do |book|
|
59
|
-
book.discounts << discounts
|
60
|
-
end
|
61
|
-
Book.import books, recursive: true
|
62
|
-
books.each do |book|
|
63
|
-
book.discounts.each do |discount|
|
64
|
-
assert_not_nil discount.discountable_id
|
65
|
-
assert_equal 'Book', discount.discountable_type
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
[{ recursive: false }, {}].each do |import_options|
|
71
|
-
it "skips recursion for #{import_options}" do
|
72
|
-
assert_difference "Book.count", 0 do
|
73
|
-
Topic.import new_topics, import_options
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'imports deeper nested associations' do
|
79
|
-
assert_difference "Chapter.count", +num_chapters do
|
80
|
-
assert_difference "EndNote.count", +num_endnotes do
|
81
|
-
Topic.import new_topics, recursive: true
|
82
|
-
new_topics.each do |topic|
|
83
|
-
topic.books.each do |book|
|
84
|
-
book.chapters.each do |chapter|
|
85
|
-
assert_equal book.id, chapter.book_id
|
86
|
-
end
|
87
|
-
book.end_notes.each do |endnote|
|
88
|
-
assert_equal book.id, endnote.book_id
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
it "skips validation of the associations if requested" do
|
97
|
-
assert_difference "Chapter.count", +num_chapters do
|
98
|
-
Topic.import new_topics_with_invalid_chapter, validate: false, recursive: true
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'imports has_one associations' do
|
103
|
-
assert_difference 'Rule.count' do
|
104
|
-
Question.import [new_question_with_rule], recursive: true
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# These models dont validate associated. So we expect that books and topics get inserted, but not chapters
|
109
|
-
# Putting a transaction around everything wouldn't work, so if you want your chapters to prevent topics from
|
110
|
-
# being created, you would need to have validates_associated in your models and insert with validation
|
111
|
-
describe "all_or_none" do
|
112
|
-
[Book, Topic, EndNote].each do |type|
|
113
|
-
it "creates #{type}" do
|
114
|
-
assert_difference "#{type}.count", send("num_#{type.to_s.downcase}s") do
|
115
|
-
Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
it "doesn't create chapters" do
|
120
|
-
assert_difference "Chapter.count", 0 do
|
121
|
-
Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
23
|
describe "with query cache enabled" do
|
128
24
|
setup do
|
129
25
|
unless ActiveRecord::Base.connection.query_cache_enabled
|
@@ -147,6 +43,20 @@ def should_support_postgresql_import_functionality
|
|
147
43
|
end
|
148
44
|
end
|
149
45
|
end
|
46
|
+
|
47
|
+
describe "no_returning" do
|
48
|
+
let(:books) { [Book.new(author_name: "foo", title: "bar")] }
|
49
|
+
|
50
|
+
it "creates records" do
|
51
|
+
assert_difference "Book.count", +1 do
|
52
|
+
Book.import books, no_returning: true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "returns no ids" do
|
57
|
+
assert_equal [], Book.import(books, no_returning: true).ids
|
58
|
+
end
|
59
|
+
end
|
150
60
|
end
|
151
61
|
end
|
152
62
|
|
@@ -164,28 +74,32 @@ def should_support_postgresql_upsert_functionality
|
|
164
74
|
let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
|
165
75
|
let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
|
166
76
|
|
167
|
-
macro(:perform_import) do |*opts|
|
168
|
-
Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_ignore: value, validate: false)
|
169
|
-
end
|
170
|
-
|
171
77
|
setup do
|
172
78
|
Topic.import columns, values, validate: false
|
173
|
-
@topic = Topic.find 99
|
174
79
|
end
|
175
80
|
|
176
|
-
|
177
|
-
|
178
|
-
|
81
|
+
it "should not update any records" do
|
82
|
+
result = Topic.import columns, updated_values, on_duplicate_key_ignore: true, validate: false
|
83
|
+
assert_equal [], result.ids
|
179
84
|
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "with :on_duplicate_key_ignore and :recursive enabled" do
|
88
|
+
let(:new_topic) { Build(1, :topic_with_book) }
|
89
|
+
let(:mixed_topics) { Build(1, :topic_with_book) + new_topic + Build(1, :topic_with_book) }
|
180
90
|
|
181
|
-
|
182
|
-
|
183
|
-
should_not_update_updated_at_on_timestamp_columns
|
91
|
+
setup do
|
92
|
+
Topic.import new_topic, recursive: true
|
184
93
|
end
|
185
94
|
|
186
|
-
|
187
|
-
|
188
|
-
|
95
|
+
# Recursive import depends on the primary keys of the parent model being returned
|
96
|
+
# on insert. With on_duplicate_key_ignore enabled, not all ids will be returned
|
97
|
+
# and it is possible that a model will be assigned the wrong id and then its children
|
98
|
+
# would be associated with the wrong parent.
|
99
|
+
it ":on_duplicate_key_ignore is ignored" do
|
100
|
+
assert_raise ActiveRecord::RecordNotUnique do
|
101
|
+
Topic.import mixed_topics, recursive: true, on_duplicate_key_ignore: true
|
102
|
+
end
|
189
103
|
end
|
190
104
|
end
|
191
105
|
|
@@ -294,19 +208,6 @@ def should_support_postgresql_upsert_functionality
|
|
294
208
|
should_update_updated_at_on_timestamp_columns
|
295
209
|
end
|
296
210
|
end
|
297
|
-
|
298
|
-
context "with recursive: true" do
|
299
|
-
let(:new_topics) { Build(1, :topic_with_book) }
|
300
|
-
|
301
|
-
it "imports objects with associations" do
|
302
|
-
assert_difference "Topic.count", +1 do
|
303
|
-
Topic.import new_topics, recursive: true, on_duplicate_key_update: [:updated_at], validate: false
|
304
|
-
new_topics.each do |topic|
|
305
|
-
assert_not_nil topic.id
|
306
|
-
end
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
211
|
end
|
311
212
|
end
|
312
213
|
end
|
@@ -5,65 +5,76 @@ def should_support_basic_on_duplicate_key_update
|
|
5
5
|
macro(:perform_import) { raise "supply your own #perform_import in a context below" }
|
6
6
|
macro(:updated_topic) { Topic.find(@topic.id) }
|
7
7
|
|
8
|
-
context "with :on_duplicate_key_update
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
context "with :on_duplicate_key_update" do
|
9
|
+
describe "argument safety" do
|
10
|
+
it "should not modify the passed in :on_duplicate_key_update columns array" do
|
11
|
+
assert_nothing_raised do
|
12
|
+
columns = %w(title author_name).freeze
|
13
|
+
Topic.import columns, [%w(foo, bar)], on_duplicate_key_update: columns
|
14
|
+
end
|
15
|
+
end
|
14
16
|
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
context "with validation checks turned off" do
|
19
|
+
asssertion_group(:should_support_on_duplicate_key_update) do
|
20
|
+
should_not_update_fields_not_mentioned
|
21
|
+
should_update_foreign_keys
|
22
|
+
should_not_update_created_at_on_timestamp_columns
|
23
|
+
should_update_updated_at_on_timestamp_columns
|
24
|
+
end
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
let(:columns) { %w( id title author_name author_email_address parent_id ) }
|
27
|
+
let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17]] }
|
28
|
+
let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57]] }
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
30
|
+
macro(:perform_import) do |*opts|
|
31
|
+
Topic.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: update_columns, validate: false)
|
32
|
+
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
+
setup do
|
35
|
+
Topic.import columns, values, validate: false
|
36
|
+
@topic = Topic.find 99
|
37
|
+
end
|
34
38
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
context "using an empty array" do
|
40
|
+
let(:update_columns) { [] }
|
41
|
+
should_not_update_fields_not_mentioned
|
42
|
+
should_update_updated_at_on_timestamp_columns
|
43
|
+
end
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
context "using string column names" do
|
46
|
+
let(:update_columns) { %w(title author_email_address parent_id) }
|
47
|
+
should_support_on_duplicate_key_update
|
48
|
+
should_update_fields_mentioned
|
49
|
+
end
|
50
|
+
|
51
|
+
context "using symbol column names" do
|
52
|
+
let(:update_columns) { [:title, :author_email_address, :parent_id] }
|
53
|
+
should_support_on_duplicate_key_update
|
54
|
+
should_update_fields_mentioned
|
55
|
+
end
|
45
56
|
end
|
46
|
-
end
|
47
57
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
58
|
+
context "with a table that has a non-standard primary key" do
|
59
|
+
let(:columns) { [:promotion_id, :code] }
|
60
|
+
let(:values) { [[1, 'DISCOUNT1']] }
|
61
|
+
let(:updated_values) { [[1, 'DISCOUNT2']] }
|
62
|
+
let(:update_columns) { [:code] }
|
53
63
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
64
|
+
macro(:perform_import) do |*opts|
|
65
|
+
Promotion.import columns, updated_values, opts.extract_options!.merge(on_duplicate_key_update: update_columns, validate: false)
|
66
|
+
end
|
67
|
+
macro(:updated_promotion) { Promotion.find(@promotion.promotion_id) }
|
58
68
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
69
|
+
setup do
|
70
|
+
Promotion.import columns, values, validate: false
|
71
|
+
@promotion = Promotion.find 1
|
72
|
+
end
|
63
73
|
|
64
|
-
|
65
|
-
|
66
|
-
|
74
|
+
it "should update specified columns" do
|
75
|
+
perform_import
|
76
|
+
assert_equal 'DISCOUNT2', updated_promotion.code
|
77
|
+
end
|
67
78
|
end
|
68
79
|
end
|
69
80
|
|
@@ -0,0 +1,122 @@
|
|
1
|
+
def should_support_recursive_import
|
2
|
+
describe "importing objects with associations" do
|
3
|
+
let(:new_topics) { Build(num_topics, :topic_with_book) }
|
4
|
+
let(:new_topics_with_invalid_chapter) do
|
5
|
+
chapter = new_topics.first.books.first.chapters.first
|
6
|
+
chapter.title = nil
|
7
|
+
new_topics
|
8
|
+
end
|
9
|
+
let(:num_topics) { 3 }
|
10
|
+
let(:num_books) { 6 }
|
11
|
+
let(:num_chapters) { 18 }
|
12
|
+
let(:num_endnotes) { 24 }
|
13
|
+
|
14
|
+
let(:new_question_with_rule) { FactoryGirl.build :question, :with_rule }
|
15
|
+
|
16
|
+
it 'imports top level' do
|
17
|
+
assert_difference "Topic.count", +num_topics do
|
18
|
+
Topic.import new_topics, recursive: true
|
19
|
+
new_topics.each do |topic|
|
20
|
+
assert_not_nil topic.id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'imports first level associations' do
|
26
|
+
assert_difference "Book.count", +num_books do
|
27
|
+
Topic.import new_topics, recursive: true
|
28
|
+
new_topics.each do |topic|
|
29
|
+
topic.books.each do |book|
|
30
|
+
assert_equal topic.id, book.topic_id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'imports polymorphic associations' do
|
37
|
+
discounts = Array.new(1) { |i| Discount.new(amount: i) }
|
38
|
+
books = Array.new(1) { |i| Book.new(author_name: "Author ##{i}", title: "Book ##{i}") }
|
39
|
+
books.each do |book|
|
40
|
+
book.discounts << discounts
|
41
|
+
end
|
42
|
+
Book.import books, recursive: true
|
43
|
+
books.each do |book|
|
44
|
+
book.discounts.each do |discount|
|
45
|
+
assert_not_nil discount.discountable_id
|
46
|
+
assert_equal 'Book', discount.discountable_type
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
[{ recursive: false }, {}].each do |import_options|
|
52
|
+
it "skips recursion for #{import_options}" do
|
53
|
+
assert_difference "Book.count", 0 do
|
54
|
+
Topic.import new_topics, import_options
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'imports deeper nested associations' do
|
60
|
+
assert_difference "Chapter.count", +num_chapters do
|
61
|
+
assert_difference "EndNote.count", +num_endnotes do
|
62
|
+
Topic.import new_topics, recursive: true
|
63
|
+
new_topics.each do |topic|
|
64
|
+
topic.books.each do |book|
|
65
|
+
book.chapters.each do |chapter|
|
66
|
+
assert_equal book.id, chapter.book_id
|
67
|
+
end
|
68
|
+
book.end_notes.each do |endnote|
|
69
|
+
assert_equal book.id, endnote.book_id
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "skips validation of the associations if requested" do
|
78
|
+
assert_difference "Chapter.count", +num_chapters do
|
79
|
+
Topic.import new_topics_with_invalid_chapter, validate: false, recursive: true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'imports has_one associations' do
|
84
|
+
assert_difference 'Rule.count' do
|
85
|
+
Question.import [new_question_with_rule], recursive: true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# These models dont validate associated. So we expect that books and topics get inserted, but not chapters
|
90
|
+
# Putting a transaction around everything wouldn't work, so if you want your chapters to prevent topics from
|
91
|
+
# being created, you would need to have validates_associated in your models and insert with validation
|
92
|
+
describe "all_or_none" do
|
93
|
+
[Book, Topic, EndNote].each do |type|
|
94
|
+
it "creates #{type}" do
|
95
|
+
assert_difference "#{type}.count", send("num_#{type.to_s.downcase}s") do
|
96
|
+
Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
it "doesn't create chapters" do
|
101
|
+
assert_difference "Chapter.count", 0 do
|
102
|
+
Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# If adapter supports on_duplicate_key_update, it is only applied to top level models so that SQL with invalid
|
108
|
+
# columns, keys, etc isn't generated for child associations when doing recursive import
|
109
|
+
describe "on_duplicate_key_update" do
|
110
|
+
let(:new_topics) { Build(1, :topic_with_book) }
|
111
|
+
|
112
|
+
it "imports objects with associations" do
|
113
|
+
assert_difference "Topic.count", +1 do
|
114
|
+
Topic.import new_topics, recursive: true, on_duplicate_key_update: [:updated_at], validate: false
|
115
|
+
new_topics.each do |topic|
|
116
|
+
assert_not_nil topic.id
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/test/travis/database.yml
CHANGED
@@ -5,6 +5,16 @@ common: &common
|
|
5
5
|
host: localhost
|
6
6
|
database: activerecord_import_test
|
7
7
|
|
8
|
+
jdbcpostgresql: &postgresql
|
9
|
+
<<: *common
|
10
|
+
username: postgres
|
11
|
+
adapter: jdbcpostgresql
|
12
|
+
min_messages: warning
|
13
|
+
|
14
|
+
jdbcmysql: &mysql2
|
15
|
+
<<: *common
|
16
|
+
adapter: jdbcmysql
|
17
|
+
|
8
18
|
mysql2: &mysql2
|
9
19
|
<<: *common
|
10
20
|
adapter: mysql2
|
@@ -12,12 +22,13 @@ mysql2: &mysql2
|
|
12
22
|
mysql2spatial:
|
13
23
|
<<: *mysql2
|
14
24
|
|
15
|
-
|
25
|
+
mysql2_makara:
|
26
|
+
<<: *mysql2
|
27
|
+
|
28
|
+
oracle:
|
16
29
|
<<: *common
|
17
|
-
adapter:
|
18
|
-
|
19
|
-
master:
|
20
|
-
host: localhost
|
30
|
+
adapter: oracle
|
31
|
+
min_messages: debug
|
21
32
|
|
22
33
|
postgresql: &postgresql
|
23
34
|
<<: *common
|
@@ -25,13 +36,19 @@ postgresql: &postgresql
|
|
25
36
|
adapter: postgresql
|
26
37
|
min_messages: warning
|
27
38
|
|
39
|
+
postresql_makara:
|
40
|
+
<<: *postgresql
|
41
|
+
|
28
42
|
postgis:
|
29
43
|
<<: *postgresql
|
30
44
|
|
31
|
-
|
45
|
+
seamless_database_pool:
|
32
46
|
<<: *common
|
33
|
-
adapter:
|
34
|
-
|
47
|
+
adapter: seamless_database_pool
|
48
|
+
pool_adapter: mysql2
|
49
|
+
prepared_statements: false
|
50
|
+
master:
|
51
|
+
host: localhost
|
35
52
|
|
36
53
|
sqlite:
|
37
54
|
adapter: sqlite
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-import
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Dennis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '3.
|
19
|
+
version: '3.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '3.
|
26
|
+
version: '3.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -69,7 +69,6 @@ files:
|
|
69
69
|
- benchmarks/models/test_memory.rb
|
70
70
|
- benchmarks/models/test_myisam.rb
|
71
71
|
- benchmarks/schema/mysql_schema.rb
|
72
|
-
- gemfiles/3.1.gemfile
|
73
72
|
- gemfiles/3.2.gemfile
|
74
73
|
- gemfiles/4.0.gemfile
|
75
74
|
- gemfiles/4.1.gemfile
|
@@ -100,9 +99,11 @@ files:
|
|
100
99
|
- test/adapters/jdbcmysql.rb
|
101
100
|
- test/adapters/jdbcpostgresql.rb
|
102
101
|
- test/adapters/mysql2.rb
|
102
|
+
- test/adapters/mysql2_makara.rb
|
103
103
|
- test/adapters/mysql2spatial.rb
|
104
104
|
- test/adapters/postgis.rb
|
105
105
|
- test/adapters/postgresql.rb
|
106
|
+
- test/adapters/postgresql_makara.rb
|
106
107
|
- test/adapters/seamless_database_pool.rb
|
107
108
|
- test/adapters/spatialite.rb
|
108
109
|
- test/adapters/sqlite3.rb
|
@@ -121,6 +122,7 @@ files:
|
|
121
122
|
- test/models/topic.rb
|
122
123
|
- test/models/widget.rb
|
123
124
|
- test/mysql2/import_test.rb
|
125
|
+
- test/mysql2_makara/import_test.rb
|
124
126
|
- test/mysqlspatial2/import_test.rb
|
125
127
|
- test/postgis/import_test.rb
|
126
128
|
- test/postgresql/import_test.rb
|
@@ -135,6 +137,7 @@ files:
|
|
135
137
|
- test/support/mysql/import_examples.rb
|
136
138
|
- test/support/postgresql/import_examples.rb
|
137
139
|
- test/support/shared_examples/on_duplicate_key_update.rb
|
140
|
+
- test/support/shared_examples/recursive_import.rb
|
138
141
|
- test/synchronize_test.rb
|
139
142
|
- test/test_helper.rb
|
140
143
|
- test/travis/database.yml
|
@@ -160,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
163
|
version: '0'
|
161
164
|
requirements: []
|
162
165
|
rubyforge_project:
|
163
|
-
rubygems_version: 2.
|
166
|
+
rubygems_version: 2.5.1
|
164
167
|
signing_key:
|
165
168
|
specification_version: 4
|
166
169
|
summary: Bulk-loading extension for ActiveRecord
|
@@ -168,9 +171,11 @@ test_files:
|
|
168
171
|
- test/adapters/jdbcmysql.rb
|
169
172
|
- test/adapters/jdbcpostgresql.rb
|
170
173
|
- test/adapters/mysql2.rb
|
174
|
+
- test/adapters/mysql2_makara.rb
|
171
175
|
- test/adapters/mysql2spatial.rb
|
172
176
|
- test/adapters/postgis.rb
|
173
177
|
- test/adapters/postgresql.rb
|
178
|
+
- test/adapters/postgresql_makara.rb
|
174
179
|
- test/adapters/seamless_database_pool.rb
|
175
180
|
- test/adapters/spatialite.rb
|
176
181
|
- test/adapters/sqlite3.rb
|
@@ -189,6 +194,7 @@ test_files:
|
|
189
194
|
- test/models/topic.rb
|
190
195
|
- test/models/widget.rb
|
191
196
|
- test/mysql2/import_test.rb
|
197
|
+
- test/mysql2_makara/import_test.rb
|
192
198
|
- test/mysqlspatial2/import_test.rb
|
193
199
|
- test/postgis/import_test.rb
|
194
200
|
- test/postgresql/import_test.rb
|
@@ -203,6 +209,7 @@ test_files:
|
|
203
209
|
- test/support/mysql/import_examples.rb
|
204
210
|
- test/support/postgresql/import_examples.rb
|
205
211
|
- test/support/shared_examples/on_duplicate_key_update.rb
|
212
|
+
- test/support/shared_examples/recursive_import.rb
|
206
213
|
- test/synchronize_test.rb
|
207
214
|
- test/test_helper.rb
|
208
215
|
- test/travis/database.yml
|
data/gemfiles/3.1.gemfile
DELETED