activerecord-import 1.0.4 → 2.0.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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +159 -0
  3. data/.gitignore +5 -0
  4. data/.rubocop.yml +76 -7
  5. data/.rubocop_todo.yml +10 -16
  6. data/Brewfile +3 -1
  7. data/CHANGELOG.md +143 -3
  8. data/Dockerfile +23 -0
  9. data/Gemfile +28 -24
  10. data/LICENSE +21 -56
  11. data/README.markdown +83 -27
  12. data/Rakefile +3 -0
  13. data/activerecord-import.gemspec +10 -5
  14. data/benchmarks/benchmark.rb +10 -6
  15. data/benchmarks/lib/base.rb +10 -5
  16. data/benchmarks/lib/cli_parser.rb +10 -6
  17. data/benchmarks/lib/float.rb +2 -0
  18. data/benchmarks/lib/mysql2_benchmark.rb +2 -0
  19. data/benchmarks/lib/output_to_csv.rb +2 -0
  20. data/benchmarks/lib/output_to_html.rb +4 -2
  21. data/benchmarks/models/test_innodb.rb +2 -0
  22. data/benchmarks/models/test_memory.rb +2 -0
  23. data/benchmarks/models/test_myisam.rb +2 -0
  24. data/benchmarks/schema/{mysql_schema.rb → mysql2_schema.rb} +2 -0
  25. data/docker-compose.yml +34 -0
  26. data/gemfiles/5.2.gemfile +2 -0
  27. data/gemfiles/6.0.gemfile +3 -0
  28. data/gemfiles/6.1.gemfile +4 -1
  29. data/gemfiles/7.0.gemfile +4 -0
  30. data/gemfiles/7.1.gemfile +3 -0
  31. data/gemfiles/7.2.gemfile +3 -0
  32. data/gemfiles/8.0.gemfile +3 -0
  33. data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +2 -0
  34. data/lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb +6 -4
  35. data/lib/activerecord-import/active_record/adapters/jdbcpostgresql_adapter.rb +2 -0
  36. data/lib/activerecord-import/active_record/adapters/jdbcsqlite3_adapter.rb +2 -0
  37. data/lib/activerecord-import/active_record/adapters/mysql2_adapter.rb +2 -0
  38. data/lib/activerecord-import/active_record/adapters/postgresql_adapter.rb +2 -0
  39. data/lib/activerecord-import/active_record/adapters/seamless_database_pool_adapter.rb +2 -0
  40. data/lib/activerecord-import/active_record/adapters/sqlite3_adapter.rb +2 -0
  41. data/lib/activerecord-import/active_record/adapters/trilogy_adapter.rb +8 -0
  42. data/lib/activerecord-import/adapters/abstract_adapter.rb +9 -6
  43. data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +2 -0
  44. data/lib/activerecord-import/adapters/mysql2_adapter.rb +2 -0
  45. data/lib/activerecord-import/adapters/mysql_adapter.rb +30 -21
  46. data/lib/activerecord-import/adapters/postgresql_adapter.rb +68 -48
  47. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +37 -30
  48. data/lib/activerecord-import/adapters/trilogy_adapter.rb +7 -0
  49. data/lib/activerecord-import/base.rb +3 -1
  50. data/lib/activerecord-import/import.rb +160 -58
  51. data/lib/activerecord-import/synchronize.rb +3 -1
  52. data/lib/activerecord-import/value_sets_parser.rb +5 -0
  53. data/lib/activerecord-import/version.rb +3 -1
  54. data/lib/activerecord-import.rb +2 -1
  55. data/test/adapters/jdbcmysql.rb +2 -0
  56. data/test/adapters/jdbcpostgresql.rb +2 -0
  57. data/test/adapters/jdbcsqlite3.rb +2 -0
  58. data/test/adapters/makara_postgis.rb +2 -0
  59. data/test/adapters/mysql2.rb +2 -0
  60. data/test/adapters/mysql2_makara.rb +2 -0
  61. data/test/adapters/mysql2spatial.rb +2 -0
  62. data/test/adapters/postgis.rb +2 -0
  63. data/test/adapters/postgresql.rb +2 -0
  64. data/test/adapters/postgresql_makara.rb +2 -0
  65. data/test/adapters/seamless_database_pool.rb +2 -0
  66. data/test/adapters/spatialite.rb +2 -0
  67. data/test/adapters/sqlite3.rb +2 -0
  68. data/test/adapters/trilogy.rb +9 -0
  69. data/test/database.yml.sample +7 -0
  70. data/test/{travis → github}/database.yml +9 -3
  71. data/test/import_test.rb +108 -41
  72. data/test/jdbcmysql/import_test.rb +5 -3
  73. data/test/jdbcpostgresql/import_test.rb +4 -2
  74. data/test/jdbcsqlite3/import_test.rb +4 -2
  75. data/test/makara_postgis/import_test.rb +4 -2
  76. data/test/models/account.rb +2 -0
  77. data/test/models/alarm.rb +2 -0
  78. data/test/models/animal.rb +8 -0
  79. data/test/models/author.rb +9 -0
  80. data/test/models/bike_maker.rb +3 -0
  81. data/test/models/book.rb +12 -3
  82. data/test/models/car.rb +2 -0
  83. data/test/models/card.rb +5 -0
  84. data/test/models/chapter.rb +2 -0
  85. data/test/models/composite_book.rb +19 -0
  86. data/test/models/composite_chapter.rb +12 -0
  87. data/test/models/customer.rb +18 -0
  88. data/test/models/deck.rb +8 -0
  89. data/test/models/dictionary.rb +2 -0
  90. data/test/models/discount.rb +2 -0
  91. data/test/models/end_note.rb +2 -0
  92. data/test/models/group.rb +2 -0
  93. data/test/models/order.rb +17 -0
  94. data/test/models/playing_card.rb +4 -0
  95. data/test/models/promotion.rb +2 -0
  96. data/test/models/question.rb +2 -0
  97. data/test/models/rule.rb +2 -0
  98. data/test/models/tag.rb +9 -1
  99. data/test/models/tag_alias.rb +11 -0
  100. data/test/models/topic.rb +8 -0
  101. data/test/models/user.rb +2 -0
  102. data/test/models/user_token.rb +2 -0
  103. data/test/models/vendor.rb +2 -0
  104. data/test/models/widget.rb +12 -3
  105. data/test/mysql2/import_test.rb +5 -3
  106. data/test/mysql2_makara/import_test.rb +5 -3
  107. data/test/mysqlspatial2/import_test.rb +5 -3
  108. data/test/postgis/import_test.rb +4 -2
  109. data/test/postgresql/import_test.rb +4 -2
  110. data/test/schema/generic_schema.rb +37 -1
  111. data/test/schema/jdbcpostgresql_schema.rb +3 -1
  112. data/test/schema/mysql2_schema.rb +2 -0
  113. data/test/schema/postgis_schema.rb +3 -1
  114. data/test/schema/postgresql_schema.rb +38 -4
  115. data/test/schema/sqlite3_schema.rb +2 -0
  116. data/test/schema/version.rb +2 -0
  117. data/test/sqlite3/import_test.rb +4 -2
  118. data/test/support/active_support/test_case_extensions.rb +3 -5
  119. data/test/support/assertions.rb +2 -0
  120. data/test/support/factories.rb +2 -0
  121. data/test/support/generate.rb +4 -2
  122. data/test/support/mysql/import_examples.rb +7 -8
  123. data/test/support/postgresql/import_examples.rb +121 -53
  124. data/test/support/shared_examples/on_duplicate_key_ignore.rb +2 -0
  125. data/test/support/shared_examples/on_duplicate_key_update.rb +69 -10
  126. data/test/support/shared_examples/recursive_import.rb +137 -1
  127. data/test/support/sqlite3/import_examples.rb +2 -1
  128. data/test/synchronize_test.rb +2 -0
  129. data/test/test_helper.rb +38 -24
  130. data/test/trilogy/import_test.rb +7 -0
  131. data/test/value_sets_bytes_parser_test.rb +3 -1
  132. data/test/value_sets_records_parser_test.rb +3 -1
  133. metadata +46 -22
  134. data/.travis.yml +0 -74
  135. data/gemfiles/3.2.gemfile +0 -2
  136. data/gemfiles/4.0.gemfile +0 -2
  137. data/gemfiles/4.1.gemfile +0 -2
  138. data/gemfiles/4.2.gemfile +0 -2
  139. data/gemfiles/5.0.gemfile +0 -2
  140. data/gemfiles/5.1.gemfile +0 -2
  141. data/lib/activerecord-import/mysql2.rb +0 -7
  142. data/lib/activerecord-import/postgresql.rb +0 -7
  143. data/lib/activerecord-import/sqlite3.rb +0 -7
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
@@ -159,6 +161,25 @@ describe "#import" do
159
161
  Tag.import columns, values, validate: false
