activerecord-import 1.8.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d1478b29daf1e757c91a0ca8693bb1b03f9a90daa2fe02f0959576bcec900d85
4
- data.tar.gz: dc938a1936c931182675a118ad24a37e2a7c5a27c0419e5bd947e0ec35aa4334
3
+ metadata.gz: f55c9faf85e948fbeb480ebca5baeca11b2275a626bc6ba7517e9d3e8c37e9e7
4
+ data.tar.gz: 80b267b08ef3a10bb91b029401e8fb6b49fdfcadeeb29a2e5e18fd6c8f529192
5
5
  SHA512:
6
- metadata.gz: e276196113f433c8989a9a06cfad36df650105183a5559a548bdd8a04bd2da22db36ca996d2d0d04c4561b33ceb44559b50b4ad98e0a2d9f050b8084ee99c8e6
7
- data.tar.gz: e699052ac2499bac23a9955fef71df853050767785d573523e23a1d216cfba9cb75b81b0db9f5e2afac02afbcb416563af6e7a2bf69f6d1288c6e6c71aeb7e5c
6
+ metadata.gz: f838da07331afe7827ad7d4f323ebf3f2191decd59a82359393f20eee866345258abb979875dd1c9b853533099797cdf7599ded20ca4e07997f8bce491f4c03e
7
+ data.tar.gz: 5a257bacb43492f25a65ecc382fe8ad126c4dac474eae7ee2beb3ba92c2cb95e64070a40cd20c48e47f46b51e64b69c2addd76a15fed75863df2ecb4a0fbdb70
@@ -21,6 +21,7 @@ jobs:
21
21
  ports:
22
22
  - 3306:3306
23
23
  env:
24
+ MYSQL_HOST: 127.0.0.1
24
25
  MYSQL_ROOT_PASSWORD: root
25
26
  MYSQL_USER: github
26
27
  MYSQL_PASSWORD: github
@@ -36,6 +37,8 @@ jobs:
36
37
  ruby:
37
38
  - 3.3
38
39
  env:
40
+ - AR_VERSION: '8.0'
41
+ RUBYOPT: --enable-frozen-string-literal
39
42
  - AR_VERSION: '7.2'
40
43
  RUBYOPT: --enable-frozen-string-literal
41
44
  - AR_VERSION: '7.1'
@@ -45,6 +48,9 @@ jobs:
45
48
  - AR_VERSION: 6.1
46
49
  RUBYOPT: --enable-frozen-string-literal
47
50
  include:
51
+ - ruby: 3.2
52
+ env:
53
+ AR_VERSION: '8.0'
48
54
  - ruby: 3.2
49
55
  env:
50
56
  AR_VERSION: '7.2'
@@ -72,7 +78,7 @@ jobs:
72
78
  - ruby: '3.0'
73
79
  env:
74
80
  AR_VERSION: 6.1
75
- - ruby: jruby-9.4.5.0
81
+ - ruby: jruby-9.4.8.0
76
82
  env:
77
83
  AR_VERSION: '7.0'
78
84
  - ruby: 2.7
@@ -84,7 +90,7 @@ jobs:
84
90
  - ruby: 2.7
85
91
  env:
86
92
  AR_VERSION: '6.0'
87
- - ruby: jruby-9.3.10.0
93
+ - ruby: jruby-9.3.15.0
88
94
  env:
89
95
  AR_VERSION: '6.1'
90
96
  - ruby: 2.6
@@ -96,6 +102,10 @@ jobs:
96
102
  DB_DATABASE: activerecord_import_test
97
103
  steps:
98
104
  - uses: actions/checkout@v4
105
+ - name: Install SQLite3 Development Library
106
+ run: |
107
+ sudo apt-get update
108
+ sudo apt-get install libsqlite3-dev
99
109
  - uses: ruby/setup-ruby@v1
100
110
  with:
101
111
  ruby-version: ${{ matrix.ruby }}
@@ -103,8 +113,6 @@ jobs:
103
113
  rubygems: latest
104
114
  - name: Set up databases
105
115
  run: |
106
- sudo /etc/init.d/mysql start
107
- mysql -e 'CREATE DATABASE ${{ env.DB_DATABASE }} CHARACTER SET utf8 COLLATE utf8_general_ci;' -u root -proot
108
116
  psql -h localhost -U postgres -c 'create database ${{ env.DB_DATABASE }};'
109
117
  psql -h localhost -U postgres -d ${{ env.DB_DATABASE }} -c 'create extension if not exists hstore;'
110
118
  psql -h localhost -U postgres -c 'create extension if not exists postgis;'
@@ -139,9 +147,13 @@ jobs:
139
147
  AR_VERSION: '7.0'
140
148
  steps:
141
149
  - uses: actions/checkout@v4
