jorahood-ar-extensions 0.9.2.3

Sign up to get free protection for your applications and to get access to all the features.
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
+