160
162
  end
161
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
162
183
  end
163
184
  end
164
185
 
@@ -169,7 +190,17 @@ describe "#import" do
169
190
  assert_difference "Dictionary.count", +1 do
170
191
  Dictionary.import dictionaries
171
192
  end
172
- assert_equal "Dictionary", Dictionary.first.type
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
173
204
  end
174
205
  end
175
206
 
@@ -252,6 +283,16 @@ describe "#import" do
252
283
  end
253
284
  end
254
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
+
255
296
  it "should set ids in valid models if adapter supports setting primary key of imported objects" do
256
297
  if ActiveRecord::Base.supports_setting_primary_key_of_imported_objects?
257
298
  Topic.import (invalid_models + valid_models), validate: true
@@ -395,6 +436,15 @@ describe "#import" do
395
436
  assert_equal 3, result.num_inserts if Topic.supports_import?
396
437
  end
397
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
398
448
  end
399
449
 
400
450
  context "with :synchronize option" do
@@ -526,7 +576,11 @@ describe "#import" do
526
576
  context "when the timestamps columns are present" do
527
577
  setup do
528
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)
529
- ActiveRecord::Base.default_timezone = :utc
579
+ if ActiveRecord.respond_to?(:default_timezone)
580
+ ActiveRecord.default_timezone = :utc
581
+ else
582
+ ActiveRecord::Base.default_timezone = :utc
583
+ end
530
584
  Timecop.freeze(time) do