150
+ - name: Install SQLite3 Development Library
151
+ run: |
152
+ sudo apt-get update
153
+ sudo apt-get install libsqlite3-dev
142
154
  - uses: ruby/setup-ruby@v1
143
155
  with:
144
- ruby-version: 2.7
156
+ ruby-version: 3.0
145
157
  bundler-cache: true
146
158
  - name: Run Rubocop
147
159
  run: bundle exec rubocop
data/.rubocop.yml CHANGED
@@ -1,5 +1,8 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
+ AllCops:
4
+ TargetRubyVersion: 3.0.x
5
+
3
6
  Metrics/AbcSize:
4
7
  Enabled: false
5
8
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## Changes in 2.0.0
2
+
3
+ ### Breaking Changes
4
+
5
+ * Fix `recursive_on_duplicate_key_update` doesn't work with non-standard
6
+ association name. Thanks to @jacob-carlborg-apoex via \#852. The documentation for the
7
+ `:recursive_on_duplicate_key_update` option specifies that the hash key is
8
+ the association name. But previously the name of associated table was used to
9
+ look up the options. Now the behavior matches the documentation and the name
10
+ of the association is used instead. This only affects associations that uses
11
+ a name that doesn't follow the ActiveRecord naming conventions of
12
+ associations and class names, i.e. when the `class_name:` option is used on
13
+ an association.
14
+
15
+ ## Changes in 1.8.1
16
+
17
+ ### Fixes
18
+
19
+ * Further update for ActiveRecord 7.2 compatibility when running validations. Thanks to @denisahearn via \##847.
20
+
1
21
  ## Changes in 1.8.0
2
22
 
3
23
  ### New Features
data/Gemfile CHANGED
@@ -6,13 +6,15 @@ gemspec
6
6
 
7
7
  version = ENV['AR_VERSION'].to_f
8
8
 
9
- mysql2_version = '0.3.0'
10
- mysql2_version = '0.4.0' if version >= 4.2
9
+ mysql2_version = '0.4.0'
11
10
  mysql2_version = '0.5.0' if version >= 6.1
11
+ mysql2_version = '0.5.6' if version >= 8.0
12
12
  sqlite3_version = '1.3.0'
13
13
  sqlite3_version = '1.4.0' if version >= 6.0
14
+ sqlite3_version = '2.2.0' if version >= 8.0
14
15
  pg_version = '0.9'
15
16
  pg_version = '1.1' if version >= 6.1
17
+ pg_version = '1.5' if version >= 8.0
16
18
 
17
19
  group :development, :test do
18
20
  gem 'rubocop'
@@ -51,19 +53,11 @@ gem "chronic"
51
53
  gem "mocha", "~> 2.1.0"
52
54
 
53
55
  # Debugging
54
- platforms :jruby do
55
- gem "ruby-debug", "= 0.10.4"
56
- end
57
-
58
56
  platforms :ruby do
59
57
  gem "pry-byebug"
60
58
  gem "pry", "~> 0.14.0"
61
59
  end
62
60
 
63
- if version >= 4.0
64
- gem "minitest"
65
- else
66
- gem "test-unit"
67
- end
61
+ gem "minitest"
68
62
 
69
63
  eval_gemfile File.expand_path("../gemfiles/#{version}.gemfile", __FILE__)
data/README.markdown CHANGED
@@ -569,11 +569,11 @@ require 'activerecord-import'
569
569
  ### Load Path Setup
570
570
  To understand how rubygems loads code you can reference the following:
571
571
 
572
- http://guides.rubygems.org/patterns/#loading-code
572
+ https://guides.rubygems.org/patterns/#loading-code
573
573
 
574
574
  And an example of how active_record dynamically load adapters:
575
575
 
576
- https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/connection_specification.rb
576
+ https://github.com/rails/rails/blob/main/activerecord/lib/active_record/connection_adapters.rb
577
577
 
578
578
  In summary, when a gem is loaded rubygems adds the `lib` folder of the gem to the global load path `$LOAD_PATH` so that all `require` lookups will not propagate through all of the folders on the load path. When a `require` is issued each folder on the `$LOAD_PATH` is checked for the file and/or folder referenced. This allows a gem (like activerecord-import) to define push the activerecord-import folder (or namespace) on the `$LOAD_PATH` and any adapters provided by activerecord-import will be found by rubygems when the require is issued.
579
579
 
@@ -44,8 +44,6 @@ require adapter_schema if File.exist?(adapter_schema)
44
44
  Dir["#{File.dirname(__FILE__)}/models/*.rb"].sort.each { |file| require file }
45
45
 
46
46
  require File.join( benchmark_dir, 'lib', "#{options.adapter}_benchmark" )
47
-
48
- table_types = nil
49
47
  table_types = if options.benchmark_all_types
