activerecord-import 1.0.4 → 2.0.0

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