531
585
  assert_difference "Book.count", +2 do
532
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]]
@@ -642,6 +696,14 @@ describe "#import" do
642
696
  assert_equal [val1, val2], scope.map(&column).sort
643
697
  end
644
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
+
645
707
  it "works importing array of hashes" do
646
708
  scope.import [{ column => val1 }, { column => val2 }]
647
709
 
@@ -679,14 +741,8 @@ describe "#import" do
679
741
  ]
680
742
  Book.import books
681
743
  assert_equal 2, Book.count
682
-
683
- if ENV['AR_VERSION'].to_i >= 5.0
684
- assert_equal 'draft', Book.first.read_attribute('status')
685
- assert_equal 'published', Book.last.read_attribute('status')
686
- else
687
- assert_equal 0, Book.first.read_attribute('status')
688
- assert_equal 1, Book.last.read_attribute('status')
689
- end
744
+ assert_equal 'draft', Book.first.read_attribute('status')
745
+ assert_equal 'published', Book.last.read_attribute('status')
690
746
  end
691
747
 
692
748
  it 'should be able to import enum fields with default value' do
@@ -696,32 +752,19 @@ describe "#import" do
696
752
  ]
697
753
  Book.import books
698
754
  assert_equal 1, Book.count
699
-
700
- if ENV['AR_VERSION'].to_i >= 5.0
701
- assert_equal 'draft', Book.first.read_attribute('status')
702
- else
703
- assert_equal 0, Book.first.read_attribute('status')
704
- end
755
+ assert_equal 'draft', Book.first.read_attribute('status')
705
756
  end
