activerecord-import 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yaml +7 -1
  3. data/.rubocop.yml +4 -4
  4. data/.rubocop_todo.yml +6 -16
  5. data/CHANGELOG.md +13 -1
  6. data/Gemfile +3 -3
  7. data/README.markdown +6 -4
  8. data/benchmarks/benchmark.rb +3 -3
  9. data/benchmarks/lib/base.rb +2 -2
  10. data/benchmarks/lib/cli_parser.rb +1 -1
  11. data/lib/activerecord-import/adapters/abstract_adapter.rb +6 -5
  12. data/lib/activerecord-import/adapters/mysql_adapter.rb +24 -18
  13. data/lib/activerecord-import/adapters/postgresql_adapter.rb +26 -18
  14. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +29 -23
  15. data/lib/activerecord-import/import.rb +39 -22
  16. data/lib/activerecord-import/value_sets_parser.rb +1 -0
  17. data/lib/activerecord-import/version.rb +1 -1
  18. data/test/jdbcmysql/import_test.rb +3 -3
  19. data/test/jdbcpostgresql/import_test.rb +2 -2
  20. data/test/jdbcsqlite3/import_test.rb +2 -2
  21. data/test/makara_postgis/import_test.rb +2 -2
  22. data/test/models/bike_maker.rb +1 -0
  23. data/test/models/topic.rb +5 -0
  24. data/test/mysql2/import_test.rb +3 -3
  25. data/test/mysql2_makara/import_test.rb +3 -3
  26. data/test/mysqlspatial2/import_test.rb +3 -3
  27. data/test/postgis/import_test.rb +2 -2
  28. data/test/postgresql/import_test.rb +2 -2
  29. data/test/schema/generic_schema.rb +1 -0
  30. data/test/schema/jdbcpostgresql_schema.rb +1 -1
  31. data/test/schema/postgis_schema.rb +1 -1
  32. data/test/sqlite3/import_test.rb +2 -2
  33. data/test/support/shared_examples/on_duplicate_key_update.rb +39 -10
  34. data/test/test_helper.rb +3 -3
  35. data/test/value_sets_bytes_parser_test.rb +1 -1
  36. data/test/value_sets_records_parser_test.rb +1 -1
  37. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b9c717d31cf5a4012568c9d8497947466408be7fef5610fba9143f7a911ed7c
4
- data.tar.gz: 925bc5f645152eeb09f9583e9d50b9be67c4bfa8049c303571f82649262e4d5b
3
+ metadata.gz: 866dd09466fbda981329e13916e89986cb47d65259f0889b8a3b53aeca1aee32
4
+ data.tar.gz: 258a0d2fc34bbb928500e2f8a83df4f5bdc8901c25e2e123a569c56d587d3f53
5
5
  SHA512:
6
- metadata.gz: 409d66e4d4e6e9ac31940cea097837d76c93cbeb4b95461323afc6a5f2ace736f945705e5ef33f2a851bb92c13c27e19ffbc14c7e776a0366f1d76091cafd51f
7
- data.tar.gz: 6a0eaa48b85f7b1863dfb2b04c3c193a5e7e1108084556ba1b25fa303bccb40f62dd706ec8d4b5c3394239f167eb1807dfff4fe292edc1e4ad550719a9a63446
6
+ metadata.gz: 989562e1fb64d669a96211c6b80df5b89d8a43aa38575ec6706d0633b405983a63849bd5fb78d4031ed7e4b2c239192f62d4b3d9e720f4c474cd3801600d11ef
7
+ data.tar.gz: 22e6ccbb750bb7851930d98c2b90f496c759d35503c8c1e58b841f4a928a283c486caec3f22cb57e6948b6960e6fff2a598499f0670f59b281e321dded20c183
@@ -20,13 +20,19 @@ jobs:
20
20
  fail-fast: false
21
21
  matrix:
22
22
  ruby:
23
- - 3.1
23
+ - 3.2
24
24
  env:
25
25
  - AR_VERSION: '7.0'
26
26
  RUBYOPT: --enable-frozen-string-literal
27
27
  - AR_VERSION: 6.1
28
28
  RUBYOPT: --enable-frozen-string-literal
29
29
  include:
30
+ - ruby: 3.1
31
+ env:
32
+ AR_VERSION: '7.0'
33
+ - ruby: 3.1
34
+ env:
35
+ AR_VERSION: 6.1
30
36
  - ruby: '3.0'
31
37
  env:
32
38
  AR_VERSION: '7.0'
data/.rubocop.yml CHANGED
@@ -66,10 +66,10 @@ Style/SymbolArray:
66
66
  Style/TrailingCommaInArrayLiteral:
67
67
  Enabled: false
68
68
 
69
- Layout/AlignArguments:
69
+ Layout/ArgumentAlignment:
70
70
  Enabled: false
71
71
 
72
- Layout/AlignParameters:
72
+ Layout/ParameterAlignment:
73
73
  EnforcedStyle: with_fixed_indentation
74
74
 
75
75
  Layout/EndAlignment:
@@ -81,7 +81,7 @@ Layout/ElseAlignment:
81
81
  Layout/EmptyLineAfterGuardClause:
82
82
  Enabled: false
83
83
 
84
- Layout/IndentHeredoc:
84
+ Layout/HeredocIndentation:
85
85
  Enabled: false
86
86
 
87
87
  Layout/SpaceInsideParens:
@@ -102,7 +102,7 @@ Lint/PercentStringArray:
102
102
  Naming/HeredocDelimiterNaming:
103
103
  Enabled: false
104
104
 
105
- Naming/UncommunicativeMethodParamName:
105
+ Naming/MethodParameterName:
106
106
  Enabled: false
107
107
 
108
108
  Security/YAMLLoad:
data/.rubocop_todo.yml CHANGED
@@ -1,36 +1,26 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2016-03-17 18:14:55 -0700 using RuboCop version 0.38.0.
3
+ # on 2023-02-15 00:58:14 UTC using RuboCop version 1.45.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 2
10
- Lint/HandleExceptions:
11
- Exclude:
12
- - 'lib/activerecord-import/base.rb'
13
- - 'test/import_test.rb'
14
-
15
9
  # Offense count: 2