50
48
  ["all"]
51
49
  else
@@ -16,7 +16,7 @@ class BenchmarkBase
16
16
  end
17
17
  end
18
18
 
19
- # Returns an OpenStruct which contains two attritues, +description+ and +tms+ after performing an
19
+ # Returns a struct which contains two attritues, +description+ and +tms+ after performing an
20
20
  # actual benchmark.
21
21
  #
22
22
  # == PARAMETERS
@@ -24,9 +24,12 @@ class BenchmarkBase
24
24
  # * blk - the block of code to benchmark
25
25
  #
26
26
  # == RETURNS
27
- # An OpenStruct object with the following attributes:
27
+ # A struct object with the following attributes:
28
28
  # * description - the description of the benchmark ran
29
29
  # * tms - a Benchmark::Tms containing the results of the benchmark
30
+
31
+ BmStruct = Struct.new( :description, :tms, :failed, keyword_init: true )
32
+
30
33
  def bm( description, &block )
31
34
  tms = nil
32
35
  puts "Benchmarking #{description}"
@@ -35,7 +38,7 @@ class BenchmarkBase
35
38
  delete_all
36
39
  failed = false
37
40
 
38
- OpenStruct.new description: description, tms: tms, failed: failed
41
+ BmStruct.new( description: description, tms: tms, failed: failed )
39
42
  end
40
43
 
41
44
  # Given a model class (ie: Topic), and an array of columns and value sets
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
- require 'ostruct'
5
4
 
6
5
  #
7
6
  # == PARAMETERS
@@ -10,7 +9,7 @@ require 'ostruct'
10
9
  # * t - the table types to test. ie: myisam, innodb, memory, temporary, etc.
11
10
  #
12
11
  module BenchmarkOptionParser
13
- BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options."
12
+ BANNER = "Usage: ruby #{$0} [options]\nSee ruby #{$0} -h for more options.".freeze
14
13
 
15
14
  def self.print_banner
16
15
  puts BANNER
@@ -38,8 +37,11 @@ module BenchmarkOptionParser
38
37
  end
39
38
  end
40
39
 
40
+ OptionsStruct = Struct.new( :adapter, :table_types, :delete_on_finish, :number_of_objects, :outputs,
41
+ :benchmark_all_types, keyword_init: true )
42
+ OutputStruct = Struct.new( :format, :filename, keyword_init: true )
41
43
  def self.parse( args )
