activerecord-import 0.16.2 → 0.17.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 +5 -13
- data/.travis.yml +1 -0
- data/CHANGELOG.md +17 -1
- data/Gemfile +1 -0
- data/Rakefile +1 -0
- data/benchmarks/benchmark.rb +1 -0
- data/gemfiles/3.2.gemfile +2 -3
- data/gemfiles/4.0.gemfile +2 -3
- data/gemfiles/4.1.gemfile +2 -3
- data/gemfiles/4.2.gemfile +2 -7
- data/gemfiles/5.0.gemfile +2 -3
- data/lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb +6 -0
- data/lib/activerecord-import/adapters/mysql_adapter.rb +1 -1
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +16 -3
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +2 -16
- data/lib/activerecord-import/import.rb +43 -8
- data/lib/activerecord-import/value_sets_parser.rb +11 -3
- data/lib/activerecord-import/version.rb +1 -1
- data/test/adapters/jdbcsqlite3.rb +1 -0
- data/test/import_test.rb +40 -0
- data/test/jdbcmysql/import_test.rb +0 -1
- data/test/jdbcpostgresql/import_test.rb +0 -1
- data/test/jdbcsqlite3/import_test.rb +4 -0
- data/test/models/book.rb +2 -0
- data/test/models/dictionary.rb +2 -0
- data/test/models/tag.rb +4 -0
- data/test/postgresql/import_test.rb +0 -4
- data/test/schema/generic_schema.rb +11 -0
- data/test/sqlite3/import_test.rb +2 -65
- data/test/support/postgresql/import_examples.rb +4 -0
- data/test/support/shared_examples/on_duplicate_key_ignore.rb +12 -0
- data/test/support/shared_examples/on_duplicate_key_update.rb +12 -0
- data/test/support/sqlite3/import_examples.rb +67 -0
- data/test/test_helper.rb +1 -0
- data/test/travis/database.yml +4 -0
- metadata +22 -13
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MDRjY2QxYTc1NmViOGI5MDM1Yjg5ODY1YmY3ZjU0ZGJkMGRiOTFhZA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8a9d274345964888ca0c5b9242a689d3953271c7
|
4
|
+
data.tar.gz: 59dcdf278fec2582d2e44a7fb416d355026856a5
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
ZTk2NGFkNjc1MjVkOGE2MGQyNTM2OTc1N2YzYjQyYmFlNjA0M2FhNjRiMDEz
|
11
|
-
YTgyNTk4MjIxOTUwYzYwOWM1ZmE5ZGQ0NDcyODkzNGNkNGYwMWU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZmRlNTc0NjhhNmYxZmNiNDFjNzZlNTM1ODcxNTNiNzE3NmUyYjhjMjliYjU4
|
14
|
-
MGY5NmYyN2JhY2FjMmQ3ZWFiODE3ZTY3OTgxMDA5M2Y5MTkwZjIyNWU2Y2Ni
|
15
|
-
MWUyYTRlODNiMzg1YzYyNDEzMmFjZTBhZTEwMzFkZGU0MDI5ZTE=
|
6
|
+
metadata.gz: 96f341704f5a40797d626039985e52813d01087e9d41427ef375b5c383c1ce7f22cfac0120939e52ea037b86d84c8ae491ea098f82c2bcc6a94fea34a823dd02
|
7
|
+
data.tar.gz: 4d0f4890f4b97ea9c3d36bf8971d6334ab880d235eda6c14a2af7a8395900562fdb09fd2127c55d3283f48a8734e543671eb2ce0734b1f91689faa95a7bbff56
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## Changes in 0.17.0
|
2
|
+
|
3
|
+
### New Features
|
4
|
+
|
5
|
+
* Add support for composite_primary_keys gem. Thanks to @jkowens
|
6
|
+
via \#350.
|
7
|
+
* Add support for importing an array of hashes. Thanks to @jkowens
|
8
|
+
via \#352.
|
9
|
+
* Add JDBC SQLite3 support. Thanks to @jkowens via \#356.
|
10
|
+
|
11
|
+
### Fixes
|
12
|
+
|
13
|
+
* Remove support for SQLite recursive imports. See \#351.
|
14
|
+
* Improve import speed for Rails 5. Thanks to @ranchodeluxe, @jkowens
|
15
|
+
via \#359.
|
16
|
+
|
1
17
|
## Changes in 0.16.2
|
2
18
|
|
3
19
|
### Fixes
|
@@ -28,7 +44,7 @@
|
|
28
44
|
* Add store accessor support for JSON, JSON, and HSTORE data types.
|
29
45
|
Thanks to @jkowens via \#322
|
30
46
|
* Log warning if database does not support :on_duplicate_key_update.
|
31
|
-
Thanks to @jkowens
|
47
|
+
Thanks to @jkowens via \#324
|
32
48
|
* Add option :on_duplicate_key_ignore for MySQL and SQLite. Thanks to
|
33
49
|
@jkowens via \#326
|
34
50
|
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/benchmarks/benchmark.rb
CHANGED
data/gemfiles/3.2.gemfile
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
end
|
1
|
+
gem 'activerecord', '~> 3.2.0'
|
2
|
+
gem 'composite_primary_keys', '~> 5.0'
|
data/gemfiles/4.0.gemfile
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
end
|
1
|
+
gem 'activerecord', '~> 4.0.0'
|
2
|
+
gem 'composite_primary_keys', '~> 6.0'
|
data/gemfiles/4.1.gemfile
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
end
|
1
|
+
gem 'activerecord', '~> 4.1.0'
|
2
|
+
gem 'composite_primary_keys', '~> 7.0'
|
data/gemfiles/4.2.gemfile
CHANGED
data/gemfiles/5.0.gemfile
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
end
|
1
|
+
gem 'activerecord', '~> 5.0.0'
|
2
|
+
gem 'composite_primary_keys', '~> 9.0'
|
@@ -31,7 +31,7 @@ module ActiveRecord::Import::MysqlAdapter
|
|
31
31
|
max = max_allowed_packet
|
32
32
|
|
33
33
|
# if we can insert it all as one statement
|
34
|
-
if NO_MAX_PACKET == max || total_bytes
|
34
|
+
if NO_MAX_PACKET == max || total_bytes <= max
|
35
35
|
number_of_inserts += 1
|
36
36
|
sql2insert = base_sql + values.join( ',' ) + post_sql
|
37
37
|
insert( sql2insert, *args )
|
@@ -44,7 +44,8 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
44
44
|
sql += super(table_name, options)
|
45
45
|
|
46
46
|
unless options[:no_returning] || options[:primary_key].blank?
|
47
|
-
|
47
|
+
primary_key = Array(options[:primary_key])
|
48
|
+
sql << " RETURNING (#{primary_key.join(', ')})"
|
48
49
|
end
|
49
50
|
|
50
51
|
sql
|
@@ -136,8 +137,20 @@ module ActiveRecord::Import::PostgreSQLAdapter
|
|
136
137
|
end
|
137
138
|
|
138
139
|
def sql_for_default_conflict_target( table_name )
|
139
|
-
|
140
|
-
|
140
|
+
pks = select_values(<<-SQL.strip_heredoc, "SCHEMA")
|
141
|
+
WITH pk_constraint AS (
|
142
|
+
SELECT conrelid, unnest(conkey) AS connum FROM pg_constraint
|
143
|
+
WHERE contype = 'p'
|
144
|
+
AND conrelid = #{quote(quote_table_name(table_name))}::regclass
|
145
|
+
), cons AS (
|
146
|
+
SELECT conrelid, connum, row_number() OVER() AS rownum FROM pk_constraint
|
147
|
+
)
|
148
|
+
SELECT attr.attname FROM pg_attribute attr
|
149
|
+
INNER JOIN cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.connum
|
150
|
+
ORDER BY cons.rownum
|
151
|
+
SQL
|
152
|
+
conflict_target = pks.join(', ')
|
153
|
+
"(#{conflict_target}) " if conflict_target.present?
|
141
154
|
end
|
142
155
|
|
143
156
|
# Return true if the statement is a duplicate key record error
|
@@ -19,7 +19,6 @@ 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
23
|
base_sql, post_sql = if sql.is_a?( String )
|
25
24
|
[sql, '']
|
@@ -34,15 +33,11 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
34
33
|
value_sets.each do |value_set|
|
35
34
|
number_of_inserts += 1
|
36
35
|
sql2insert = base_sql + value_set.join( ',' ) + post_sql
|
37
|
-
|
38
|
-
if last_insert_id > 0
|
39
|
-
first_insert_id = last_insert_id - affected_rows + 1
|
40
|
-
ids.concat((first_insert_id..last_insert_id).to_a)
|
41
|
-
end
|
36
|
+
insert( sql2insert, *args )
|
42
37
|
end
|
43
38
|
end
|
44
39
|
|
45
|
-
[number_of_inserts,
|
40
|
+
[number_of_inserts, []]
|
46
41
|
end
|
47
42
|
|
48
43
|
def pre_sql_statements( options)
|
@@ -57,13 +52,4 @@ module ActiveRecord::Import::SQLite3Adapter
|
|
57
52
|
def next_value_for_sequence(sequence_name)
|
58
53
|
%{nextval('#{sequence_name}')}
|
59
54
|
end
|
60
|
-
|
61
|
-
def affected_rows
|
62
|
-
result = execute('SELECT changes();')
|
63
|
-
result.first[0]
|
64
|
-
end
|
65
|
-
|
66
|
-
def support_setting_primary_key_of_imported_objects?
|
67
|
-
true
|
68
|
-
end
|
69
55
|
end
|
@@ -144,6 +144,9 @@ class ActiveRecord::Base
|
|
144
144
|
#
|
145
145
|
# == Usage
|
146
146
|
# Model.import array_of_models
|
147
|
+
# Model.import column_names, array_of_models
|
148
|
+
# Model.import array_of_hash_objects
|
149
|
+
# Model.import column_names, array_of_hash_objects
|
147
150
|
# Model.import column_names, array_of_values
|
148
151
|
# Model.import column_names, array_of_values, options
|
149
152
|
#
|
@@ -187,7 +190,7 @@ class ActiveRecord::Base
|
|
187
190
|
# (if false) even if record timestamps is disabled in ActiveRecord::Base
|
188
191
|
# * +recursive+ - true|false, tells import to import all has_many/has_one
|
189
192
|
# associations if the adapter supports setting the primary keys of the
|
190
|
-
# newly imported objects.
|
193
|
+
# newly imported objects. PostgreSQL only.
|
191
194
|
# * +batch_size+ - an integer value to specify the max number of records to
|
192
195
|
# include per insert. Defaults to the total number of records to import.
|
193
196
|
#
|
@@ -200,6 +203,15 @@ class ActiveRecord::Base
|
|
200
203
|
# BlogPost.new author_name: 'Zach Dennis', title: 'AREXT3' ]
|
201
204
|
# BlogPost.import posts
|
202
205
|
#
|
206
|
+
# # Example using array_of_hash_objects
|
207
|
+
# values = [ {author_name: 'zdennis', title: 'test post'} ], [ {author_name: 'jdoe', title: 'another test post'} ] ]
|
208
|
+
# BlogPost.import values
|
209
|
+
#
|
210
|
+
# # Example using column_names and array_of_hash_objects
|
211
|
+
# columns = [ :author_name, :title ]
|
212
|
+
# values = [ {author_name: 'zdennis', title: 'test post'} ], [ {author_name: 'jdoe', title: 'another test post'} ] ]
|
213
|
+
# BlogPost.import columns, values
|
214
|
+
#
|
203
215
|
# # Example using column_names and array_of_values
|
204
216
|
# columns = [ :author_name, :title ]
|
205
217
|
# values = [ [ 'zdennis', 'test post' ], [ 'jdoe', 'another test post' ] ]
|
@@ -382,6 +394,21 @@ class ActiveRecord::Base
|
|
382
394
|
end
|
383
395
|
end
|
384
396
|
end
|
397
|
+
# supports array of hash objects
|
398
|
+
elsif args.last.is_a?( Array ) && args.last.first.is_a?(Hash)
|
399
|
+
if args.length == 2
|
400
|
+
array_of_hashes = args.last
|
401
|
+
column_names = args.first.dup
|
402
|
+
else
|
403
|
+
array_of_hashes = args.first
|
404
|
+
column_names = array_of_hashes.first.keys
|
405
|
+
end
|
406
|
+
|
407
|
+
array_of_attributes = array_of_hashes.map do |h|
|
408
|
+
column_names.map do |key|
|
409
|
+
h[key]
|
410
|
+
end
|
411
|
+
end
|
385
412
|
# supports empty array
|
386
413
|
elsif args.last.is_a?( Array ) && args.last.empty?
|
387
414
|
return ActiveRecord::Import::Result.new([], 0, [])
|
@@ -404,9 +431,15 @@ class ActiveRecord::Base
|
|
404
431
|
# Force the primary key col into the insert if it's not
|
405
432
|
# on the list and we are using a sequence and stuff a nil
|
406
433
|
# value for it into each row so the sequencer will fire later
|
407
|
-
|
408
|
-
|
409
|
-
|
434
|
+
symbolized_column_names = Array(column_names).map(&:to_sym)
|
435
|
+
symbolized_primary_key = Array(primary_key).map(&:to_sym)
|
436
|
+
|
437
|
+
if !symbolized_primary_key.to_set.subset?(symbolized_column_names.to_set) && connection.prefetch_primary_key? && sequence_name
|
438
|
+
column_count = column_names.size
|
439
|
+
column_names.concat(primary_key).uniq!
|
440
|
+
columns_added = column_names.size - column_count
|
441
|
+
new_fields = Array.new(columns_added)
|
442
|
+
array_of_attributes.each { |a| a.concat(new_fields) }
|
410
443
|
end
|
411
444
|
|
412
445
|
# record timestamps unless disabled in ActiveRecord::Base
|
@@ -626,9 +659,11 @@ class ActiveRecord::Base
|
|
626
659
|
# Returns SQL the VALUES for an INSERT statement given the passed in +columns+
|
627
660
|
# and +array_of_attributes+.
|
628
661
|
def values_sql_for_columns_and_attributes(columns, array_of_attributes) # :nodoc:
|
629
|
-
# connection
|
630
|
-
# Reuse the same
|
662
|
+
# connection and type_caster get called a *lot* in this high intensity loop.
|
663
|
+
# Reuse the same ones w/in the loop, otherwise they would keep being re-retreived (= lots of time for large imports)
|
631
664
|
connection_memo = connection
|
665
|
+
type_caster_memo = type_caster if respond_to?(:type_caster)
|
666
|
+
|
632
667
|
array_of_attributes.map do |arr|
|
633
668
|
my_values = arr.each_with_index.map do |val, j|
|
634
669
|
column = columns[j]
|
@@ -637,8 +672,8 @@ class ActiveRecord::Base
|
|
637
672
|
if val.nil? && column.name == primary_key && !sequence_name.blank?
|
638
673
|
connection_memo.next_value_for_sequence(sequence_name)
|
639
674
|
elsif column
|
640
|
-
if
|
641
|
-
connection_memo.quote(
|
675
|
+
if defined?(type_caster_memo) && type_caster_memo.respond_to?(:type_cast_for_database) # Rails 5.0 and higher
|
676
|
+
connection_memo.quote(type_caster_memo.type_cast_for_database(column.name, val))
|
642
677
|
elsif column.respond_to?(:type_cast_from_user) # Rails 4.2 and higher
|
643
678
|
connection_memo.quote(column.type_cast_from_user(val), column)
|
644
679
|
else # Rails 3.2, 4.0 and 4.1
|
@@ -8,8 +8,8 @@ module ActiveRecord::Import
|
|
8
8
|
|
9
9
|
def initialize(values, options)
|
10
10
|
@values = values
|
11
|
-
@reserved_bytes = options[:reserved_bytes]
|
12
|
-
@max_bytes = options
|
11
|
+
@reserved_bytes = options[:reserved_bytes] || 0
|
12
|
+
@max_bytes = options.fetch(:max_bytes) { default_max_bytes }
|
13
13
|
end
|
14
14
|
|
15
15
|
def parse
|
@@ -32,7 +32,15 @@ module ActiveRecord::Import
|
|
32
32
|
value_sets << arr if i == (values.size - 1)
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
value_sets
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def default_max_bytes
|
41
|
+
values_in_bytes = values.sum(&:bytesize)
|
42
|
+
comma_separated_bytes = values.size - 1
|
43
|
+
reserved_bytes + values_in_bytes + comma_separated_bytes
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
@@ -0,0 +1 @@
|
|
1
|
+
ENV["ARE_DB"] = "jdbcsqlite3"
|
data/test/import_test.rb
CHANGED
@@ -59,6 +59,46 @@ describe "#import" do
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
describe "with an array of hashes" do
|
63
|
+
let(:columns) { [:title, :author_name] }
|
64
|
+
let(:values) { [{ title: "LDAP", author_name: "Jerry Carter", author_email_address: "jcarter@test.com" }, { title: "Rails Recipes", author_name: "Chad Fowler", author_email_address: "cfowler@test.com" }] }
|
65
|
+
|
66
|
+
it "should import hash data successfully" do
|
67
|
+
assert_difference "Topic.count", +2 do
|
68
|
+
Topic.import values, validate: false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should import specified hash data successfully" do
|
73
|
+
assert_difference "Topic.count", +2 do
|
74
|
+
Topic.import columns, values, validate: false
|
75
|
+
end
|
76
|
+
|
77
|
+
Topic.all.each do |t|
|
78
|
+
assert_nil t.author_email_address
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "with composite primary keys" do
|
84
|
+
it "should import models successfully" do
|
85
|
+
tags = [Tag.new(tag_id: 1, publisher_id: 1, tag: 'Mystery')]
|
86
|
+
|
87
|
+
assert_difference "Tag.count", +1 do
|
88
|
+
Tag.import tags
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should import array of values successfully" do
|
93
|
+
columns = [:tag_id, :publisher_id, :tag]
|
94
|
+
values = [[1, 1, 'Mystery'], [2, 1, 'Science']]
|
95
|
+
|
96
|
+
assert_difference "Tag.count", +2 do
|
97
|
+
Tag.import columns, values, validate: false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
62
102
|
describe "with STI models" do
|
63
103
|
it "should import models successfully" do
|
64
104
|
dictionaries = [Dictionary.new(author_name: "Noah Webster", title: "Webster's Dictionary")]
|
data/test/models/book.rb
CHANGED
data/test/models/dictionary.rb
CHANGED
data/test/models/tag.rb
ADDED
@@ -2,7 +2,3 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
2
2
|
require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
|
3
3
|
|
4
4
|
should_support_postgresql_import_functionality
|
5
|
-
|
6
|
-
if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
|
7
|
-
should_support_postgresql_upsert_functionality
|
8
|
-
end
|
@@ -62,6 +62,8 @@ ActiveRecord::Schema.define do
|
|
62
62
|
t.datetime :updated_on
|
63
63
|
t.date :publish_date
|
64
64
|
t.integer :topic_id
|
65
|
+
t.integer :tag_id
|
66
|
+
t.integer :publisher_id
|
65
67
|
t.boolean :for_sale, default: true
|
66
68
|
t.integer :status, default: 0
|
67
69
|
t.string :type
|
@@ -151,4 +153,13 @@ ActiveRecord::Schema.define do
|
|
151
153
|
t.text :config
|
152
154
|
t.text :settings
|
153
155
|
end
|
156
|
+
|
157
|
+
execute %(
|
158
|
+
CREATE TABLE IF NOT EXISTS tags (
|
159
|
+
tag_id INT NOT NULL,
|
160
|
+
publisher_id INT NOT NULL,
|
161
|
+
tag VARCHAR(50),
|
162
|
+
PRIMARY KEY (tag_id, publisher_id)
|
163
|
+
);
|
164
|
+
).split.join(' ').strip
|
154
165
|
end
|
data/test/sqlite3/import_test.rb
CHANGED
@@ -1,67 +1,4 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../support/sqlite3/import_examples')
|
2
3
|
|
3
|
-
|
4
|
-
should_support_on_duplicate_key_ignore
|
5
|
-
|
6
|
-
describe "#supports_imports?" do
|
7
|
-
context "and SQLite is 3.7.11 or higher" do
|
8
|
-
it "supports import" do
|
9
|
-
version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.11")
|
10
|
-
assert ActiveRecord::Base.supports_import?(version)
|
11
|
-
|
12
|
-
version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.12")
|
13
|
-
assert ActiveRecord::Base.supports_import?(version)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
context "and SQLite less than 3.7.11" do
|
18
|
-
it "doesn't support import" do
|
19
|
-
version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.10")
|
20
|
-
assert !ActiveRecord::Base.supports_import?(version)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
describe "#import" do
|
26
|
-
it "imports with a single insert on SQLite 3.7.11 or higher" do
|
27
|
-
assert_difference "Topic.count", +507 do
|
28
|
-
result = Topic.import Build(7, :topics)
|
29
|
-
assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
30
|
-
assert_equal 7, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
31
|
-
|
32
|
-
result = Topic.import Build(500, :topics)
|
33
|
-
assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
34
|
-
assert_equal 507, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
it "imports with a two inserts on SQLite 3.7.11 or higher" do
|
39
|
-
assert_difference "Topic.count", +501 do
|
40
|
-
result = Topic.import Build(501, :topics)
|
41
|
-
assert_equal 2, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
42
|
-
assert_equal 501, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
it "imports with a five inserts on SQLite 3.7.11 or higher" do
|
47
|
-
assert_difference "Topic.count", +2500 do
|
48
|
-
result = Topic.import Build(2500, :topics)
|
49
|
-
assert_equal 5, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
50
|
-
assert_equal 2500, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
context "with :on_duplicate_key_update" do
|
55
|
-
let(:topics) { Build(1, :topics) }
|
56
|
-
|
57
|
-
it "should log a warning message" do
|
58
|
-
log = StringIO.new
|
59
|
-
logger = Logger.new(log)
|
60
|
-
logger.level = Logger::WARN
|
61
|
-
ActiveRecord::Base.connection.stubs(:logger).returns(logger)
|
62
|
-
|
63
|
-
Topic.import topics, on_duplicate_key_update: true
|
64
|
-
assert_match(/Ignoring on_duplicate_key_update/, log.string)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
4
|
+
should_support_sqlite3_import_functionality
|
@@ -2,6 +2,10 @@
|
|
2
2
|
def should_support_postgresql_import_functionality
|
3
3
|
should_support_recursive_import
|
4
4
|
|
5
|
+
if ActiveRecord::Base.connection.supports_on_duplicate_key_update?
|
6
|
+
should_support_postgresql_upsert_functionality
|
7
|
+
end
|
8
|
+
|
5
9
|
describe "#supports_imports?" do
|
6
10
|
it "should support import" do
|
7
11
|
assert ActiveRecord::Base.supports_import?
|
@@ -11,6 +11,18 @@ def should_support_on_duplicate_key_ignore
|
|
11
11
|
Topic.import topics, on_duplicate_key_ignore: true, validate: false
|
12
12
|
end
|
13
13
|
end
|
14
|
+
|
15
|
+
context "with composite primary keys" do
|
16
|
+
it "should import array of values successfully" do
|
17
|
+
columns = [:tag_id, :publisher_id, :tag]
|
18
|
+
values = [[1, 1, 'Mystery'], [1, 1, 'Science']]
|
19
|
+
|
20
|
+
assert_difference "Tag.count", +1 do
|
21
|
+
Tag.import columns, values, on_duplicate_key_ignore: true, validate: false
|
22
|
+
end
|
23
|
+
assert_equal 'Mystery', Tag.first.tag
|
24
|
+
end
|
25
|
+
end
|
14
26
|
end
|
15
27
|
|
16
28
|
context "with :ignore" do
|
@@ -76,6 +76,18 @@ def should_support_basic_on_duplicate_key_update
|
|
76
76
|
assert_equal 'DISCOUNT2', updated_promotion.code
|
77
77
|
end
|
78
78
|
end
|
79
|
+
|
80
|
+
context "with composite primary keys" do
|
81
|
+
it "should import array of values successfully" do
|
82
|
+
columns = [:tag_id, :publisher_id, :tag]
|
83
|
+
Tag.import columns, [[1, 1, 'Mystery']], validate: false
|
84
|
+
|
85
|
+
assert_difference "Tag.count", +0 do
|
86
|
+
Tag.import columns, [[1, 1, 'Science']], on_duplicate_key_update: [:tag], validate: false
|
87
|
+
end
|
88
|
+
assert_equal 'Science', Tag.first.tag
|
89
|
+
end
|
90
|
+
end
|
79
91
|
end
|
80
92
|
|
81
93
|
context "with :on_duplicate_key_update turned off" do
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
def should_support_sqlite3_import_functionality
|
3
|
+
should_support_on_duplicate_key_ignore
|
4
|
+
|
5
|
+
describe "#supports_imports?" do
|
6
|
+
context "and SQLite is 3.7.11 or higher" do
|
7
|
+
it "supports import" do
|
8
|
+
version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.11")
|
9
|
+
assert ActiveRecord::Base.supports_import?(version)
|
10
|
+
|
11
|
+
version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.12")
|
12
|
+
assert ActiveRecord::Base.supports_import?(version)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "and SQLite less than 3.7.11" do
|
17
|
+
it "doesn't support import" do
|
18
|
+
version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.10")
|
19
|
+
assert !ActiveRecord::Base.supports_import?(version)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#import" do
|
25
|
+
it "imports with a single insert on SQLite 3.7.11 or higher" do
|
26
|
+
assert_difference "Topic.count", +507 do
|
27
|
+
result = Topic.import Build(7, :topics)
|
28
|
+
assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
29
|
+
assert_equal 7, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
30
|
+
|
31
|
+
result = Topic.import Build(500, :topics)
|
32
|
+
assert_equal 1, result.num_inserts, "Failed to issue a single INSERT statement. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
33
|
+
assert_equal 507, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "imports with a two inserts on SQLite 3.7.11 or higher" do
|
38
|
+
assert_difference "Topic.count", +501 do
|
39
|
+
result = Topic.import Build(501, :topics)
|
40
|
+
assert_equal 2, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
41
|
+
assert_equal 501, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "imports with a five inserts on SQLite 3.7.11 or higher" do
|
46
|
+
assert_difference "Topic.count", +2500 do
|
47
|
+
result = Topic.import Build(2500, :topics)
|
48
|
+
assert_equal 5, result.num_inserts, "Failed to issue a two INSERT statements. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
49
|
+
assert_equal 2500, Topic.count, "Failed to insert all records. Make sure you have a supported version of SQLite3 (3.7.11 or higher) installed"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "with :on_duplicate_key_update" do
|
54
|
+
let(:topics) { Build(1, :topics) }
|
55
|
+
|
56
|
+
it "should log a warning message" do
|
57
|
+
log = StringIO.new
|
58
|
+
logger = Logger.new(log)
|
59
|
+
logger.level = Logger::WARN
|
60
|
+
ActiveRecord::Base.connection.stubs(:logger).returns(logger)
|
61
|
+
|
62
|
+
Topic.import topics, on_duplicate_key_update: true
|
63
|
+
assert_match(/Ignoring on_duplicate_key_update/, log.string)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/test/test_helper.rb
CHANGED
data/test/travis/database.yml
CHANGED
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-import
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.17.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:
|
11
|
+
date: 2017-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
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
26
|
version: '3.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description: Extraction of the ActiveRecord::Base#import functionality from ar-extensions
|
@@ -46,10 +46,10 @@ executables: []
|
|
46
46
|
extensions: []
|
47
47
|
extra_rdoc_files: []
|
48
48
|
files:
|
49
|
-
- .gitignore
|
50
|
-
- .rubocop.yml
|
51
|
-
- .rubocop_todo.yml
|
52
|
-
- .travis.yml
|
49
|
+
- ".gitignore"
|
50
|
+
- ".rubocop.yml"
|
51
|
+
- ".rubocop_todo.yml"
|
52
|
+
- ".travis.yml"
|
53
53
|
- Brewfile
|
54
54
|
- CHANGELOG.md
|
55
55
|
- Gemfile
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- lib/activerecord-import/active_record/adapters/abstract_adapter.rb
|
79
79
|
- lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb
|
80
80
|
- lib/activerecord-import/active_record/adapters/jdbcpostgresql_adapter.rb
|
81
|
+
- lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb
|
81
82
|
- lib/activerecord-import/active_record/adapters/mysql2_adapter.rb
|
82
83
|
- lib/activerecord-import/active_record/adapters/postgresql_adapter.rb
|
83
84
|
- lib/activerecord-import/active_record/adapters/seamless_database_pool_adapter.rb
|
@@ -98,6 +99,7 @@ files:
|
|
98
99
|
- lib/activerecord-import/version.rb
|
99
100
|
- test/adapters/jdbcmysql.rb
|
100
101
|
- test/adapters/jdbcpostgresql.rb
|
102
|
+
- test/adapters/jdbcsqlite3.rb
|
101
103
|
- test/adapters/mysql2.rb
|
102
104
|
- test/adapters/mysql2_makara.rb
|
103
105
|
- test/adapters/mysql2spatial.rb
|
@@ -111,6 +113,7 @@ files:
|
|
111
113
|
- test/import_test.rb
|
112
114
|
- test/jdbcmysql/import_test.rb
|
113
115
|
- test/jdbcpostgresql/import_test.rb
|
116
|
+
- test/jdbcsqlite3/import_test.rb
|
114
117
|
- test/models/alarm.rb
|
115
118
|
- test/models/book.rb
|
116
119
|
- test/models/chapter.rb
|
@@ -121,6 +124,7 @@ files:
|
|
121
124
|
- test/models/promotion.rb
|
122
125
|
- test/models/question.rb
|
123
126
|
- test/models/rule.rb
|
127
|
+
- test/models/tag.rb
|
124
128
|
- test/models/topic.rb
|
125
129
|
- test/models/vendor.rb
|
126
130
|
- test/models/widget.rb
|
@@ -145,6 +149,7 @@ files:
|
|
145
149
|
- test/support/shared_examples/on_duplicate_key_ignore.rb
|
146
150
|
- test/support/shared_examples/on_duplicate_key_update.rb
|
147
151
|
- test/support/shared_examples/recursive_import.rb
|
152
|
+
- test/support/sqlite3/import_examples.rb
|
148
153
|
- test/synchronize_test.rb
|
149
154
|
- test/test_helper.rb
|
150
155
|
- test/travis/database.yml
|
@@ -160,23 +165,24 @@ require_paths:
|
|
160
165
|
- lib
|
161
166
|
required_ruby_version: !ruby/object:Gem::Requirement
|
162
167
|
requirements:
|
163
|
-
- -
|
168
|
+
- - ">="
|
164
169
|
- !ruby/object:Gem::Version
|
165
170
|
version: 1.9.2
|
166
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
172
|
requirements:
|
168
|
-
- -
|
173
|
+
- - ">="
|
169
174
|
- !ruby/object:Gem::Version
|
170
175
|
version: '0'
|
171
176
|
requirements: []
|
172
177
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
178
|
+
rubygems_version: 2.6.2
|
174
179
|
signing_key:
|
175
180
|
specification_version: 4
|
176
181
|
summary: Bulk-loading extension for ActiveRecord
|
177
182
|
test_files:
|
178
183
|
- test/adapters/jdbcmysql.rb
|
179
184
|
- test/adapters/jdbcpostgresql.rb
|
185
|
+
- test/adapters/jdbcsqlite3.rb
|
180
186
|
- test/adapters/mysql2.rb
|
181
187
|
- test/adapters/mysql2_makara.rb
|
182
188
|
- test/adapters/mysql2spatial.rb
|
@@ -190,6 +196,7 @@ test_files:
|
|
190
196
|
- test/import_test.rb
|
191
197
|
- test/jdbcmysql/import_test.rb
|
192
198
|
- test/jdbcpostgresql/import_test.rb
|
199
|
+
- test/jdbcsqlite3/import_test.rb
|
193
200
|
- test/models/alarm.rb
|
194
201
|
- test/models/book.rb
|
195
202
|
- test/models/chapter.rb
|
@@ -200,6 +207,7 @@ test_files:
|
|
200
207
|
- test/models/promotion.rb
|
201
208
|
- test/models/question.rb
|
202
209
|
- test/models/rule.rb
|
210
|
+
- test/models/tag.rb
|
203
211
|
- test/models/topic.rb
|
204
212
|
- test/models/vendor.rb
|
205
213
|
- test/models/widget.rb
|
@@ -224,6 +232,7 @@ test_files:
|
|
224
232
|
- test/support/shared_examples/on_duplicate_key_ignore.rb
|
225
233
|
- test/support/shared_examples/on_duplicate_key_update.rb
|
226
234
|
- test/support/shared_examples/recursive_import.rb
|
235
|
+
- test/support/sqlite3/import_examples.rb
|
227
236
|
- test/synchronize_test.rb
|
228
237
|
- test/test_helper.rb
|
229
238
|
- test/travis/database.yml
|