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