activerecord-import 1.4.1 → 1.5.0

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