42
- options = OpenStruct.new(
44
+ options = OptionsStruct.new(
43
45
  adapter: 'mysql2',
44
46
  table_types: {},
45
47
  delete_on_finish: true,
@@ -81,12 +83,12 @@ module BenchmarkOptionParser
81
83
 
82
84
  # print results in CSV format
83
85
  opts.on( "--to-csv [String]", "Print results in a CSV file format" ) do |filename|
84
- options.outputs << OpenStruct.new( format: 'csv', filename: filename)
86
+ options.outputs << OutputStruct.new( format: 'csv', filename: filename)
85
87
  end
86
88
 
87
89
  # print results in HTML format
88
90
  opts.on( "--to-html [String]", "Print results in HTML format" ) do |filename|
89
- options.outputs << OpenStruct.new( format: 'html', filename: filename )
91
+ options.outputs << OutputStruct.new( format: 'html', filename: filename )
90
92
  end
91
93
  end # end opt.parse!
92
94
 
@@ -100,7 +102,7 @@ module BenchmarkOptionParser
100
102
  end
101
103
 
102
104
  options.number_of_objects = [1000] if options.number_of_objects.empty?
103
- options.outputs = [OpenStruct.new( format: 'html', filename: 'benchmark.html')] if options.outputs.empty?
105
+ options.outputs = [OutputStruct.new( format: 'html', filename: 'benchmark.html')] if options.outputs.empty?
104
106
 
105
107
  print_options( options )
106
108
 
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem 'activerecord', '~> 8.0.0'
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ostruct"
4
-
5
3
  module ActiveRecord::Import::ConnectionAdapters; end
6
4
 
7
5
  module ActiveRecord::Import # :nodoc:
@@ -94,7 +92,7 @@ module ActiveRecord::Import # :nodoc:
94
92
  env = ActiveSupport::Callbacks::Filters::Environment.new(model, false, nil)
95
93
  if runner.respond_to?(:call) # ActiveRecord < 5.1
96
94
  runner.call(env)
97
- else # ActiveRecord 5.1
95
+ else # ActiveRecord >= 5.1
98
96
  # Note that this is a gross simplification of ActiveSupport::Callbacks#run_callbacks.
99
97
  # It's technically possible for there to exist an "around" callback in the
100
98
  # :validate chain, but this would be an aberration, since Rails doesn't define
@@ -107,7 +105,8 @@ module ActiveRecord::Import # :nodoc:
107
105
  # no real-world use case for it.
108
106
  raise "The :validate callback chain contains an 'around' callback, which is unsupported" unless runner.final?
109
107
  runner.invoke_before(env)
110
- runner.invoke_after(env)
108
+ # Ensure a truthy value is returned. ActiveRecord < 7.2 always returned an array.
109
+ runner.invoke_after(env) || []
111
110
  end
112
111
  elsif @validate_callbacks.method(:compile).arity == 0 # ActiveRecord = 4.0
113
112
  model.instance_eval @validate_callbacks.compile
@@ -858,12 +857,11 @@ class ActiveRecord::Base
858
857
 
859
858
  private
860
859
 
861
- def associated_options(options, associated_class)
860
+ def associated_options(options, association)
862
861
  return options unless options.key?(:recursive_on_duplicate_key_update)
863
862
 
864
- table_name = associated_class.arel_table.name.to_sym
865
863
  options.merge(
866
- on_duplicate_key_update: options[:recursive_on_duplicate_key_update][table_name]
864
+ on_duplicate_key_update: options[:recursive_on_duplicate_key_update][association]
867
865
  )
868
866
  end
869
867
 
@@ -972,12 +970,12 @@ class ActiveRecord::Base
972
970
  options.delete(:returning)
973
971
 
974
972
  associated_objects_by_class.each_value do |associations|
975
- associations.each_value do |associated_records|
973
+ associations.each do |association, associated_records|
976
974
  next if associated_records.empty?
977
975
 
978
976
  associated_class = associated_records.first.class
979
977
  associated_class.bulk_import(associated_records,
980
- associated_options(options, associated_class))
978
+ associated_options(options, association))
981
979
  end
982
980
  end
983
981
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Import
5
- VERSION = "1.8.0"
5
+ VERSION = "2.0.0"
6
6
  end
7
7
  end
@@ -3,7 +3,7 @@ common: &common
3
3
  password: root
4
4
  encoding: utf8
5
5
  collation: utf8_general_ci
6
- host: localhost
6
+ host: 127.0.0.1
7
7
  database: activerecord_import_test
8
8
 
9
9
  jdbcpostgresql: &postgresql
@@ -54,7 +54,7 @@ seamless_database_pool:
54
54
  pool_adapter: mysql2
55
55
  prepared_statements: false
56
56
  master:
57
- host: localhost
57
+ host: 127.0.0.1
58
58
 
59
59
  sqlite:
60
60
  adapter: sqlite
data/test/import_test.rb CHANGED
@@ -741,14 +741,8 @@ describe "#import" do
741
741
  ]
742
742
  Book.import books
743
743
  assert_equal 2, Book.count
744
-
745
- if ENV['AR_VERSION'].to_i >= 5.0
746
- assert_equal 'draft', Book.first.read_attribute('status')
747
- assert_equal 'published', Book.last.read_attribute('status')
748
- else
749
- assert_equal 0, Book.first.read_attribute('status')
750
- assert_equal 1, Book.last.read_attribute('status')
751
- end
744
+ assert_equal 'draft', Book.first.read_attribute('status')
745
+ assert_equal 'published', Book.last.read_attribute('status')
752
746
  end
753
747
 
754
748
  it 'should be able to import enum fields with default value' do
@@ -758,32 +752,19 @@ describe "#import" do
758
752
  ]
759
753
  Book.import books
760
754
  assert_equal 1, Book.count
761
-
762
- if ENV['AR_VERSION'].to_i >= 5.0
763
- assert_equal 'draft', Book.first.read_attribute('status')
764
- else
765
- assert_equal 0, Book.first.read_attribute('status')
766
- end
755
+ assert_equal 'draft', Book.first.read_attribute('status')
767
756
  end
768
757
 
769
- if ENV['AR_VERSION'].to_f > 4.1
770
- it 'should be able to import enum fields by name' do
771
- Book.delete_all if Book.count > 0
772
- books = [
773
- Book.new(author_name: "Foo", title: "Baz", status: :draft),
774
- Book.new(author_name: "Foo2", title: "Baz2", status: :published),
775
- ]
776
- Book.import books
777
- assert_equal 2, Book.count
778
-
779
- if ENV['AR_VERSION'].to_i >= 5.0
780
- assert_equal 'draft', Book.first.read_attribute('status')
781
- assert_equal 'published', Book.last.read_attribute('status')
782
- else
783
- assert_equal 0, Book.first.read_attribute('status')
784
- assert_equal 1, Book.last.read_attribute('status')
785
- end
786
- 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')
787
768
  end
788
769
  end
789
770
 
@@ -796,13 +777,8 @@ describe "#import" do
796
777
  Book.import columns, values
