activerecord-import 1.0.0 → 1.0.5

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.
@@ -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