activerecord-import 1.8.0 → 2.0.0

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