797
778
  assert_equal 2, Book.count
798
779
 
799
- if ENV['AR_VERSION'].to_i >= 5.0
800
- assert_equal 'draft', Book.first.read_attribute('status')
801
- assert_equal 'published', Book.last.read_attribute('status')
802
- else
803
- assert_equal 0, Book.first.read_attribute('status')
804
- assert_equal 1, Book.last.read_attribute('status')
805
- end
780
+ assert_equal 'draft', Book.first.read_attribute('status')
781
+ assert_equal 'published', Book.last.read_attribute('status')
806
782
  end
807
783
  end
808
784
 
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Author < ActiveRecord::Base
4
- if ENV['AR_VERSION'].to_f >= 7.1
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
5
7
  has_many :composite_books, query_constraints: [:id, :author_id], inverse_of: :author
6
8
  end
7
9
  end
data/test/models/book.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Book < ActiveRecord::Base
4
4
  belongs_to :topic, inverse_of: :books
5
- if ENV['AR_VERSION'].to_f <= 7.0
5
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.0
6
6
  belongs_to :tag, foreign_key: [:tag_id, :parent_id] unless ENV["SKIP_COMPOSITE_PK"]
7
7
  else
8
8
  belongs_to :tag, query_constraints: [:tag_id, :parent_id] unless ENV["SKIP_COMPOSITE_PK"]
@@ -10,5 +10,9 @@ class Book < ActiveRecord::Base
10
10
  has_many :chapters, inverse_of: :book
11
11
  has_many :discounts, as: :discountable
12
12
  has_many :end_notes, inverse_of: :book
13
- 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
14
18
  end
@@ -3,7 +3,7 @@
3
3
  class CompositeBook < ActiveRecord::Base
4
4
  self.primary_key = %i[id author_id]
5
5
  belongs_to :author
6
- if ENV['AR_VERSION'].to_f <= 7.0
6
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.0
7
7
  unless ENV["SKIP_COMPOSITE_PK"]
8
8
  has_many :composite_chapters, inverse_of: :composite_book,
9
9
  foreign_key: [:id, :author_id]
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class CompositeChapter < ActiveRecord::Base
4
- if ENV['AR_VERSION'].to_f >= 7.1
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
5
8
  belongs_to :composite_book, inverse_of: :composite_chapters,
6
9
  query_constraints: [:composite_book_id, :author_id]
7
10
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Customer < ActiveRecord::Base
4
4
  unless ENV["SKIP_COMPOSITE_PK"]
5
- if ENV['AR_VERSION'].to_f <= 7.0
5
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.0
6
6
  has_many :orders,
7
7
  inverse_of: :customer,
8
8
  primary_key: %i(account_id id),
data/test/models/order.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Order < ActiveRecord::Base
4
4
  unless ENV["SKIP_COMPOSITE_PK"]
5
- if ENV['AR_VERSION'].to_f <= 7.0
5
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.0
6
6
  belongs_to :customer,
7
7
  inverse_of: :orders,
8
8
  primary_key: %i(account_id id),
@@ -2,7 +2,7 @@
2
2
 
3
3
  class TagAlias < ActiveRecord::Base
4
4
  unless ENV["SKIP_COMPOSITE_PK"]
5
- if ENV['AR_VERSION'].to_f <= 7.0
5
+ if ENV['AR_VERSION'].to_f <= 7.0 || ENV['AR_VERSION'].to_f >= 8.0
6
6
  belongs_to :tag, foreign_key: [:tag_id, :parent_id], required: true
7
7
  else
8
8
  belongs_to :tag, query_constraints: [:tag_id, :parent_id], required: true
data/test/models/topic.rb CHANGED
@@ -16,6 +16,7 @@ class Topic < ActiveRecord::Base
16
16
  before_validation -> { errors.add(:title, :invalid) if title == 'invalid' }
17
17
 
18
18
  has_many :books, inverse_of: :topic
19
+ has_many :novels, inverse_of: :topic, class_name: "Book"
19
20
  belongs_to :parent, class_name: "Topic"
20
21
 
21
22
  composed_of :description, mapping: [%w(title title), %w(author_name author_name)], allow_nil: true, class_name: "TopicDescription"
@@ -3,11 +3,7 @@
3
3
  class ActiveSupport::TestCase
4
4
  include ActiveRecord::TestFixtures
5
5
 
6
- if ENV['AR_VERSION'].to_f >= 5.0
7
- self.use_transactional_tests = true
8
- else
9
- self.use_transactional_fixtures = true
10
- end
6
+ self.use_transactional_tests = true
11
7
 
12
8
  class << self
13
9
  def requires_active_record_version(version_string, &blk)
@@ -84,14 +84,12 @@ def should_support_mysql_import_functionality
84
84
  end
