jorahood-ar-extensions 0.9.2.3

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 (71) hide show
  1. data/ChangeLog +145 -0
  2. data/README +167 -0
  3. data/Rakefile +79 -0
  4. data/config/database.yml +7 -0
  5. data/config/database.yml.template +7 -0
  6. data/config/mysql.schema +72 -0
  7. data/config/postgresql.schema +39 -0
  8. data/db/migrate/generic_schema.rb +96 -0
  9. data/db/migrate/mysql_schema.rb +31 -0
  10. data/db/migrate/oracle_schema.rb +5 -0
  11. data/db/migrate/version.rb +4 -0
  12. data/init.rb +31 -0
  13. data/lib/ar-extensions/create_and_update.rb +509 -0
  14. data/lib/ar-extensions/csv.rb +309 -0
  15. data/lib/ar-extensions/delete.rb +143 -0
  16. data/lib/ar-extensions/extensions.rb +506 -0
  17. data/lib/ar-extensions/finder_options.rb +275 -0
  18. data/lib/ar-extensions/finders.rb +94 -0
  19. data/lib/ar-extensions/foreign_keys.rb +70 -0
  20. data/lib/ar-extensions/fulltext.rb +62 -0
  21. data/lib/ar-extensions/import.rb +352 -0
  22. data/lib/ar-extensions/insert_select.rb +178 -0
  23. data/lib/ar-extensions/synchronize.rb +30 -0
  24. data/lib/ar-extensions/temporary_table.rb +124 -0
  25. data/lib/ar-extensions/union.rb +204 -0
  26. data/lib/ar-extensions/version.rb +9 -0
  27. data/tests/connections/native_mysql/connection.rb +16 -0
  28. data/tests/connections/native_oracle/connection.rb +16 -0
  29. data/tests/connections/native_postgresql/connection.rb +19 -0
  30. data/tests/connections/native_sqlite/connection.rb +14 -0
  31. data/tests/connections/native_sqlite3/connection.rb +14 -0
  32. data/tests/fixtures/addresses.yml +25 -0
  33. data/tests/fixtures/books.yml +46 -0
  34. data/tests/fixtures/developers.yml +20 -0
  35. data/tests/fixtures/unit/active_record_base_finders/addresses.yml +25 -0
  36. data/tests/fixtures/unit/active_record_base_finders/books.yml +64 -0
  37. data/tests/fixtures/unit/active_record_base_finders/developers.yml +20 -0
  38. data/tests/fixtures/unit/synchronize/books.yml +16 -0
  39. data/tests/fixtures/unit/to_csv_headers/addresses.yml +8 -0
  40. data/tests/fixtures/unit/to_csv_headers/developers.yml +6 -0
  41. data/tests/fixtures/unit/to_csv_with_common_options/addresses.yml +40 -0
  42. data/tests/fixtures/unit/to_csv_with_common_options/developers.yml +13 -0
  43. data/tests/fixtures/unit/to_csv_with_common_options/languages.yml +29 -0
  44. data/tests/fixtures/unit/to_csv_with_common_options/teams.yml +3 -0
  45. data/tests/fixtures/unit/to_csv_with_default_options/developers.yml +7 -0
  46. data/tests/models/address.rb +4 -0
  47. data/tests/models/animal.rb +2 -0
  48. data/tests/models/book.rb +3 -0
  49. data/tests/models/cart_item.rb +4 -0
  50. data/tests/models/developer.rb +8 -0
  51. data/tests/models/group.rb +3 -0
  52. data/tests/models/language.rb +5 -0
  53. data/tests/models/mysql/book.rb +3 -0
  54. data/tests/models/mysql/test_innodb.rb +3 -0
  55. data/tests/models/mysql/test_memory.rb +3 -0
  56. data/tests/models/mysql/test_myisam.rb +3 -0
  57. data/tests/models/project.rb +2 -0
  58. data/tests/models/shopping_cart.rb +4 -0
  59. data/tests/models/team.rb +4 -0
  60. data/tests/models/topic.rb +13 -0
  61. data/tests/mysql/test_create_and_update.rb +290 -0
  62. data/tests/mysql/test_delete.rb +142 -0
  63. data/tests/mysql/test_finder_options.rb +121 -0
  64. data/tests/mysql/test_finders.rb +29 -0
  65. data/tests/mysql/test_import.rb +354 -0
  66. data/tests/mysql/test_insert_select.rb +173 -0
  67. data/tests/mysql/test_mysql_adapter.rb +45 -0
  68. data/tests/mysql/test_union.rb +81 -0
  69. data/tests/oracle/test_adapter.rb +14 -0
  70. data/tests/postgresql/test_adapter.rb +14 -0
  71. metadata +147 -0
