activerecord-import 0.25.0 → 1.7.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 -5
- data/.github/workflows/test.yaml +151 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +74 -8
- data/.rubocop_todo.yml +10 -16
- data/Brewfile +3 -1
- data/CHANGELOG.md +232 -2
- data/Dockerfile +23 -0
- data/Gemfile +26 -14
- data/LICENSE +21 -56
- data/README.markdown +612 -21
- data/Rakefile +4 -1
- data/activerecord-import.gemspec +6 -5
- data/benchmarks/benchmark.rb +10 -4
- data/benchmarks/lib/base.rb +4 -2
- data/benchmarks/lib/cli_parser.rb +4 -2
- data/benchmarks/lib/float.rb +2 -0
- data/benchmarks/lib/mysql2_benchmark.rb +2 -0
- data/benchmarks/lib/output_to_csv.rb +2 -0
- data/benchmarks/lib/output_to_html.rb +4 -2
- data/benchmarks/models/test_innodb.rb +2 -0
- data/benchmarks/models/test_memory.rb +2 -0
- data/benchmarks/models/test_myisam.rb +2 -0
- data/benchmarks/schema/{mysql_schema.rb → mysql2_schema.rb} +2 -0
- data/docker-compose.yml +34 -0
- data/gemfiles/4.2.gemfile +2 -0
- data/gemfiles/5.0.gemfile +2 -0
- data/gemfiles/5.1.gemfile +2 -0
- data/gemfiles/5.2.gemfile +2 -0
- data/gemfiles/6.0.gemfile +4 -0
- data/gemfiles/6.1.gemfile +4 -0
- data/gemfiles/7.0.gemfile +4 -0
- data/gemfiles/7.1.gemfile +3 -0
- data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +6 -4
- data/lib/activerecord-import/active_record/adapters/jdbcpostgresql_adapter.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/postgresql_adapter.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/seamless_database_pool_adapter.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +2 -0
- data/lib/activerecord-import/active_record/adapters/trilogy_adapter.rb +8 -0
- data/lib/activerecord-import/adapters/abstract_adapter.rb +15 -6
- data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +2 -0
- data/lib/activerecord-import/adapters/mysql2_adapter.rb +2 -0
- data/lib/activerecord-import/adapters/mysql_adapter.rb +34 -29
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +74 -55
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +138 -13
- data/lib/activerecord-import/adapters/trilogy_adapter.rb +7 -0
- data/lib/activerecord-import/base.rb +11 -2
- data/lib/activerecord-import/import.rb +290 -114
- data/lib/activerecord-import/mysql2.rb +2 -0
- data/lib/activerecord-import/postgresql.rb +2 -0
- data/lib/activerecord-import/sqlite3.rb +2 -0
- data/lib/activerecord-import/synchronize.rb +4 -2
- data/lib/activerecord-import/value_sets_parser.rb +5 -0
- data/lib/activerecord-import/version.rb +3 -1
- data/lib/activerecord-import.rb +2 -1
- data/test/adapters/jdbcmysql.rb +2 -0
- data/test/adapters/jdbcpostgresql.rb +2 -0
- data/test/adapters/jdbcsqlite3.rb +2 -0
- data/test/adapters/makara_postgis.rb +2 -0
- data/test/adapters/mysql2.rb +2 -0
- data/test/adapters/mysql2_makara.rb +2 -0
- data/test/adapters/mysql2spatial.rb +2 -0
- data/test/adapters/postgis.rb +2 -0
- data/test/adapters/postgresql.rb +2 -0
- data/test/adapters/postgresql_makara.rb +2 -0
- data/test/adapters/seamless_database_pool.rb +2 -0
- data/test/adapters/spatialite.rb +2 -0
- data/test/adapters/sqlite3.rb +2 -0
- data/test/adapters/trilogy.rb +9 -0
- data/test/database.yml.sample +7 -0
- data/test/{travis → github}/database.yml +7 -1
- data/test/import_test.rb +151 -8
- data/test/jdbcmysql/import_test.rb +5 -3
- data/test/jdbcpostgresql/import_test.rb +4 -2
- data/test/jdbcsqlite3/import_test.rb +4 -2
- data/test/makara_postgis/import_test.rb +4 -2
- data/test/models/account.rb +2 -0
- data/test/models/alarm.rb +2 -0
- data/test/models/animal.rb +8 -0
- data/test/models/author.rb +7 -0
- data/test/models/bike_maker.rb +3 -0
- data/test/models/book.rb +7 -2
- data/test/models/car.rb +2 -0
- data/test/models/card.rb +5 -0
- data/test/models/chapter.rb +2 -0
- data/test/models/composite_book.rb +19 -0
- data/test/models/composite_chapter.rb +9 -0
- data/test/models/customer.rb +18 -0
- data/test/models/deck.rb +8 -0
- data/test/models/dictionary.rb +2 -0
- data/test/models/discount.rb +2 -0
- data/test/models/end_note.rb +2 -0
- data/test/models/group.rb +2 -0
- data/test/models/order.rb +17 -0
- data/test/models/playing_card.rb +4 -0
- data/test/models/promotion.rb +2 -0
- data/test/models/question.rb +2 -0
- data/test/models/rule.rb +2 -0
- data/test/models/tag.rb +9 -1
- data/test/models/tag_alias.rb +11 -0
- data/test/models/topic.rb +7 -0
- data/test/models/user.rb +2 -0
- data/test/models/user_token.rb +3 -0
- data/test/models/vendor.rb +2 -0
- data/test/models/widget.rb +2 -0
- data/test/mysql2/import_test.rb +5 -3
- data/test/mysql2_makara/import_test.rb +5 -3
- data/test/mysqlspatial2/import_test.rb +5 -3
- data/test/postgis/import_test.rb +4 -2
- data/test/postgresql/import_test.rb +4 -2
- data/test/schema/generic_schema.rb +37 -1
- data/test/schema/jdbcpostgresql_schema.rb +3 -1
- data/test/schema/mysql2_schema.rb +2 -0
- data/test/schema/postgis_schema.rb +3 -1
- data/test/schema/postgresql_schema.rb +49 -0
- data/test/schema/sqlite3_schema.rb +15 -0
- data/test/schema/version.rb +2 -0
- data/test/sqlite3/import_test.rb +4 -2
- data/test/support/active_support/test_case_extensions.rb +2 -0
- data/test/support/assertions.rb +2 -0
- data/test/support/factories.rb +10 -8
- data/test/support/generate.rb +10 -8
- data/test/support/mysql/import_examples.rb +2 -1
- data/test/support/postgresql/import_examples.rb +152 -3
- data/test/support/shared_examples/on_duplicate_key_ignore.rb +2 -0
- data/test/support/shared_examples/on_duplicate_key_update.rb +122 -9
- data/test/support/shared_examples/recursive_import.rb +128 -2
- data/test/support/sqlite3/import_examples.rb +191 -26
- data/test/synchronize_test.rb +2 -0
- data/test/test_helper.rb +34 -7
- data/test/trilogy/import_test.rb +7 -0
- data/test/value_sets_bytes_parser_test.rb +3 -1
- data/test/value_sets_records_parser_test.rb +3 -1
- metadata +46 -16
- data/.travis.yml +0 -71
- data/gemfiles/3.2.gemfile +0 -2
- data/gemfiles/4.0.gemfile +0 -2
- data/gemfiles/4.1.gemfile +0 -2
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActiveRecord # :nodoc:
|
|
2
4
|
class Base # :nodoc:
|
|
3
5
|
# Synchronizes the passed in ActiveRecord instances with data
|
|
@@ -39,8 +41,8 @@ module ActiveRecord # :nodoc:
|
|
|
39
41
|
|
|
40
42
|
next unless matched_instance
|
|
41
43
|
|
|
42
|
-
instance.
|
|
43
|
-
instance.send :
|
|
44
|
+
instance.instance_variable_set :@association_cache, {}
|
|
45
|
+
instance.send :clear_aggregation_cache if instance.respond_to?(:clear_aggregation_cache, true)
|
|
44
46
|
instance.instance_variable_set :@attributes, matched_instance.instance_variable_get(:@attributes)
|
|
45
47
|
|
|
46
48
|
if instance.respond_to?(:clear_changes_information)
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/array'
|
|
4
|
+
|
|
1
5
|
module ActiveRecord::Import
|
|
2
6
|
class ValueSetTooLargeError < StandardError
|
|
3
7
|
attr_reader :size
|
|
8
|
+
|
|
4
9
|
def initialize(msg = "Value set exceeds max size", size = 0)
|
|
5
10
|
@size = size
|
|
6
11
|
super(msg)
|
data/lib/activerecord-import.rb
CHANGED
data/test/adapters/jdbcmysql.rb
CHANGED
data/test/adapters/mysql2.rb
CHANGED
data/test/adapters/postgis.rb
CHANGED
data/test/adapters/postgresql.rb
CHANGED
data/test/adapters/spatialite.rb
CHANGED
data/test/adapters/sqlite3.rb
CHANGED
data/test/database.yml.sample
CHANGED
|
@@ -8,6 +8,7 @@ common: &common
|
|
|
8
8
|
mysql2: &mysql2
|
|
9
9
|
<<: *common
|
|
10
10
|
adapter: mysql2
|
|
11
|
+
host: mysql
|
|
11
12
|
|
|
12
13
|
mysql2spatial:
|
|
13
14
|
<<: *mysql2
|
|
@@ -19,6 +20,7 @@ postgresql: &postgresql
|
|
|
19
20
|
<<: *common
|
|
20
21
|
username: postgres
|
|
21
22
|
adapter: postgresql
|
|
23
|
+
host: postgresql
|
|
22
24
|
min_messages: warning
|
|
23
25
|
|
|
24
26
|
postresql_makara:
|
|
@@ -50,3 +52,8 @@ sqlite3: &sqlite3
|
|
|
50
52
|
|
|
51
53
|
spatialite:
|
|
52
54
|
<<: *sqlite3
|
|
55
|
+
|
|
56
|
+
trilogy:
|
|
57
|
+
<<: *common
|
|
58
|
+
adapter: trilogy
|
|
59
|
+
host: mysql
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
common: &common
|
|
2
2
|
username: root
|
|
3
|
-
password:
|
|
3
|
+
password: root
|
|
4
4
|
encoding: utf8
|
|
5
|
+
collation: utf8_general_ci
|
|
5
6
|
host: localhost
|
|
6
7
|
database: activerecord_import_test
|
|
7
8
|
|
|
@@ -37,6 +38,7 @@ oracle:
|
|
|
37
38
|
postgresql: &postgresql
|
|
38
39
|
<<: *common
|
|
39
40
|
username: postgres
|
|
41
|
+
password: postgres
|
|
40
42
|
adapter: postgresql
|
|
41
43
|
min_messages: warning
|
|
42
44
|
|
|
@@ -64,3 +66,7 @@ sqlite3: &sqlite3
|
|
|
64
66
|
|
|
65
67
|
spatialite:
|
|
66
68
|
<<: *sqlite3
|
|
69
|
+
|
|
70
|
+
trilogy:
|
|
71
|
+
<<: *common
|
|
72
|
+
adapter: trilogy
|
data/test/import_test.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require File.expand_path('../test_helper', __FILE__)
|
|
2
4
|
|
|
3
5
|
describe "#import" do
|
|
@@ -17,6 +19,11 @@ describe "#import" do
|
|
|
17
19
|
assert_equal error.message, "Last argument should be a two dimensional array '[[]]'. First element in array was a String"
|
|
18
20
|
end
|
|
19
21
|
|
|
22
|
+
it "warns you that you're passing more data than you ought to" do
|
|
23
|
+
error = assert_raise(ArgumentError) { Topic.import %w(title author_name), [['Author #1', 'Book #1', 0]] }
|
|
24
|
+
assert_equal error.message, "Number of values (8) exceeds number of columns (7)"
|
|
25
|
+
end
|
|
26
|
+
|
|
20
27
|
it "should not produce an error when importing empty arrays" do
|
|
21
28
|
assert_nothing_raised do
|
|
22
29
|
Topic.import []
|
|
@@ -154,6 +161,25 @@ describe "#import" do
|
|
|
154
161
|
Tag.import columns, values, validate: false
|
|
155
162
|
end
|
|
156
163
|
end
|
|
164
|
+
|
|
165
|
+
it "should import models that are required to belong to models with composite primary keys" do
|
|
166
|
+
tag = Tag.create!(tag_id: 1, publisher_id: 1, tag: 'Mystery')
|
|
167
|
+
valid_tag_alias = TagAlias.new(tag_id: tag.tag_id, parent_id: tag.publisher_id, alias: 'Detective')
|
|
168
|
+
invalid_tag_aliases = [
|
|
169
|
+
TagAlias.new(tag_id: nil, parent_id: nil, alias: 'Detective'),
|
|
170
|
+
TagAlias.new(tag_id: tag.tag_id, parent_id: nil, alias: 'Detective'),
|
|
171
|
+
TagAlias.new(tag_id: nil, parent_id: tag.publisher_id, alias: 'Detective'),
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
assert_difference "TagAlias.count", +1 do
|
|
175
|
+
TagAlias.import [valid_tag_alias]
|
|
176
|
+
end
|
|
177
|
+
invalid_tag_aliases.each do |invalid_tag_alias|
|
|
178
|
+
assert_no_difference "TagAlias.count" do
|
|
179
|
+
TagAlias.import [invalid_tag_alias]
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
157
183
|
end
|
|
158
184
|
end
|
|
159
185
|
|
|
@@ -164,7 +190,17 @@ describe "#import" do
|
|
|
164
190
|
assert_difference "Dictionary.count", +1 do
|
|
165
191
|
Dictionary.import dictionaries
|
|
166
192
|
end
|
|
167
|
-
assert_equal "Dictionary", Dictionary.
|
|
193
|
+
assert_equal "Dictionary", Dictionary.last.type
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "should import arrays successfully" do
|
|
197
|
+
columns = [:author_name, :title]
|
|
198
|
+
values = [["Noah Webster", "Webster's Dictionary"]]
|
|
199
|
+
|
|
200
|
+
assert_difference "Dictionary.count", +1 do
|
|
201
|
+
Dictionary.import columns, values
|
|
202
|
+
end
|
|
203
|
+
assert_equal "Dictionary", Dictionary.last.type
|
|
168
204
|
end
|
|
169
205
|
end
|
|
170
206
|
|
|
@@ -210,9 +246,9 @@ describe "#import" do
|
|
|
210
246
|
end
|
|
211
247
|
|
|
212
248
|
it "should ignore uniqueness validators" do
|
|
213
|
-
Topic.import columns, valid_values
|
|
249
|
+
Topic.import columns, valid_values
|
|
214
250
|
assert_difference "Topic.count", +2 do
|
|
215
|
-
Topic.import columns, valid_values
|
|
251
|
+
Topic.import columns, valid_values
|
|
216
252
|
end
|
|
217
253
|
end
|
|
218
254
|
|
|
@@ -247,6 +283,16 @@ describe "#import" do
|
|
|
247
283
|
end
|
|
248
284
|
end
|
|
249
285
|
|
|
286
|
+
it "should index the failed instances by their poistion in the set if `track_failures` is true" do
|
|
287
|
+
index_offset = valid_values.length
|
|
288
|
+
results = Topic.import columns, valid_values + invalid_values, validate: true, track_validation_failures: true
|
|
289
|
+
assert_equal invalid_values.size, results.failed_instances.size
|
|
290
|
+
invalid_values.each_with_index do |value_set, index|
|
|
291
|
+
assert_equal index + index_offset, results.failed_instances[index].first
|
|
292
|
+
assert_equal value_set.first, results.failed_instances[index].last.title
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
250
296
|
it "should set ids in valid models if adapter supports setting primary key of imported objects" do
|
|
251
297
|
if ActiveRecord::Base.supports_setting_primary_key_of_imported_objects?
|
|
252
298
|
Topic.import (invalid_models + valid_models), validate: true
|
|
@@ -294,6 +340,36 @@ describe "#import" do
|
|
|
294
340
|
end
|
|
295
341
|
end
|
|
296
342
|
end
|
|
343
|
+
|
|
344
|
+
context "with uniqueness validators included" do
|
|
345
|
+
it "should not import duplicate records" do
|
|
346
|
+
Topic.import columns, valid_values
|
|
347
|
+
assert_no_difference "Topic.count" do
|
|
348
|
+
Topic.import columns, valid_values, validate_uniqueness: true
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
context "when validatoring presence of belongs_to association" do
|
|
354
|
+
it "should not import records without foreign key" do
|
|
355
|
+
assert_no_difference "UserToken.count" do
|
|
356
|
+
UserToken.import [:token], [['12345abcdef67890']]
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it "should import records with foreign key" do
|
|
361
|
+
assert_difference "UserToken.count", +1 do
|
|
362
|
+
UserToken.import [:user_name, :token], [%w("Bob", "12345abcdef67890")]
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
it "should not mutate the defined validations" do
|
|
367
|
+
UserToken.import [:user_name, :token], [%w("Bob", "12345abcdef67890")]
|
|
368
|
+
ut = UserToken.new
|
|
369
|
+
ut.valid?
|
|
370
|
+
assert_includes ut.errors.messages, :user
|
|
371
|
+
end
|
|
372
|
+
end
|
|
297
373
|
end
|
|
298
374
|
|
|
299
375
|
context "without :validation option" do
|
|
@@ -360,6 +436,15 @@ describe "#import" do
|
|
|
360
436
|
assert_equal 3, result.num_inserts if Topic.supports_import?
|
|
361
437
|
end
|
|
362
438
|
end
|
|
439
|
+
|
|
440
|
+
it "should accept and call an optional callable to run after each batch" do
|
|
441
|
+
lambda_called = 0
|
|
442
|
+
|
|
443
|
+
my_proc = ->(_row_count, _batches, _batch, _duration) { lambda_called += 1 }
|
|
444
|
+
Topic.import Build(10, :topics), batch_size: 4, batch_progress: my_proc
|
|
445
|
+
|
|
446
|
+
assert_equal 3, lambda_called
|
|
447
|
+
end
|
|
363
448
|
end
|
|
364
449
|
|
|
365
450
|
context "with :synchronize option" do
|
|
@@ -490,11 +575,15 @@ describe "#import" do
|
|
|
490
575
|
|
|
491
576
|
context "when the timestamps columns are present" do
|
|
492
577
|
setup do
|
|
493
|
-
@existing_book = Book.create(title: "Fell", author_name: "Curry", publisher: "Bayer", created_at: 2.years.ago.utc, created_on: 2.years.ago.utc)
|
|
494
|
-
ActiveRecord
|
|
578
|
+
@existing_book = Book.create(title: "Fell", author_name: "Curry", publisher: "Bayer", created_at: 2.years.ago.utc, created_on: 2.years.ago.utc, updated_at: 2.years.ago.utc, updated_on: 2.years.ago.utc)
|
|
579
|
+
if ActiveRecord.respond_to?(:default_timezone)
|
|
580
|
+
ActiveRecord.default_timezone = :utc
|
|
581
|
+
else
|
|
582
|
+
ActiveRecord::Base.default_timezone = :utc
|
|
583
|
+
end
|
|
495
584
|
Timecop.freeze(time) do
|
|
496
585
|
assert_difference "Book.count", +2 do
|
|
497
|
-
Book.import %w(title author_name publisher created_at created_on), [["LDAP", "Big Bird", "Del Rey", nil, nil], [@existing_book.title, @existing_book.author_name, @existing_book.publisher, @existing_book.created_at, @existing_book.created_on]]
|
|
586
|
+
Book.import %w(title author_name publisher created_at created_on updated_at updated_on), [["LDAP", "Big Bird", "Del Rey", nil, nil, nil, nil], [@existing_book.title, @existing_book.author_name, @existing_book.publisher, @existing_book.created_at, @existing_book.created_on, @existing_book.updated_at, @existing_book.updated_on]]
|
|
498
587
|
end
|
|
499
588
|
end
|
|
500
589
|
@new_book, @existing_book = Book.last 2
|
|
@@ -523,6 +612,23 @@ describe "#import" do
|
|
|
523
612
|
it "should set the updated_on column for new records" do
|
|
524
613
|
assert_in_delta time.to_i, @new_book.updated_on.to_i, 1.second
|
|
525
614
|
end
|
|
615
|
+
|
|
616
|
+
it "should not set the updated_at column for existing records" do
|
|
617
|
+
assert_equal 2.years.ago.utc.strftime("%Y:%d"), @existing_book.updated_at.strftime("%Y:%d")
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
it "should not set the updated_on column for existing records" do
|
|
621
|
+
assert_equal 2.years.ago.utc.strftime("%Y:%d"), @existing_book.updated_on.strftime("%Y:%d")
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
it "should not set the updated_at column on models if changed" do
|
|
625
|
+
timestamp = Time.now.utc
|
|
626
|
+
books = [
|
|
627
|
+
Book.new(author_name: "Foo", title: "Baz", created_at: timestamp, updated_at: timestamp)
|
|
628
|
+
]
|
|
629
|
+
Book.import books
|
|
630
|
+
assert_equal timestamp.strftime("%Y:%d"), Book.last.updated_at.strftime("%Y:%d")
|
|
631
|
+
end
|
|
526
632
|
end
|
|
527
633
|
|
|
528
634
|
context "when a custom time zone is set" do
|
|
@@ -567,7 +673,7 @@ describe "#import" do
|
|
|
567
673
|
|
|
568
674
|
context "importing through an association scope" do
|
|
569
675
|
{ has_many: :chapters, polymorphic: :discounts }.each do |association_type, association|
|
|
570
|
-
book =
|
|
676
|
+
book = FactoryBot.create :book
|
|
571
677
|
scope = book.public_send association
|
|
572
678
|
klass = { chapters: Chapter, discounts: Discount }[association]
|
|
573
679
|
column = { chapters: :title, discounts: :amount }[association]
|
|
@@ -590,6 +696,14 @@ describe "#import" do
|
|
|
590
696
|
assert_equal [val1, val2], scope.map(&column).sort
|
|
591
697
|
end
|
|
592
698
|
|
|
699
|
+
context "for cards and decks" do
|
|
700
|
+
it "works when the polymorphic name is different than base class name" do
|
|
701
|
+
deck = Deck.create(id: 1, name: 'test')
|
|
702
|
+
deck.cards.import [:id, :deck_type], [[1, 'PlayingCard']]
|
|
703
|
+
assert_equal deck.cards.first.deck_type, "PlayingCard"
|
|
704
|
+
end
|
|
705
|
+
end
|
|
706
|
+
|
|
593
707
|
it "works importing array of hashes" do
|
|
594
708
|
scope.import [{ column => val1 }, { column => val2 }]
|
|
595
709
|
|
|
@@ -609,7 +723,7 @@ describe "#import" do
|
|
|
609
723
|
|
|
610
724
|
context "importing model with polymorphic belongs_to" do
|
|
611
725
|
it "works without error" do
|
|
612
|
-
book =
|
|
726
|
+
book = FactoryBot.create :book
|
|
613
727
|
discount = Discount.new(discountable: book)
|
|
614
728
|
|
|
615
729
|
Discount.import([discount])
|
|
@@ -848,4 +962,33 @@ describe "#import" do
|
|
|
848
962
|
end
|
|
849
963
|
end
|
|
850
964
|
end
|
|
965
|
+
describe "importing model with after_initialize callback" do
|
|
966
|
+
let(:columns) { %w(name size) }
|
|
967
|
+
let(:valid_values) { [%w("Deer", "Small"), %w("Monkey", "Medium")] }
|
|
968
|
+
let(:invalid_values) do
|
|
969
|
+
[
|
|
970
|
+
{ name: "giraffe", size: "Large" },
|
|
971
|
+
{ size: "Medium" } # name is missing
|
|
972
|
+
]
|
|
973
|
+
end
|
|
974
|
+
context "with validation checks turned off" do
|
|
975
|
+
it "should import valid data" do
|
|
976
|
+
Animal.import(columns, valid_values, validate: false)
|
|
977
|
+
assert_equal 2, Animal.count
|
|
978
|
+
end
|
|
979
|
+
it "should raise ArgumentError" do
|
|
980
|
+
assert_raise(ArgumentError) { Animal.import(invalid_values, validate: false) }
|
|
981
|
+
end
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
context "with validation checks turned on" do
|
|
985
|
+
it "should import valid data" do
|
|
986
|
+
Animal.import(columns, valid_values, validate: true)
|
|
987
|
+
assert_equal 2, Animal.count
|
|
988
|
+
end
|
|
989
|
+
it "should raise ArgumentError" do
|
|
990
|
+
assert_raise(ArgumentError) { Animal.import(invalid_values, validate: true) }
|
|
991
|
+
end
|
|
992
|
+
end
|
|
993
|
+
end
|
|
851
994
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
|
|
4
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../support/assertions")
|
|
5
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../support/mysql/import_examples")
|
|
4
6
|
|
|
5
7
|
should_support_mysql_import_functionality
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
|
|
4
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
|
|
3
5
|
|
|
4
6
|
should_support_postgresql_import_functionality
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
|
|
4
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../support/sqlite3/import_examples")
|
|
3
5
|
|
|
4
6
|
should_support_sqlite3_import_functionality
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
|
|
4
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
|
|
3
5
|
|
|
4
6
|
should_support_postgresql_import_functionality
|
|
5
7
|
|
data/test/models/account.rb
CHANGED
data/test/models/alarm.rb
CHANGED
data/test/models/bike_maker.rb
CHANGED
data/test/models/book.rb
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Book < ActiveRecord::Base
|
|
2
4
|
belongs_to :topic, inverse_of: :books
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
if ENV['AR_VERSION'].to_f <= 7.0
|
|
6
|
+
belongs_to :tag, foreign_key: [:tag_id, :parent_id] unless ENV["SKIP_COMPOSITE_PK"]
|
|
7
|
+
else
|
|
8
|
+
belongs_to :tag, query_constraints: [:tag_id, :parent_id] unless ENV["SKIP_COMPOSITE_PK"]
|
|
9
|
+
end
|
|
5
10
|
has_many :chapters, inverse_of: :book
|
|
6
11
|
has_many :discounts, as: :discountable
|
|
7
12
|
has_many :end_notes, inverse_of: :book
|
data/test/models/car.rb
CHANGED
data/test/models/card.rb
ADDED
data/test/models/chapter.rb
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CompositeBook < ActiveRecord::Base
|
|
4
|
+
self.primary_key = %i[id author_id]
|
|
5
|
+
belongs_to :author
|
|
6
|
+
if ENV['AR_VERSION'].to_f <= 7.0
|
|
7
|
+
unless ENV["SKIP_COMPOSITE_PK"]
|
|
8
|
+
has_many :composite_chapters, inverse_of: :composite_book,
|
|
9
|
+
foreign_key: [:id, :author_id]
|
|
10
|
+
end
|
|
11
|
+
else
|
|
12
|
+
has_many :composite_chapters, inverse_of: :composite_book,
|
|
13
|
+
query_constraints: [:id, :author_id]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.sequence_name
|
|
17
|
+
"composite_book_id_seq"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CompositeChapter < ActiveRecord::Base
|
|
4
|
+
if ENV['AR_VERSION'].to_f >= 7.1
|
|
5
|
+
belongs_to :composite_book, inverse_of: :composite_chapters,
|
|
6
|
+
query_constraints: [:composite_book_id, :author_id]
|
|
7
|
+
end
|
|
8
|
+
validates :title, presence: true
|
|
9
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Customer < ActiveRecord::Base
|
|
4
|
+
unless ENV["SKIP_COMPOSITE_PK"]
|
|
5
|
+
if ENV['AR_VERSION'].to_f <= 7.0
|
|
6
|
+
has_many :orders,
|
|
7
|
+
inverse_of: :customer,
|
|
8
|
+
primary_key: %i(account_id id),
|
|
9
|
+
foreign_key: %i(account_id customer_id)
|
|
10
|
+
else
|
|
11
|
+
has_many :orders,
|
|
12
|
+
inverse_of: :customer,
|
|
13
|
+
primary_key: %i(account_id id),
|
|
14
|
+
query_constraints: %i(account_id customer_id)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
data/test/models/deck.rb
ADDED
data/test/models/dictionary.rb
CHANGED
data/test/models/discount.rb
CHANGED