ibm_db 2.5.26-universal-darwin-14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +233 -0
  3. data/LICENSE +18 -0
  4. data/MANIFEST +14 -0
  5. data/ParameterizedQueries README +39 -0
  6. data/README +225 -0
  7. data/ext/Makefile.nt32 +181 -0
  8. data/ext/Makefile.nt32.191 +212 -0
  9. data/ext/extconf.rb +261 -0
  10. data/ext/ibm_db.c +11793 -0
  11. data/ext/ruby_ibm_db.h +240 -0
  12. data/ext/ruby_ibm_db_cli.c +845 -0
  13. data/ext/ruby_ibm_db_cli.h +489 -0
  14. data/init.rb +42 -0
  15. data/lib/IBM_DB.rb +19 -0
  16. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3289 -0
  17. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
  18. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +2 -0
  19. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  20. data/lib/linux/rb18x/ibm_db.bundle +0 -0
  21. data/lib/linux/rb19x/ibm_db.bundle +0 -0
  22. data/lib/linux/rb20x/ibm_db.bundle +0 -0
  23. data/lib/linux/rb21x/ibm_db.bundle +0 -0
  24. data/test/cases/adapter_test.rb +207 -0
  25. data/test/cases/associations/belongs_to_associations_test.rb +711 -0
  26. data/test/cases/associations/cascaded_eager_loading_test.rb +181 -0
  27. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +851 -0
  28. data/test/cases/associations/join_model_test.rb +743 -0
  29. data/test/cases/attribute_methods_test.rb +822 -0
  30. data/test/cases/base_test.rb +2133 -0
  31. data/test/cases/calculations_test.rb +482 -0
  32. data/test/cases/migration_test.rb +2408 -0
  33. data/test/cases/persistence_test.rb +642 -0
  34. data/test/cases/query_cache_test.rb +257 -0
  35. data/test/cases/relations_test.rb +1182 -0
  36. data/test/cases/schema_dumper_test.rb +256 -0
  37. data/test/cases/transaction_callbacks_test.rb +300 -0
  38. data/test/cases/validations/uniqueness_validation_test.rb +299 -0
  39. data/test/cases/xml_serialization_test.rb +408 -0
  40. data/test/config.yml +154 -0
  41. data/test/connections/native_ibm_db/connection.rb +44 -0
  42. data/test/ibm_db_test.rb +25 -0
  43. data/test/models/warehouse_thing.rb +5 -0
  44. data/test/schema/i5/ibm_db_specific_schema.rb +137 -0
  45. data/test/schema/ids/ibm_db_specific_schema.rb +140 -0
  46. data/test/schema/luw/ibm_db_specific_schema.rb +137 -0
  47. data/test/schema/schema.rb +751 -0
  48. data/test/schema/zOS/ibm_db_specific_schema.rb +208 -0
  49. metadata +114 -0