85
85
  end
86
86
 
87
- if ENV['AR_VERSION'].to_f >= 5.1
88
- context "with virtual columns" do
89
- let(:books) { [Book.new(author_name: "foo", title: "bar")] }
90
-
91
- it "ignores virtual columns and creates record" do
92
- assert_difference "Book.count", +1 do
93
- Book.import books
94
- end
87
+ context "with virtual columns" do
88
+ let(:books) { [Book.new(author_name: "foo", title: "bar")] }
89
+
90
+ it "ignores virtual columns and creates record" do
91
+ assert_difference "Book.count", +1 do
92
+ Book.import books
95
93
  end
96
94
  end
97
95
  end
@@ -38,10 +38,8 @@ def should_support_postgresql_import_functionality
38
38
  assert !topic.changed?
39
39
  end
40
40
 
41
- if ENV['AR_VERSION'].to_f > 4.1
42
- it "moves the dirty changes to previous_changes" do
43
- assert topic.previous_changes.present?
44
- end
41
+ it "moves the dirty changes to previous_changes" do
42
+ assert topic.previous_changes.present?
45
43
  end
46
44
 
47
45
  it "marks models as persisted" do
@@ -96,15 +94,9 @@ def should_support_postgresql_import_functionality
96
94
  describe "returning" do
97
95
  let(:books) { [Book.new(author_name: "King", title: "It")] }
98
96
  let(:result) { Book.import(books, returning: %w(author_name title)) }
99
- let(:book_id) do
100
- if RUBY_PLATFORM == 'java' || ENV['AR_VERSION'].to_i >= 5.0
101
- books.first.id
102
- else
103
- books.first.id.to_s
104
- end
105
- end
106
- let(:true_returning_value) { ENV['AR_VERSION'].to_f >= 5.0 ? true : 't' }
107
- let(:false_returning_value) { ENV['AR_VERSION'].to_f >= 5.0 ? false : 'f' }
97
+ let(:book_id) { books.first.id }
98
+ let(:true_returning_value) { true }
99
+ let(:false_returning_value) { false }
108
100
 
109
101
  it "creates records" do
110
102
  assert_difference("Book.count", +1) { result }
@@ -222,23 +214,21 @@ def should_support_postgresql_import_functionality
222
214
  end
223
215
  end
224
216
 
225
- if ENV['AR_VERSION'].to_f >= 4.0
226
- describe "with a uuid primary key" do
227
- let(:vendor) { Vendor.new(name: "foo") }
228
- let(:vendors) { [vendor] }
217
+ describe "with a uuid primary key" do
218
+ let(:vendor) { Vendor.new(name: "foo") }
219
+ let(:vendors) { [vendor] }
229
220
 
230
- it "creates records" do
231
- assert_difference "Vendor.count", +1 do
232
- Vendor.import vendors
233
- end
234
- end
235
-
236
- it "assigns an id to the model objects" do
221
+ it "creates records" do
222
+ assert_difference "Vendor.count", +1 do
237
223
  Vendor.import vendors
238
- assert_not_nil vendor.id
239
224
  end
240
225
  end
241
226
 
227
+ it "assigns an id to the model objects" do
228
+ Vendor.import vendors
229
+ assert_not_nil vendor.id
230
+ end
231
+
242
232
  describe "with an assigned uuid primary key" do
243
233
  let(:id) { SecureRandom.uuid }
244
234
  let(:vendor) { Vendor.new(id: id, name: "foo") }
@@ -254,44 +244,38 @@ def should_support_postgresql_import_functionality
254
244
  end
255
245
 
256
246
  describe "with store accessor fields" do
257
- if ENV['AR_VERSION'].to_f >= 4.0
258
- it "imports values for json fields" do
259
- vendors = [Vendor.new(name: 'Vendor 1', size: 100)]
260
- assert_difference "Vendor.count", +1 do
261
- Vendor.import vendors
262
- end
263
- assert_equal(100, Vendor.first.size)
247
+ it "imports values for json fields" do
248
+ vendors = [Vendor.new(name: 'Vendor 1', size: 100)]
249
+ assert_difference "Vendor.count", +1 do
250
+ Vendor.import vendors
264
251
  end
252
+ assert_equal(100, Vendor.first.size)
253
+ end
265
254
 
266
- it "imports values for hstore fields" do
267
- vendors = [Vendor.new(name: 'Vendor 1', contact: 'John Smith')]
268
- assert_difference "Vendor.count", +1 do
269
- Vendor.import vendors
270
- end
271
- assert_equal('John Smith', Vendor.first.contact)
255
+ it "imports values for hstore fields" do
256
+ vendors = [Vendor.new(name: 'Vendor 1', contact: 'John Smith')]
257
+ assert_difference "Vendor.count", +1 do
258
+ Vendor.import vendors
272
259
  end