706
757
 
707
- if ENV['AR_VERSION'].to_f > 4.1
708
- it 'should be able to import enum fields by name' do
709
- Book.delete_all if Book.count > 0
710
- books = [
711
- Book.new(author_name: "Foo", title: "Baz", status: :draft),
712
- Book.new(author_name: "Foo2", title: "Baz2", status: :published),
713
- ]
714
- Book.import books
715
- assert_equal 2, Book.count
716
-
717
- if ENV['AR_VERSION'].to_i >= 5.0
718
- assert_equal 'draft', Book.first.read_attribute('status')
719
- assert_equal 'published', Book.last.read_attribute('status')
720
- else
721
- assert_equal 0, Book.first.read_attribute('status')
722
- assert_equal 1, Book.last.read_attribute('status')
723
- end
724
- end
758
+ it 'should be able to import enum fields by name' do
759
+ Book.delete_all if Book.count > 0
760
+ books = [
761
+ Book.new(author_name: "Foo", title: "Baz", status: :draft),
762
+ Book.new(author_name: "Foo2", title: "Baz2", status: :published),
763
+ ]
764
+ Book.import books
765
+ assert_equal 2, Book.count
766
+ assert_equal 'draft', Book.first.read_attribute('status')
767
+ assert_equal 'published', Book.last.read_attribute('status')
725
768
  end
726
769
  end
727
770
 
@@ -734,13 +777,8 @@ describe "#import" do
734
777
  Book.import columns, values
735
778
  assert_equal 2, Book.count
736
779
 
737
- if ENV['AR_VERSION'].to_i >= 5.0
738
- assert_equal 'draft', Book.first.read_attribute('status')
739
- assert_equal 'published', Book.last.read_attribute('status')
740
- else
741
- assert_equal 0, Book.first.read_attribute('status')
742
- assert_equal 1, Book.last.read_attribute('status')
743
- end
780
+ assert_equal 'draft', Book.first.read_attribute('status')
781
+ assert_equal 'published', Book.last.read_attribute('status')
744
782
  end
745
783
  end
746
784
 
@@ -900,4 +938,33 @@ describe "#import" do
900
938
  end
901
939
  end
902
940
  end
941
+ describe "importing model with after_initialize callback" do
942
+ let(:columns) { %w(name size) }
943
+ let(:valid_values) { [%w("Deer", "Small"), %w("Monkey", "Medium")] }
944
+ let(:invalid_values) do
945
+ [
946
+ { name: "giraffe", size: "Large" },
947
+ { size: "Medium" } # name is missing
948
+ ]
949
+ end
950
+ context "with validation checks turned off" do
951
+ it "should import valid data" do
952
+ Animal.import(columns, valid_values, validate: false)
953
+ assert_equal 2, Animal.count
954
+ end
955
+ it "should raise ArgumentError" do
956
+ assert_raise(ArgumentError) { Animal.import(invalid_values, validate: false) }
957
+ end
958
+ end
959
+
960
+ context "with validation checks turned on" do
961
+ it "should import valid data" do
962
+ Animal.import(columns, valid_values, validate: true)
963
+ assert_equal 2, Animal.count
964
+ end
965
+ it "should raise ArgumentError" do
966
+ assert_raise(ArgumentError) { Animal.import(invalid_values, validate: true) }
967
+ end
968
+ end
969
+ end
903
970
  end
@@ -1,5 +1,7 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
3
- require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
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
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
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
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/sqlite3/import_examples')
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
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
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
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Account < ActiveRecord::Base
2
4
  self.locking_column = :lock
3
5
  end