@@ -0,0 +1,29 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), '..', 'test_helper' ) )
2
+
3
+ class MysqlFindersTest< TestCaseSuperClass
4
+ include ActiveRecord::ConnectionAdapters
5
+ self.fixture_path = File.join( File.dirname( __FILE__ ), '../fixtures/unit/active_record_base_finders' )
6
+ self.fixtures :books
7
+
8
+ def setup
9
+ @connection = ActiveRecord::Base.connection
10
+ end
11
+
12
+ def teardown
13
+ Book.delete_all
14
+ end
15
+
16
+ # FIXME this won't work until full text index/searching is added for
17
+ # any db adapter outside of MySQL.
18
+ # For PostgreSQL support look into TSearch2 support which is
19
+ # builtin to PostgreSQL 8.x (but not in 7.x)
20
+ def test_find_three_results_using_match
21
+ unless Book.supports_full_text_searching?
22
+ STDERR.puts "test_find_three_results_using_match is not testing, since your database adapter doesn't support fulltext searching"
23
+ else
24
+ books = Book.find( :all, :conditions=>{ :match_title=> 'Terry' } )
25
+ assert_equal( 4, books.size )
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,354 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), '..', 'test_helper') )
2
+
3
+ class MysqlImportTest< TestCaseSuperClass
4
+ fixtures :topics, :books
5
+
6
+ def setup
7
+ @connection = ActiveRecord::Base.connection
8
+ @columns_for_on_duplicate_key_update = [ 'id', 'title', 'author_name']
9
+ Topic.delete_all
10
+ end
11
+
12
+ def teardown
13
+ Topic.delete_all
14
+ Book.delete_all
15
+ end
16
+
17
+ # sets up base data for on duplicate key update tests
18
+ def setup_import_without_validations_but_with_on_duplicate_key_update
19
+ columns = @columns_for_on_duplicate_key_update
20
+ values = [ [ 1, 'Book', 'Author' ] ]
21
+ Topic.import( columns, values, :validate=>false )
22
+ Topic.find_by_id( 1 )
23
+ end
24
+
25
+ def test_import_without_validations_but_with_on_duplicate_key_update_that_synchronizes_existing_AR_instances
26
+ topics = []
27
+ topics << Topic.create!( :title=>"LDAP", :author_name=>"Big Bird" )
28
+ topics << Topic.create!( :title=>"Rails Recipes", :author_name=>"Elmo")
29
+
30
+ columns = %W{ id author_name }
31
+ values = []
32
+ values << [ topics.first.id, "Jerry Carter" ]
33
+ values << [ topics.last.id, "Chad Fowler" ]
34
+
35
+ columns2update = [ 'author_name' ]
36
+
37
+ expected_count = Topic.count
38
+ Topic.import( columns, values,
39
+ :validate=>false,
40
+ :on_duplicate_key_update=>columns2update,
41
+ :synchronize=>topics )
42
+
43
+ assert_equal expected_count, Topic.count, "no new records should have been created!"
44
+ assert_equal "Jerry Carter", topics.first.author_name, "wrong author!"
45
+ assert_equal "Chad Fowler", topics.last.author_name, "wrong author!"
46
+ end
47
+
48
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_string_array1
49
+ return unless Topic.supports_on_duplicate_key_update?
50
+
51
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
52
+ columns = @columns_for_on_duplicate_key_update
53
+
54
+ # The author_name is NOT supposed to change.
55
+ columns2update = [ 'title' ]
56
+ updated_values = [ [ 1, 'Book - 2nd Edition', 'New Author' ] ]
57
+ Topic.import( columns, updated_values,
58
+ :validate=>false,
59
+ :on_duplicate_key_update=>columns2update )
60
+ topic = Topic.find_by_id( 1 )
61
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
62
+ assert_equal orig_topic.author_name, topic.author_name, "The author's name is incorrect! It wasn't supposed to change!"
63
+ end
64
+
65
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_string_array2
66
+ return unless Topic.supports_on_duplicate_key_update?
67
+
68
+ setup_import_without_validations_but_with_on_duplicate_key_update
69
+ columns = @columns_for_on_duplicate_key_update
70
+
71
+ # note that both the title and the author name should change here
72
+ columns2update = [ 'title', 'author_name' ]
73
+ updated_values = [ [ 1, 'Book - 2nd Edition', 'New Author' ] ]
74
+ Topic.import( columns, updated_values,
75
+ :validate=>false,
76
+ :on_duplicate_key_update=>columns2update )
77
+ topic = Topic.find_by_id( 1 )
78
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
79
+ assert_equal updated_values[0][2], topic.author_name, "The author's name is incorrect! It was supposed to change!"
80
+ end
81
+
82
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_symbol_array1
83
+ return unless Topic.supports_on_duplicate_key_update?
84
+
85
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
86
+ columns = @columns_for_on_duplicate_key_update
87
+
88
+ # test updates with array with symbol(s) *note that author_name isn't supposed to change
89
+ columns2update = [ :title ]
90
+ updated_values = [ [ 1, 'Book - 3rd Edition', 'New Author' ] ]
91
+ Topic.import( columns, updated_values,
92
+ :validate=>false,
93
+ :on_duplicate_key_update=>columns2update )
94
+ topic = Topic.find_by_id( 1 )
95
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
96
+ assert_equal orig_topic.author_name, topic.author_name, "The author's name is incorrect! It wasn't supposed to change!"
97
+ end
98
+
99
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_symbol_array2
100
+ return unless Topic.supports_on_duplicate_key_update?
101
+
102
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
103
+ columns = @columns_for_on_duplicate_key_update
104
+
105
+ # Note that the title and author's name are supposed to change unlik the previous assertion
106
+ columns2update = [ :title, :author_name ]
107
+ updated_values = [ [ 1, 'Book - 4th Edition', 'New Author' ] ]
108
+ Topic.import( columns, updated_values,
109
+ :validate=>false,
110
+ :on_duplicate_key_update=>columns2update )
111
+ topic = Topic.find_by_id( 1 )
112
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
113
+ assert_equal updated_values[0][2], topic.author_name, "The author's name is incorrect! It was supposed to change!"
114
+ end
115
+
116
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_string_hash1
117
+ return unless Topic.supports_on_duplicate_key_update?
118
+
119
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
120
+ columns = @columns_for_on_duplicate_key_update
121
+
122
+ # Note that the title is supposed to change but NOT the author's name
123
+ columns2update = { 'title'=>'title' }
124
+ updated_values = [ [ 1, 'Book - 5th Edition', 'New Author' ] ]
125
+ Topic.import( columns, updated_values,
126
+ :validate=>false,
127
+ :on_duplicate_key_update=>columns2update )
128
+ topic = Topic.find_by_id( 1 )
129
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
130
+ assert_equal orig_topic.author_name, topic.author_name, "The author's name is incorrect! It wasn't supposed to change!"
131
+ end
132
+
133
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_string_hash2
134
+ return unless Topic.supports_on_duplicate_key_update?
135
+
136
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
137
+ columns = @columns_for_on_duplicate_key_update
138
+
139
+ # Note that the title is supposed to change to the author's name, but the
140
+ # author's name is NOT supposed to change
141
+ columns2update = { 'title'=>'author_name' }
142
+ updated_values = [ [ 1, 'Book - 6th Edition', 'New Author' ] ]
143
+ Topic.import( columns, updated_values,
144
+ :validate=>false,
145
+ :on_duplicate_key_update=>columns2update )
146
+ topic = Topic.find_by_id( 1 )
147
+ assert_equal updated_values[0][2], topic.title, "The book title is wrong! It was supposed to change to the author's name!"
148
+ assert_equal orig_topic.author_name, topic.author_name, "The author's name is incorrect! It wasn't supposed to change!"
149
+ end
150
+
151
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_string_hash3
152
+ return unless Topic.supports_on_duplicate_key_update?
153
+
154
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
155
+ columns = @columns_for_on_duplicate_key_update
156
+
157
+ # Note that the title AND the author_name is supposed to change
158
+ columns2update = { 'title'=>'title', 'author_name'=>'author_name' }
159
+ updated_values = [ [ 1, 'Book - 7th Edition', 'New Author' ] ]
160
+ Topic.import( columns, updated_values,
161
+ :validate=>false,
162
+ :on_duplicate_key_update=>columns2update )
163
+ topic = Topic.find_by_id( 1 )
164
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
165
+ assert_equal updated_values[0][2], topic.author_name, "The author's name is incorrect! It was supposed to change!"
166
+ end
167
+
168
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_symbol_hash1
169
+ return unless Topic.supports_on_duplicate_key_update?
170
+
171
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
172
+ columns = @columns_for_on_duplicate_key_update
173
+
174
+ # Note that the title is supposed to change but NOT the author's name
175
+ columns2update = { :title=>:title }
176
+ updated_values = [ [ 1, 'Book - 8th Edition', 'New Author' ] ]
177
+ Topic.import( columns, updated_values,
178
+ :validate=>false,
179
+ :on_duplicate_key_update=>columns2update )
180
+ topic = Topic.find_by_id( 1 )
181
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
182
+ assert_equal orig_topic.author_name, topic.author_name, "The author's name is incorrect! It wasn't supposed to change!"
183
+ end
184
+
185
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_symbol_hash2
186
+ return unless Topic.supports_on_duplicate_key_update?
187
+
188
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
189
+ columns = @columns_for_on_duplicate_key_update
190
+
191
+ # Note that the title is supposed to change to the author's name, but the
192
+ # author's name is NOT supposed to change
193
+ columns2update = { :title=>:author_name }
194
+ updated_values = [ [ 1, 'Book - 9th Edition', 'New Author' ] ]
195
+ Topic.import( columns, updated_values,
196
+ :validate=>false,
197
+ :on_duplicate_key_update=>columns2update )
198
+ topic = Topic.find_by_id( 1 )
199
+ assert_equal updated_values[0][2], topic.title, "The book title is wrong! It was supposed to change to the author's name!"
200
+ assert_equal orig_topic.author_name, topic.author_name, "The author's name is incorrect! It wasn't supposed to change!"
201
+ end
202
+
203
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_symbol_hash3
204
+ return unless Topic.supports_on_duplicate_key_update?
205
+ orig_topic = setup_import_without_validations_but_with_on_duplicate_key_update
206
+ columns = @columns_for_on_duplicate_key_update
207
+
208
+ # Note that the title AND the author_name is supposed to change
209
+ columns2update = { :title=>:title, :author_name=>:author_name }
210
+ updated_values = [ [ 1, 'Book - 10th Edition', 'New Author' ] ]
211
+
212
+ Topic.import( columns, updated_values,
213
+ :validate=>false,
214
+ :on_duplicate_key_update=>columns2update )
215
+
216
+ topic = Topic.find_by_id( 1 )
217
+ assert_equal updated_values[0][1], topic.title, "The book title is wrong! It was supposed to change!"
218
+ assert_equal updated_values[0][2], topic.author_name, "The author's name is incorrect! It was supposed to change!"
219
+ end
220
+
221
+ def test_import_with_array_of_model_objects_with_on_duplicate_key_update
222
+ return unless Topic.supports_on_duplicate_key_update?
223
+
224
+ topic = Topic.create( :title=>"Book", :author_name=>"Someguy" )
225
+ topic2 = Topic.create( :title=>"Book2", :author_name=>"Someguy" )
226
+
227
+ topic.author_name = "SomeNewguy"
228
+ topic2.author_name = "SomeOtherNewguy"
229
+
230
+ Topic.import( [ topic, topic2 ], :on_duplicate_key_update=>[ :author_name ] )
231
+ topic.reload
232
+ topic2.reload
233
+
234
+ assert_equal "SomeNewguy", topic.author_name
235
+ assert_equal "SomeOtherNewguy", topic2.author_name
236
+ end
237
+
238
+ def test_import_without_validations_but_with_on_duplicate_key_update_using_associated_objects
239
+ return unless Topic.supports_on_duplicate_key_update?
240
+
241
+ topic1 = Topic.create( :title=>"Topic1", :author_name=>"Someguy" )
242
+ topic2 = Topic.create( :title=>"Topic2", :author_name=>"Someguy" )
243
+
244
+ book1 = Book.create :title=>"book1", :author_name=>"Zach", :publisher=>"Pub", :topic_id=>topic1.id
245
+ book2 = Book.create :title=>"book2", :author_name=>"Mark", :publisher=>"Pub", :topic_id=>topic1.id
246
+
247
+ book1.topic = topic2
248
+ book2.topic = topic1
249
+
250
+ # Note that the title is supposed to change
251
+ columns = [ :id, :title, :author_name, :topic_id ]
252
+ columns2update = [ :title, :author_name, :topic_id ]
253
+ updated_values = [
254
+ [ book1.id, 'Book - 1st Edition', 'New Author', book1.topic.id ],
255
+ [ book2.id, 'Book - 2nd Edition', 'New Author', book2.topic.id ] ]
256
+ Book.import( columns, updated_values,
257
+ :validate=>false,
258
+ :on_duplicate_key_update=>columns2update )
259
+
260
+ book1.reload
261
+ book2.reload
262
+
263
+ assert_equal updated_values[0][1], book1.title, "The book title is wrong! It was supposed to change!"
264
+ assert_equal updated_values[0][2], book1.author_name, "The author's name is incorrect! It was supposed to change!"
265
+ assert_equal updated_values[0][3], book1.topic_id, "The topic id is wrong!"
266
+
267
+ assert_equal updated_values[1][1], book2.title, "The book title is wrong! It was supposed to change!"
268
+ assert_equal updated_values[1][2], book2.author_name, "The author's name is incorrect! It was supposed to change!"
269
+ assert_equal updated_values[1][3], book2.topic_id, "The topic id is wrong!"
270
+ end
271
+
272
+ def test_import_with_on_duplicate_key_update_with_associated_objects_saves_foreign_keys
273
+ return unless Topic.supports_on_duplicate_key_update?
274
+
275
+ topic1 = Topic.create( :title=>"Topic1", :author_name=>"Someguy" )
276
+ topic2 = Topic.create( :title=>"Topic2", :author_name=>"Someguy" )
277
+
278
+ book1 = Book.create :title=>"book1", :author_name=>"Zach", :publisher=>"Pub", :topic_id=>topic1.id
279
+ book2 = Book.create :title=>"book2", :author_name=>"Mark", :publisher=>"Pub", :topic_id=>topic1.id
280
+ book3 = Book.create :title=>"book3", :author_name=>"Zach", :publisher=>"Pub", :topic_id=>topic1.id
281
+
282
+ book1.topic = topic2
283
+ book2.topic = topic1
284
+ book3.topic = topic2
285
+
286
+ books = [ book1, book2, book3 ]
287
+ Book.import( books, :on_duplicate_key_update=>[ :topic_id ])
288
+ books.each{ |b| b.reload }
289
+
290
+ assert book1.topic_id == topic2.id, "wrong topic id for book1!"
291
+ assert book2.topic_id == topic1.id, "wrong topic id for book2!"
292
+ assert book3.topic_id == topic2.id, "wrong topic id for book3!"
293
+ end
294
+
295
+ def test_import_should_not_update_created_at_or_created_on_columns_on_duplicate_keys_by_default
296
+ return unless Topic.supports_on_duplicate_key_update?
297
+
298
+ book1 = Book.create :title=>"book1", :author_name=>"Zach", :publisher=>"Pub"
299
+ book2 = Book.create :title=>"book2", :author_name=>"Mark", :publisher=>"Pub"
300
+ book3 = Book.create :title=>"book3", :author_name=>"Zach", :publisher=>"Pub"
301
+ books = [ book1, book2, book3 ]
302
+ created_at_arr = books.inject([]){ |arr,book| arr << book.created_at }
303
+ created_on_arr = books.inject([]){ |arr,book| arr << book.created_on }
304
+
305
+ Book.import books
306
+ books.each{ |b| b.reload }
307
+
308
+ created_at_arr.each_with_index do |time,i|
309
+ assert_equal time.to_s(:db), books[i].created_at.to_s(:db)
310
+ end
311
+
312
+ created_on_arr.each_with_index do |time,i|
313
+ assert_equal time.to_s(:db), books[i].created_on.to_s(:db)
314
+ end
315
+ end
316
+
317
+ def test_import_should_update_updated_at_or_updated_on_columns_with_duplicate_keys_by_default
318
+ return unless Topic.supports_on_duplicate_key_update?
319
+
320
+ book1 = Book.create :title=>"book1", :author_name=>"Zach", :publisher=>"Pub"
321
+ book2 = Book.create :title=>"book2", :author_name=>"Mark", :publisher=>"Pub"
322
+ sleep 2
323
+ books = [ book1, book2 ]
324
+ updated_at_arr = books.inject([]){ |arr,book| arr << book.updated_at }
325
+ updated_on_arr = books.inject([]){ |arr,book| arr << book.updated_on }
326
+ Book.import books
327
+ books.each{ |b| b.reload }
328
+
329
+ updated_at_arr.each_with_index do |time,i|
330
+ assert time.to_f < books[i].updated_at.to_f
331
+ end
332
+
333
+ updated_on_arr.each_with_index do |time,i|
334
+ assert time.to_f < books[i].updated_on.to_f
335
+ end
336
+ end
337
+
338
+ def test_import_without_timestamps
339
+ columns = %W{ id author_name }
340
+ values = []
341
+ values << [ 1, "Jerry Carter" ]
342
+ values << [ 2, "Chad Fowler" ]
343
+
344
+ expected_count = Topic.count
345
+ Topic.import( columns, values,
346
+ :validate=>false,
347
+ :timestamps=>false )
348
+
349
+ assert_equal expected_count+values.size, Topic.count, "#{ values.size } new records should have been created!"
350
+ assert_equal Topic.find( 1 ).created_at, nil, "created_at should be nil"
351
+ assert_equal Topic.find( 2 ).updated_at, nil, "updated_at should be nil"
352
+ end
353
+
354
+ end
@@ -0,0 +1,173 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), '..', 'test_helper' ))
2
+
3
+ class InsertSelectTest < TestCaseSuperClass
4
+ self.fixtures 'books'
5
+ if ActiveRecord::Base.connection.class.name =~ /sqlite/i
6
+ self.use_transactional_fixtures = false
7
+ end
8
+
9
+ #define the duplicate key update for mysql for testing
10
+ #add oracle, postgre, sqlite, etc when implemented
11
+ if ENV["ARE_DB"] == 'mysql'
12
+ DUPLICATE_UPDATE_STR = 'cart_items.updated_at=VALUES(`updated_at`), copies=VALUES(copies), book_id=VALUES(`book_id`)'
13
+ else
14
+ DUPLICATE_UPDATE_STR = [:updated_at, :copies, :book_id]
15
+ end
16
+
17
+ def setup
18
+ @connection = ActiveRecord::Base.connection
19
+ @conditions = ['author_name like :author_name', {:author_name => 'Terry Brooks'}]
20
+ @into_columns = [:book_id, :shopping_cart_id, :copies, :updated_at, :created_at]
21
+ @cart = ShoppingCart.create!(:name => 'My Shopping Cart')
22
+ @time = Time.now - 2.seconds
23
+
24
+ Topic.destroy_all
25
+ ShoppingCart.destroy_all
26
+ end
27
+
28
+ def teardown
29
+ Topic.destroy_all
30
+ ShoppingCart.destroy_all
31
+ end
32
+
33
+ #test simple insert select
34
+ def test_insert_select_should_import_data_from_one_model_into_another
35
+ assert_equal 0, Topic.count
36
+
37
+ timestamp = Time.now
38
+ Topic.insert_select(
39
+ :from => :book,
40
+ :select => ['title, author_name, ?', timestamp],
41
+ :into => [:title, :author_name, :updated_at])
42
+
43
+ books = Book.find :all, :order => 'title'
44
+ topics = Topic.find :all, :order => 'title'
45
+
46
+ assert_equal books.length, topics.length
47
+
48
+ topics.each_with_index {|topic, idx|
49
+ assert_equal topic.author_name, books[idx].author_name
50
+ assert_equal topic.title, books[idx].title
51
+ assert_equal topic.updated_at.to_s, timestamp.to_s
52
+ }
53
+ end
54
+
55
+ def test_insert_select_should_import_data_from_one_model_into_another_ignoring_existing_data
56
+ time = Time.now - 4.seconds
57
+ #insert book data into cart
58
+ CartItem.insert_select(
59
+ :from => :book,
60
+ :select => ['books.id, ?, ?, ?, now()', @cart.to_param, 1, time],
61
+ :into => [:book_id, :shopping_cart_id, :copies, :updated_at, :created_at])
62
+
63
+ total = CartItem.count(:id, :conditions => ['shopping_cart_id = ? and updated_at = ?', @cart.to_param, time])
64
+ assert_equal 9, total, "Expecting 6 cart items. Instead got #{total}"
65
+
66
+ #insert the same data from book into the cart
67
+ CartItem.insert_select(:from => Book,
68
+ :select => ['books.id, ?, ?, ?, now()', @cart.to_param, 1, Time.now],
69
+ :into => 'cart_items.book_id, shopping_cart_id, copies, updated_at, created_at',
70
+ :ignore => true )
71
+
72
+ #ensure that the data has not changed
73
+ total = CartItem.count(:id, :conditions => ['shopping_cart_id = ? and updated_at = ?', @cart.to_param, time])
74
+ assert_equal 9, total, "Expecting 6 cart items. Instead got #{total}"
75
+ end
76
+
77
+ def test_insert_select_should_import_data_from_one_model_into_another_updating_existing_data(options_one={}, options_two={})
78
+ fun_topic = Topic.create!(:title => 'Fun Books', :author_name => 'Big Bird')
79
+ ok_topic = Topic.create!(:title => 'OK Books', :author_name => 'sloth')
80
+ boring_topic = Topic.create!(:title => 'Boring Books', :author_name => 'Giraffe')
81
+
82
+ Book.update_all(['topic_id = ?', boring_topic])
83
+ Book.update_all(['topic_id = ?', fun_topic], 'books.id < 3')
84
+ Book.update_all(['topic_id = ?', ok_topic], 'books.id = 3')
85
+
86
+ CartItem.insert_select(
87
+ {:from => :book,
88
+ :select => ['books.id, ?, ?, ?, ?', @cart.to_param, 1, @time, @time],
89
+ :into => @into_columns,
90
+ :conditions => ['topics.title = :title', {:title => 'Fun Books'}],
91
+ :include => :topic }.merge(options_one))
92
+
93
+ validate_cart_items({:total => 2, :copies => 1 },
94
+ :conditions => ['topics.title in (?)', ['Fun Books']],
95
+ :include => { :book => :topic })
96
+
97
+ #insert select with on duplicate key update written as a string
98
+ new_time = Time.now
99
+ CartItem.insert_select(
100
+ {:from => :book,
101
+ :select => ['books.id, ?, ?, ?, ?', @cart.to_param, 2, new_time, new_time],
102
+ :into => @into_columns,
103
+ :conditions => ['topics.title in (?)', ['Fun Books', 'OK Books']],
104
+ :include => :topic ,
105
+ :on_duplicate_key_update => DUPLICATE_UPDATE_STR}.merge(options_two))
106
+
107
+ # 3 total items
108
+ assert_equal 3, CartItem.count
109
+
110
+ #2 fun books should have updated the updated_at and copies field
111
+ validate_cart_items({:total => 2, :updated_at => new_time, :copies => 2},
112
+ :conditions => ['topics.title in (?)', ['Fun Books']],
113
+ :include => { :book => :topic })
114
+
115
+ #1 ok book
116
+ validate_cart_items({:total => 1, :updated_at => new_time, :created_at => new_time, :copies => 2},
117
+ :conditions => ['topics.title in (?)', ['OK Books']],
118
+ :include => { :book => :topic })
119
+ end
120
+
121
+ def test_insert_select_should_import_data_from_one_model_into_another_updating_existing_data_using_joins_and_limit
122
+ #use a join instead of include
123
+ options = {:include => nil, :joins => 'inner join topics on topics.id = books.topic_id', :limit => 4}
124
+ test_insert_select_should_import_data_from_one_model_into_another_updating_existing_data options, options
125
+ end
126
+
127
+ #test insert select with ignore and duplicate options
128
+ def test_insert_select_should_import_data_from_one_model_into_another_updating_multiple_columns
129
+
130
+ @cart_copies = Book.count(:all, :conditions => @conditions)
131
+ assert @cart_copies > 0
132
+
133
+ @time = Time.now
134
+ CartItem.insert_select(
135
+ :from => :book,
136
+ :select => ['books.id, ?, ?, ?, ?', @cart.to_param, 1, @time, @time],
137
+ :conditions => @conditions,
138
+ :into => @into_columns)
139
+
140
+ validate_cart_items :total => @cart_copies, :copies => 1
141
+
142
+ #use on duplicate update
143
+ #this means that the book count should change to 2 and the updated time should be changed to new_time
144
+ new_time = Time.now
145
+ CartItem.insert_select(
146
+ :from => :book,
147
+ :select => ['books.id, :cart, :copies, :updated_at, :created_at', {:copies => 2, :cart => @cart, :created_at => new_time, :updated_at => new_time}],
148
+ :conditions => @conditions,
149
+ :into => @into_columns,
150
+ :on_duplicate_key_update => [:updated_at, :copies])
151
+
152
+ validate_cart_items :total => @cart_copies, :updated_at => new_time, :copies => 2
153
+ end
154
+
155
+ protected
156
+
157
+ def validate_cart_items(expected_values = {}, find_options = {})
158
+
159
+ vals = {:shopping_cart_id => @cart.to_param, :updated_at => @time, :created_at => @time, :copies => 1}.merge expected_values
160
+ total_count = vals.delete(:total)
161
+
162
+ items = CartItem.find(:all, find_options)
163
+ assert_equal(total_count, items.length, "Expecting #{total_count}, recieved #{items.length}") unless total_count.nil?
164
+
165
+ items.each do |item|
166
+ vals.each do |method, val|
167
+ actual = item.send method
168
+ assert_equal val.to_s, actual.to_s, "Expecting #{method} = #{val}. Instead got #{actual}"
169
+ end
170
+ end
171
+ end
172
+ end
173
+