260
+ assert_equal('John Smith', Vendor.first.contact)
273
261
  end
274
262
 
275
- if ENV['AR_VERSION'].to_f >= 4.2
276
- it "imports values for jsonb fields" do
277
- vendors = [Vendor.new(name: 'Vendor 1', charge_code: '12345')]
278
- assert_difference "Vendor.count", +1 do
279
- Vendor.import vendors
280
- end
281
- assert_equal('12345', Vendor.first.charge_code)
263
+ it "imports values for jsonb fields" do
264
+ vendors = [Vendor.new(name: 'Vendor 1', charge_code: '12345')]
265
+ assert_difference "Vendor.count", +1 do
266
+ Vendor.import vendors
282
267
  end
268
+ assert_equal('12345', Vendor.first.charge_code)
283
269
  end
284
270
  end
285
271
 
286
- if ENV['AR_VERSION'].to_f >= 4.2
287
- describe "with serializable fields" do
288
- it "imports default values as correct data type" do
289
- vendors = [Vendor.new(name: 'Vendor 1')]
290
- assert_difference "Vendor.count", +1 do
291
- Vendor.import vendors
292
- end
293
- assert_equal({}, Vendor.first.json_data)
272
+ describe "with serializable fields" do
273
+ it "imports default values as correct data type" do
274
+ vendors = [Vendor.new(name: 'Vendor 1')]
275
+ assert_difference "Vendor.count", +1 do
276
+ Vendor.import vendors
294
277
  end
278
+ assert_equal({}, Vendor.first.json_data)
295
279
  end
296
280
 
297
281
  %w(json jsonb).each do |json_type|
@@ -278,6 +278,45 @@ def should_support_recursive_import
278
278
  end
279
279
  assert_equal new_chapter_title, Chapter.find(example_chapter.id).title
280
280
  end
281
+
282
+ context "when a non-standard association name is used" do
283
+ let(:new_topics) do
284
+ topic = Build(:topic)
285
+
286
+ 2.times do
287
+ novel = topic.novels.build(title: FactoryBot.generate(:book_title), author_name: 'Stephen King')
288
+ 3.times do
289
+ novel.chapters.build(title: FactoryBot.generate(:chapter_title))
290
+ end
291
+
292
+ 4.times do
293
+ novel.end_notes.build(note: FactoryBot.generate(:end_note))
294
+ end
295
+ end
296
+
297
+ [topic]
298
+ end
299
+
300
+ it "updates nested associated objects" do
301
+ new_chapter_title = 'The Final Chapter'
302
+ novel = new_topics.first.novels.first
303
+ novel.author_name = 'Richard Bachman'
304
+
305
+ example_chapter = novel.chapters.first
306
+ example_chapter.title = new_chapter_title
307
+
308
+ assert_nothing_raised do
309
+ Topic.import new_topics,
310
+ recursive: true,
311
+ on_duplicate_key_update: [:id],
312
+ recursive_on_duplicate_key_update: {
313
+ novels: { conflict_target: [:id], columns: [:author_name] },
314
+ chapters: { conflict_target: [:id], columns: [:title] }
315
+ }
316
+ end
317
+ assert_equal new_chapter_title, Chapter.find(example_chapter.id).title
318
+ end
319
+ end
281
320
  end
282
321
  end
283
322
 
data/test/test_helper.rb CHANGED
@@ -13,19 +13,16 @@ ENV["RAILS_ENV"] = "test"
13
13
  require "bundler"
14
14
  Bundler.setup
15
15
 
16
- require 'pry' unless RbConfig::CONFIG["RUBY_INSTALL_NAME"] =~ /jruby/
16
+ unless RbConfig::CONFIG["RUBY_INSTALL_NAME"] =~ /jruby/
17
+ require 'pry'
18
+ require 'pry-byebug'
19
+ end
17
20
 
18
21
  require "active_record"
19
22
  require "active_record/fixtures"
20
23
  require "active_support/test_case"
21
-
22
- if ActiveSupport::VERSION::STRING < "4.0"
23
- require 'test/unit'
24
- require 'mocha/test_unit'
25
- else
26
- require 'active_support/testing/autorun'
27
- require "mocha/minitest"
28
- end
24
+ require 'active_support/testing/autorun'
25
+ require "mocha/minitest"
29
26
 
30
27
  require 'timecop'
31
28
  require 'chronic'
@@ -38,16 +35,6 @@ rescue LoadError
38
35
  end
39
36
  end
40
37
 