16
10
  Lint/RescueException:
17
11
  Exclude:
18
12
  - 'benchmarks/lib/cli_parser.rb'
19
13
  - 'test/import_test.rb'
20
14
 
21
- # Offense count: 4
22
- # Cop supports --auto-correct.
23
- # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
15
+ # Offense count: 3
16
+ # This cop supports safe autocorrection (--autocorrect).
17
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods.
24
18
  Lint/UnusedMethodArgument:
25
19
  Exclude:
26
20
  - 'lib/activerecord-import/adapters/postgresql_adapter.rb'
27
21
  - 'lib/activerecord-import/import.rb'
28
22
 
29
23
  # Offense count: 2
30
- # Cop supports --auto-correct.
31
- # Configuration parameters: Keywords.
32
- # Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW
33
- Style/CommentAnnotation:
24
+ Style/CombinableLoops:
34
25
  Exclude:
35
- - 'benchmarks/lib/cli_parser.rb'
36
- - 'lib/activerecord-import/import.rb'
26
+ - 'test/support/shared_examples/recursive_import.rb'
data/CHANGELOG.md CHANGED
@@ -1,8 +1,20 @@
1
+ ## Changes in 1.5.0
2
+
3
+ ### New Features
4
+
5
+ * Add Rails 7.1 support. Thanks to @gucki via \##807.
6
+ * Add support for alias attributes. Thanks to @leonidkroka via \##799.
7
+
8
+ ### Fixes
9
+
10
+ * Support for multi-byte column names when splitting queries. Thanks to @TakuyaKurimoto via \##801.
11
+ * Fix issue with track_validation_failures when import models. Thanks to @OtaYohihiro via \##798.
12
+
1
13
  ## Changes in 1.4.1
2
14
 
3
15
  ### Fixes
4
16
 
5
- * Fix importing models that have required belongs_to associations and use composite primary keys. Thanks to @thoughtbot-summer vi \##783.
17
+ * Fix importing models that have required belongs_to associations and use composite primary keys. Thanks to @thoughtbot-summer via \##783.
6
18
 
7
19
  ## Changes in 1.4.0
8
20
 
data/Gemfile CHANGED
@@ -15,7 +15,7 @@ pg_version = '0.9'
15
15
  pg_version = '1.1' if version >= 6.1
16
16
 
17
17
  group :development, :test do
18
- gem 'rubocop', '~> 0.71.0'
18
+ gem 'rubocop'
19
19
  gem 'rake'
20
20
  end
21
21
 
@@ -40,7 +40,7 @@ end
40
40
  gem "factory_bot"
41
41
  gem "timecop"
42
42
  gem "chronic"
43
- gem "mocha", "~> 1.3.0"
43
+ gem "mocha", "~> 2.1.0"
44
44
 
45
45
  # Debugging
46
46
  platforms :jruby do
@@ -49,7 +49,7 @@ end
49
49
 
50
50
  platforms :ruby do
51
51
  gem "pry-byebug"
52
- gem "pry", "~> 0.12.0"
52
+ gem "pry", "~> 0.14.0"
53
53
  end
54
54
 
55
55
  if version >= 4.0
data/README.markdown CHANGED
@@ -245,8 +245,8 @@ Book.import columns, books, batch_size: 2, batch_progress: my_proc
245
245
 
246
246
  #### Recursive
247
247
 
248
- NOTE: This only works with PostgreSQL and ActiveRecord objects. This won't work with
249
- hashes or arrays as recursive inputs.
248
+ > **Note**
249
+ > This only works with PostgreSQL and ActiveRecord objects. This won't work with hashes or arrays as recursive inputs.
250
250
 
251
251
  Assume that Books <code>has_many</code> Reviews.
252
252
 