@@ -0,0 +1,181 @@
1
+ require "cases/helper"
2
+ require 'models/post'
3
+ require 'models/comment'
4
+ require 'models/author'
5
+ require 'models/categorization'
6
+ require 'models/category'
7
+ require 'models/company'
8
+ require 'models/topic'
9
+ require 'models/reply'
10
+ require 'models/person'
11
+ require 'models/vertex'
12
+ require 'models/edge'
13
+
14
+ class CascadedEagerLoadingTest < ActiveRecord::TestCase
15
+ fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments,
16
+ :categorizations, :people, :categories, :edges, :vertices
17
+
18
+ def test_eager_association_loading_with_cascaded_two_levels
19
+ authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id")
20
+ assert_equal 3, authors.size
21
+ assert_equal 5, authors[0].posts.size
22
+ assert_equal 3, authors[1].posts.size
23
+ assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
24
+ end
25
+
26
+ def test_eager_association_loading_with_cascaded_two_levels_and_one_level
27
+ authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id")
28
+ assert_equal 3, authors.size
29
+ assert_equal 5, authors[0].posts.size
30
+ assert_equal 3, authors[1].posts.size
31
+ assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
32
+ assert_equal 1, authors[0].categorizations.size
33
+ assert_equal 2, authors[1].categorizations.size
34
+ end
35
+
36
+ def test_eager_association_loading_with_hmt_does_not_table_name_collide_when_joining_associations
37
+ assert_nothing_raised do
38
+ Author.joins(:posts).eager_load(:comments).where(:posts => {:taggings_count => 1}).all
39
+ end
40
+ authors = Author.joins(:posts).eager_load(:comments).where(:posts => {:taggings_count => 1}).all
41
+ assert_equal 1, assert_no_queries { authors.size }
42
+ assert_equal 10, assert_no_queries { authors[0].comments.size }
43
+ end
44
+
45
+ def test_eager_association_loading_grafts_stashed_associations_to_correct_parent
46
+ assert_nothing_raised do
47
+ Person.eager_load(:primary_contact => :primary_contact).where('primary_contacts_people_2.first_name = ?', 'Susan').order('people.id').all
48
+ end
49
+ assert_equal people(:michael), Person.eager_load(:primary_contact => :primary_contact).where('primary_contacts_people_2.first_name = ?', 'Susan').order('people.id').first
50
+ end
51
+
52
+ def test_cascaded_eager_association_loading_with_join_for_count
53
+ categories = Category.joins(:categorizations).includes([{:posts=>:comments}, :authors])
54
+
55
+ assert_nothing_raised do
56
+ assert_equal 4, categories.count
57
+ assert_equal 4, categories.all.count
58
+ assert_equal 3, categories.count(:distinct => true)
59
+ assert_equal 3, categories.all.uniq.size # Must uniq since instantiating with inner joins will get dupes
60
+ end
61
+ end
62
+
63
+ def test_cascaded_eager_association_loading_with_duplicated_includes
64
+ categories = Category.includes(:categorizations).includes(:categorizations => :author).where("categorizations.id is not null")
65
+ assert_nothing_raised do
66
+ assert_equal 3, categories.count
67
+ assert_equal 3, categories.all.size
68
+ end
69
+ end
70
+
71
+ def test_cascaded_eager_association_loading_with_twice_includes_edge_cases
72
+ categories = Category.includes(:categorizations => :author).includes(:categorizations => :post).where("posts.id is not null")
73
+ assert_nothing_raised do
74
+ assert_equal 3, categories.count
75
+ assert_equal 3, categories.all.size
76
+ end
77
+ end
78
+
79
+ def test_eager_association_loading_with_join_for_count
80
+ authors = Author.joins(:special_posts).includes([:posts, :categorizations])
81
+
82
+ assert_nothing_raised { authors.count }
83
+ assert_queries(3) { authors.all }
84
+ end
85
+
86
+ def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations
87
+ authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id")
88
+ assert_equal 3, authors.size
89
+ assert_equal 5, authors[0].posts.size
90
+ assert_equal 3, authors[1].posts.size
91
+ assert_equal 10, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
92
+ end
93
+
94
+ def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference
95
+ authors = Author.find(:all, :include=>{:posts=>[:comments, :author]}, :order=>"authors.id")
96
+ assert_equal 3, authors.size
97
+ assert_equal 5, authors[0].posts.size
98
+ assert_equal authors(:david).name, authors[0].name
99
+ assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq
100
+ end
101
+
102
+ def test_eager_association_loading_with_cascaded_two_levels_with_condition
103
+ authors = Author.find(:all, :include=>{:posts=>:comments}, :conditions=>"authors.id=1", :order=>"authors.id")
104
+ assert_equal 1, authors.size
105
+ assert_equal 5, authors[0].posts.size
106
+ end
107
+
108
+ def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong
109
+ firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id")
110
+ assert_equal 2, firms.size
111
+ assert_equal firms.first.account, firms.first.account.firm.account
112
+ assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account }
113
+ assert_equal companies(:first_firm).account.firm.account, assert_no_queries { firms.first.account.firm.account }
114
+ end
115
+
116
+ def test_eager_association_loading_with_has_many_sti
117
+ topics = Topic.find(:all, :include => :replies, :order => 'topics.id')
118
+ first, second, = topics(:first).replies.size, topics(:second).replies.size
119
+ assert_no_queries do
120
+ assert_equal first, topics[0].replies.size
121
+ assert_equal second, topics[1].replies.size
122
+ end
123
+ end
124
+
125
+ def test_eager_association_loading_with_has_many_sti_and_subclasses
126
+ silly = SillyReply.new(:title => "gaga", :content => "boo-boo", :parent_id => 1)
127
+ silly.parent_id = 1
128
+ assert silly.save
129
+
130
+ topics = Topic.find(:all, :include => :replies, :order => 'topics.id, replies_topics.id')
131
+ assert_no_queries do
132
+ assert_equal 2, topics[0].replies.size
133
+ assert_equal 0, topics[1].replies.size
134
+ end
135
+ end
136
+
137
+ def test_eager_association_loading_with_belongs_to_sti
138
+ replies = Reply.find(:all, :include => :topic, :order => 'topics.id')
139
+ assert replies.include?(topics(:second))
140
+ assert !replies.include?(topics(:first))
141
+ assert_equal topics(:first), assert_no_queries { replies.first.topic }
142
+ end
143
+
144
+ unless current_adapter?(:IBM_DBAdapter)
145
+ def test_eager_association_loading_with_multiple_stis_and_order
146
+ author = Author.find(:first, :include => { :posts => [ :special_comments , :very_special_comment ] }, :order => ['authors.name', 'comments.body', 'very_special_comments_posts.body'], :conditions => 'posts.id = 4')
147
+ assert_equal authors(:david), author
148
+ assert_no_queries do
149
+ author.posts.first.special_comments
150
+ author.posts.first.very_special_comment
151
+ end
152
+ end
153
+ end
154
+
155
+ def test_eager_association_loading_of_stis_with_multiple_references
156
+ authors = Author.find(:all, :include => { :posts => { :special_comments => { :post => [ :special_comments, :very_special_comment ] } } }, :order => 'comments.body, very_special_comments_posts.body', :conditions => 'posts.id = 4')
157
+ assert_equal [authors(:david)], authors
158
+ assert_no_queries do
159
+ authors.first.posts.first.special_comments.first.post.special_comments
160
+ authors.first.posts.first.special_comments.first.post.very_special_comment
161
+ end
162
+ end
163
+
164
+ def test_eager_association_loading_where_first_level_returns_nil
165
+ authors = Author.find(:all, :include => {:post_about_thinking => :comments}, :order => 'authors.id DESC')
166
+ assert_equal [authors(:bob), authors(:mary), authors(:david)], authors
167
+ assert_no_queries do
168
+ authors[2].post_about_thinking.comments.first
169
+ end
170
+ end
171
+
172
+ def test_eager_association_loading_with_recursive_cascading_four_levels_has_many_through
173
+ source = Vertex.find(:first, :include=>{:sinks=>{:sinks=>{:sinks=>:sinks}}}, :order => 'vertices.id')
174
+ assert_equal vertices(:vertex_4), assert_no_queries { source.sinks.first.sinks.first.sinks.first }
175
+ end
176
+
177
+ def test_eager_association_loading_with_recursive_cascading_four_levels_has_and_belongs_to_many
178
+ sink = Vertex.find(:first, :include=>{:sources=>{:sources=>{:sources=>:sources}}}, :order => 'vertices.id DESC')
179
+ assert_equal vertices(:vertex_1), assert_no_queries { sink.sources.first.sources.first.sources.first.sources.first }
180
+ end
181
+ end
@@ -0,0 +1,851 @@
1
+ require "cases/helper"
2
+ require 'models/developer'
3
+ require 'models/project'
4
+ require 'models/company'
5
+ require 'models/customer'
6
+ require 'models/order'
7
+ require 'models/categorization'
8
+ require 'models/category'
9
+ require 'models/post'
10
+ require 'models/author'
11
+ require 'models/tag'
12
+ require 'models/tagging'
13
+ require 'models/parrot'
14
+ require 'models/pirate'
15
+ require 'models/treasure'
16
+ require 'models/price_estimate'
17
+ require 'models/club'
18
+ require 'models/member'
19
+ require 'models/membership'
20
+ require 'models/sponsor'
21
+ require 'models/country'
22
+ require 'models/treaty'
23
+ require 'active_support/core_ext/string/conversions'
24
+
25
+ class ProjectWithAfterCreateHook < ActiveRecord::Base
26
+ self.table_name = 'projects'
27
+ has_and_belongs_to_many :developers,
28
+ :class_name => "DeveloperForProjectWithAfterCreateHook",
29
+ :join_table => "developers_projects",
30
+ :foreign_key => "project_id",
31
+ :association_foreign_key => "developer_id"
32
+
33
+ after_create :add_david
34
+
35
+ def add_david
36
+ david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
37
+ david.projects << self
38
+ end
39
+ end
40
+
41
+ class DeveloperForProjectWithAfterCreateHook < ActiveRecord::Base
42
+ self.table_name = 'developers'
43
+ has_and_belongs_to_many :projects,
44
+ :class_name => "ProjectWithAfterCreateHook",
45
+ :join_table => "developers_projects",
46
+ :association_foreign_key => "project_id",
47
+ :foreign_key => "developer_id"
48
+ end
49
+
50
+ class ProjectWithSymbolsForKeys < ActiveRecord::Base
51
+ self.table_name = 'projects'
52
+ has_and_belongs_to_many :developers,
53
+ :class_name => "DeveloperWithSymbolsForKeys",
54
+ :join_table => :developers_projects,
55
+ :foreign_key => :project_id,
56
+ :association_foreign_key => "developer_id"
57
+ end
58
+
59
+ class DeveloperWithSymbolsForKeys < ActiveRecord::Base
60
+ self.table_name = 'developers'
61
+ has_and_belongs_to_many :projects,
62
+ :class_name => "ProjectWithSymbolsForKeys",
63
+ :join_table => :developers_projects,
64
+ :association_foreign_key => :project_id,
65
+ :foreign_key => "developer_id"
66
+ end
67
+
68
+ class DeveloperWithCounterSQL < ActiveRecord::Base
69
+ self.table_name = 'developers'
70
+ has_and_belongs_to_many :projects,
71
+ :class_name => "DeveloperWithCounterSQL",
72
+ :join_table => "developers_projects",
73
+ :association_foreign_key => "project_id",
74
+ :foreign_key => "developer_id",
75
+ :counter_sql => proc { "SELECT COUNT(*) AS count_all FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE developers_projects.developer_id =#{id}" }
76
+ end
77
+
78
+ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
79
+ fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
80
+ :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings
81
+
82
+ def setup_data_for_habtm_case
83
+ ActiveRecord::Base.connection.execute('delete from countries_treaties')
84
+
85
+ country = Country.new(:name => 'India')
86
+ country.country_id = 'c1'
87
+ country.save!
88
+
89
+ treaty = Treaty.new(:name => 'peace')
90
+ treaty.treaty_id = 't1'
91
+ country.treaties << treaty
92
+ end
93
+
94
+ def test_should_property_quote_string_primary_keys
95
+ setup_data_for_habtm_case
96
+
97
+ con = ActiveRecord::Base.connection
98
+ sql = 'select * from countries_treaties'
99
+ record = con.select_rows(sql).last
100
+ assert_equal 'c1', record[0]
101
+ assert_equal 't1', record[1]
102
+ end
103
+
104
+ def test_proper_usage_of_primary_keys_and_join_table
105
+ setup_data_for_habtm_case
106
+
107
+ assert_equal 'country_id', Country.primary_key
108
+ assert_equal 'treaty_id', Treaty.primary_key
109
+
110
+ country = Country.first
111
+ assert_equal 1, country.treaties.count
112
+ end
113
+
114
+ def test_has_and_belongs_to_many
115
+ david = Developer.find(1)
116
+
117
+ assert !david.projects.empty?
118
+ assert_equal 2, david.projects.size
119
+
120
+ active_record = Project.find(1)
121
+ assert !active_record.developers.empty?
122
+ assert_equal 3, active_record.developers.size
123
+ assert active_record.developers.include?(david)
124
+ end
125
+
126
+ def test_triple_equality
127
+ assert !(Array === Developer.find(1).projects)
128
+ assert Developer.find(1).projects === Array
129
+ end
130
+
131
+ def test_adding_single
132
+ jamis = Developer.find(2)
133
+ jamis.projects.reload # causing the collection to load
134
+ action_controller = Project.find(2)
135
+ assert_equal 1, jamis.projects.size
136
+ assert_equal 1, action_controller.developers.size
137
+
138
+ jamis.projects << action_controller
139
+
140
+ assert_equal 2, jamis.projects.size
141
+ assert_equal 2, jamis.projects(true).size
142
+ assert_equal 2, action_controller.developers(true).size
143
+ end
144
+
145
+ def test_adding_type_mismatch
146
+ jamis = Developer.find(2)
147
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << nil }
148
+ assert_raise(ActiveRecord::AssociationTypeMismatch) { jamis.projects << 1 }
149
+ end
150
+
151
+ def test_adding_from_the_project
152
+ jamis = Developer.find(2)
153
+ action_controller = Project.find(2)
154
+ action_controller.developers.reload
155
+ assert_equal 1, jamis.projects.size
156
+ assert_equal 1, action_controller.developers.size
157
+
158
+ action_controller.developers << jamis
159
+
160
+ assert_equal 2, jamis.projects(true).size
161
+ assert_equal 2, action_controller.developers.size
162
+ assert_equal 2, action_controller.developers(true).size
163
+ end
164
+
165
+ def test_adding_from_the_project_fixed_timestamp
166
+ jamis = Developer.find(2)
167
+ action_controller = Project.find(2)
168
+ action_controller.developers.reload
169
+ assert_equal 1, jamis.projects.size
170
+ assert_equal 1, action_controller.developers.size
171
+ updated_at = jamis.updated_at
172
+
173
+ action_controller.developers << jamis
174
+
175
+ assert_equal updated_at, jamis.updated_at
176
+ assert_equal 2, jamis.projects(true).size
177
+ assert_equal 2, action_controller.developers.size
178
+ assert_equal 2, action_controller.developers(true).size
179
+ end
180
+
181
+ def test_adding_multiple
182
+ aredridel = Developer.new("name" => "Aredridel")
183
+ aredridel.save
184
+ aredridel.projects.reload
185
+ aredridel.projects.push(Project.find(1), Project.find(2))
186
+ assert_equal 2, aredridel.projects.size
187
+ assert_equal 2, aredridel.projects(true).size
188
+ end
189
+
190
+ def test_adding_a_collection
191
+ aredridel = Developer.new("name" => "Aredridel")
192
+ aredridel.save
193
+ aredridel.projects.reload
194
+ aredridel.projects.concat([Project.find(1), Project.find(2)])
195
+ assert_equal 2, aredridel.projects.size
196
+ assert_equal 2, aredridel.projects(true).size
197
+ end
198
+
199
+ def test_habtm_adding_before_save
200
+ no_of_devels = Developer.count
201
+ no_of_projects = Project.count
202
+ aredridel = Developer.new("name" => "Aredridel")
203
+ aredridel.projects.concat([Project.find(1), p = Project.new("name" => "Projekt")])
204
+ assert !aredridel.persisted?
205
+ assert !p.persisted?
206
+ assert aredridel.save
207
+ assert aredridel.persisted?
208
+ assert_equal no_of_devels+1, Developer.count
209
+ assert_equal no_of_projects+1, Project.count
210
+ assert_equal 2, aredridel.projects.size
211
+ assert_equal 2, aredridel.projects(true).size
212
+ end
213
+
214
+ def test_habtm_saving_multiple_relationships
215
+ new_project = Project.new("name" => "Grimetime")
216
+ amount_of_developers = 4
217
+ developers = (0...amount_of_developers).collect {|i| Developer.create(:name => "JME #{i}") }.reverse
218
+
219
+ new_project.developer_ids = [developers[0].id, developers[1].id]
220
+ new_project.developers_with_callback_ids = [developers[2].id, developers[3].id]
221
+ assert new_project.save
222
+
223
+ new_project.reload
224
+ assert_equal amount_of_developers, new_project.developers.size
225
+ assert_equal developers, new_project.developers
226
+ end
227
+
228
+ def test_habtm_unique_order_preserved
229
+ assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).non_unique_developers
230
+ assert_equal developers(:poor_jamis, :jamis, :david), projects(:active_record).developers
231
+ end
232
+
233
+ def test_build
234
+ devel = Developer.find(1)
235
+ proj = assert_no_queries { devel.projects.build("name" => "Projekt") }
236
+ assert !devel.projects.loaded?
237
+
238
+ assert_equal devel.projects.last, proj
239
+ assert devel.projects.loaded?
240
+
241
+ assert !proj.persisted?
242
+ devel.save
243
+ assert proj.persisted?
244
+ assert_equal devel.projects.last, proj
245
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
246
+ end
247
+
248
+ def test_new_aliased_to_build
249
+ devel = Developer.find(1)
250
+ proj = assert_no_queries { devel.projects.new("name" => "Projekt") }
251
+ assert !devel.projects.loaded?
252
+
253
+ assert_equal devel.projects.last, proj
254
+ assert devel.projects.loaded?
255
+
256
+ assert !proj.persisted?
257
+ devel.save
258
+ assert proj.persisted?
259
+ assert_equal devel.projects.last, proj
260
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
261
+ end
262
+
263
+ def test_build_by_new_record
264
+ devel = Developer.new(:name => "Marcel", :salary => 75000)
265
+ devel.projects.build(:name => "Make bed")
266
+ proj2 = devel.projects.build(:name => "Lie in it")
267
+ assert_equal devel.projects.last, proj2
268
+ assert !proj2.persisted?
269
+ devel.save
270
+ assert devel.persisted?
271
+ assert proj2.persisted?
272
+ assert_equal devel.projects.last, proj2
273
+ assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
274
+ end
275
+
276
+ def test_create
277
+ devel = Developer.find(1)
278
+ proj = devel.projects.create("name" => "Projekt")
279
+ assert !devel.projects.loaded?
280
+
281
+ assert_equal devel.projects.last, proj
282
+ assert !devel.projects.loaded?
283
+
284
+ assert proj.persisted?
285
+ assert_equal Developer.find(1).projects.sort_by(&:id).last, proj # prove join table is updated
286
+ end
287
+
288
+ def test_create_by_new_record
289
+ devel = Developer.new(:name => "Marcel", :salary => 75000)
290
+ devel.projects.build(:name => "Make bed")
291
+ proj2 = devel.projects.build(:name => "Lie in it")
292
+ assert_equal devel.projects.last, proj2
293
+ assert !proj2.persisted?
294
+ devel.save
295
+ assert devel.persisted?
296
+ assert proj2.persisted?
297
+ assert_equal devel.projects.last, proj2
298
+ assert_equal Developer.find_by_name("Marcel").projects.last, proj2 # prove join table is updated
299
+ end
300
+
301
+ def test_creation_respects_hash_condition
302
+ # in Oracle '' is saved as null therefore need to save ' ' in not null column
303
+ post = categories(:general).post_with_conditions.build(:body => ' ')
304
+
305
+ assert post.save
306
+ assert_equal 'Yet Another Testing Title', post.title
307
+
308
+ # in Oracle '' is saved as null therefore need to save ' ' in not null column
309
+ another_post = categories(:general).post_with_conditions.create(:body => ' ')
310
+
311
+ assert another_post.persisted?
312
+ assert_equal 'Yet Another Testing Title', another_post.title
313
+ end
314
+
315
+ def test_uniq_after_the_fact
316
+ dev = developers(:jamis)
317
+ dev.projects << projects(:active_record)
318
+ dev.projects << projects(:active_record)
319
+
320
+ assert_equal 3, dev.projects.size
321
+ assert_equal 1, dev.projects.uniq.size
322
+ end
323
+
324
+ def test_uniq_before_the_fact
325
+ projects(:active_record).developers << developers(:jamis)
326
+ projects(:active_record).developers << developers(:david)
327
+ assert_equal 3, projects(:active_record, :reload).developers.size
328
+ end
329
+
330
+ def test_uniq_option_prevents_duplicate_push
331
+ project = projects(:active_record)
332
+ project.developers << developers(:jamis)
333
+ project.developers << developers(:david)
334
+ assert_equal 3, project.developers.size
335
+
336
+ project.developers << developers(:david)
337
+ project.developers << developers(:jamis)
338
+ assert_equal 3, project.developers.size
339
+ end
340
+
341
+ def test_deleting
342
+ david = Developer.find(1)
343
+ active_record = Project.find(1)
344
+ david.projects.reload
345
+ assert_equal 2, david.projects.size
346
+ assert_equal 3, active_record.developers.size
347
+
348
+ david.projects.delete(active_record)
349
+
350
+ assert_equal 1, david.projects.size
351
+ assert_equal 1, david.projects(true).size
352
+ assert_equal 2, active_record.developers(true).size
353
+ end
354
+
355
+ def test_deleting_array
356
+ david = Developer.find(1)
357
+ david.projects.reload
358
+ david.projects.delete(Project.find(:all))
359
+ assert_equal 0, david.projects.size
360
+ assert_equal 0, david.projects(true).size
361
+ end
362
+
363
+ def test_deleting_with_sql
364
+ david = Developer.find(1)
365
+ active_record = Project.find(1)
366
+ active_record.developers.reload
367
+ assert_equal 3, active_record.developers_by_sql.size
368
+
369
+ active_record.developers_by_sql.delete(david)
370
+ assert_equal 2, active_record.developers_by_sql(true).size
371
+ end
372
+
373
+ def test_deleting_array_with_sql
374
+ active_record = Project.find(1)
375
+ active_record.developers.reload
376
+ assert_equal 3, active_record.developers_by_sql.size
377
+
378
+ active_record.developers_by_sql.delete(Developer.find(:all))
379
+ assert_equal 0, active_record.developers_by_sql(true).size
380
+ end
381
+
382
+ def test_deleting_all
383
+ david = Developer.find(1)
384
+ david.projects.reload
385
+ david.projects.clear
386
+ assert_equal 0, david.projects.size
387
+ assert_equal 0, david.projects(true).size
388
+ end
389
+
390
+ def test_removing_associations_on_destroy
391
+ david = DeveloperWithBeforeDestroyRaise.find(1)
392
+ assert !david.projects.empty?
393
+ david.destroy
394
+ assert david.projects.empty?
395
+ assert DeveloperWithBeforeDestroyRaise.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty?
396
+ end
397
+
398
+ def test_destroying
399
+ david = Developer.find(1)
400
+ project = Project.find(1)
401
+ david.projects.reload
402
+ assert_equal 2, david.projects.size
403
+ assert_equal 3, project.developers.size
404
+
405
+ assert_no_difference "Project.count" do
406
+ david.projects.destroy(project)
407
+ end
408
+
409
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id} AND project_id = #{project.id}")
410
+ assert join_records.empty?
411
+
412
+ assert_equal 1, david.reload.projects.size
413
+ assert_equal 1, david.projects(true).size
414
+ end
415
+
416
+ def test_destroying_many
417
+ david = Developer.find(1)
418
+ david.projects.reload
419
+ projects = Project.all
420
+
421
+ assert_no_difference "Project.count" do
422
+ david.projects.destroy(*projects)
423
+ end
424
+
425
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
426
+ assert join_records.empty?
427
+
428
+ assert_equal 0, david.reload.projects.size
429
+ assert_equal 0, david.projects(true).size
430
+ end
431
+
432
+ def test_destroy_all
433
+ david = Developer.find(1)
434
+ david.projects.reload
435
+ assert !david.projects.empty?
436
+
437
+ assert_no_difference "Project.count" do
438
+ david.projects.destroy_all
439
+ end
440
+
441
+ join_records = Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = #{david.id}")
442
+ assert join_records.empty?
443
+
444
+ assert david.projects.empty?
445
+ assert david.projects(true).empty?
446
+ end
447
+
448
+ def test_destroy_associations_destroys_multiple_associations
449
+ george = parrots(:george)
450
+ assert !george.pirates.empty?
451
+ assert !george.treasures.empty?
452
+
453
+ assert_no_difference "Pirate.count" do
454
+ assert_no_difference "Treasure.count" do
455
+ george.destroy_associations
456
+ end
457
+ end
458
+
459
+ join_records = Parrot.connection.select_all("SELECT * FROM parrots_pirates WHERE parrot_id = #{george.id}")
460
+ assert join_records.empty?
461
+ assert george.pirates(true).empty?
462
+
463
+ join_records = Parrot.connection.select_all("SELECT * FROM parrots_treasures WHERE parrot_id = #{george.id}")
464
+ assert join_records.empty?
465
+ assert george.treasures(true).empty?
466
+ end
467
+
468
+ def test_deprecated_push_with_attributes_was_removed
469
+ jamis = developers(:jamis)
470
+ assert_raise(NoMethodError) do
471
+ jamis.projects.push_with_attributes(projects(:action_controller), :joined_on => Date.today)
472
+ end
473
+ end
474
+
475
+ def test_associations_with_conditions
476
+ assert_equal 3, projects(:active_record).developers.size
477
+ assert_equal 1, projects(:active_record).developers_named_david.size
478
+ assert_equal 1, projects(:active_record).developers_named_david_with_hash_conditions.size
479
+
480
+ assert_equal developers(:david), projects(:active_record).developers_named_david.find(developers(:david).id)
481
+ assert_equal developers(:david), projects(:active_record).developers_named_david_with_hash_conditions.find(developers(:david).id)
482
+ assert_equal developers(:david), projects(:active_record).salaried_developers.find(developers(:david).id)
483
+
484
+ projects(:active_record).developers_named_david.clear
485
+ assert_equal 2, projects(:active_record, :reload).developers.size
486
+ end
487
+
488
+ def test_find_in_association
489
+ # Using sql
490
+ assert_equal developers(:david), projects(:active_record).developers.find(developers(:david).id), "SQL find"
491
+
492
+ # Using ruby
493
+ active_record = projects(:active_record)
494
+ active_record.developers.reload
495
+ assert_equal developers(:david), active_record.developers.find(developers(:david).id), "Ruby find"
496
+ end
497
+
498
+ def test_include_uses_array_include_after_loaded
499
+ project = projects(:active_record)
500
+ project.developers.class # force load target
501
+
502
+ developer = project.developers.first
503
+
504
+ assert_no_queries do
505
+ assert project.developers.loaded?
506
+ assert project.developers.include?(developer)
507
+ end
508
+ end
509
+
510
+ def test_include_checks_if_record_exists_if_target_not_loaded
511
+ project = projects(:active_record)
512
+ developer = project.developers.first
513
+
514
+ project.reload
515
+ assert ! project.developers.loaded?
516
+ assert_queries(1) do
517
+ assert project.developers.include?(developer)
518
+ end
519
+ assert ! project.developers.loaded?
520
+ end
521
+
522
+ def test_include_returns_false_for_non_matching_record_to_verify_scoping
523
+ project = projects(:active_record)
524
+ developer = Developer.create :name => "Bryan", :salary => 50_000
525
+
526
+ assert ! project.developers.loaded?
527
+ assert ! project.developers.include?(developer)
528
+ end
529
+
530
+ def test_find_in_association_with_custom_finder_sql
531
+ assert_equal developers(:david), projects(:active_record).developers_with_finder_sql.find(developers(:david).id), "SQL find"
532
+
533
+ active_record = projects(:active_record)
534
+ active_record.developers_with_finder_sql.reload
535
+ assert_equal developers(:david), active_record.developers_with_finder_sql.find(developers(:david).id), "Ruby find"
536
+ end
537
+
538
+ def test_find_in_association_with_custom_finder_sql_and_multiple_interpolations
539
+ # interpolate once:
540
+ assert_equal [developers(:david), developers(:jamis), developers(:poor_jamis)], projects(:active_record).developers_with_finder_sql, "first interpolation"
541
+ # interpolate again, for a different project id
542
+ assert_equal [developers(:david)], projects(:action_controller).developers_with_finder_sql, "second interpolation"
543
+ end
544
+
545
+ def test_find_in_association_with_custom_finder_sql_and_string_id
546
+ assert_equal developers(:david), projects(:active_record).developers_with_finder_sql.find(developers(:david).id.to_s), "SQL find"
547
+ end
548
+
549
+ def test_find_with_merged_options
550
+ assert_equal 1, projects(:active_record).limited_developers.size
551
+ assert_equal 1, projects(:active_record).limited_developers.find(:all).size
552
+ assert_equal 3, projects(:active_record).limited_developers.find(:all, :limit => nil).size
553
+ end
554
+
555
+ def test_dynamic_find_should_respect_association_order
556
+ # Developers are ordered 'name DESC, id DESC'
557
+ high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
558
+
559
+ assert_equal high_id_jamis, projects(:active_record).developers.find(:first, :conditions => "name = 'Jamis'")
560
+ assert_equal high_id_jamis, projects(:active_record).developers.find_by_name('Jamis')
561
+ end
562
+
563
+ def test_dynamic_find_all_should_respect_association_order
564
+ # Developers are ordered 'name DESC, id DESC'
565
+ low_id_jamis = developers(:jamis)
566
+ middle_id_jamis = developers(:poor_jamis)
567
+ high_id_jamis = projects(:active_record).developers.create(:name => 'Jamis')
568
+
569
+ assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find(:all, :conditions => "name = 'Jamis'")
570
+ assert_equal [high_id_jamis, middle_id_jamis, low_id_jamis], projects(:active_record).developers.find_all_by_name('Jamis')
571
+ end
572
+
573
+ def test_find_should_append_to_association_order
574
+ ordered_developers = projects(:active_record).developers.order('projects.id')
575
+ assert_equal ['developers.name desc, developers.id desc', 'projects.id'], ordered_developers.order_values
576
+ end
577
+
578
+ def test_dynamic_find_all_should_respect_association_limit
579
+ assert_equal 1, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'").length
580
+ assert_equal 1, projects(:active_record).limited_developers.find_all_by_name('Jamis').length
581
+ end
582
+
583
+ def test_dynamic_find_all_order_should_override_association_limit
584
+ assert_equal 2, projects(:active_record).limited_developers.find(:all, :conditions => "name = 'Jamis'", :limit => 9_000).length
585
+ assert_equal 2, projects(:active_record).limited_developers.find_all_by_name('Jamis', :limit => 9_000).length
586
+ end
587
+
588
+ def test_dynamic_find_all_should_respect_readonly_access
589
+ projects(:active_record).readonly_developers.each { |d| assert_raise(ActiveRecord::ReadOnlyRecord) { d.save! } if d.valid?}
590
+ projects(:active_record).readonly_developers.each { |d| d.readonly? }
591
+ end
592
+
593
+ def test_new_with_values_in_collection
594
+ jamis = DeveloperForProjectWithAfterCreateHook.find_by_name('Jamis')
595
+ david = DeveloperForProjectWithAfterCreateHook.find_by_name('David')
596
+ project = ProjectWithAfterCreateHook.new(:name => "Cooking with Bertie")
597
+ project.developers << jamis
598
+ project.save!
599
+ project.reload
600
+
601
+ assert project.developers.include?(jamis)
602
+ assert project.developers.include?(david)
603
+ end
604
+
605
+ def test_find_in_association_with_options
606
+ developers = projects(:active_record).developers.all
607
+ assert_equal 3, developers.size
608
+
609
+ assert_equal developers(:poor_jamis), projects(:active_record).developers.where("salary < 10000").first
610
+ end
611
+
612
+ def test_replace_with_less
613
+ david = developers(:david)
614
+ david.projects = [projects(:action_controller)]
615
+ assert david.save
616
+ assert_equal 1, david.projects.length
617
+ end
618
+
619
+ def test_replace_with_new
620
+ david = developers(:david)
621
+ david.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
622
+ david.save
623
+ assert_equal 2, david.projects.length
624
+ assert !david.projects.include?(projects(:active_record))
625
+ end
626
+
627
+ def test_replace_on_new_object
628
+ new_developer = Developer.new("name" => "Matz")
629
+ new_developer.projects = [projects(:action_controller), Project.new("name" => "ActionWebSearch")]
630
+ new_developer.save
631
+ assert_equal 2, new_developer.projects.length
632
+ end
633
+
634
+ def test_consider_type
635
+ developer = Developer.find(:first)
636
+ special_project = SpecialProject.create("name" => "Special Project")
637
+
638
+ other_project = developer.projects.first
639
+ developer.special_projects << special_project
640
+ developer.reload
641
+
642
+ assert developer.projects.include?(special_project)
643
+ assert developer.special_projects.include?(special_project)
644
+ assert !developer.special_projects.include?(other_project)
645
+ end
646
+
647
+ def test_update_attributes_after_push_without_duplicate_join_table_rows
648
+ developer = Developer.new("name" => "Kano")
649
+ project = SpecialProject.create("name" => "Special Project")
650
+ assert developer.save
651
+ developer.projects << project
652
+ developer.update_column("name", "Bruza")
653
+ assert_equal 1, Developer.connection.select_value(<<-end_sql).to_i
654
+ SELECT count(*) FROM developers_projects
655
+ WHERE project_id = #{project.id}
656
+ AND developer_id = #{developer.id}
657
+ end_sql
658
+ end
659
+
660
+ def test_updating_attributes_on_non_rich_associations
661
+ welcome = categories(:technology).posts.first
662
+ welcome.title = "Something else"
663
+ assert welcome.save!
664
+ end
665
+
666
+ def test_habtm_respects_select
667
+ categories(:technology).select_testing_posts(true).each do |o|
668
+ assert_respond_to o, :correctness_marker
669
+ end
670
+ assert_respond_to categories(:technology).select_testing_posts.find(:first), :correctness_marker
671
+ end
672
+
673
+ def test_habtm_selects_all_columns_by_default
674
+ assert_equal Project.column_names.sort, developers(:david).projects.first.attributes.keys.sort
675
+ end
676
+
677
+ def test_habtm_respects_select_query_method
678
+ assert_equal ['id'], developers(:david).projects.select(:id).first.attributes.keys
679
+ end
680
+
681
+ def test_join_table_alias
682
+ assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size
683
+ end
684
+
685
+ def test_join_with_group
686
+ group = Developer.columns.inject([]) do |g, c|
687
+ g << "developers.#{c.name}"
688
+ g << "developers_projects_2.#{c.name}"
689
+ end
690
+ Project.columns.each { |c| group << "projects.#{c.name}" }
691
+
692
+ assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL', :group => group.join(",")).size
693
+ end
694
+
695
+ def test_find_grouped
696
+ all_posts_from_category1 = Post.find(:all, :conditions => "category_id = 1", :joins => :categories)
697
+ grouped_posts_of_category1 = Post.find(:all, :conditions => "category_id = 1", :group => "author_id", :select => 'count(posts.id) as posts_count', :joins => :categories)
698
+ assert_equal 5, all_posts_from_category1.size
699
+ assert_equal 2, grouped_posts_of_category1.size
700
+ end
701
+
702
+ def test_find_scoped_grouped
703
+ assert_equal 5, categories(:general).posts_grouped_by_title.size
704
+ assert_equal 1, categories(:technology).posts_grouped_by_title.size
705
+ end
706
+
707
+ def test_find_scoped_grouped_having
708
+ assert_equal 2, projects(:active_record).well_payed_salary_groups.size
709
+ assert projects(:active_record).well_payed_salary_groups.all? { |g| g.salary > 10000 }
710
+ end
711
+
712
+ def test_get_ids
713
+ assert_equal projects(:active_record, :action_controller).map(&:id).sort, developers(:david).project_ids.sort
714
+ assert_equal [projects(:active_record).id], developers(:jamis).project_ids
715
+ end
716
+
717
+ def test_get_ids_for_loaded_associations
718
+ developer = developers(:david)
719
+ developer.projects(true)
720
+ assert_queries(0) do
721
+ developer.project_ids
722
+ developer.project_ids
723
+ end
724
+ end
725
+
726
+ def test_get_ids_for_unloaded_associations_does_not_load_them
727
+ developer = developers(:david)
728
+ assert !developer.projects.loaded?
729
+ assert_equal projects(:active_record, :action_controller).map(&:id).sort, developer.project_ids.sort
730
+ assert !developer.projects.loaded?
731
+ end
732
+
733
+ def test_assign_ids
734
+ developer = Developer.new("name" => "Joe")
735
+ developer.project_ids = projects(:active_record, :action_controller).map(&:id)
736
+ developer.save
737
+ developer.reload
738
+ assert_equal 2, developer.projects.length
739
+ assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
740
+ end
741
+
742
+ def test_assign_ids_ignoring_blanks
743
+ developer = Developer.new("name" => "Joe")
744
+ developer.project_ids = [projects(:active_record).id, nil, projects(:action_controller).id, '']
745
+ developer.save
746
+ developer.reload
747
+ assert_equal 2, developer.projects.length
748
+ assert_equal [projects(:active_record), projects(:action_controller)].map(&:id).sort, developer.project_ids.sort
749
+ end
750
+
751
+ def test_scoped_find_on_through_association_doesnt_return_read_only_records
752
+ tag = Post.find(1).tags.find_by_name("General")
753
+
754
+ assert_nothing_raised do
755
+ tag.save!
756
+ end
757
+ end
758
+
759
+ def test_has_many_through_polymorphic_has_manys_works
760
+ assert_equal [10, 20].to_set, pirates(:redbeard).treasure_estimates.map(&:price).to_set
761
+ end
762
+
763
+ def test_symbols_as_keys
764
+ developer = DeveloperWithSymbolsForKeys.new(:name => 'David')
765
+ project = ProjectWithSymbolsForKeys.new(:name => 'Rails Testing')
766
+ project.developers << developer
767
+ project.save!
768
+
769
+ assert_equal 1, project.developers.size
770
+ assert_equal 1, developer.projects.size
771
+ assert_equal developer, project.developers.find(:first)
772
+ assert_equal project, developer.projects.find(:first)
773
+ end
774
+
775
+ def test_self_referential_habtm_without_foreign_key_set_should_raise_exception
776
+ assert_raise(ActiveRecord::HasAndBelongsToManyAssociationForeignKeyNeeded) {
777
+ Member.class_eval do
778
+ has_and_belongs_to_many :friends, :class_name => "Member", :join_table => "member_friends"
779
+ end
780
+ }
781
+ end
782
+
783
+ def test_dynamic_find_should_respect_association_include
784
+ # SQL error in sort clause if :include is not included
785
+ # due to Unknown column 'authors.id'
786
+ assert Category.find(1).posts_with_authors_sorted_by_author_id.find_by_title('Welcome to the weblog')
787
+ end
788
+
789
+ def test_counting_on_habtm_association_and_not_array
790
+ david = Developer.find(1)
791
+ # Extra parameter just to make sure we aren't falling back to
792
+ # Array#count in Ruby >=1.8.7, which would raise an ArgumentError
793
+ assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') }
794
+ end
795
+
796
+ def test_count
797
+ david = Developer.find(1)
798
+ assert_equal 2, david.projects.count
799
+ end
800
+
801
+ def test_count_with_counter_sql
802
+ developer = DeveloperWithCounterSQL.create(:name => 'tekin')
803
+ developer.project_ids = [projects(:active_record).id]
804
+ developer.save
805
+ developer.reload
806
+ assert_equal 1, developer.projects.count
807
+ end
808
+
809
+ unless current_adapter?(:PostgreSQLAdapter, :IBM_DBAdapter)
810
+ def test_count_with_finder_sql
811
+ assert_equal 3, projects(:active_record).developers_with_finder_sql.count
812
+ assert_equal 3, projects(:active_record).developers_with_multiline_finder_sql.count
813
+ end
814
+ end
815
+
816
+ def test_association_proxy_transaction_method_starts_transaction_in_association_class
817
+ Post.expects(:transaction)
818
+ Category.find(:first).posts.transaction do
819
+ # nothing
820
+ end
821
+ end
822
+
823
+ def test_caching_of_columns
824
+ david = Developer.find(1)
825
+ # clear cache possibly created by other tests
826
+ david.projects.reset_column_information
827
+
828
+ assert_queries(1) { david.projects.columns; david.projects.columns }
829
+
830
+ ## and again to verify that reset_column_information clears the cache correctly
831
+ david.projects.reset_column_information
832
+ assert_queries(1) { david.projects.columns; david.projects.columns }
833
+ end
834
+
835
+ def test_attributes_are_being_set_when_initialized_from_habm_association_with_where_clause
836
+ new_developer = projects(:action_controller).developers.where(:name => "Marcelo").build
837
+ assert_equal new_developer.name, "Marcelo"
838
+ end
839
+
840
+ def test_attributes_are_being_set_when_initialized_from_habm_association_with_multiple_where_clauses
841
+ new_developer = projects(:action_controller).developers.where(:name => "Marcelo").where(:salary => 90_000).build
842
+ assert_equal new_developer.name, "Marcelo"
843
+ assert_equal new_developer.salary, 90_000
844
+ end
845
+
846
+ def test_include_method_in_has_and_belongs_to_many_association_should_return_true_for_instance_added_with_build
847
+ project = Project.new
848
+ developer = project.developers.build
849
+ assert project.developers.include?(developer)
850
+ end
851
+ end