activerecord-import 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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