41
- # Support MySQL 5.7
42
- if ActiveSupport::VERSION::STRING < "4.1"
43
- require "active_record/connection_adapters/mysql2_adapter"
44
- class ActiveRecord::ConnectionAdapters::Mysql2Adapter
45
- NATIVE_DATABASE_TYPES[:primary_key] = "int(11) auto_increment PRIMARY KEY"
46
- end
47
- end
48
-
49
- require "ruby-debug" if RUBY_VERSION.to_f < 1.9
50
-
51
38
  adapter = ENV["ARE_DB"] || "sqlite3"
52
39
 
53
40
  FileUtils.mkdir_p 'log'
@@ -99,4 +86,4 @@ Dir["#{File.dirname(__FILE__)}/models/*.rb"].sort.each { |file| require file }
99
86
  # Prevent this deprecation warning from breaking the tests.
100
87
  Rake::FileList.send(:remove_method, :import)
101
88
 
102
- ActiveSupport::TestCase.test_order = :random if ENV['AR_VERSION'].to_f >= 4.2
89
+ ActiveSupport::TestCase.test_order = :random
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-import
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Dennis
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-23 00:00:00.000000000 Z
11
+ date: 2024-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -70,15 +70,13 @@ files:
70
70
  - benchmarks/models/test_myisam.rb
71
71
  - benchmarks/schema/mysql2_schema.rb
72
72
  - docker-compose.yml
73
- - gemfiles/4.2.gemfile
74
- - gemfiles/5.0.gemfile
75
- - gemfiles/5.1.gemfile
76
73
  - gemfiles/5.2.gemfile
77
74
  - gemfiles/6.0.gemfile
78
75
  - gemfiles/6.1.gemfile
79
76
  - gemfiles/7.0.gemfile
80
77
  - gemfiles/7.1.gemfile
81
78
  - gemfiles/7.2.gemfile
79
+ - gemfiles/8.0.gemfile
82
80
  - lib/activerecord-import.rb
83
81
  - lib/activerecord-import/active_record/adapters/abstract_adapter.rb
84
82
  - lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb
@@ -98,9 +96,6 @@ files:
98
96
  - lib/activerecord-import/adapters/trilogy_adapter.rb
99
97
  - lib/activerecord-import/base.rb
100
98
  - lib/activerecord-import/import.rb
101
- - lib/activerecord-import/mysql2.rb
102
- - lib/activerecord-import/postgresql.rb
103
- - lib/activerecord-import/sqlite3.rb
104
99
  - lib/activerecord-import/synchronize.rb
105
100
  - lib/activerecord-import/value_sets_parser.rb
106
101
  - lib/activerecord-import/version.rb
@@ -187,7 +182,7 @@ licenses:
187
182
  - MIT
188
183
  metadata:
189
184
  changelog_uri: https://github.com/zdennis/activerecord-import/blob/master/CHANGELOG.md
190
- post_install_message:
185
+ post_install_message:
191
186
  rdoc_options: []
192
187
  require_paths:
193
188
  - lib
@@ -202,8 +197,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
197
  - !ruby/object:Gem::Version
203
198
  version: '0'
204
199
  requirements: []
205
- rubygems_version: 3.5.11
206
- signing_key:
200
+ rubygems_version: 3.0.3.1
201
+ signing_key:
207
202
  specification_version: 4
208
203
  summary: Bulk insert extension for ActiveRecord
209
204
  test_files:
data/gemfiles/4.2.gemfile DELETED
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- gem 'activerecord', '~> 4.2.0'
4
- gem 'composite_primary_keys', '~> 8.0'
data/gemfiles/5.0.gemfile DELETED
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- gem 'activerecord', '~> 5.0.0'
4
- gem 'composite_primary_keys', '~> 9.0'
data/gemfiles/5.1.gemfile DELETED
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- gem 'activerecord', '~> 5.1.0'
4
- gem 'composite_primary_keys', '~> 10.0'
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- warn <<-MSG
4
- [DEPRECATION] loading activerecord-import via 'require "activerecord-import/<adapter-name>"'
5
- is deprecated. Update to autorequire using 'require "activerecord-import"'. See
6
- http://github.com/zdennis/activerecord-import/wiki/Requiring for more information
7
- MSG
8
-
9
- require "activerecord-import"
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- warn <<-MSG
4
- [DEPRECATION] loading activerecord-import via 'require "activerecord-import/<adapter-name>"'
5
- is deprecated. Update to autorequire using 'require "activerecord-import"'. See
6
- http://github.com/zdennis/activerecord-import/wiki/Requiring for more information
7
- MSG
8
-
9
- require "activerecord-import"
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- warn <<-MSG
4
- [DEPRECATION] loading activerecord-import via 'require "activerecord-import/<adapter-name>"'
5
- is deprecated. Update to autorequire using 'require "activerecord-import"'. See
6
- http://github.com/zdennis/activerecord-import/wiki/Requiring for more information
7
- MSG
8
-
9
- require "activerecord-import"