activerecord-import 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +31 -0
  3. data/Brewfile +3 -0
  4. data/Gemfile +39 -0
  5. data/Rakefile +1 -24
  6. data/activerecord-import.gemspec +22 -0
  7. data/benchmarks/README +32 -0
  8. data/benchmarks/benchmark.rb +64 -0
  9. data/benchmarks/boot.rb +18 -0
  10. data/benchmarks/lib/base.rb +137 -0
  11. data/benchmarks/lib/cli_parser.rb +103 -0
  12. data/benchmarks/lib/float.rb +15 -0
  13. data/benchmarks/lib/mysql_benchmark.rb +22 -0
  14. data/benchmarks/lib/output_to_csv.rb +18 -0
  15. data/benchmarks/lib/output_to_html.rb +69 -0
  16. data/benchmarks/models/test_innodb.rb +3 -0
  17. data/benchmarks/models/test_memory.rb +3 -0
  18. data/benchmarks/models/test_myisam.rb +3 -0
  19. data/benchmarks/schema/mysql_schema.rb +16 -0
  20. data/gemfiles/3.1.gemfile +4 -0
  21. data/gemfiles/3.2.gemfile +4 -0
  22. data/gemfiles/4.0.gemfile +4 -0
  23. data/lib/activerecord-import/active_record/adapters/abstract_adapter.rb +0 -1
  24. data/lib/activerecord-import/active_record/adapters/em_mysql2_adapter.rb +8 -0
  25. data/lib/activerecord-import/adapters/abstract_adapter.rb +5 -58
  26. data/lib/activerecord-import/adapters/em_mysql2_adapter.rb +5 -0
  27. data/lib/activerecord-import/adapters/mysql_adapter.rb +50 -3
  28. data/lib/activerecord-import/adapters/sqlite3_adapter.rb +28 -3
  29. data/lib/activerecord-import/base.rb +3 -2
  30. data/lib/activerecord-import/em_mysql2.rb +7 -0
  31. data/lib/activerecord-import/import.rb +29 -29
  32. data/lib/activerecord-import/synchronize.rb +11 -10
  33. data/lib/activerecord-import/value_sets_parser.rb +54 -0
  34. data/lib/activerecord-import/version.rb +5 -0
  35. data/test/adapters/em_mysql2.rb +1 -0
  36. data/test/adapters/jdbcmysql.rb +1 -0
  37. data/test/adapters/mysql.rb +1 -0
  38. data/test/adapters/mysql2.rb +1 -0
  39. data/test/adapters/mysql2spatial.rb +1 -0
  40. data/test/adapters/mysqlspatial.rb +1 -0
  41. data/test/adapters/postgis.rb +1 -0
  42. data/test/adapters/postgresql.rb +1 -0
  43. data/test/adapters/seamless_database_pool.rb +1 -0
  44. data/test/adapters/spatialite.rb +1 -0
  45. data/test/adapters/sqlite3.rb +1 -0
  46. data/test/database.yml.sample +57 -0
  47. data/test/em_mysql2/import_test.rb +6 -0
  48. data/test/import_test.rb +350 -0
  49. data/test/jdbcmysql/import_test.rb +6 -0
  50. data/test/models/book.rb +3 -0
  51. data/test/models/group.rb +3 -0
  52. data/test/models/topic.rb +7 -0
  53. data/test/models/widget.rb +7 -0
  54. data/test/mysql/import_test.rb +6 -0
  55. data/test/mysql2/import_test.rb +6 -0
  56. data/test/mysqlspatial/import_test.rb +6 -0
  57. data/test/mysqlspatial2/import_test.rb +6 -0
  58. data/test/postgis/import_test.rb +4 -0
  59. data/test/postgresql/import_test.rb +4 -0
  60. data/test/schema/generic_schema.rb +104 -0
  61. data/test/schema/mysql_schema.rb +17 -0
  62. data/test/schema/version.rb +10 -0
  63. data/test/sqlite3/import_test.rb +52 -0
  64. data/test/support/active_support/test_case_extensions.rb +67 -0
  65. data/test/support/factories.rb +19 -0
  66. data/test/support/generate.rb +29 -0
  67. data/test/support/mysql/assertions.rb +55 -0
  68. data/test/support/mysql/import_examples.rb +147 -0
  69. data/test/support/postgresql/import_examples.rb +21 -0
  70. data/test/synchronize_test.rb +22 -0
  71. data/test/test_helper.rb +48 -0
  72. data/test/value_sets_bytes_parser_test.rb +96 -0
  73. data/test/value_sets_records_parser_test.rb +32 -0
  74. metadata +120 -58
  75. data/VERSION +0 -1
@@ -1,22 +1,22 @@
1
1
  module ActiveRecord # :nodoc:
2
2
  class Base # :nodoc:
3
-
3
+
4
4
  # Synchronizes the passed in ActiveRecord instances with data
5
5
  # from the database. This is like calling reload on an individual
6
- # ActiveRecord instance but it is intended for use on multiple instances.
7
- #
6
+ # ActiveRecord instance but it is intended for use on multiple instances.
7
+ #
8
8
  # This uses one query for all instance updates and then updates existing
9
9
  # instances rather sending one query for each instance
10
10
  #
11
11
  # == Examples
12
12
  # # Synchronizing existing models by matching on the primary key field
13
- # posts = Post.find_by_author("Zach")
13
+ # posts = Post.where(author: "Zach").first
14
14
  # <.. out of system changes occur to change author name from Zach to Zachary..>
15
15
  # Post.synchronize posts
16
16
  # posts.first.author # => "Zachary" instead of Zach
17
- #
17
+ #
18
18
  # # Synchronizing using custom key fields
19
- # posts = Post.find_by_author("Zach")
19
+ # posts = Post.where(author: "Zach").first
20
20
  # <.. out of system changes occur to change the address of author 'Zach' to 1245 Foo Ln ..>
21
21
  # Post.synchronize posts, [:name] # queries on the :name column and not the :id column
22
22
  # posts.first.address # => "1245 Foo Ln" instead of whatever it was
@@ -26,23 +26,24 @@ module ActiveRecord # :nodoc:
26
26
 
27
27
  conditions = {}
28
28
  order = ""
29
-
29
+
30
30
  key_values = keys.map { |key| instances.map(&"#{key}".to_sym) }
31
31
  keys.zip(key_values).each { |key, values| conditions[key] = values }
32
32
  order = keys.map{ |key| "#{key} ASC" }.join(",")
33
-
33
+
34
34
  klass = instances.first.class
35
35
 
36
- fresh_instances = klass.find( :all, :conditions=>conditions, :order=>order )
36
+ fresh_instances = klass.where(conditions).order(order)
37
37
  instances.each do |instance|
38
38
  matched_instance = fresh_instances.detect do |fresh_instance|
39
39
  keys.all?{ |key| fresh_instance.send(key) == instance.send(key) }
40
40
  end
41
-
41
+
42
42
  if matched_instance
43
43
  instance.clear_aggregation_cache
44
44
  instance.clear_association_cache
45
45
  instance.instance_variable_set '@attributes', matched_instance.attributes
46
+ instance.instance_variable_set '@attributes_cache', {}
46
47
  # Since the instance now accurately reflects the record in
47
48
  # the database, ensure that instance.persisted? is true.
48
49
  instance.instance_variable_set '@new_record', false
