activerecord-import 1.0.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -39,8 +39,8 @@ module ActiveRecord # :nodoc:
39
39
 
40
40
  next unless matched_instance
41
41
 
42
- instance.send :clear_aggregation_cache
43
42
  instance.send :clear_association_cache
43
+ instance.send :clear_aggregation_cache if instance.respond_to?(:clear_aggregation_cache, true)
44
44
  instance.instance_variable_set :@attributes, matched_instance.instance_variable_get(:@attributes)
45
45
 
46
46
  if instance.respond_to?(:clear_changes_information)
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module Import
3
- VERSION = "1.0.0".freeze
3
+ VERSION = "1.0.5".freeze
4
4
  end
5
5
  end
@@ -17,6 +17,11 @@ describe "#import" do
17
17
  assert_equal error.message, "Last argument should be a two dimensional array '[[]]'. First element in array was a String"
18
18
  end
19
19
 
20
+ it "warns you that you're passing more data than you ought to" do
21
+ error = assert_raise(ArgumentError) { Topic.import %w(title author_name), [['Author #1', 'Book #1', 0]] }
22
+ assert_equal error.message, "Number of values (8) exceeds number of columns (7)"
23
+ end
24
+
20
25
  it "should not produce an error when importing empty arrays" do
21
26
  assert_nothing_raised do
22
27
  Topic.import []
@@ -3,11 +3,24 @@ ActiveRecord::Schema.define do
3
3
  execute('CREATE extension IF NOT EXISTS "pgcrypto";')
4
4
  execute('CREATE extension IF NOT EXISTS "uuid-ossp";')
5
5
 
6
+ # create ENUM if it does not exist yet
7
+ begin
8
+ execute('CREATE TYPE vendor_type AS ENUM (\'wholesaler\', \'retailer\');')
9
+ rescue ActiveRecord::StatementInvalid => e
10
+ # since PostgreSQL does not support IF NOT EXISTS when creating a TYPE,
11
+ # rescue the error and check the error class
12
+ raise unless e.cause.is_a? PG::DuplicateObject
13
+ execute('ALTER TYPE vendor_type ADD VALUE IF NOT EXISTS \'wholesaler\';')
14
+ execute('ALTER TYPE vendor_type ADD VALUE IF NOT EXISTS \'retailer\';')
15
+ end
16
+
6
17
  create_table :vendors, id: :uuid, force: :cascade do |t|
7
18
  t.string :name, null: true
19
+ t.text :hours
8
20
  t.text :preferences
9
21
 
10
22
  if t.respond_to?(:json)
23
+ t.json :pure_json_data
11
24
  t.json :data
12
25
  else
13
26
  t.text :data
@@ -20,6 +33,7 @@ ActiveRecord::Schema.define do
20
33
  end
21
34
 
22
35
  if t.respond_to?(:jsonb)
36
+ t.jsonb :pure_jsonb_data
23
37
  t.jsonb :settings
24
38
  t.jsonb :json_data, null: false, default: {}
25
39
  else
@@ -27,6 +41,8 @@ ActiveRecord::Schema.define do
27
41
  t.text :json_data
28
42
  end
29
43
 
44
+ t.column :vendor_type, :vendor_type
45
+
30
46
  t.datetime :created_at
31
47
  t.datetime :updated_at
32
48
  end
@@ -116,6 +116,26 @@ def should_support_postgresql_import_functionality
116
116
  assert_equal [%w(King It)], result.results
117
117
  end
118
118
 
119
+ context "when given an empty array" do
120
+ let(:result) { Book.import([], returning: %w(title)) }
121
+
122
+ setup { result }
123
+
124
+ it "returns empty arrays for ids and results" do
125
+ assert_equal [], result.ids
126
+ assert_equal [], result.results
127
+ end
128
+ end
129
+
130
+ context "when a returning column is a serialized attribute" do
131
+ let(:vendor) { Vendor.new(hours: { monday: '8-5' }) }
132
+ let(:result) { Vendor.import([vendor], returning: %w(hours)) }
133
+
134
+ it "creates records" do
135
+ assert_difference("Vendor.count", +1) { result }
136
+ end
137
+ end
138
+
119
139
  context "when primary key and returning overlap" do
120
140
  let(:result) { Book.import(books, returning: %w(id title)) }
121
141
 
@@ -234,6 +254,30 @@ def should_support_postgresql_import_functionality
234
254
  assert_equal({}, Vendor.first.json_data)
235
255
  end
236
256
  end
257
+
258
+ %w(json jsonb).each do |json_type|
259
+ describe "with pure #{json_type} fields" do
260
+ let(:data) { { a: :b } }
261
+ let(:json_field_name) { "pure_#{json_type}_data" }
262
+ it "imports the values from saved records" do
263
+ vendor = Vendor.create!(name: 'Vendor 1', json_field_name => data)
264
+
265
+ Vendor.import [vendor], on_duplicate_key_update: [json_field_name]
266
+ assert_equal(data.as_json, vendor.reload[json_field_name])
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ describe "with enum field" do
273
+ let(:vendor_type) { "retailer" }
274
+ it "imports the correct values for enum fields" do
275
+ vendor = Vendor.new(name: 'Vendor 1', vendor_type: vendor_type)
276
+ assert_difference "Vendor.count", +1 do
277
+ Vendor.import [vendor]
278
+ end
279
+ assert_equal(vendor_type, Vendor.first.vendor_type)
280
+ end
237
281
  end