@@ -434,7 +434,8 @@ Should you wish to specify those columns, you may use the option `timestamps: fa
434
434
  However, it is also possible to set just `:created_at` in specific records. In this case despite using `timestamps: true`, `:created_at` will be updated only in records where that field is `nil`. Same rule applies for record associations when enabling the option `recursive: true`.
435
435
 
436
436
  If you are using custom time zones, these will be respected when performing imports as well as long as `ActiveRecord::Base.default_timezone` is set, which for practically all Rails apps it is.
437
- NOTE: If you are using ActiveRecord 7.0 or later, please use `ActiveRecord.default_timezone` instead.
437
+ > **Note**
438
+ > If you are using ActiveRecord 7.0 or later, please use `ActiveRecord.default_timezone` instead.
438
439
 
439
440
  ### Callbacks
440
441
 
@@ -506,7 +507,8 @@ This allows an external gem to dynamically add an adapter without the need to ad
506
507
 
507
508
  ### Requiring
508
509
 
509
- Note: These instructions will only work if you are using version 0.2.0 or higher.
510
+ > **Note**
511
+ > These instructions will only work if you are using version 0.2.0 or higher.
510
512
 
511
513
  #### Autoloading via Bundler
512
514
 
@@ -41,7 +41,7 @@ require File.join(benchmark_dir, "../test/schema/generic_schema")
41
41
  adapter_schema = File.join(benchmark_dir, "schema/#{options.adapter}_schema.rb")
42
42
  require adapter_schema if File.exist?(adapter_schema)
43
43
 
44
- Dir[File.dirname(__FILE__) + "/models/*.rb"].each { |file| require file }
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
47
 
@@ -53,8 +53,8 @@ else
53
53
  end
54
54
 
55
55
  letter = options.adapter[0].chr
56
- clazz_str = letter.upcase + options.adapter[1..-1].downcase
57
- clazz = Object.const_get( clazz_str + "Benchmark" )
56
+ clazz_str = letter.upcase + options.adapter[1..].downcase
57
+ clazz = Object.const_get( "#{clazz_str}Benchmark" )
58
58
 
59
59
  benchmarks = []
60
60
  options.number_of_objects.each do |num|
@@ -27,11 +27,11 @@ class BenchmarkBase
27
27
  # An OpenStruct 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
- def bm( description )
30
+ def bm( description, &block )
31
31
  tms = nil
32
32
  puts "Benchmarking #{description}"
33
33
 
34
- Benchmark.bm { |x| tms = x.report { yield } }
34
+ Benchmark.bm { |x| tms = x.report(&block) }
35
35
  delete_all
36
36
  failed = false
37
37
 
@@ -29,7 +29,7 @@ module BenchmarkOptionParser
29
29
  print_valid_table_types( options, prefix: " " )
30
30
  end
31
31
 
32
- # TODO IMPLEMENT THIS
32
+ # TODO: IMPLEMENT THIS
33
33
  def self.print_valid_table_types( options, hsh = { prefix: '' } )
34
34
  if !options.table_types.keys.empty?
35
35
  options.table_types.keys.sort.each { |type| puts hsh[:prefix].to_s + type.to_s }
@@ -9,10 +9,11 @@ module ActiveRecord::Import::AbstractAdapter
9
9
  def insert_many( sql, values, _options = {}, *args ) # :nodoc:
10
10
  number_of_inserts = 1
11
11
 
12
- base_sql, post_sql = if sql.is_a?( String )
13
- [sql, '']
14
- elsif sql.is_a?( Array )
15
- [sql.shift, sql.join( ' ' )]
12
+ base_sql, post_sql = case sql
13
+ when String
14
+ [sql, '']
15
+ when Array
16
+ [sql.shift, sql.join( ' ' )]
16
17
  end
17
18
 
18
19
  sql2insert = base_sql + values.join( ',' ) + post_sql
@@ -47,7 +48,7 @@ module ActiveRecord::Import::AbstractAdapter
47
48
  post_sql_statements = []
48
49
 
49
50
  if supports_on_duplicate_key_update? && options[:on_duplicate_key_update]
50
- post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:primary_key], options[:locking_column] )
51
+ post_sql_statements << sql_for_on_duplicate_key_update( table_name, options[:on_duplicate_key_update], options[:model], options[:primary_key], options[:locking_column] )
51
52
  elsif logger && options[:on_duplicate_key_update]
52
53
  logger.warn "Ignoring on_duplicate_key_update because it is not supported by the database."
53
54
  end
@@ -13,13 +13,14 @@ module ActiveRecord::Import::MysqlAdapter
13
13
  # the number of inserts default
14
14
  number_of_inserts = 0
15
15
 
16
- base_sql, post_sql = if sql.is_a?( String )
17
- [sql, '']
18
- elsif sql.is_a?( Array )
19
- [sql.shift, sql.join( ' ' )]
16
+ base_sql, post_sql = case sql
17
+ when String
18
+ [sql, '']
19
+ when Array
20
+ [sql.shift, sql.join( ' ' )]
20
21
  end
21
22
 
22
- sql_size = QUERY_OVERHEAD + base_sql.size + post_sql.size
23
+ sql_size = QUERY_OVERHEAD + base_sql.bytesize + post_sql.bytesize
23
24
 
24
25
  # the number of bytes the requested insert statement values will take up
25
26
  values_in_bytes = values.sum(&:bytesize)
@@ -33,7 +34,7 @@ module ActiveRecord::Import::MysqlAdapter
33
34
  max = max_allowed_packet
34
35
 
35
36
  # if we can insert it all as one statement
36
- if NO_MAX_PACKET == max || total_bytes <= max || options[:force_single_insert]
37
+ if max == NO_MAX_PACKET || total_bytes <= max || options[:force_single_insert]
37
38
  number_of_inserts += 1
38
39
  sql2insert = base_sql + values.join( ',' ) + post_sql
39
40
  insert( sql2insert, *args )
@@ -85,13 +86,13 @@ module ActiveRecord::Import::MysqlAdapter
85
86
  # in +args+.
86
87
  def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
87
88
  sql = ' ON DUPLICATE KEY UPDATE '.dup
88
- arg = args.first
89
- locking_column = args.last
90
- if arg.is_a?( Array )
91
- sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arg )
92
- elsif arg.is_a?( Hash )
93
- sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, arg )
94
- elsif arg.is_a?( String )
89
+ arg, model, _primary_key, locking_column = args
90
+ case arg
91
+ when Array
92
+ sql << sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, arg )
93
+ when Hash
94
+ sql << sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, arg )
95
+ when String
95
96
  sql << arg
96
97
  else
97
98
  raise ArgumentError, "Expected Array or Hash"
@@ -99,19 +100,24 @@ module ActiveRecord::Import::MysqlAdapter
99
100
  sql
100
101
  end
101
102
 
102
- def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
103
+ def sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, arr ) # :nodoc:
103
104
  results = arr.map do |column|
104
- qc = quote_column_name( column )
105
+ original_column_name = model.attribute_alias?( column ) ? model.attribute_alias( column ) : column
106
+ qc = quote_column_name( original_column_name )
105
107
  "#{table_name}.#{qc}=VALUES(#{qc})"
106
108
  end
107
109
  increment_locking_column!(table_name, results, locking_column)
108
110
  results.join( ',' )
109
111
  end
110
112
 
111
- def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
113
+ def sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, hsh ) # :nodoc:
112
114
  results = hsh.map do |column1, column2|
113
- qc1 = quote_column_name( column1 )
114
- qc2 = quote_column_name( column2 )
115
+ original_column1_name = model.attribute_alias?( column1 ) ? model.attribute_alias( column1 ) : column1
116
+ qc1 = quote_column_name( original_column1_name )
117
+
118
+ original_column2_name = model.attribute_alias?( column2 ) ? model.attribute_alias( column2 ) : column2
119
+ qc2 = quote_column_name( original_column2_name )
120
+
115
121
  "#{table_name}.#{qc1}=VALUES( #{qc2} )"
116
122
  end
117
123
  increment_locking_column!(table_name, results, locking_column)
@@ -12,10 +12,11 @@ module ActiveRecord::Import::PostgreSQLAdapter
12
12
  ids = []
13
13
  results = []
14
14
 
15
- base_sql, post_sql = if sql.is_a?( String )
16
- [sql, '']
17
- elsif sql.is_a?( Array )
18
- [sql.shift, sql.join( ' ' )]
15
+ base_sql, post_sql = case sql
16
+ when String
17
+ [sql, '']
18
+ when Array
19
+ [sql.shift, sql.join( ' ' )]
19
20
  end
20
21
 
21
22
  sql2insert = base_sql + values.join( ',' ) + post_sql
@@ -110,13 +111,14 @@ module ActiveRecord::Import::PostgreSQLAdapter
110
111
  # Add a column to be updated on duplicate key update
111
112
  def add_column_for_on_duplicate_key_update( column, options = {} ) # :nodoc:
112
113
  arg = options[:on_duplicate_key_update]
113
- if arg.is_a?( Hash )
114
+ case arg
115
+ when Hash
114
116
  columns = arg.fetch( :columns ) { arg[:columns] = [] }
115
117
  case columns
116
118
  when Array then columns << column.to_sym unless columns.include?( column.to_sym )
117
119
  when Hash then columns[column.to_sym] = column.to_sym
118
120
  end
119
- elsif arg.is_a?( Array )
121
+ when Array
120
122
  arg << column.to_sym unless arg.include?( column.to_sym )
121
123
  end
122
124
  end
@@ -132,7 +134,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
132
134
  # Returns a generated ON CONFLICT DO UPDATE statement given the passed
133
135
  # in +args+.
134
136
  def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
135
- arg, primary_key, locking_column = args
137
+ arg, model, primary_key, locking_column = args
136
138
  arg = { columns: arg } if arg.is_a?( Array ) || arg.is_a?( String )
137
139
  return unless arg.is_a?( Hash )
138
140
 
@@ -151,11 +153,12 @@ module ActiveRecord::Import::PostgreSQLAdapter
151
153
  end
152
154
 
153
155
  sql << "#{conflict_target}DO UPDATE SET "
154
- if columns.is_a?( Array )
155
- sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, columns )
156
- elsif columns.is_a?( Hash )
157
- sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, columns )
158
- elsif columns.is_a?( String )
156
+ case columns
157
+ when Array
158
+ sql << sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, columns )
159
+ when Hash
160
+ sql << sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, columns )
161
+ when String
159
162
  sql << columns
160
163
  else
161
164
  raise ArgumentError, 'Expected :columns to be an Array or Hash'
@@ -166,19 +169,24 @@ module ActiveRecord::Import::PostgreSQLAdapter
166
169
  sql
167
170
  end
168
171
 
169
- def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
172
+ def sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, arr ) # :nodoc:
170
173
  results = arr.map do |column|
171
- qc = quote_column_name( column )
174
+ original_column_name = model.attribute_alias?( column ) ? model.attribute_alias( column ) : column
175
+ qc = quote_column_name( original_column_name )
172
176
  "#{qc}=EXCLUDED.#{qc}"
173
177
  end
174
178
  increment_locking_column!(table_name, results, locking_column)
175
179
  results.join( ',' )
176
180
  end
177
181
 
178
- def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
182
+ def sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, hsh ) # :nodoc:
179
183
  results = hsh.map do |column1, column2|
180
- qc1 = quote_column_name( column1 )
181
- qc2 = quote_column_name( column2 )
184
+ original_column1_name = model.attribute_alias?( column1 ) ? model.attribute_alias( column1 ) : column1
185
+ qc1 = quote_column_name( original_column1_name )
186
+
187
+ original_column2_name = model.attribute_alias?( column2 ) ? model.attribute_alias( column2 ) : column2
188
+ qc2 = quote_column_name( original_column2_name )
189
+
182
190
  "#{qc1}=EXCLUDED.#{qc2}"
183
191
  end
184
192
  increment_locking_column!(table_name, results, locking_column)
@@ -192,7 +200,7 @@ module ActiveRecord::Import::PostgreSQLAdapter
192
200
  if constraint_name.present?
193
201
  "ON CONSTRAINT #{constraint_name} "
194
202
  elsif conflict_target.present?
195
- sql = '(' + Array( conflict_target ).reject( &:blank? ).join( ', ' ) + ') '
203
+ sql = "(#{Array( conflict_target ).reject( &:blank? ).join( ', ' )}) "
196
204
  sql += "WHERE #{index_predicate} " if index_predicate
197
205
  sql
198
206
  end
@@ -24,10 +24,11 @@ module ActiveRecord::Import::SQLite3Adapter
24
24
  def insert_many( sql, values, _options = {}, *args ) # :nodoc:
25
25
  number_of_inserts = 0
26
26
 
27
- base_sql, post_sql = if sql.is_a?( String )
28
- [sql, '']
29
- elsif sql.is_a?( Array )
30
- [sql.shift, sql.join( ' ' )]
27
+ base_sql, post_sql = case sql
28
+ when String
29
+ [sql, '']
30
+ when Array
31
+ [sql.shift, sql.join( ' ' )]
31
32
  end
32
33
 
33
34
  value_sets = ::ActiveRecord::Import::ValueSetsRecordsParser.parse(values,
@@ -56,11 +57,9 @@ module ActiveRecord::Import::SQLite3Adapter
56
57
  def post_sql_statements( table_name, options ) # :nodoc:
57
58
  sql = []
58
59
 
59
- if supports_on_duplicate_key_update?
60
- # Options :recursive and :on_duplicate_key_ignore are mutually exclusive
61
- if (options[:ignore] || options[:on_duplicate_key_ignore]) && !options[:on_duplicate_key_update]
62
- sql << sql_for_on_duplicate_key_ignore( options[:on_duplicate_key_ignore] )
63
- end
60
+ # Options :recursive and :on_duplicate_key_ignore are mutually exclusive
61
+ if supports_on_duplicate_key_update? && ((options[:ignore] || options[:on_duplicate_key_ignore]) && !options[:on_duplicate_key_update])
62
+ sql << sql_for_on_duplicate_key_ignore( options[:on_duplicate_key_ignore] )
64
63
  end
65
64
 
66
65
  sql + super
@@ -73,13 +72,14 @@ module ActiveRecord::Import::SQLite3Adapter
73
72
  # Add a column to be updated on duplicate key update
74
73
  def add_column_for_on_duplicate_key_update( column, options = {} ) # :nodoc:
75
74
  arg = options[:on_duplicate_key_update]
76
- if arg.is_a?( Hash )
75
+ case arg
76
+ when Hash
77
77
  columns = arg.fetch( :columns ) { arg[:columns] = [] }
78
78
  case columns
79
79
  when Array then columns << column.to_sym unless columns.include?( column.to_sym )
80
80
  when Hash then columns[column.to_sym] = column.to_sym
81
81
  end
82
- elsif arg.is_a?( Array )
82
+ when Array
83
83
  arg << column.to_sym unless arg.include?( column.to_sym )
84
84
  end
85
85
  end
@@ -95,7 +95,7 @@ module ActiveRecord::Import::SQLite3Adapter
95
95
  # Returns a generated ON CONFLICT DO UPDATE statement given the passed
96
96
  # in +args+.
97
97
  def sql_for_on_duplicate_key_update( table_name, *args ) # :nodoc:
98
- arg, primary_key, locking_column = args
98
+ arg, model, primary_key, locking_column = args
99
99
  arg = { columns: arg } if arg.is_a?( Array ) || arg.is_a?( String )
100
100
  return unless arg.is_a?( Hash )
101
101
 
@@ -114,11 +114,12 @@ module ActiveRecord::Import::SQLite3Adapter
114
114
  end
115
115
 
116
116
  sql << "#{conflict_target}DO UPDATE SET "
117
- if columns.is_a?( Array )
118
- sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, columns )
119
- elsif columns.is_a?( Hash )
120
- sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, columns )
121
- elsif columns.is_a?( String )
117
+ case columns
118
+ when Array
119
+ sql << sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, columns )
120
+ when Hash
121
+ sql << sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, columns )
122
+ when String
122
123
  sql << columns
123
124
  else
124
125
  raise ArgumentError, 'Expected :columns to be an Array or Hash'
@@ -129,19 +130,24 @@ module ActiveRecord::Import::SQLite3Adapter
129
130
  sql
130
131
  end
131
132
 
132
- def sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arr ) # :nodoc:
133
+ def sql_for_on_duplicate_key_update_as_array( table_name, model, locking_column, arr ) # :nodoc:
133
134
  results = arr.map do |column|
134
- qc = quote_column_name( column )
135
+ original_column_name = model.attribute_alias?( column ) ? model.attribute_alias( column ) : column
136
+ qc = quote_column_name( original_column_name )
135
137
  "#{qc}=EXCLUDED.#{qc}"
136
138
  end
137
139
  increment_locking_column!(table_name, results, locking_column)
138
140
  results.join( ',' )
139
141
  end
140
142
 
141
- def sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, hsh ) # :nodoc:
143
+ def sql_for_on_duplicate_key_update_as_hash( table_name, model, locking_column, hsh ) # :nodoc:
142
144
  results = hsh.map do |column1, column2|
143
- qc1 = quote_column_name( column1 )
144
- qc2 = quote_column_name( column2 )
145
+ original_column1_name = model.attribute_alias?( column1 ) ? model.attribute_alias( column1 ) : column1
146
+ qc1 = quote_column_name( original_column1_name )
147
+
148
+ original_column2_name = model.attribute_alias?( column2 ) ? model.attribute_alias( column2 ) : column2
149
+ qc2 = quote_column_name( original_column2_name )
150
+
145
151
  "#{qc1}=EXCLUDED.#{qc2}"
146
152
  end
147
153
  increment_locking_column!(table_name, results, locking_column)
@@ -152,7 +158,7 @@ module ActiveRecord::Import::SQLite3Adapter
152
158
  conflict_target = args[:conflict_target]
153
159
  index_predicate = args[:index_predicate]
154
160
  if conflict_target.present?
155
- sql = '(' + Array( conflict_target ).reject( &:blank? ).join( ', ' ) + ') '
161
+ sql = "(#{Array( conflict_target ).reject( &:blank? ).join( ', ' )}) "
156
162
  sql += "WHERE #{index_predicate} " if index_predicate
157
163
  sql
158
164
  end
@@ -4,17 +4,17 @@ require "ostruct"
4
4
 
5
5
  module ActiveRecord::Import::ConnectionAdapters; end
6
6
 
7
- module ActiveRecord::Import #:nodoc:
7
+ module ActiveRecord::Import # :nodoc:
8
8
  Result = Struct.new(:failed_instances, :num_inserts, :ids, :results)
9
9
 
10
- module ImportSupport #:nodoc:
11
- def supports_import? #:nodoc:
10
+ module ImportSupport # :nodoc:
11
+ def supports_import? # :nodoc:
12
12
  true
13
13
  end
14
14
  end
15
15
 
16
- module OnDuplicateKeyUpdateSupport #:nodoc:
17
- def supports_on_duplicate_key_update? #:nodoc:
16
+ module OnDuplicateKeyUpdateSupport # :nodoc:
17
+ def supports_on_duplicate_key_update? # :nodoc:
18
18
  true
19
19
  end
20
20
  end
@@ -73,7 +73,7 @@ module ActiveRecord::Import #:nodoc:
73
73
  end
74
74
 
75
75
  def valid_model?(model)
76
- init_validations(model.class) unless model.class == @validator_class
76
+ init_validations(model.class) unless model.instance_of?(@validator_class)
77
77
 
78
78
  validation_context = @options[:validate_with_context]
79
79
  validation_context ||= (model.new_record? ? :create : :update)
@@ -85,7 +85,11 @@ module ActiveRecord::Import #:nodoc:
85
85
 
86
86
  model.run_callbacks(:validation) do
87
87
  if defined?(ActiveSupport::Callbacks::Filters::Environment) # ActiveRecord >= 4.1
88
- runner = @validate_callbacks.compile
88
+ runner = if @validate_callbacks.method(:compile).arity == 0
89
+ @validate_callbacks.compile
90
+ else # ActiveRecord >= 7.1
91
+ @validate_callbacks.compile(nil)
92
+ end
89
93
  env = ActiveSupport::Callbacks::Filters::Environment.new(model, false, nil)
90
94
  if runner.respond_to?(:call) # ActiveRecord < 5.1
91
95
  runner.call(env)
@@ -165,7 +169,7 @@ class ActiveRecord::Associations::CollectionAssociation
165
169
  m.public_send "#{reflection.type}=", owner.class.name if reflection.type
166
170
  end
167
171
 
168
- return model_klass.bulk_import column_names, models, options
172
+ model_klass.bulk_import column_names, models, options
169
173
 
170
174
  # supports array of hash objects
171
175
  elsif args.last.is_a?( Array ) && args.last.first.is_a?(Hash)
@@ -204,11 +208,11 @@ class ActiveRecord::Associations::CollectionAssociation
204
208
  end
205
209
  end
206
210
 
207
- return model_klass.bulk_import column_names, array_of_attributes, options
211
+ model_klass.bulk_import column_names, array_of_attributes, options
208
212
 
209
213
  # supports empty array
210
214
  elsif args.last.is_a?( Array ) && args.last.empty?
211
- return ActiveRecord::Import::Result.new([], 0, [])
215
+ ActiveRecord::Import::Result.new([], 0, [])
212
216
 
213
217
  # supports 2-element array and array
214
218
  elsif args.size == 2 && args.first.is_a?( Array ) && args.last.is_a?( Array )
@@ -239,7 +243,7 @@ class ActiveRecord::Associations::CollectionAssociation
239
243
  end
240
244
  end
241
245
 
242
- return model_klass.bulk_import column_names, array_of_attributes, options
246
+ model_klass.bulk_import column_names, array_of_attributes, options
243
247
  else
244
248
  raise ArgumentError, "Invalid arguments!"
245
249
  end
@@ -574,7 +578,7 @@ class ActiveRecord::Base
574
578
 
575
579
  if models.first.id.nil?
576
580
  Array(primary_key).each do |c|
577
- if column_names.include?(c) && columns_hash[c].type == :uuid
581
+ if column_names.include?(c) && schema_columns_hash[c].type == :uuid
578
582
  column_names.delete(c)
579
583
  end
580
584
  end
@@ -697,7 +701,11 @@ class ActiveRecord::Base
697
701
  return_obj = if is_validating
698
702
  import_with_validations( column_names, array_of_attributes, options ) do |failed_instances|
699
703
  if models
700
- models.each { |m| failed_instances << m if m.errors.any? }
704
+ models.each_with_index do |m, i|
705
+ next unless m.errors.any?
706
+
707
+ failed_instances << (options[:track_validation_failures] ? [i, m] : m)
708
+ end
701
709
  else
702
710
  # create instances for each of our column/value sets
703
711
  arr = validations_array_for_column_names_and_attributes( column_names, array_of_attributes )
@@ -774,7 +782,10 @@ class ActiveRecord::Base
774
782
  def import_without_validations_or_callbacks( column_names, array_of_attributes, options = {} )
775
783
  return ActiveRecord::Import::Result.new([], 0, [], []) if array_of_attributes.empty?
776
784
 
777
- column_names = column_names.map(&:to_sym)
785
+ column_names = column_names.map do |name|
786
+ original_name = attribute_alias?(name) ? attribute_alias(name) : name
787
+ original_name.to_sym
788
+ end
778
789
  scope_columns, scope_values = scope_attributes.to_a.transpose
779
790
 
780
791
  unless scope_columns.blank?
@@ -786,15 +797,13 @@ class ActiveRecord::Base
786
797
  end
787
798
  end
788
799
 
789
- if finder_needs_type_condition?
790
- unless column_names.include?(inheritance_column.to_sym)
791
- column_names << inheritance_column.to_sym
792
- array_of_attributes.each { |attrs| attrs << sti_name }
793
- end
800
+ if finder_needs_type_condition? && !column_names.include?(inheritance_column.to_sym)
801
+ column_names << inheritance_column.to_sym
802
+ array_of_attributes.each { |attrs| attrs << sti_name }
794
803
  end
795
804
 
796
805
  columns = column_names.each_with_index.map do |name, i|
797
- column = columns_hash[name.to_s]
806
+ column = schema_columns_hash[name.to_s]
798
807
  raise ActiveRecord::Import::MissingColumnError.new(name.to_s, i) if column.nil?
799
808
  column
800
809
  end
@@ -859,13 +868,13 @@ class ActiveRecord::Base
859
868
  model.id = id
860
869
 
861
870
  timestamps.each do |attr, value|
862
- model.send(attr + "=", value) if model.send(attr).nil?
871
+ model.send("#{attr}=", value) if model.send(attr).nil?
863
872
  end
864
873
  end
865
874
  end
866
875
 
867
876
  deserialize_value = lambda do |column, value|
868
- column = columns_hash[column]
877
+ column = schema_columns_hash[column]
869
878
  return value unless column
870
879
  if respond_to?(:type_caster)
871
880
  type = type_for_attribute(column.name)
@@ -959,6 +968,14 @@ class ActiveRecord::Base
959
968
  end
960
969
  end
961
970
 
971
+ def schema_columns_hash
972
+ @schema_columns_hash ||= if respond_to?(:ignored_columns) && ignored_columns.any?
973
+ connection.schema_cache.columns_hash(table_name)
974
+ else
975
+ columns_hash
976
+ end
977
+ end
978
+
962
979
  # We are eventually going to call Class.import <objects> so we build up a hash
963
980
  # of class => objects to import.
964
981
  def find_associated_objects_for_import(associated_objects_by_class, model)
@@ -5,6 +5,7 @@ require 'active_support/core_ext/array'
5
5
  module ActiveRecord::Import
6
6
  class ValueSetTooLargeError < StandardError
7
7
  attr_reader :size
8
+
8
9
  def initialize(msg = "Value set exceeds max size", size = 0)
9
10
  @size = size
10
11
  super(msg)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Import
5
- VERSION = "1.4.1"
5
+ VERSION = "1.5.0"
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
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')
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")
6
6
 
7
7
  should_support_mysql_import_functionality
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
5
5
 
6
6
  should_support_postgresql_import_functionality
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/sqlite3/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/sqlite3/import_examples")
5
5
 
6
6
  should_support_sqlite3_import_functionality
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
5
5
 
6
6
  should_support_postgresql_import_functionality
7
7
 
@@ -4,6 +4,7 @@ module Bike
4
4
  def self.table_name_prefix
5
5
  'bike_'
6
6
  end
7
+
7
8
  class Maker < ActiveRecord::Base
8
9
  end
9
10
  end
data/test/models/topic.rb CHANGED
@@ -1,6 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Topic < ActiveRecord::Base
4
+ if ENV['AR_VERSION'].to_i >= 6.0
5
+ self.ignored_columns = [:priority]
6
+ end
7
+ alias_attribute :name, :title
8
+
4
9
  validates_presence_of :author_name
5
10
  validates :title, numericality: { only_integer: true }, on: :context_test
6
11
  validates :title, uniqueness: true
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
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')
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")
6
6
 
7
7
  should_support_mysql_import_functionality
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
4
 
5
- require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
6
- require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
5
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/assertions")
6
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/mysql/import_examples")
7
7
 
8
8
  should_support_mysql_import_functionality
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
4
 
5
- require File.expand_path(File.dirname(__FILE__) + '/../support/assertions')
6
- require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
5
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/assertions")
6
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/mysql/import_examples")
7
7
 
8
8
  should_support_mysql_import_functionality
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
5
5
 
6
6
  should_support_postgresql_import_functionality
7
7
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/postgresql/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/postgresql/import_examples")
5
5
 
6
6
  should_support_postgresql_import_functionality
@@ -22,6 +22,7 @@ ActiveRecord::Schema.define do
22
22
  t.boolean :approved, default: '1'
23
23
  t.integer :replies_count
24
24
  t.integer :parent_id
25
+ t.integer :priority, default: 0
25
26
  t.string :type
26
27
  t.datetime :created_at
27
28
  t.datetime :created_on
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/postgresql_schema')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/postgresql_schema")
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/postgresql_schema')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/postgresql_schema")
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
4
- require File.expand_path(File.dirname(__FILE__) + '/../support/sqlite3/import_examples')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
4
+ require File.expand_path("#{File.dirname(__FILE__)}/../support/sqlite3/import_examples")
5
5
 
6
6
  should_support_sqlite3_import_functionality
@@ -26,7 +26,7 @@ def should_support_basic_on_duplicate_key_update
26
26
  User.import(updated_users, on_duplicate_key_update: [:name])
27
27
  assert User.count == updated_users.length
28
28
  User.all.each_with_index do |user, i|
29
- assert_equal user.name, users[i].name + ' Rothschild'
29
+ assert_equal user.name, "#{users[i].name} Rothschild"
30
30
  assert_equal 1, user.lock_version
31
31
  end
32
32
  end
@@ -50,7 +50,7 @@ def should_support_basic_on_duplicate_key_update
50
50
  User.import(columns, updated_values, on_duplicate_key_update: [:name])
51
51
  assert User.count == updated_values.length
52
52
  User.all.each_with_index do |user, i|
53
- assert_equal user.name, users[i].name + ' Rothschild'
53
+ assert_equal user.name, "#{users[i].name} Rothschild"
54
54
  assert_equal 1, user.lock_version
55
55
  end
56
56
  end
@@ -72,7 +72,7 @@ def should_support_basic_on_duplicate_key_update
72
72
  User.import(updated_values, on_duplicate_key_update: [:name])
73
73
  assert User.count == updated_values.length
74
74
  User.all.each_with_index do |user, i|
75
- assert_equal user.name, users[i].name + ' Rothschild'
75
+ assert_equal user.name, "#{users[i].name} Rothschild"
76
76
  assert_equal 1, user.lock_version
77
77
  end
78
78
  updated_values2 = User.all.map do |user|
@@ -82,7 +82,7 @@ def should_support_basic_on_duplicate_key_update
82
82
  User.import(updated_values2, on_duplicate_key_update: [:name])
83
83
  assert User.count == updated_values2.length
84
84
  User.all.each_with_index do |user, i|
85
- assert_equal user.name, users[i].name + ' Rothschild jr.'
85
+ assert_equal user.name, "#{users[i].name} Rothschild jr."
86
86
  assert_equal 2, user.lock_version
87
87
  end
88
88
  end
@@ -104,7 +104,7 @@ def should_support_basic_on_duplicate_key_update
104
104
  Account.import(updated_accounts, on_duplicate_key_update: [:id, :name])
105
105
  assert Account.count == updated_accounts.length
106
106
  Account.all.each_with_index do |user, i|
107
- assert_equal user.name, accounts[i].name + ' Rothschild'
107
+ assert_equal user.name, "#{accounts[i].name} Rothschild"
108
108
  assert_equal 1, user.lock
109
109
  end
110
110
  end
@@ -128,7 +128,7 @@ def should_support_basic_on_duplicate_key_update
128
128
  Account.import(columns, updated_values, on_duplicate_key_update: [:name])
129
129
  assert Account.count == updated_values.length
130
130
  Account.all.each_with_index do |user, i|
131
- assert_equal user.name, accounts[i].name + ' Rothschild'
131
+ assert_equal user.name, "#{accounts[i].name} Rothschild"
132
132
  assert_equal 1, user.lock
133
133
  end
134
134
  end
@@ -150,7 +150,7 @@ def should_support_basic_on_duplicate_key_update
150
150
  Account.import(updated_values, on_duplicate_key_update: [:name])
151
151
  assert Account.count == updated_values.length
152
152
  Account.all.each_with_index do |user, i|
153
- assert_equal user.name, accounts[i].name + ' Rothschild'
153
+ assert_equal user.name, "#{accounts[i].name} Rothschild"
154
154
  assert_equal 1, user.lock
155
155
  end
156
156
  end
@@ -172,10 +172,11 @@ def should_support_basic_on_duplicate_key_update
172
172
  Bike::Maker.import(updated_makers, on_duplicate_key_update: [:name])
173
173
  assert Bike::Maker.count == updated_makers.length
174
174
  Bike::Maker.all.each_with_index do |maker, i|
175
- assert_equal maker.name, makers[i].name + ' bikes'
175
+ assert_equal maker.name, "#{makers[i].name} bikes"
176
176
  assert_equal 1, maker.lock_version
177
177
  end
178
178
  end
179
+
179
180
  it 'update the lock_version of models separated by namespaces by array' do
180
181
  makers = [
181
182
  Bike::Maker.new(name: 'Yamaha'),
@@ -195,7 +196,7 @@ def should_support_basic_on_duplicate_key_update
195
196
  Bike::Maker.import(columns, updated_values, on_duplicate_key_update: [:name])
196
197
  assert Bike::Maker.count == updated_values.length
197
198
  Bike::Maker.all.each_with_index do |maker, i|
198
- assert_equal maker.name, makers[i].name + ' bikes'
199
+ assert_equal maker.name, "#{makers[i].name} bikes"
199
200
  assert_equal 1, maker.lock_version
200
201
  end
201
202
  end
@@ -217,7 +218,7 @@ def should_support_basic_on_duplicate_key_update
217
218
  Bike::Maker.import(updated_values, on_duplicate_key_update: [:name])
218
219
  assert Bike::Maker.count == updated_values.length
219
220
  Bike::Maker.all.each_with_index do |maker, i|
220
- assert_equal maker.name, makers[i].name + ' bikes'
221
+ assert_equal maker.name, "#{makers[i].name} bikes"
221
222
  assert_equal 1, maker.lock_version
222
223
  end
223
224
  end
@@ -316,6 +317,34 @@ def should_support_basic_on_duplicate_key_update
316
317
  should_support_on_duplicate_key_update
317
318
  should_update_fields_mentioned
318
319
  end
320
+
321
+ context "using column aliases" do
322
+ let(:columns) { %w( id title author_name author_email_address parent_id ) }
323
+ let(:update_columns) { %w(title author_email_address parent_id) }
324
+
325
+ context "with column aliases in column list" do
326
+ let(:columns) { %w( id name author_name author_email_address parent_id ) }
327
+ should_support_on_duplicate_key_update
328
+ should_update_fields_mentioned
329
+ end
330
+
331
+ context "with column aliases in update columns list" do
332
+ let(:update_columns) { %w(name author_email_address parent_id) }
333
+ should_support_on_duplicate_key_update
334
+ should_update_fields_mentioned
335
+ end
336
+ end
337
+
338
+ if ENV['AR_VERSION'].to_i >= 6.0
339
+ context "using ignored columns" do
340
+ let(:columns) { %w( id title author_name author_email_address parent_id priority ) }
341
+ let(:values) { [[99, "Book", "John Doe", "john@doe.com", 17, 1]] }
342
+ let(:update_columns) { %w(name author_email_address parent_id priority) }
343
+ let(:updated_values) { [[99, "Book - 2nd Edition", "Author Should Not Change", "johndoe@example.com", 57, 2]] }
344
+ should_support_on_duplicate_key_update
345
+ should_update_fields_mentioned
346
+ end
347
+ end
319
348
  end
320
349
 
321
350
  context "with a table that has a non-standard primary key" do
data/test/test_helper.rb CHANGED
@@ -24,7 +24,7 @@ if ActiveSupport::VERSION::STRING < "4.0"
24
24
  require 'mocha/test_unit'
25
25
  else
26
26
  require 'active_support/testing/autorun'
27
- require "mocha/mini_test"
27
+ require "mocha/minitest"
28
28
  end
29
29
 
30
30
  require 'timecop'
@@ -84,7 +84,7 @@ ActiveSupport::Notifications.subscribe(/active_record.sql/) do |_, _, _, _, hsh|
84
84
  end
85
85
 
86
86
  require "factory_bot"
87
- Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |file| require file }
87
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |file| require file }
88
88
 
89
89
  # Load base/generic schema
90
90
  require test_dir.join("schema/version")
@@ -92,7 +92,7 @@ require test_dir.join("schema/generic_schema")
92
92
  adapter_schema = test_dir.join("schema/#{adapter}_schema.rb")
93
93
  require adapter_schema if File.exist?(adapter_schema)
94
94
 
95
- Dir[File.dirname(__FILE__) + "/models/*.rb"].each { |file| require file }
95
+ Dir["#{File.dirname(__FILE__)}/models/*.rb"].sort.each { |file| require file }
96
96
 
97
97
  # Prevent this deprecation warning from breaking the tests.
98
98
  Rake::FileList.send(:remove_method, :import)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/test_helper')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/test_helper")
4
4
 
5
5
  require 'activerecord-import/value_sets_parser'
6
6
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require File.expand_path(File.dirname(__FILE__) + '/test_helper')
3
+ require File.expand_path("#{File.dirname(__FILE__)}/test_helper")
4
4
 
5
5
  require 'activerecord-import/value_sets_parser'
6
6
 
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.4.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Dennis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-07 00:00:00.000000000 Z
11
+ date: 2023-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord