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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yaml +7 -1
- data/.rubocop.yml +4 -4
- data/.rubocop_todo.yml +6 -16
- data/CHANGELOG.md +13 -1
- data/Gemfile +3 -3
- data/README.markdown +6 -4
- data/benchmarks/benchmark.rb +3 -3
- data/benchmarks/lib/base.rb +2 -2
- data/benchmarks/lib/cli_parser.rb +1 -1
- data/lib/activerecord-import/adapters/abstract_adapter.rb +6 -5
- data/lib/activerecord-import/adapters/mysql_adapter.rb +24 -18
- data/lib/activerecord-import/adapters/postgresql_adapter.rb +26 -18
- data/lib/activerecord-import/adapters/sqlite3_adapter.rb +29 -23
- data/lib/activerecord-import/import.rb +39 -22
- data/lib/activerecord-import/value_sets_parser.rb +1 -0
- data/lib/activerecord-import/version.rb +1 -1
- data/test/jdbcmysql/import_test.rb +3 -3
- data/test/jdbcpostgresql/import_test.rb +2 -2
- data/test/jdbcsqlite3/import_test.rb +2 -2
- data/test/makara_postgis/import_test.rb +2 -2
- data/test/models/bike_maker.rb +1 -0
- data/test/models/topic.rb +5 -0
- data/test/mysql2/import_test.rb +3 -3
- data/test/mysql2_makara/import_test.rb +3 -3
- data/test/mysqlspatial2/import_test.rb +3 -3
- data/test/postgis/import_test.rb +2 -2
- data/test/postgresql/import_test.rb +2 -2
- data/test/schema/generic_schema.rb +1 -0
- data/test/schema/jdbcpostgresql_schema.rb +1 -1
- data/test/schema/postgis_schema.rb +1 -1
- data/test/sqlite3/import_test.rb +2 -2
- data/test/support/shared_examples/on_duplicate_key_update.rb +39 -10
- data/test/test_helper.rb +3 -3
- data/test/value_sets_bytes_parser_test.rb +1 -1
- data/test/value_sets_records_parser_test.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 866dd09466fbda981329e13916e89986cb47d65259f0889b8a3b53aeca1aee32
|
|
4
|
+
data.tar.gz: 258a0d2fc34bbb928500e2f8a83df4f5bdc8901c25e2e123a569c56d587d3f53
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 989562e1fb64d669a96211c6b80df5b89d8a43aa38575ec6706d0633b405983a63849bd5fb78d4031ed7e4b2c239192f62d4b3d9e720f4c474cd3801600d11ef
|
|
7
|
+
data.tar.gz: 22e6ccbb750bb7851930d98c2b90f496c759d35503c8c1e58b841f4a928a283c486caec3f22cb57e6948b6960e6fff2a598499f0670f59b281e321dded20c183
|
data/.github/workflows/test.yaml
CHANGED
|
@@ -20,13 +20,19 @@ jobs:
|
|
|
20
20
|
fail-fast: false
|
|
21
21
|
matrix:
|
|
22
22
|
ruby:
|
|
23
|
-
- 3.
|
|
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/
|
|
69
|
+
Layout/ArgumentAlignment:
|
|
70
70
|
Enabled: false
|
|
71
71
|
|
|
72
|
-
Layout/
|
|
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/
|
|
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/
|
|
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
|
|
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:
|
|
22
|
-
#
|
|
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
|
-
|
|
31
|
-
# Configuration parameters: Keywords.
|
|
32
|
-
# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW
|
|
33
|
-
Style/CommentAnnotation:
|
|
24
|
+
Style/CombinableLoops:
|
|
34
25
|
Exclude:
|
|
35
|
-
- '
|
|
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
|
|
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'
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
data/benchmarks/benchmark.rb
CHANGED
|
@@ -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__)
|
|
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
|
|
57
|
-
clazz = Object.const_get( clazz_str
|
|
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|
|
data/benchmarks/lib/base.rb
CHANGED
|
@@ -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
|
|
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 =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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.
|
|
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
|
|
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
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
sql << sql_for_on_duplicate_key_update_as_array( table_name, locking_column, arg )
|
|
92
|
-
|
|
93
|
-
sql << sql_for_on_duplicate_key_update_as_hash( table_name, locking_column, arg )
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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 =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
181
|
-
|
|
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 =
|
|
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 =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
144
|
-
|
|
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 =
|
|
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
|
|
7
|
+
module ActiveRecord::Import # :nodoc:
|
|
8
8
|
Result = Struct.new(:failed_instances, :num_inserts, :ids, :results)
|
|
9
9
|
|
|
10
|
-
module ImportSupport
|
|
11
|
-
def supports_import?
|
|
10
|
+
module ImportSupport # :nodoc:
|
|
11
|
+
def supports_import? # :nodoc:
|
|
12
12
|
true
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
module OnDuplicateKeyUpdateSupport
|
|
17
|
-
def supports_on_duplicate_key_update?
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) &&
|
|
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.
|
|
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
|
|
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
|
-
|
|
791
|
-
|
|
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 =
|
|
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
|
|
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 =
|
|
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)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
5
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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
|
|
data/test/models/bike_maker.rb
CHANGED
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
|
data/test/mysql2/import_test.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
5
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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__)
|
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
|
|
4
4
|
|
|
5
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
6
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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__)
|
|
3
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../test_helper")
|
|
4
4
|
|
|
5
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
6
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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
|
data/test/postgis/import_test.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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
|
data/test/sqlite3/import_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
4
|
-
require File.expand_path(File.dirname(__FILE__)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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/
|
|
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__)
|
|
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__)
|
|
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)
|
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
|
+
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:
|
|
11
|
+
date: 2023-08-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|