238
282
 
239
283
  describe "with binary field" do
@@ -73,6 +73,16 @@ def should_support_basic_on_duplicate_key_update
73
73
  assert_equal user.name, users[i].name + ' Rothschild'
74
74
  assert_equal 1, user.lock_version
75
75
  end
76
+ updated_values2 = User.all.map do |user|
77
+ user.name += ' jr.'
78
+ { id: user.id, name: user.name }
79
+ end
80
+ User.import(updated_values2, on_duplicate_key_update: [:name])
81
+ assert User.count == updated_values2.length
82
+ User.all.each_with_index do |user, i|
83
+ assert_equal user.name, users[i].name + ' Rothschild jr.'
84
+ assert_equal 2, user.lock_version
85
+ end
76
86
  end
77
87
 
78
88
  it 'upsert optimistic lock columns other than lock_version by model' do
@@ -138,6 +138,15 @@ def should_support_recursive_import
138
138
  books.each do |book|
139
139
  assert_equal book.topic_id, second_new_topic.id
140
140
  end
141
+
142
+ books.each { |book| book.topic_id = nil }
143
+ assert_no_difference "Book.count", books.size do
144
+ Book.import books, validate: false, on_duplicate_key_update: [:topic_id]
145
+ end
146
+
147
+ books.each do |book|
148
+ assert_equal book.topic_id, nil
149
+ end
141
150
  end
142
151
 
143
152
  unless ENV["SKIP_COMPOSITE_PK"]
@@ -183,5 +192,34 @@ def should_support_recursive_import
183
192
  end
184
193
  end
185
194
  end
195
+
196
+ # If returning option is provided, it is only applied to top level models so that SQL with invalid
197
+ # columns, keys, etc isn't generated for child associations when doing recursive import
198
+ describe "returning" do
199
+ let(:new_topics) { Build(1, :topic_with_book) }
200
+
201
+ it "imports objects with associations" do
202
+ assert_difference "Topic.count", +1 do
203
+ Topic.import new_topics, recursive: true, returning: [:content], validate: false
204
+ new_topics.each do |topic|
205
+ assert_not_nil topic.id
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ # If no returning option is provided, it is ignored
212
+ describe "no returning" do
213
+ let(:new_topics) { Build(1, :topic_with_book) }
214
+
215
+ it "is ignored and imports objects with associations" do
216
+ assert_difference "Topic.count", +1 do
217
+ Topic.import new_topics, recursive: true, no_returning: true, validate: false
218
+ new_topics.each do |topic|
219
+ assert_not_nil topic.id
220
+ end
221
+ end
222
+ end
223
+ end
186
224
  end
187
225
  end
@@ -5,21 +5,8 @@ def should_support_sqlite3_import_functionality
5
5
  end
6
6
 
7
7
  describe "#supports_imports?" do
8
- context "and SQLite is 3.7.11 or higher" do
9
- it "supports import" do
10
- version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.11")
11
- assert ActiveRecord::Base.supports_import?(version)
12
-
13
- version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.12")
14
- assert ActiveRecord::Base.supports_import?(version)
15
- end
16
- end
17
-
18
- context "and SQLite less than 3.7.11" do
19
- it "doesn't support import" do
20
- version = ActiveRecord::ConnectionAdapters::SQLite3Adapter::Version.new("3.7.10")
21
- assert !ActiveRecord::Base.supports_import?(version)
22
- end
8
+ it "should support import" do
9
+ assert ActiveRecord::Base.supports_import?
23
10
  end
24
11
  end
25
12
 
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.0.0
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Dennis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-30 00:00:00.000000000 Z
11
+ date: 2020-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -75,6 +75,8 @@ files:
75
75
  - gemfiles/5.0.gemfile
76
76
  - gemfiles/5.1.gemfile
77
77
  - gemfiles/5.2.gemfile
78
+ - gemfiles/6.0.gemfile
79
+ - gemfiles/6.1.gemfile
78
80
  - lib/activerecord-import.rb
79
81
  - lib/activerecord-import/active_record/adapters/abstract_adapter.rb
80
82
  - lib/activerecord-import/active_record/adapters/jdbcmysql_adapter.rb
@@ -166,7 +168,7 @@ files:
166
168
  - test/value_sets_records_parser_test.rb
167
169
  homepage: http://github.com/zdennis/activerecord-import
168
170
  licenses:
169
- - Ruby
171
+ - MIT
170
172
  metadata: {}
171
173
  post_install_message:
172
174
  rdoc_options: []
@@ -176,15 +178,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
176
178
  requirements:
177
179
  - - ">="
178
180
  - !ruby/object:Gem::Version
179
- version: 1.9.2
181
+ version: 2.0.0
180
182
  required_rubygems_version: !ruby/object:Gem::Requirement
181
183
  requirements:
182
184
  - - ">="
183
185
  - !ruby/object:Gem::Version
184
186
  version: '0'
185
187
  requirements: []
186
- rubyforge_project:
187
- rubygems_version: 2.7.7
188
+ rubygems_version: 3.0.6
188
189
  signing_key:
189
190
  specification_version: 4
190
191
  summary: Bulk insert extension for ActiveRecord