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,290 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), '../test_helper') )
2
+
3
+ class CreateAndUpdateTest < TestCaseSuperClass
4
+ if ActiveRecord::Base.connection.class.name =~ /sqlite/i
5
+ self.use_transactional_fixtures = false
6
+ end
7
+
8
+ def setup
9
+ super
10
+ Animal.delete_all
11
+ end
12
+
13
+ #Input Validation Tests
14
+ def test_replace_should_replace_existing_record_with_new_data
15
+ create_animal
16
+ assert_nil(@animal.size)
17
+
18
+ new_animal = Animal.new(:name => 'giraffe', :size => 'big')
19
+ assert_raise(ActiveRecord::StatementInvalid,
20
+ "Should not be able to save duplicate.") { new_animal.save }
21
+
22
+ new_animal.replace
23
+
24
+ validate_animal(:size => 'big', :name => 'giraffe')
25
+ assert(@animal.updated_at < @new_animal.updated_at)
26
+ assert(@animal.created_at < @new_animal.created_at)
27
+ assert(@new_animal.id > @animal.id)
28
+
29
+ assert_nil(Animal.find_by_id(@original_animal_id))
30
+ end
31
+
32
+ #Input Validation Tests
33
+ def test_create_ignore_without_duplicate_columns_should_throw_exception_for_missing_duplicate_columns
34
+ assert_raise(ArgumentError) {
35
+ test_create({:method => 'create'}, :ignore => true, :reload => true)
36
+ }
37
+ end
38
+
39
+ def test_save_with_invalid_option_should_throw_exception
40
+ assert_raise(ArgumentError) {
41
+ test_save({:method => 'create'}, :ignore => true, :reload => true, :unknown_argument => true)
42
+ }
43
+ end
44
+
45
+ #Create tests
46
+ def test_create_ignore_should_ignore_existing_data
47
+ test_create({:method => 'create'}, :ignore => true)
48
+ validate_animal(:name => 'giraffe',
49
+ :updated_at => @animal.updated_at,
50
+ :created_at => @animal.created_at)
51
+ end
52
+
53
+ def test_create_ignore_with_reload_should_ignore_existing_data_then_reload
54
+ create_animal
55
+
56
+ @new_animal = Animal.create!({:name => 'giraffe', :size => 'little'}, :ignore => true)
57
+ assert(@new_animal.stale_record?)
58
+ assert_equal('little', @new_animal.size)
59
+
60
+ @new_animal.reload_duplicate :duplicate_columns => [:name]
61
+ assert(!@new_animal.stale_record?)
62
+ assert_nil(@new_animal.size)
63
+ end
64
+
65
+ def test_create_bang_ignore_should_ignore_existing_data
66
+ test_create({:method => 'create!'}, :ignore => true)
67
+ validate_animal(:name => 'giraffe',
68
+ :updated_at => @animal.updated_at,
69
+ :created_at => @animal.created_at)
70
+ end
71
+
72
+ def test_create_duplicate_should_update_duplicate_data
73
+ test_create({:method =>'create', :size => 'big'}, :on_duplicate_key_update => [:updated_at, :size])
74
+ validate_animal(:name => 'giraffe',
75
+ :size => 'big',
76
+ :created_at => @animal.created_at)
77
+ assert(@animal.updated_at < @new_animal.updated_at)
78
+ end
79
+
80
+ def test_create_bang_duplicate_should_update_duplicate_data
81
+ test_create({:method =>'create!', :size => 'big'}, :on_duplicate_key_update => [:updated_at, :size])
82
+ validate_animal(:name => 'giraffe',
83
+ :size => 'big',
84
+ :created_at => @animal.created_at)
85
+ assert(@animal.updated_at < @new_animal.updated_at)
86
+ end
87
+
88
+ #Save insert tests
89
+ def test_save_ignore_should_ignore_existing_data
90
+ test_save({:method => 'save'}, :ignore => true)
91
+ validate_animal(:name => 'giraffe',
92
+ :updated_at => @animal.updated_at,
93
+ :created_at => @animal.created_at)
94
+ end
95
+
96
+ def test_save_bang_ignore_should_ignore_existing_data_and_reload
97
+ test_save({:method => 'save!'},
98
+ :ignore => true, :reload => true, :duplicate_columns => [:name])
99
+ validate_animal(:name => 'giraffe',
100
+ :updated_at => @animal.updated_at,
101
+ :created_at => @animal.created_at)
102
+ end
103
+
104
+
105
+ def test_save_duplicate_should_update_duplicate_data_and_reload
106
+ test_save({:method =>'save', :size => 'big'},
107
+ :on_duplicate_key_update => [:updated_at, :size],
108
+ :reload => true, :duplicate_columns => [:name])
109
+
110
+ validate_animal(:name => 'giraffe',
111
+ :size => 'big',
112
+ :created_at => @animal.created_at)
113
+
114
+ assert(@animal.updated_at < @new_animal.updated_at)
115
+ end
116
+
117
+ def test_save_bang_duplicate_should_update_duplicate_data
118
+ test_save({:method => 'save!', :size => 'big'},
119
+ :on_duplicate_key_update => [:updated_at, :size])
120
+
121
+ validate_animal(:name => 'giraffe',
122
+ :size => 'big',
123
+ :created_at => @animal.created_at)
124
+
125
+ assert(@animal.updated_at < @new_animal.updated_at)
126
+ end
127
+
128
+ def test_save_existing_record_should_just_save_without_reload
129
+ test_save_existing_record(:ignore => true)
130
+ assert_equal(@bear.name, 'giraffe')
131
+ assert_equal(@bear.size, 'huge')
132
+ end
133
+
134
+ def test_save_existing_record_should_just_save_with_reload
135
+ test_save_existing_record(:ignore => true, :reload => true, :duplicate_columns => [:name])
136
+ assert_equal(@bear.name, 'giraffe')
137
+ assert_nil(@bear.size)
138
+ end
139
+
140
+ def test_save_existing_record_should_update_duplicate
141
+ test_save_existing_record(:on_duplicate_key_update => [:updated_at, :size], :reload => true, :duplicate_columns => [:name])
142
+ assert_equal(@bear.name, 'giraffe')
143
+ assert_equal(@bear.size, 'huge')
144
+
145
+ #ensure record was modified in database
146
+ @bear = Animal.find_by_name('giraffe')
147
+ assert_equal(@bear.name, 'giraffe')
148
+ assert_equal(@bear.size, 'huge')
149
+ end
150
+
151
+ #RELOAD tests
152
+
153
+
154
+ def test_create_ignore_with_reload_should_ignore_existing_data_then_reload
155
+ create_animal
156
+
157
+ @new_animal = Animal.create!({:name => 'giraffe', :size => 'little'}, :ignore => true)
158
+ assert(@new_animal.stale_record?)
159
+ assert_equal('little', @new_animal.size)
160
+
161
+ @new_animal.reload_duplicate :duplicate_columns => [:name]
162
+ assert(!@new_animal.stale_record?)
163
+ assert_nil(@new_animal.size)
164
+ end
165
+
166
+ def test_save_should_update_existing_data_then_reload_later
167
+ create_animal
168
+
169
+ @new_animal = Animal.new :name => 'giraffe', :size => 'little'
170
+ @new_animal.save!(:on_duplicate_key_update => [:updated_at])
171
+
172
+
173
+ assert(@new_animal.stale_record?)
174
+ assert_equal(0, @new_animal.id)
175
+ assert_equal('little', @new_animal.size)
176
+ assert(@animal.updated_at < @new_animal.updated_at)
177
+ new_updated = @new_animal.updated_at
178
+
179
+ @new_animal.reload_duplicate :duplicate_columns => [:name]
180
+
181
+ assert(!@new_animal.stale_record?)
182
+ assert_nil(@new_animal.size)
183
+ assert_equal(new_updated.to_s, @new_animal.updated_at.to_s)
184
+ assert_equal(@animal.id, @new_animal.id)
185
+ end
186
+
187
+ def test_update_should_delete_duplicate_record_on_reload
188
+ create_animal
189
+
190
+ @new_animal = Animal.create! :name => 'bear', :size => 'little'
191
+ @new_animal.name = 'giraffe'
192
+ assert(@new_animal.id > @animal.id)
193
+
194
+ @new_animal.reload_duplicate :force => true, :duplicate_columns => [:name]
195
+ assert(!@new_animal.stale_record?)
196
+ assert_nil(@new_animal.size)
197
+ assert_equal(@animal.updated_at.to_s, @new_animal.updated_at.to_s)
198
+ assert_equal(@animal.id, @new_animal.id)
199
+ assert_nil(Animal.find_by_name('bear'))
200
+
201
+ end
202
+
203
+ protected
204
+
205
+ def test_create(options, ex_options)
206
+ method = options.delete(:method)
207
+ create_animal
208
+ assert_raises(ActiveRecord::StatementInvalid,
209
+ "Should not be able to create duplicate.") { Animal.send(method, {:name => 'giraffe'}) }
210
+ @new_animal = Animal.send(method, {:name => 'giraffe'}.merge(options), ex_options)
211
+ assert(@new_animal)
212
+ validate_state_state(ex_options)
213
+ end
214
+
215
+ def test_save(options, ex_options)
216
+ method = options.delete(:method)
217
+ create_animal
218
+ @new_animal = Animal.new({:name => 'giraffe'}.merge(options))
219
+ assert_raise(ActiveRecord::StatementInvalid,
220
+ "Should not be able to save duplicate.") { @new_animal.send(method) }
221
+ assert(@new_animal.send(method, ex_options))
222
+ validate_state_state(ex_options)
223
+ end
224
+
225
+ def validate_state_state(ex_options)
226
+ if ex_options[:reload]
227
+ assert_equal(@new_animal.created_at.to_s, @animal.created_at.to_s)
228
+ assert(!@new_animal.stale_record?)
229
+ assert_equal(@original_animal_id, @new_animal.id)
230
+ else
231
+ assert_equal(0, @new_animal.id)
232
+ assert(@new_animal.created_at > @animal.created_at)
233
+ assert(@new_animal.stale_record?)
234
+ assert(Animal.find_by_name('giraffe'))
235
+ end
236
+ end
237
+
238
+ def test_save_existing_record(save_options)
239
+ @giraffe = create_animal
240
+
241
+ @bear = create_animal(:name => 'bear')
242
+ @bear.name = 'giraffe'
243
+ @bear.size = 'huge'
244
+
245
+ @original_bear_id = @bear.id
246
+ @original_giraffe_id = @giraffe.id
247
+
248
+ assert_raises(ActiveRecord::StatementInvalid,
249
+ "Should not be able to create duplicate."){ @bear.save }
250
+
251
+ @bear.save(save_options)
252
+ assert(Animal.find_by_name('giraffe'))
253
+
254
+ if save_options[:reload] || (save_options[:on_duplicate_key_update] && save_options[:duplicate_columns])
255
+ assert_equal(@original_giraffe_id, @bear.id)
256
+ assert(!@bear.stale_record?)
257
+ assert_nil(Animal.find_by_name('bear'))
258
+ else
259
+ assert_equal(@original_bear_id, @bear.id)
260
+ assert(@bear.stale_record?)
261
+ assert(Animal.find_by_name('bear'))
262
+ end
263
+ end
264
+
265
+ def create_animal(options={})
266
+ Animal.create!(options.reverse_merge(:name => 'giraffe'))
267
+
268
+ #back set the date so we can compare the new timestamp
269
+ reset_time = Time.now - 1.day
270
+ Animal.update_all(['updated_at = ?, created_at = ?', reset_time, reset_time])
271
+
272
+ @animal = Animal.find_by_name options[:name] || 'giraffe'
273
+ @original_animal_id = @animal.id
274
+ @animal
275
+ end
276
+
277
+ def validate_animal(fields)
278
+ @new_animal = Animal.find_by_name fields[:name]
279
+ assert(@new_animal)
280
+
281
+ assert(@new_animal.updated_at)
282
+ assert(@new_animal.created_at)
283
+
284
+ fields.each do|field, exp_val|
285
+ assert_equal(exp_val.to_s, @new_animal.send(field).to_s,
286
+ "Expecting #{exp_val} for #{field} but got #{@new_animal.send(field)}")
287
+ end
288
+ end
289
+
290
+ end
@@ -0,0 +1,142 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), '../test_helper') )
2
+
3
+ {:execute => [/^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/],
4
+ :insert => [],
5
+ :delete => []
6
+ }.each do |method, ignore_list|
7
+
8
+ ActiveRecord::Base.connection.class.class_eval <<-END_SRC
9
+ cattr_accessor :#{method}_count
10
+ # Array of regexes of queries that are not counted against query_count
11
+ @@ignore_#{method}_list = #{ignore_list.inspect}
12
+ alias_method :#{method}_without_query_counting, :#{method}
13
+ def #{method}_with_query_counting(sql, name = nil, &block)
14
+ self.#{method}_count += 1 unless @@ignore_#{method}_list.any? { |r| sql =~ r }
15
+ #{method}_without_query_counting(sql, name, &block)
16
+ end
17
+ END_SRC
18
+ end
19
+
20
+ class DeleteTestCaseSuperClass < TestCaseSuperClass
21
+ protected
22
+
23
+ def assert_query(method, num = 1)
24
+ ActiveRecord::Base.connection.class.class_eval do
25
+ self.send "#{method}_count=", 0
26
+ alias_method method, "#{method}_with_query_counting"
27
+ end
28
+ yield
29
+ ensure
30
+ ActiveRecord::Base.connection.class.class_eval do
31
+ alias_method method, "#{method}_without_query_counting"
32
+ end
33
+ count = ActiveRecord::Base.connection.send "#{method}_count"
34
+ assert_equal num, count, "#{count} instead of #{num} #{method} queries were executed."
35
+ end
36
+
37
+ end
38
+
39
+
40
+ class DeleteTest < DeleteTestCaseSuperClass
41
+
42
+ def setup
43
+ super
44
+ insert_books
45
+ end
46
+
47
+ def test_delete_limit_should_only_delete_three_records
48
+ count = Book.count(:all, :conditions => ['author_name = ?', 'giraffe'])
49
+ assert_equal 50, count
50
+
51
+ deleted = Book.delete_all(['author_name = ?', 'giraffe'], :limit => 24)
52
+
53
+ assert_equal 24, deleted
54
+
55
+ count = Book.count(:all, :conditions => ['author_name = ?', 'giraffe'])
56
+ assert_equal 26, count
57
+ end
58
+
59
+ def test_delete_limit_should_delete_less_than_limit
60
+ count = Book.count(:all, :conditions => ['author_name = ?', 'giraffe'])
61
+ assert_equal 50, count
62
+
63
+ deleted = Book.delete_all(['author_name = ?', 'giraffe'], :limit => 55)
64
+ assert_equal(50, deleted)
65
+
66
+ count = Book.count(:all, :conditions => ['author_name = ?', 'giraffe'])
67
+ assert_equal 0, count
68
+ end
69
+
70
+ def test_delete_batch_should_execute_6_deletes
71
+ assert_query(:delete, 6){
72
+ assert_equal(50, Book.delete_all(nil, :batch => 10))
73
+ }
74
+ assert_equal 0, Book.count
75
+ end
76
+
77
+ def test_delete_batch_with_limit_should_delete_until_limit_reached
78
+ assert_query(:delete, 4){
79
+ assert_equal(32, Book.delete_all('id > 0', :batch => 10, :limit => 32))
80
+ }
81
+ assert_equal 18, Book.count
82
+ end
83
+
84
+
85
+ def test_delete_batch_default_should_delete_all
86
+ assert_query(:delete, 1){
87
+ assert_equal(50, Book.delete_all(nil, :batch => true))
88
+ }
89
+ assert_equal 0, Book.count
90
+ end
91
+
92
+
93
+ def test_delete_batch_bigger_than_limit_should_delete_limit
94
+ assert_query(:delete, 1){
95
+ assert_equal(12, Book.delete_all(nil, :batch => 20, :limit => 12))
96
+ }
97
+ assert_equal 38, Book.count
98
+ end
99
+
100
+
101
+ def test_delete_duplicates_should_leave_one_by_author_with_low_id
102
+ min_id = Book.minimum :id
103
+
104
+ Book.delete_duplicates(:fields => [:author_name])
105
+ assert_equal 0, Book.count(:all, :group => :author_name, :having => 'count(*) > 1' ).length
106
+
107
+ assert_equal(min_id, Book.find_by_author_name('giraffe').id)
108
+ end
109
+
110
+
111
+ def test_delete_duplicates_should_delete_all_but_one_with_publisher_one
112
+
113
+ min_id = Book.minimum :id
114
+
115
+ Book.delete_duplicates(:fields => [:author_name], :conditions => ['c1.publisher = ? and c2.publisher = ?', 'Pub1', 'Pub1'])
116
+
117
+ books = Book.find_all_by_author_name('giraffe', :order => :id)
118
+ assert_equal 41, books.length
119
+
120
+ assert_equal min_id, books.first.id
121
+
122
+ assert_equal 1, Book.find_all_by_author_name_and_publisher('giraffe', 'Pub1').length
123
+
124
+ end
125
+
126
+ def test_delete_duplicates_should_delete_all_but_five
127
+ Book.delete_duplicates(:fields => [:author_name, :publisher])
128
+ assert_equal(5, Book.count)
129
+ end
130
+
131
+
132
+
133
+ protected
134
+ def insert_books
135
+ Book.delete_all
136
+ 1.upto(50){|count|
137
+ Book.create!(:author_name => 'giraffe', :title => "Title#{count}", :publisher => "Pub#{count % 5}")
138
+ }
139
+ end
140
+
141
+ end
142
+
@@ -0,0 +1,121 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), '..', 'test_helper' ))
2
+
3
+
4
+ class FinderOptionsTest < TestCaseSuperClass
5
+ include ActiveRecord::ConnectionAdapters
6
+ self.fixture_path = File.join( File.dirname( __FILE__ ), 'fixtures/unit/active_record_base_finders' )
7
+ self.fixtures 'books'
8
+
9
+ def setup
10
+ @connection = ActiveRecord::Base.connection
11
+ end
12
+
13
+ def teardown
14
+ Topic.delete_all
15
+ Book.delete_all
16
+ end
17
+
18
+ def test_find_with_having_should_add_having_option_to_sql
19
+ create_books_and_topics
20
+
21
+ #test having without associations
22
+ books = Book.find(:all, :select => 'count(*) as count_all, topic_id', :group => :topic_id, :having => 'count(*) > 1')
23
+ assert_equal 2, books.size
24
+
25
+ #test having with associations
26
+ books = Book.find(:all,
27
+ :include => :topic,
28
+ :conditions => " topics.id is not null", #the conditions forces eager loading in Rails 2.2
29
+ :select => 'count(*) as count_all, topic_id',
30
+ :group => :topic_id,
31
+ :having => 'count(*) > 1')
32
+
33
+ assert_equal 2, books.size
34
+ end
35
+
36
+ def test_finder_sql_to_string_should_select_from_one_table
37
+ book_sql = Book.finder_sql_to_string(:select => 'topic_id', :include => :topic)
38
+
39
+ # current generated output looks like this now:
40
+ # SELECT topic_id FROM `books`
41
+ assert(/^SELECT\s/.match(book_sql))
42
+ assert_nil(/\sJOIN\s/.match(book_sql))
43
+ (Book.column_names - ['topic_id']).each do |col|
44
+ assert_nil(book_sql.match(Regexp.new("^SELECT .*[`\s]#{col}.*FROM")))
45
+ end
46
+
47
+ assert(/^SELECT\s.*topic_id.*FROM/.match(book_sql))
48
+ end
49
+
50
+ def test_finder_sql_to_string_w_forced_eager_load_should_generate_sql_with_joined_table
51
+ book_sql = Book.finder_sql_to_string(:select => 'topic_id',
52
+ :include => :topic,
53
+ :force_eager_load => true)
54
+ assert(/^SELECT\s/.match(book_sql))
55
+ assert(/\sJOIN\s/.match(book_sql))
56
+
57
+ #assert that each column was included in the sql
58
+ Book.column_names.each do |col|
59
+ assert(book_sql.match(Regexp.new("^SELECT .*[`\s\.]#{col}.*FROM")))
60
+ end
61
+
62
+ # current generated output looks like this now:
63
+ # SELECT `books`.`id` AS t0_r0, `books`.`title` AS t0_r1, `books`.`publisher` AS t0_r2, `books`.`author_name` AS t0_r3, `books`.`created_at` AS t0_r4, `books`.`created_on` AS t0_r5, `books`.`updated_at` AS t0_r6, `books`.`updated_on` AS t0_r7, `books`.`topic_id` AS t0_r8, `books`.`for_sale` AS t0_r9, `topics`.`id` AS t1_r0, `topics`.`title` AS t1_r1, `topics`.`author_name` AS t1_r2, `topics`.`author_email_address` AS t1_r3, `topics`.`written_on` AS t1_r4, `topics`.`bonus_time` AS t1_r5, `topics`.`last_read` AS t1_r6, `topics`.`content` AS t1_r7, `topics`.`approved` AS t1_r8, `topics`.`replies_count` AS t1_r9, `topics`.`parent_id` AS t1_r10, `topics`.`type` AS t1_r11, `topics`.`created_at` AS t1_r12, `topics`.`updated_at` AS t1_r13 FROM `books` LEFT OUTER JOIN `topics` ON `topics`.id = `books`.topic_id
64
+ end
65
+
66
+ def test_finder_sql_to_string_should_generate_sql_with_joined_table
67
+ conditions = 'topics.id is not null'
68
+ book_sql = Book.finder_sql_to_string(:select => 'topic_id', :include => :topic, :conditions => conditions)
69
+
70
+ assert(/^SELECT\s/.match(book_sql))
71
+ assert(/\sJOIN\s/.match(book_sql))
72
+ assert(book_sql.include?(conditions))
73
+
74
+ #assert that each column was included in the sql
75
+ Book.column_names.each do |col|
76
+ assert(book_sql.match(Regexp.new("^SELECT .*[`\s\.]#{col}.*FROM")))
77
+ end
78
+
79
+ # current generated output looks like this now:
80
+ #"SELECT `books`.`id` AS t0_r0, `books`.`title` AS t0_r1, `books`.`publisher` AS t0_r2, `books`.`author_name` AS t0_r3, `books`.`created_at` AS t0_r4, `books`.`created_on` AS t0_r5, `books`.`updated_at` AS t0_r6, `books`.`updated_on` AS t0_r7, `books`.`topic_id` AS t0_r8, `books`.`for_sale` AS t0_r9, `topics`.`id` AS t1_r0, `topics`.`title` AS t1_r1, `topics`.`author_name` AS t1_r2, `topics`.`author_email_address` AS t1_r3, `topics`.`written_on` AS t1_r4, `topics`.`bonus_time` AS t1_r5, `topics`.`last_read` AS t1_r6, `topics`.`content` AS t1_r7, `topics`.`approved` AS t1_r8, `topics`.`replies_count` AS t1_r9, `topics`.`parent_id` AS t1_r10, `topics`.`type` AS t1_r11, `topics`.`created_at` AS t1_r12, `topics`.`updated_at` AS t1_r13 FROM `books` LEFT OUTER JOIN `topics` ON `topics`.id = `books`.topic_id WHERE (topics.id is not null)"
81
+ end
82
+
83
+ def test_pre_sql_should_ensure_pre_sql_option_is_added_to_beginning_of_sql
84
+ book_sql = Book.finder_sql_to_string(:select => 'topic_id', :pre_sql => "/* BLAH */")
85
+ assert(/^\/\* BLAH \*\/\sSELECT/.match(book_sql))
86
+ end
87
+
88
+ def test_pre_sql_should_ensure_pre_sql_option_is_added_to_beginning_of_sql_with_eager_loading
89
+ book_sql = Book.finder_sql_to_string(:select => 'topic_id', :pre_sql => "/* BLAH */", :include => :topic, :conditions => 'topics.id is not null')
90
+ assert(/^\/\* BLAH \*\/\sSELECT/.match(book_sql))
91
+ end
92
+
93
+ def test_pre_sql_should_ensure_post_sql_option_is_added_to_end_of_sql
94
+ book_sql = Book.finder_sql_to_string(:select => 'topic_id', :post_sql => "/* BLAH */")
95
+ assert(/\s\/\* BLAH \*\/$/.match(book_sql))
96
+ end
97
+
98
+ def test_pre_sql_should_ensure_post_sql_option_is_added_to_end_of_sql_with_eager_loading
99
+ book_sql = Book.finder_sql_to_string(:select => 'topic_id', :post_sql => "/* BLAH */", :include => :topic, :conditions => 'topics.id is not null')
100
+ assert(/\s\/\* BLAH \*\/$/.match(book_sql))
101
+ end
102
+
103
+ protected
104
+
105
+ def create_books_and_topics
106
+ Book.destroy_all
107
+ Topic.destroy_all
108
+
109
+ topics = [Topic.create!(:title => 'My Topic', :author_name => 'Giraffe'),
110
+ Topic.create!(:title => 'Other Topic', :author_name => 'Giraffe'),
111
+ Topic.create!(:title => 'Last Topic', :author_name => 'Giraffe')]
112
+
113
+ Book.create!(:title => 'Title A', :topic_id => topics[0].to_param, :author_name => 'Giraffe')
114
+ Book.create!(:title => 'Title B', :topic_id => topics[0].to_param, :author_name => 'Giraffe')
115
+ Book.create!(:title => 'Title C', :topic_id => topics[0].to_param, :author_name => 'Giraffe')
116
+ Book.create!(:title => 'Title D', :topic_id => topics[1].to_param, :author_name => 'Giraffe')
117
+ Book.create!(:title => 'Title E', :topic_id => topics[1].to_param, :author_name => 'Giraffe')
118
+ Book.create!(:title => 'Title F', :topic_id => topics[2].to_param, :author_name => 'Giraffe')
119
+ end
120
+
121
+ end