data/test/models/alarm.rb CHANGED
@@ -1,2 +1,4 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Alarm < ActiveRecord::Base
2
4
  end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Animal < ActiveRecord::Base
4
+ after_initialize :validate_name_presence, if: :new_record?
5
+ def validate_name_presence
6
+ raise ArgumentError if name.nil?
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Author < ActiveRecord::Base
4
+ if ENV['AR_VERSION'].to_f >= 8.0
5
+ has_many :composite_books, foreign_key: [:id, :author_id], inverse_of: :author
6
+ elsif ENV['AR_VERSION'].to_f >= 7.1
7
+ has_many :composite_books, query_constraints: [:id, :author_id], inverse_of: :author
8
+ end
9
+ end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bike
2
4
  def self.table_name_prefix
3
5
  'bike_'
4
6
  end
7
+
5
8
  class Maker < ActiveRecord::Base
6
9
  end
7
10
  end
data/test/models/book.rb CHANGED
@@ -1,9 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Book < ActiveRecord::Base
2
4
  belongs_to :topic, inverse_of: :books
3
- belongs_to :tag, foreign_key: [:tag_id, :parent_id]
4
-
5
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.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
8
- enum status: [:draft, :published] if ENV['AR_VERSION'].to_f >= 4.1
13
+ if ENV['AR_VERSION'].to_f >= 8.0
14
+ enum :status, [:draft, :published]
15
+ else
16
+ enum status: [:draft, :published]
17
+ end
9
18
  end
data/test/models/car.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Car < ActiveRecord::Base
2
4
  self.primary_key = :Name
3
5
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Card < ActiveRecord::Base
4
+ belongs_to :deck, polymorphic: true
5
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Chapter < ActiveRecord::Base
2
4
  belongs_to :book, inverse_of: :chapters
3
5
  validates :title, presence: true
@@ -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 || ENV['AR_VERSION'].to_f >= 8.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,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CompositeChapter < ActiveRecord::Base
4
+ if ENV['AR_VERSION'].to_f >= 8.0
5
+ belongs_to :composite_book, inverse_of: :composite_chapters,
6
+ foreign_key: [:composite_book_id, :author_id]
7
+ elsif ENV['AR_VERSION'].to_f >= 7.1
8
+ belongs_to :composite_book, inverse_of: :composite_chapters,
9
+ query_constraints: [:composite_book_id, :author_id]
10
+ end
11
+ validates :title, presence: true
12
+ 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 || ENV['AR_VERSION'].to_f >= 8.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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Deck < ActiveRecord::Base
4
+ has_many :cards
5
+ def self.polymorphic_name
6
+ "PlayingCard"
7
+ end
8
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'book'
2
4
 
3
5
  class Dictionary < Book
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Discount < ActiveRecord::Base
2
4
  belongs_to :discountable, polymorphic: true
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class EndNote < ActiveRecord::Base
2
4
  belongs_to :book, inverse_of: :end_notes
3
5
  validates :note, presence: true
data/test/models/group.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Group < ActiveRecord::Base
2
4
  self.table_name = 'group'
3
5
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Order < ActiveRecord::Base
4
+ unless ENV["SKIP_COMPOSITE_PK"]
5
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.0
6
+ belongs_to :customer,
7
+ inverse_of: :orders,
8
+ primary_key: %i(account_id id),
9
+ foreign_key: %i(account_id customer_id)
10
+ else
11
+ belongs_to :customer,
12
+ inverse_of: :orders,
13
+ primary_key: %i(account_id id),
14
+ query_constraints: %i(account_id customer_id)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class PlayingCard < ActiveRecord::Base
4
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Promotion < ActiveRecord::Base
2
4
  self.primary_key = :promotion_id
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Question < ActiveRecord::Base
2
4
  has_one :rule
3
5
  end
data/test/models/rule.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Rule < ActiveRecord::Base
2
4
  belongs_to :question