@@ -0,0 +1,54 @@
1
+ module ActiveRecord::Import
2
+ class ValuesSetsBytesParser
3
+ attr_reader :reserved_bytes, :max_bytes, :values
4
+
5
+ def self.parse(values, options)
6
+ new(values, options).parse
7
+ end
8
+
9
+ def initialize(values, options)
10
+ @values = values
11
+ @reserved_bytes = options[:reserved_bytes]
12
+ @max_bytes = options[:max_bytes]
13
+ end
14
+
15
+ def parse
16
+ value_sets = []
17
+ arr, current_arr_values_size, current_size = [], 0, 0
18
+ values.each_with_index do |val,i|
19
+ comma_bytes = arr.size
20
+ bytes_thus_far = reserved_bytes + current_size + val.bytesize + comma_bytes
21
+ if bytes_thus_far <= max_bytes
22
+ current_size += val.bytesize
23
+ arr << val
24
+ else
25
+ value_sets << arr
26
+ arr = [ val ]
27
+ current_size = val.bytesize
28
+ end
29
+
30
+ # if we're on the last iteration push whatever we have in arr to value_sets
31
+ value_sets << arr if i == (values.size-1)
32
+ end
33
+
34
+ [ *value_sets ]
35
+ end
36
+ end
37
+
38
+ class ValueSetsRecordsParser
39
+ attr_reader :max_records, :values
40
+
41
+ def self.parse(values, options)
42
+ new(values, options).parse
43
+ end
44
+
45
+ def initialize(values, options)
46
+ @values = values
47
+ @max_records = options[:max_records]
48
+ end
49
+
50
+ def parse
51
+ @values.in_groups_of(max_records, with_fill=false)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveRecord
2
+ module Import
3
+ VERSION = "0.4.0"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "em_mysql2"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "jdbcmysql"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "mysql"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "mysql2"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "mysql2spatial"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "mysqlspatial"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "postgis"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "postgresql"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "seamless_database_pool"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "spatialite"
@@ -0,0 +1 @@
1
+ ENV["ARE_DB"] = "sqlite3"
@@ -0,0 +1,57 @@
1
+ common: &common
2
+ username: root
3
+ password:
4
+ encoding: utf8
5
+ host: localhost
6
+ database: activerecord_import_test
7
+
8
+ mysql: &mysql
9
+ <<: *common
10
+ adapter: mysql
11
+
12
+ mysql2: &mysql2
13
+ <<: *common
14
+ adapter: mysql2
15
+
16
+ mysqlspatial:
17
+ <<: *mysql
18
+
19
+ mysql2spatial:
20
+ <<: *mysql2
21
+
22
+ em_mysql2:
23
+ <<: *common
24
+ adapter: em_mysql2
25
+ pool: 5
26
+
27
+ seamless_database_pool:
28
+ <<: *common
29
+ adapter: seamless_database_pool
30
+ pool_adapter: mysql2
31
+ master:
32
+ host: localhost
33
+
34
+ postgresql: &postgresql
35
+ <<: *common
36
+ username: postgres
37
+ adapter: postgresql
38
+ min_messages: warning
39
+
40
+ postgis:
41
+ <<: *postgresql
42
+
43
+ oracle:
44
+ <<: *common
45
+ adapter: oracle
46
+ min_messages: debug
47
+
48
+ sqlite:
49
+ adapter: sqlite
50
+ dbfile: test.db
51
+
52
+ sqlite3: &sqlite3
53
+ adapter: sqlite3
54
+ database: test.db
55
+
56
+ spatialite:
57
+ <<: *sqlite3
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/assertions')
4
+ require File.expand_path(File.dirname(__FILE__) + '/../support/mysql/import_examples')
5
+
6
+ should_support_mysql_import_functionality
@@ -0,0 +1,350 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe "#import" do
4
+ it "should return the number of inserts performed" do
5
+ # see ActiveRecord::ConnectionAdapters::AbstractAdapter test for more specifics
6
+ assert_difference "Topic.count", +10 do
7
+ result = Topic.import Build(3, :topics)
8
+ assert result.num_inserts > 0
9
+
10
+ result = Topic.import Build(7, :topics)
11
+ assert result.num_inserts > 0
12
+ end
13
+ end
14
+
15
+ it "should not produce an error when importing empty arrays" do
16
+ assert_nothing_raised do
17
+ Topic.import []
18
+ Topic.import %w(title author_name), []
19
+ end
20
+ end
21
+
22
+ describe "with non-default ActiveRecord models" do
23
+ context "that have a non-standard primary key (that is no sequence)" do
24
+ it "should import models successfully" do
25
+ assert_difference "Widget.count", +3 do
26
+ Widget.import Build(3, :widgets)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ context "with :validation option" do
33
+ let(:columns) { %w(title author_name) }
34
+ let(:valid_values) { [[ "LDAP", "Jerry Carter"], ["Rails Recipes", "Chad Fowler"]] }
35
+ let(:invalid_values) { [[ "The RSpec Book", ""], ["Agile+UX", ""]] }
36
+
37
+ context "with validation checks turned off" do
38
+ it "should import valid data" do
39
+ assert_difference "Topic.count", +2 do
40
+ result = Topic.import columns, valid_values, :validate => false
41
+ end
42
+ end
43
+
44
+ it "should import invalid data" do
45
+ assert_difference "Topic.count", +2 do
46
+ result = Topic.import columns, invalid_values, :validate => false
47
+ end
48
+ end
49
+
50
+ it 'should raise a specific error if a column does not exist' do
51
+ assert_raises ActiveRecord::Import::MissingColumnError do
52
+ Topic.import ['foo'], [['bar']], :validate => false
53
+ end
54
+ end
55
+ end
56
+
57
+ context "with validation checks turned on" do
58
+ it "should import valid data" do
59
+ assert_difference "Topic.count", +2 do
60
+ result = Topic.import columns, valid_values, :validate => true
61
+ end
62
+ end
63
+
64
+ it "should not import invalid data" do
65
+ assert_no_difference "Topic.count" do
66
+ result = Topic.import columns, invalid_values, :validate => true
67
+ end
68
+ end
69
+
70
+ it "should report the failed instances" do
71
+ results = Topic.import columns, invalid_values, :validate => true
72
+ assert_equal invalid_values.size, results.failed_instances.size
73
+ results.failed_instances.each{ |e| assert_kind_of Topic, e }
74
+ end
75
+
76
+ it "should import valid data when mixed with invalid data" do
77
+ assert_difference "Topic.count", +2 do
78
+ result = Topic.import columns, valid_values + invalid_values, :validate => true
79
+ end
80
+ assert_equal 0, Topic.where(title: invalid_values.map(&:first)).count
81
+ end
82
+ end
83
+ end
84
+
85
+ context "with :all_or_none option" do
86
+ let(:columns) { %w(title author_name) }
87
+ let(:valid_values) { [[ "LDAP", "Jerry Carter"], ["Rails Recipes", "Chad Fowler"]] }
88
+ let(:invalid_values) { [[ "The RSpec Book", ""], ["Agile+UX", ""]] }
89
+ let(:mixed_values) { valid_values + invalid_values }
90
+
91
+ context "with validation checks turned on" do
92
+ it "should import valid data" do
93
+ assert_difference "Topic.count", +2 do
94
+ result = Topic.import columns, valid_values, :all_or_none => true
95
+ end
96
+ end
97
+
98
+ it "should not import invalid data" do
99
+ assert_no_difference "Topic.count" do
100
+ result = Topic.import columns, invalid_values, :all_or_none => true
101
+ end
102
+ end
103
+
104
+ it "should not import valid data when mixed with invalid data" do
105
+ assert_no_difference "Topic.count" do
106
+ result = Topic.import columns, mixed_values, :all_or_none => true
107
+ end
108
+ end
109
+
110
+ it "should report the failed instances" do
111
+ results = Topic.import columns, mixed_values, :all_or_none => true
112
+ assert_equal invalid_values.size, results.failed_instances.size
113
+ results.failed_instances.each { |e| assert_kind_of Topic, e }
114
+ end
115
+
116
+ it "should report the zero inserts" do
117
+ results = Topic.import columns, mixed_values, :all_or_none => true
118
+ assert_equal 0, results.num_inserts
119
+ end
120
+ end
121
+ end
122
+
123
+ context "with :synchronize option" do
124
+ context "synchronizing on new records" do
125
+ let(:new_topics) { Build(3, :topics) }
126
+
127
+ it "doesn't reload any data (doesn't work)" do
128
+ Topic.import new_topics, :synchronize => new_topics
129
+ assert new_topics.all?(&:new_record?), "No record should have been reloaded"
130
+ end
131
+ end
132
+
133
+ context "synchronizing on new records with explicit conditions" do
134
+ let(:new_topics) { Build(3, :topics) }
135
+
136
+ it "reloads data for existing in-memory instances" do
137
+ Topic.import(new_topics, :synchronize => new_topics, :synchronize_keys => [:title] )
138
+ assert new_topics.all?(&:persisted?), "Records should have been reloaded"
139
+ end
140
+ end
141
+
142
+ context "synchronizing on destroyed records with explicit conditions" do
143
+ let(:new_topics) { Generate(3, :topics) }
144
+
145
+ it "reloads data for existing in-memory instances" do
146
+ new_topics.each &:destroy
147
+ Topic.import(new_topics, :synchronize => new_topics, :synchronize_keys => [:title] )
148
+ assert new_topics.all?(&:persisted?), "Records should have been reloaded"
149
+ end
150
+ end
151
+ end
152
+
153
+ context "with an array of unsaved model instances" do
154
+ let(:topic) { Build(:topic, :title => "The RSpec Book", :author_name => "David Chelimsky")}
155
+ let(:topics) { Build(9, :topics) }
156
+ let(:invalid_topics){ Build(7, :invalid_topics)}
157
+
158
+ it "should import records based on those model's attributes" do
159
+ assert_difference "Topic.count", +9 do
160
+ result = Topic.import topics
161
+ end
162
+
163
+ Topic.import [topic]
164
+ assert Topic.where(title: "The RSpec Book", author_name: "David Chelimsky").first
165
+ end
166
+
167
+ it "should not overwrite existing records" do
168
+ topic = Generate(:topic, :title => "foobar")
169
+ assert_no_difference "Topic.count" do
170
+ begin
171
+ Topic.transaction do
172
+ topic.title = "baz"
173
+ Topic.import [topic]
174
+ end
175
+ rescue Exception
176
+ # PostgreSQL raises PgError due to key constraints
177
+ # I don't know why ActiveRecord doesn't catch these. *sigh*
178
+ end
179
+ end
180
+ assert_equal "foobar", topic.reload.title
181
+ end
182
+
183
+ context "with validation checks turned on" do
184
+ it "should import valid models" do
185
+ assert_difference "Topic.count", +9 do
186
+ result = Topic.import topics, :validate => true
187
+ end
188
+ end
189
+
190
+ it "should not import invalid models" do
191
+ assert_no_difference "Topic.count" do
192
+ result = Topic.import invalid_topics, :validate => true
193
+ end
194
+ end
195
+ end
196
+
197
+ context "with validation checks turned off" do
198
+ it "should import invalid models" do
199
+ assert_difference "Topic.count", +7 do
200
+ result = Topic.import invalid_topics, :validate => false
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ context "with an array of columns and an array of unsaved model instances" do
207
+ let(:topics) { Build(2, :topics) }
208
+
209
+ it "should import records populating the supplied columns with the corresponding model instance attributes" do
210
+ assert_difference "Topic.count", +2 do
211
+ result = Topic.import [:author_name, :title], topics
212
+ end
213
+
214
+ # imported topics should be findable by their imported attributes
215
+ assert Topic.where(author_name: topics.first.author_name).first
216
+ assert Topic.where(author_name: topics.last.author_name).first
217
+ end
218
+
219
+ it "should not populate fields for columns not imported" do
220
+ topics.first.author_email_address = "zach.dennis@gmail.com"
221
+ assert_difference "Topic.count", +2 do
222
+ result = Topic.import [:author_name, :title], topics
223
+ end
224
+
225
+ assert !Topic.where(author_email_address: "zach.dennis@gmail.com").first
226
+ end
227
+ end
228
+
229
+ context "with an array of columns and an array of values" do
230
+ it "should import ids when specified" do
231
+ Topic.import [:id, :author_name, :title], [[99, "Bob Jones", "Topic 99"]]
232
+ assert_equal 99, Topic.last.id
233
+ end
234
+ end
235
+
236
+ context "ActiveRecord timestamps" do
237
+ context "when the timestamps columns are present" do
238
+ setup do
239
+ ActiveRecord::Base.default_timezone = :utc
240
+ Delorean.time_travel_to("5 minutes ago") do
241
+ assert_difference "Book.count", +1 do
242
+ result = Book.import [:title, :author_name, :publisher], [["LDAP", "Big Bird", "Del Rey"]]
243
+ end
244
+ end
245
+ @book = Book.last
246
+ end
247
+
248
+ it "should set the created_at column for new records" do
249
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.created_at.strftime("%H:%M")
250
+ end
251
+
252
+ it "should set the created_on column for new records" do
253
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.created_on.strftime("%H:%M")
254
+ end
255
+
256
+ it "should set the updated_at column for new records" do
257
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.updated_at.strftime("%H:%M")
258
+ end
259
+
260
+ it "should set the updated_on column for new records" do
261
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.updated_on.strftime("%H:%M")
262
+ end
263
+ end
264
+
265
+ context "when a custom time zone is set" do
266
+ setup do
267
+ original_timezone = ActiveRecord::Base.default_timezone
268
+ ActiveRecord::Base.default_timezone = :utc
269
+ Delorean.time_travel_to("5 minutes ago") do
270
+ assert_difference "Book.count", +1 do
271
+ result = Book.import [:title, :author_name, :publisher], [["LDAP", "Big Bird", "Del Rey"]]
272
+ end
273
+ end
274
+ ActiveRecord::Base.default_timezone = original_timezone
275
+ @book = Book.last
276
+ end
277
+
278
+ it "should set the created_at and created_on timestamps for new records" do
279
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.created_at.strftime("%H:%M")
280
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.created_on.strftime("%H:%M")
281
+ end
282
+
283
+ it "should set the updated_at and updated_on timestamps for new records" do
284
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.updated_at.strftime("%H:%M")
285
+ assert_equal 5.minutes.ago.utc.strftime("%H:%M"), @book.updated_on.strftime("%H:%M")
286
+ end
287
+ end
288
+ end
289
+
290
+ context "importing with database reserved words" do
291
+ let(:group) { Build(:group, :order => "superx") }
292
+
293
+ it "should import just fine" do
294
+ assert_difference "Group.count", +1 do
295
+ result = Group.import [group]
296
+ end
297
+ assert_equal "superx", Group.first.order
298
+ end
299
+ end
300
+
301
+ context "importing a datetime field" do
302
+ it "should import a date with YYYY/MM/DD format just fine" do
303
+ Topic.import [:author_name, :title, :last_read], [["Bob Jones", "Topic 2", "2010/05/14"]]
304
+ assert_equal "2010/05/14".to_date, Topic.last.last_read.to_date
305
+ end
306
+ end
307
+
308
+ context "importing through an association scope" do
309
+ [ true, false ].each do |b|
310
+ context "when validation is " + (b ? "enabled" : "disabled") do
311
+ it "should automatically set the foreign key column" do
312
+ books = [[ "David Chelimsky", "The RSpec Book" ], [ "Chad Fowler", "Rails Recipes" ]]
313
+ topic = FactoryGirl.create :topic
314
+ topic.books.import [ :author_name, :title ], books, :validate => b
315
+ assert_equal 2, topic.books.count
316
+ assert topic.books.all? { |b| b.topic_id == topic.id }
317
+ end
318
+ end
319
+ end
320
+ end
321
+
322
+ describe "importing when model has default_scope" do
323
+ it "doesn't import the default scope values" do
324
+ assert_difference "Widget.unscoped.count", +2 do
325
+ Widget.import [:w_id], [[1], [2]]
326
+ end
327
+ default_scope_value = Widget.scope_attributes[:active]
328
+ assert_not_equal default_scope_value, Widget.unscoped.find_by_w_id(1)
329
+ assert_not_equal default_scope_value, Widget.unscoped.find_by_w_id(2)
330
+ end
331
+
332
+ it "imports columns that are a part of the default scope using the value specified" do
333
+ assert_difference "Widget.unscoped.count", +2 do
334
+ Widget.import [:w_id, :active], [[1, true], [2, false]]
335
+ end
336
+ assert_not_equal true, Widget.unscoped.find_by_w_id(1)
337
+ assert_not_equal false, Widget.unscoped.find_by_w_id(2)
338
+ end
339
+ end
340
+
341
+ describe "importing serialized fields" do
342
+ it "imports values for serialized fields" do
343
+ assert_difference "Widget.unscoped.count", +1 do
344
+ Widget.import [:w_id, :data], [[1, {:a => :b}]]
345
+ end
346
+ assert_equal({:a => :b}, Widget.find_by_w_id(1).data)
347
+ end
348
+ end
349
+
350
+ end