3
5
  end
data/test/models/tag.rb CHANGED
@@ -1,4 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Tag < ActiveRecord::Base
2
- self.primary_keys = :tag_id, :publisher_id unless ENV["SKIP_COMPOSITE_PK"]
4
+ if ENV['AR_VERSION'].to_f <= 7.0
5
+ self.primary_keys = :tag_id, :publisher_id unless ENV["SKIP_COMPOSITE_PK"]
6
+ else
7
+ self.primary_key = [:tag_id, :publisher_id] unless ENV["SKIP_COMPOSITE_PK"]
8
+ end
9
+ self.primary_key = [:tag_id, :publisher_id] unless ENV["SKIP_COMPOSITE_PK"]
3
10
  has_many :books, inverse_of: :tag
11
+ has_many :tag_aliases, inverse_of: :tag
4
12
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TagAlias < ActiveRecord::Base
4
+ unless ENV["SKIP_COMPOSITE_PK"]
5
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.0
6
+ belongs_to :tag, foreign_key: [:tag_id, :parent_id], required: true
7
+ else
8
+ belongs_to :tag, query_constraints: [:tag_id, :parent_id], required: true
9
+ end
10
+ end
11
+ end
data/test/models/topic.rb CHANGED
@@ -1,4 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Topic < ActiveRecord::Base
4
+ if ENV['AR_VERSION'].to_f >= 6.0
5
+ self.ignored_columns = [:priority]
6
+ end
7
+ alias_attribute :name, :title
8
+
2
9
  validates_presence_of :author_name
3
10
  validates :title, numericality: { only_integer: true }, on: :context_test
4
11
  validates :title, uniqueness: true
@@ -9,6 +16,7 @@ class Topic < ActiveRecord::Base
9
16
  before_validation -> { errors.add(:title, :invalid) if title == 'invalid' }
10
17
 
11
18
  has_many :books, inverse_of: :topic
19
+ has_many :novels, inverse_of: :topic, class_name: "Book"
12
20
  belongs_to :parent, class_name: "Topic"
13
21
 
14
22
  composed_of :description, mapping: [%w(title title), %w(author_name author_name)], allow_nil: true, class_name: "TopicDescription"
data/test/models/user.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class User < ActiveRecord::Base
2
4
  has_many :user_tokens, primary_key: :name, foreign_key: :user_name
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class UserToken < ActiveRecord::Base
2
4
  belongs_to :user, primary_key: :name, foreign_key: :user_name
3
5
  validates :user, presence: true
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Vendor < ActiveRecord::Base
2
4
  store :preferences, accessors: [:color], coder: JSON
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class CustomCoder
2
4
  def load(value)
3
5
  if value.nil?
@@ -17,8 +19,15 @@ class Widget < ActiveRecord::Base
17
19
 
18
20
  default_scope -> { where(active: true) }
19
21
 
20
- serialize :data, Hash
21
- serialize :json_data, JSON
22
+ if ENV['AR_VERSION'].to_f >= 7.1
23
+ serialize :data, coder: YAML
24
+ serialize :json_data, coder: JSON
25
+ serialize :custom_data, coder: CustomCoder.new
26
+ else
27
+ serialize :data, Hash
28
+ serialize :json_data, JSON
29
+ serialize :custom_data, CustomCoder.new
30
+ end
31
+
22
32
  serialize :unspecified_data
23
- serialize :custom_data, CustomCoder.new
24
33
  end
@@ -1,5 +1,7 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
3
- require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
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,6 +1,8 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
1
+ # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+
5
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/assertions")
6
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/mysql/import_examples")
5
7
 
6
8
  should_support_mysql_import_functionality
@@ -1,6 +1,8 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
1
+ # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+
5
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/assertions")
6
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/mysql/import_examples")
5
7
 
6
8
  should_support_mysql_import_functionality
@@ -1,5 +1,7 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
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
 
@@ -1,4 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
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