activerecord 1.15.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +2454 -34
- data/README +1 -1
- data/RUNNING_UNIT_TESTS +3 -34
- data/Rakefile +98 -77
- data/install.rb +1 -1
- data/lib/active_record.rb +13 -22
- data/lib/active_record/aggregations.rb +38 -49
- data/lib/active_record/associations.rb +452 -333
- data/lib/active_record/associations/association_collection.rb +66 -20
- data/lib/active_record/associations/association_proxy.rb +9 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -51
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +38 -18
- data/lib/active_record/associations/has_one_association.rb +30 -14
- data/lib/active_record/attribute_methods.rb +253 -0
- data/lib/active_record/base.rb +719 -494
- data/lib/active_record/calculations.rb +62 -63
- data/lib/active_record/callbacks.rb +57 -83
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +38 -9
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +191 -62
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -17
- data/lib/active_record/connection_adapters/mysql_adapter.rb +119 -37
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +473 -210
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +91 -107
- data/lib/active_record/fixtures.rb +503 -113
- data/lib/active_record/locking/optimistic.rb +72 -34
- data/lib/active_record/migration.rb +80 -57
- data/lib/active_record/observer.rb +13 -10
- data/lib/active_record/query_cache.rb +16 -57
- data/lib/active_record/reflection.rb +35 -38
- data/lib/active_record/schema.rb +5 -5
- data/lib/active_record/schema_dumper.rb +35 -13
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/{xml_serialization.rb → serializers/xml_serializer.rb} +90 -83
- data/lib/active_record/timestamp.rb +20 -21
- data/lib/active_record/transactions.rb +39 -43
- data/lib/active_record/validations.rb +256 -107
- data/lib/active_record/version.rb +3 -3
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +15 -2
- data/test/abstract_unit.rb +24 -17
- data/test/active_schema_test_mysql.rb +20 -8
- data/test/adapter_test.rb +23 -5
- data/test/adapter_test_sqlserver.rb +15 -1
- data/test/aggregations_test.rb +16 -1
- data/test/all.sh +2 -2
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +51 -30
- data/test/associations/cascaded_eager_loading_test.rb +1 -29
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +42 -6
- data/test/associations/extension_test.rb +6 -1
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +47 -16
- data/test/associations_test.rb +449 -226
- data/test/attribute_methods_test.rb +97 -0
- data/test/base_test.rb +251 -105
- data/test/binary_test.rb +22 -27
- data/test/calculations_test.rb +37 -5
- data/test/callbacks_test.rb +23 -0
- data/test/connection_test_firebird.rb +2 -2
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_mysql/connection.rb +3 -0
- data/test/connections/native_sqlite/connection.rb +5 -14
- data/test/connections/native_sqlite3/connection.rb +5 -14
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
- data/test/{copy_table_sqlite.rb → copy_table_test_sqlite.rb} +8 -3
- data/test/datatype_test_postgresql.rb +178 -27
- data/test/{empty_date_time_test.rb → date_time_test.rb} +13 -1
- data/test/defaults_test.rb +8 -1
- data/test/deprecated_finder_test.rb +7 -128
- data/test/finder_test.rb +192 -54
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +12 -5
- data/test/fixtures/binaries.yml +130 -435
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +8 -1
- data/test/fixtures/computer.rb +1 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/customer.rb +2 -2
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +4 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +3 -1
- data/test/fixtures/db_definitions/firebird.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase.sql +5 -0
- data/test/fixtures/db_definitions/openbase.sql +41 -25
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +5 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +7 -0
- data/test/fixtures/db_definitions/postgresql.sql +87 -58
- data/test/fixtures/db_definitions/postgresql2.sql +1 -2
- data/test/fixtures/db_definitions/schema.rb +280 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +4 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +1 -0
- data/test/fixtures/db_definitions/sybase.sql +4 -0
- data/test/fixtures/developer.rb +10 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +0 -3
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixins.yml +2 -100
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +1 -0
- data/test/fixtures/project.rb +3 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/tagging.rb +4 -0
- data/test/fixtures/taggings.yml +8 -1
- data/test/fixtures/topic.rb +13 -1
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures_test.rb +205 -24
- data/test/inheritance_test.rb +7 -1
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +1 -1
- data/test/locking_test.rb +85 -2
- data/test/migration_test.rb +206 -40
- data/test/mixin_test.rb +13 -515
- data/test/pk_test.rb +3 -6
- data/test/query_cache_test.rb +104 -0
- data/test/reflection_test.rb +16 -0
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_dumper_test.rb +38 -3
- data/test/serialization_test.rb +47 -0
- data/test/transactions_test.rb +74 -23
- data/test/unconnected_test.rb +1 -1
- data/test/validations_test.rb +322 -32
- data/test/xml_serialization_test.rb +121 -44
- metadata +48 -41
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -85
- data/lib/active_record/acts/list.rb +0 -256
- data/lib/active_record/acts/nested_set.rb +0 -211
- data/lib/active_record/acts/tree.rb +0 -96
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -228
- data/lib/active_record/connection_adapters/firebird_adapter.rb +0 -728
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +0 -861
- data/lib/active_record/connection_adapters/openbase_adapter.rb +0 -350
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -690
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +0 -591
- data/lib/active_record/connection_adapters/sybase_adapter.rb +0 -662
- data/lib/active_record/deprecated_associations.rb +0 -104
- data/lib/active_record/deprecated_finders.rb +0 -44
- data/lib/active_record/vendor/simple.rb +0 -693
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -58
- data/test/connections/native_sqlserver/connection.rb +0 -23
- data/test/connections/native_sqlserver_odbc/connection.rb +0 -25
- data/test/deprecated_associations_test.rb +0 -396
- data/test/fixtures/db_definitions/mysql.drop.sql +0 -32
- data/test/fixtures/db_definitions/mysql.sql +0 -234
- data/test/fixtures/db_definitions/mysql2.drop.sql +0 -2
- data/test/fixtures/db_definitions/mysql2.sql +0 -5
- data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -34
- data/test/fixtures/db_definitions/sqlserver.sql +0 -243
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +0 -2
- data/test/fixtures/db_definitions/sqlserver2.sql +0 -5
- data/test/fixtures/mixin.rb +0 -63
- data/test/mixin_nested_set_test.rb +0 -196
@@ -1,11 +1,9 @@
|
|
1
1
|
require 'abstract_unit'
|
2
|
-
require 'active_record/acts/list'
|
3
2
|
require 'fixtures/post'
|
4
3
|
require 'fixtures/comment'
|
5
4
|
require 'fixtures/author'
|
6
5
|
require 'fixtures/category'
|
7
6
|
require 'fixtures/categorization'
|
8
|
-
require 'fixtures/mixin'
|
9
7
|
require 'fixtures/company'
|
10
8
|
require 'fixtures/topic'
|
11
9
|
require 'fixtures/reply'
|
@@ -53,16 +51,6 @@ class CascadedEagerLoadingTest < Test::Unit::TestCase
|
|
53
51
|
assert_equal 5, authors[0].posts.size
|
54
52
|
end
|
55
53
|
|
56
|
-
def test_eager_association_loading_with_acts_as_tree
|
57
|
-
roots = TreeMixin.find(:all, :include=>"children", :conditions=>"mixins.parent_id IS NULL", :order=>"mixins.id")
|
58
|
-
assert_equal [mixins(:tree_1), mixins(:tree2_1), mixins(:tree3_1)], roots
|
59
|
-
assert_no_queries do
|
60
|
-
assert_equal 2, roots[0].children.size
|
61
|
-
assert_equal 0, roots[1].children.size
|
62
|
-
assert_equal 0, roots[2].children.size
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
54
|
def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong
|
67
55
|
firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id")
|
68
56
|
assert_equal 2, firms.size
|
@@ -73,7 +61,7 @@ class CascadedEagerLoadingTest < Test::Unit::TestCase
|
|
73
61
|
|
74
62
|
def test_eager_association_loading_with_has_many_sti
|
75
63
|
topics = Topic.find(:all, :include => :replies, :order => 'topics.id')
|
76
|
-
assert_equal
|
64
|
+
assert_equal topics(:first, :second), topics
|
77
65
|
assert_no_queries do
|
78
66
|
assert_equal 1, topics[0].replies.size
|
79
67
|
assert_equal 0, topics[1].replies.size
|
@@ -103,24 +91,8 @@ class CascadedEagerLoadingTest < Test::Unit::TestCase
|
|
103
91
|
authors.first.posts.first.special_comments.first.post.very_special_comment
|
104
92
|
end
|
105
93
|
end
|
106
|
-
|
107
|
-
def test_eager_association_loading_with_recursive_cascading_three_levels_has_many
|
108
|
-
root_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:children=>{:children=>:children}}, :order => 'mixins.id')
|
109
|
-
assert_equal mixins(:recursively_cascaded_tree_4), assert_no_queries { root_node.children.first.children.first.children.first }
|
110
|
-
end
|
111
|
-
|
112
|
-
def test_eager_association_loading_with_recursive_cascading_three_levels_has_one
|
113
|
-
root_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:first_child=>{:first_child=>:first_child}}, :order => 'mixins.id')
|
114
|
-
assert_equal mixins(:recursively_cascaded_tree_4), assert_no_queries { root_node.first_child.first_child.first_child }
|
115
|
-
end
|
116
|
-
|
117
|
-
def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to
|
118
|
-
leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include=>{:parent=>{:parent=>:parent}}, :order => 'mixins.id DESC')
|
119
|
-
assert_equal mixins(:recursively_cascaded_tree_1), assert_no_queries { leaf_node.parent.parent.parent }
|
120
|
-
end
|
121
94
|
end
|
122
95
|
|
123
|
-
|
124
96
|
require 'fixtures/vertex'
|
125
97
|
require 'fixtures/edge'
|
126
98
|
class CascadedEagerLoadingTest < Test::Unit::TestCase
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class Virus < ActiveRecord::Base
|
4
|
+
belongs_to :octopus
|
5
|
+
end
|
6
|
+
class Octopus < ActiveRecord::Base
|
7
|
+
has_one :virus
|
8
|
+
end
|
9
|
+
class Pass < ActiveRecord::Base
|
10
|
+
belongs_to :bus
|
11
|
+
end
|
12
|
+
class Bus < ActiveRecord::Base
|
13
|
+
has_many :passes
|
14
|
+
end
|
15
|
+
class Mess < ActiveRecord::Base
|
16
|
+
has_and_belongs_to_many :crises
|
17
|
+
end
|
18
|
+
class Crisis < ActiveRecord::Base
|
19
|
+
has_and_belongs_to_many :messes
|
20
|
+
has_many :analyses, :dependent => :destroy
|
21
|
+
has_many :successes, :through => :analyses
|
22
|
+
has_many :dresses, :dependent => :destroy
|
23
|
+
has_many :compresses, :through => :dresses
|
24
|
+
end
|
25
|
+
class Analysis < ActiveRecord::Base
|
26
|
+
belongs_to :crisis
|
27
|
+
belongs_to :success
|
28
|
+
end
|
29
|
+
class Success < ActiveRecord::Base
|
30
|
+
has_many :analyses, :dependent => :destroy
|
31
|
+
has_many :crises, :through => :analyses
|
32
|
+
end
|
33
|
+
class Dress < ActiveRecord::Base
|
34
|
+
belongs_to :crisis
|
35
|
+
has_many :compresses
|
36
|
+
end
|
37
|
+
class Compress < ActiveRecord::Base
|
38
|
+
belongs_to :dress
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
class EagerSingularizationTest < Test::Unit::TestCase
|
43
|
+
|
44
|
+
def setup
|
45
|
+
if ActiveRecord::Base.connection.supports_migrations?
|
46
|
+
ActiveRecord::Base.connection.create_table :viri do |t|
|
47
|
+
t.column :octopus_id, :integer
|
48
|
+
t.column :species, :string
|
49
|
+
end
|
50
|
+
ActiveRecord::Base.connection.create_table :octopi do |t|
|
51
|
+
t.column :species, :string
|
52
|
+
end
|
53
|
+
ActiveRecord::Base.connection.create_table :passes do |t|
|
54
|
+
t.column :bus_id, :integer
|
55
|
+
t.column :rides, :integer
|
56
|
+
end
|
57
|
+
ActiveRecord::Base.connection.create_table :buses do |t|
|
58
|
+
t.column :name, :string
|
59
|
+
end
|
60
|
+
ActiveRecord::Base.connection.create_table :crises_messes, :id => false do |t|
|
61
|
+
t.column :crisis_id, :integer
|
62
|
+
t.column :mess_id, :integer
|
63
|
+
end
|
64
|
+
ActiveRecord::Base.connection.create_table :messes do |t|
|
65
|
+
t.column :name, :string
|
66
|
+
end
|
67
|
+
ActiveRecord::Base.connection.create_table :crises do |t|
|
68
|
+
t.column :name, :string
|
69
|
+
end
|
70
|
+
ActiveRecord::Base.connection.create_table :successes do |t|
|
71
|
+
t.column :name, :string
|
72
|
+
end
|
73
|
+
ActiveRecord::Base.connection.create_table :analyses do |t|
|
74
|
+
t.column :crisis_id, :integer
|
75
|
+
t.column :success_id, :integer
|
76
|
+
end
|
77
|
+
ActiveRecord::Base.connection.create_table :dresses do |t|
|
78
|
+
t.column :crisis_id, :integer
|
79
|
+
end
|
80
|
+
ActiveRecord::Base.connection.create_table :compresses do |t|
|
81
|
+
t.column :dress_id, :integer
|
82
|
+
end
|
83
|
+
@have_tables = true
|
84
|
+
else
|
85
|
+
@have_tables = false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def teardown
|
90
|
+
ActiveRecord::Base.connection.drop_table :viri
|
91
|
+
ActiveRecord::Base.connection.drop_table :octopi
|
92
|
+
ActiveRecord::Base.connection.drop_table :passes
|
93
|
+
ActiveRecord::Base.connection.drop_table :buses
|
94
|
+
ActiveRecord::Base.connection.drop_table :crises_messes
|
95
|
+
ActiveRecord::Base.connection.drop_table :messes
|
96
|
+
ActiveRecord::Base.connection.drop_table :crises
|
97
|
+
ActiveRecord::Base.connection.drop_table :successes
|
98
|
+
ActiveRecord::Base.connection.drop_table :analyses
|
99
|
+
ActiveRecord::Base.connection.drop_table :dresses
|
100
|
+
ActiveRecord::Base.connection.drop_table :compresses
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_eager_no_extra_singularization_belongs_to
|
104
|
+
return unless @have_tables
|
105
|
+
assert_nothing_raised do
|
106
|
+
Virus.find(:all, :include => :octopus)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_eager_no_extra_singularization_has_one
|
111
|
+
return unless @have_tables
|
112
|
+
assert_nothing_raised do
|
113
|
+
Octopus.find(:all, :include => :virus)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_eager_no_extra_singularization_has_many
|
118
|
+
return unless @have_tables
|
119
|
+
assert_nothing_raised do
|
120
|
+
Bus.find(:all, :include => :passes)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_eager_no_extra_singularization_has_and_belongs_to_many
|
125
|
+
return unless @have_tables
|
126
|
+
assert_nothing_raised do
|
127
|
+
Crisis.find(:all, :include => :messes)
|
128
|
+
Mess.find(:all, :include => :crises)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_eager_no_extra_singularization_has_many_through_belongs_to
|
133
|
+
return unless @have_tables
|
134
|
+
assert_nothing_raised do
|
135
|
+
Crisis.find(:all, :include => :successes)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_eager_no_extra_singularization_has_many_through_has_many
|
140
|
+
return unless @have_tables
|
141
|
+
assert_nothing_raised do
|
142
|
+
Crisis.find(:all, :include => :compresses)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -37,6 +37,18 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
def test_with_two_tables_in_from_without_getting_double_quoted
|
41
|
+
posts = Post.find(:all,
|
42
|
+
:select => "posts.*",
|
43
|
+
:from => "authors, posts",
|
44
|
+
:include => :comments,
|
45
|
+
:conditions => "posts.author_id = authors.id",
|
46
|
+
:order => "posts.id"
|
47
|
+
)
|
48
|
+
|
49
|
+
assert_equal 2, posts.first.comments.size
|
50
|
+
end
|
51
|
+
|
40
52
|
def test_loading_with_multiple_associations
|
41
53
|
posts = Post.find(:all, :include => [ :comments, :author, :categories ], :order => "posts.id")
|
42
54
|
assert_equal 2, posts.first.comments.size
|
@@ -103,6 +115,11 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
103
115
|
assert_equal [2], posts.collect { |p| p.id }
|
104
116
|
end
|
105
117
|
|
118
|
+
def test_eager_association_loading_with_explicit_join
|
119
|
+
posts = Post.find(:all, :include => :comments, :joins => "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", :limit => 1, :order => 'author_id')
|
120
|
+
assert_equal 1, posts.length
|
121
|
+
end
|
122
|
+
|
106
123
|
def test_eager_with_has_many_through
|
107
124
|
posts_with_comments = people(:michael).posts.find(:all, :include => :comments)
|
108
125
|
posts_with_author = people(:michael).posts.find(:all, :include => :author )
|
@@ -135,13 +152,21 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
135
152
|
end
|
136
153
|
|
137
154
|
def test_eager_with_has_many_and_limit_and_conditions
|
138
|
-
|
155
|
+
if current_adapter?(:OpenBaseAdapter)
|
156
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "FETCHBLOB(posts.body) = 'hello'", :order => "posts.id")
|
157
|
+
else
|
158
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.body = 'hello'", :order => "posts.id")
|
159
|
+
end
|
139
160
|
assert_equal 2, posts.size
|
140
161
|
assert_equal [4,5], posts.collect { |p| p.id }
|
141
162
|
end
|
142
163
|
|
143
164
|
def test_eager_with_has_many_and_limit_and_conditions_array
|
144
|
-
|
165
|
+
if current_adapter?(:OpenBaseAdapter)
|
166
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "FETCHBLOB(posts.body) = ?", 'hello' ], :order => "posts.id")
|
167
|
+
else
|
168
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "posts.body = ?", 'hello' ], :order => "posts.id")
|
169
|
+
end
|
145
170
|
assert_equal 2, posts.size
|
146
171
|
assert_equal [4,5], posts.collect { |p| p.id }
|
147
172
|
end
|
@@ -237,6 +262,15 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
237
262
|
assert_equal count, posts.size
|
238
263
|
end
|
239
264
|
end
|
265
|
+
|
266
|
+
def test_eager_with_scoped_order_using_association_limiting_without_explicit_scope
|
267
|
+
posts_with_explicit_order = Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :order => 'posts.id DESC', :limit => 2)
|
268
|
+
posts_with_scoped_order = Post.with_scope(:find => {:order => 'posts.id DESC'}) do
|
269
|
+
Post.find(:all, :conditions => 'comments.id is not null', :include => :comments, :limit => 2)
|
270
|
+
end
|
271
|
+
assert_equal posts_with_explicit_order, posts_with_scoped_order
|
272
|
+
end
|
273
|
+
|
240
274
|
def test_eager_association_loading_with_habtm
|
241
275
|
posts = Post.find(:all, :include => :categories, :order => "posts.id")
|
242
276
|
assert_equal 2, posts[0].categories.size
|
@@ -305,13 +339,13 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
305
339
|
end
|
306
340
|
|
307
341
|
def test_limited_eager_with_order
|
308
|
-
assert_equal
|
309
|
-
assert_equal
|
342
|
+
assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title)', :limit => 2, :offset => 1)
|
343
|
+
assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC', :limit => 2, :offset => 1)
|
310
344
|
end
|
311
345
|
|
312
346
|
def test_limited_eager_with_multiple_order_columns
|
313
|
-
assert_equal
|
314
|
-
assert_equal
|
347
|
+
assert_equal posts(:thinking, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title), posts.id', :limit => 2, :offset => 1)
|
348
|
+
assert_equal posts(:sti_post_and_comments, :sti_comments), Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC, posts.id', :limit => 2, :offset => 1)
|
315
349
|
end
|
316
350
|
|
317
351
|
def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm
|
@@ -399,6 +433,8 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
399
433
|
def test_count_with_include
|
400
434
|
if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
401
435
|
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15")
|
436
|
+
elsif current_adapter?(:OpenBaseAdapter)
|
437
|
+
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(FETCHBLOB(comments.body)) > 15")
|
402
438
|
else
|
403
439
|
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(comments.body) > 15")
|
404
440
|
end
|
@@ -23,7 +23,12 @@ class AssociationsExtensionsTest < Test::Unit::TestCase
|
|
23
23
|
assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_twice.find_most_recent
|
24
24
|
assert_equal projects(:active_record), developers(:david).projects_extended_by_name_twice.find_least_recent
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
|
+
def test_named_extension_and_block_on_habtm
|
28
|
+
assert_equal projects(:action_controller), developers(:david).projects_extended_by_name_and_block.find_most_recent
|
29
|
+
assert_equal projects(:active_record), developers(:david).projects_extended_by_name_and_block.find_least_recent
|
30
|
+
end
|
31
|
+
|
27
32
|
def test_marshalling_extensions
|
28
33
|
david = developers(:david)
|
29
34
|
assert_equal projects(:action_controller), david.projects.find_most_recent
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/post'
|
3
|
+
require 'fixtures/comment'
|
4
|
+
require 'fixtures/author'
|
5
|
+
require 'fixtures/category'
|
6
|
+
require 'fixtures/categorization'
|
7
|
+
|
8
|
+
class InnerJoinAssociationTest < Test::Unit::TestCase
|
9
|
+
fixtures :authors, :posts, :comments, :categories, :categories_posts, :categorizations
|
10
|
+
|
11
|
+
def test_construct_finder_sql_creates_inner_joins
|
12
|
+
sql = Author.send(:construct_finder_sql, :joins => :posts)
|
13
|
+
assert_match /INNER JOIN `?posts`? ON `?posts`?.author_id = authors.id/, sql
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_construct_finder_sql_cascades_inner_joins
|
17
|
+
sql = Author.send(:construct_finder_sql, :joins => {:posts => :comments})
|
18
|
+
assert_match /INNER JOIN `?posts`? ON `?posts`?.author_id = authors.id/, sql
|
19
|
+
assert_match /INNER JOIN `?comments`? ON `?comments`?.post_id = posts.id/, sql
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_construct_finder_sql_inner_joins_through_associations
|
23
|
+
sql = Author.send(:construct_finder_sql, :joins => :categorized_posts)
|
24
|
+
assert_match /INNER JOIN `?categorizations`?.*INNER JOIN `?posts`?/, sql
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_construct_finder_sql_applies_association_conditions
|
28
|
+
sql = Author.send(:construct_finder_sql, :joins => :categories_like_general, :conditions => "TERMINATING_MARKER")
|
29
|
+
assert_match /INNER JOIN `?categories`? ON.*AND.*`?General`?.*TERMINATING_MARKER/, sql
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_construct_finder_sql_unpacks_nested_joins
|
33
|
+
sql = Author.send(:construct_finder_sql, :joins => {:posts => [[:comments]]})
|
34
|
+
assert_no_match /inner join.*inner join.*inner join/i, sql, "only two join clauses should be present"
|
35
|
+
assert_match /INNER JOIN `?posts`? ON `?posts`?.author_id = authors.id/, sql
|
36
|
+
assert_match /INNER JOIN `?comments`? ON `?comments`?.post_id = `?posts`?.id/, sql
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_construct_finder_sql_ignores_empty_joins_hash
|
40
|
+
sql = Author.send(:construct_finder_sql, :joins => {})
|
41
|
+
assert_no_match /JOIN/i, sql
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_construct_finder_sql_ignores_empty_joins_array
|
45
|
+
sql = Author.send(:construct_finder_sql, :joins => [])
|
46
|
+
assert_no_match /JOIN/i, sql
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_find_with_implicit_inner_joins_honors_readonly_without_select
|
50
|
+
authors = Author.find(:all, :joins => :posts)
|
51
|
+
assert !authors.empty?, "expected authors to be non-empty"
|
52
|
+
assert authors.all? {|a| a.readonly? }, "expected all authors to be readonly"
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_find_with_implicit_inner_joins_honors_readonly_with_select
|
56
|
+
authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
|
57
|
+
assert !authors.empty?, "expected authors to be non-empty"
|
58
|
+
assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_find_with_implicit_inner_joins_honors_readonly_false
|
62
|
+
authors = Author.find(:all, :joins => :posts, :readonly => false)
|
63
|
+
assert !authors.empty?, "expected authors to be non-empty"
|
64
|
+
assert authors.all? {|a| !a.readonly? }, "expected no authors to be readonly"
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_find_with_implicit_inner_joins_does_not_set_associations
|
68
|
+
authors = Author.find(:all, :select => 'authors.*', :joins => :posts)
|
69
|
+
assert !authors.empty?, "expected authors to be non-empty"
|
70
|
+
assert authors.all? {|a| !a.send(:instance_variables).include?("@posts")}, "expected no authors to have the @posts association loaded"
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_count_honors_implicit_inner_joins
|
74
|
+
real_count = Author.find(:all).sum{|a| a.posts.count }
|
75
|
+
assert_equal real_count, Author.count(:joins => :posts), "plain inner join count should match the number of referenced posts records"
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_calculate_honors_implicit_inner_joins
|
79
|
+
real_count = Author.find(:all).sum{|a| a.posts.count }
|
80
|
+
assert_equal real_count, Author.calculate(:count, 'authors.id', :joins => :posts), "plain inner join count should match the number of referenced posts records"
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_calculate_honors_implicit_inner_joins_and_distinct_and_conditions
|
84
|
+
real_count = Author.find(:all).select {|a| a.posts.any? {|p| p.title =~ /^Welcome/} }.length
|
85
|
+
authors_with_welcoming_post_titles = Author.calculate(:count, 'authors.id', :joins => :posts, :distinct => true, :conditions => "posts.title like 'Welcome%'")
|
86
|
+
assert_equal real_count, authors_with_welcoming_post_titles, "inner join and conditions should have only returned authors posting titles starting with 'Welcome'"
|
87
|
+
end
|
88
|
+
end
|
@@ -2,6 +2,7 @@ require 'abstract_unit'
|
|
2
2
|
require 'fixtures/tag'
|
3
3
|
require 'fixtures/tagging'
|
4
4
|
require 'fixtures/post'
|
5
|
+
require 'fixtures/item'
|
5
6
|
require 'fixtures/comment'
|
6
7
|
require 'fixtures/author'
|
7
8
|
require 'fixtures/category'
|
@@ -13,7 +14,7 @@ require 'fixtures/citation'
|
|
13
14
|
|
14
15
|
class AssociationsJoinModelTest < Test::Unit::TestCase
|
15
16
|
self.use_transactional_fixtures = false
|
16
|
-
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :books
|
17
|
+
fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books
|
17
18
|
|
18
19
|
def test_has_many
|
19
20
|
assert authors(:david).categories.include?(categories(:general))
|
@@ -36,8 +37,8 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
36
37
|
author = authors(:mary)
|
37
38
|
assert !authors(:mary).unique_categorized_posts.loaded?
|
38
39
|
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count }
|
39
|
-
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title
|
40
|
-
assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title,
|
40
|
+
assert_queries(1) { assert_equal 1, author.unique_categorized_posts.count(:title) }
|
41
|
+
assert_queries(1) { assert_equal 0, author.unique_categorized_posts.count(:title, :conditions => "title is NULL") }
|
41
42
|
assert !authors(:mary).unique_categorized_posts.loaded?
|
42
43
|
end
|
43
44
|
|
@@ -240,7 +241,15 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
240
241
|
assert_equal tagging, post.tagging
|
241
242
|
end
|
242
243
|
end
|
243
|
-
|
244
|
+
|
245
|
+
def test_include_polymorphic_has_one_defined_in_abstract_parent
|
246
|
+
item = Item.find_by_id(items(:dvd).id, :include => :tagging)
|
247
|
+
tagging = taggings(:godfather)
|
248
|
+
assert_no_queries do
|
249
|
+
assert_equal tagging, item.tagging
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
244
253
|
def test_include_polymorphic_has_many_through
|
245
254
|
posts = Post.find(:all, :order => 'posts.id')
|
246
255
|
posts_with_tags = Post.find(:all, :include => :tags, :order => 'posts.id')
|
@@ -275,10 +284,10 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
275
284
|
assert_equal categories(:general), authors(:david).categories.find(:first, :conditions => "categories.name = 'General'")
|
276
285
|
assert_equal nil, authors(:david).categories.find(:first, :conditions => "categories.name = 'Technology'")
|
277
286
|
end
|
278
|
-
|
287
|
+
|
279
288
|
def test_has_many_class_methods_called_by_method_missing
|
280
289
|
assert_equal categories(:general), authors(:david).categories.find_all_by_name('General').first
|
281
|
-
|
290
|
+
assert_equal nil, authors(:david).categories.find_by_name('Technology')
|
282
291
|
end
|
283
292
|
|
284
293
|
def test_has_many_going_through_join_model_with_custom_foreign_key
|
@@ -305,20 +314,20 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
305
314
|
|
306
315
|
def test_has_many_polymorphic
|
307
316
|
assert_raises ActiveRecord::HasManyThroughAssociationPolymorphicError do
|
308
|
-
assert_equal
|
317
|
+
assert_equal posts(:welcome, :thinking), tags(:general).taggables
|
309
318
|
end
|
310
319
|
assert_raises ActiveRecord::EagerLoadPolymorphicError do
|
311
|
-
assert_equal
|
320
|
+
assert_equal posts(:welcome, :thinking), tags(:general).taggings.find(:all, :include => :taggable)
|
312
321
|
end
|
313
322
|
end
|
314
323
|
|
315
324
|
def test_has_many_polymorphic_with_source_type
|
316
|
-
assert_equal
|
325
|
+
assert_equal posts(:welcome, :thinking), tags(:general).tagged_posts
|
317
326
|
end
|
318
327
|
|
319
328
|
def test_eager_has_many_polymorphic_with_source_type
|
320
329
|
tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
|
321
|
-
desired =
|
330
|
+
desired = posts(:welcome, :thinking)
|
322
331
|
assert_no_queries do
|
323
332
|
assert_equal desired, tag_with_include.tagged_posts
|
324
333
|
end
|
@@ -350,12 +359,12 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
350
359
|
end
|
351
360
|
|
352
361
|
def test_has_many_through_polymorphic_has_many
|
353
|
-
assert_equal
|
362
|
+
assert_equal taggings(:welcome_general, :thinking_general), authors(:david).taggings.uniq.sort_by { |t| t.id }
|
354
363
|
end
|
355
364
|
|
356
365
|
def test_include_has_many_through_polymorphic_has_many
|
357
366
|
author = Author.find_by_id(authors(:david).id, :include => :taggings)
|
358
|
-
expected_taggings =
|
367
|
+
expected_taggings = taggings(:welcome_general, :thinking_general)
|
359
368
|
assert_no_queries do
|
360
369
|
assert_equal expected_taggings, author.taggings.uniq.sort_by { |t| t.id }
|
361
370
|
end
|
@@ -401,6 +410,12 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
401
410
|
authors(:david).author_favorites.create :favorite_author => new_author
|
402
411
|
assert_equal new_author, authors(:david).reload.favorite_authors.first
|
403
412
|
end
|
413
|
+
|
414
|
+
def test_has_many_through_uses_conditions_specified_on_the_has_many_association
|
415
|
+
author = Author.find(:first)
|
416
|
+
assert !author.comments.blank?
|
417
|
+
assert author.nonexistant_comments.blank?
|
418
|
+
end
|
404
419
|
|
405
420
|
def test_has_many_through_uses_correct_attributes
|
406
421
|
assert_nil posts(:thinking).tags.find_by_name("General").attributes["tag_id"]
|
@@ -410,6 +425,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
410
425
|
assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags << tags(:general).clone }
|
411
426
|
assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).clone.tags << tags(:general) }
|
412
427
|
assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags.build }
|
428
|
+
assert_raise(ActiveRecord::HasManyThroughCantAssociateNewRecords) { posts(:thinking).tags.new }
|
413
429
|
end
|
414
430
|
|
415
431
|
def test_create_associate_when_adding_to_has_many_through
|
@@ -424,7 +440,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
424
440
|
assert_equal(count + 1, post_thinking.tags.size)
|
425
441
|
assert_equal(count + 1, post_thinking.tags(true).size)
|
426
442
|
|
427
|
-
|
443
|
+
assert_kind_of Tag, post_thinking.tags.create!(:name => 'foo')
|
428
444
|
assert_nil( wrong = post_thinking.tags.detect { |t| t.class != Tag },
|
429
445
|
message = "Expected a Tag in tags collection, got #{wrong.class}.")
|
430
446
|
assert_nil( wrong = post_thinking.taggings.detect { |t| t.class != Tagging },
|
@@ -444,6 +460,21 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
444
460
|
assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
|
445
461
|
end
|
446
462
|
|
463
|
+
def test_has_many_through_collection_size_doesnt_load_target_if_not_loaded
|
464
|
+
author = authors(:david)
|
465
|
+
assert_equal 9, author.comments.size
|
466
|
+
assert !author.comments.loaded?
|
467
|
+
end
|
468
|
+
|
469
|
+
uses_mocha('has_many_through_collection_size_uses_counter_cache_if_it_exists') do
|
470
|
+
def test_has_many_through_collection_size_uses_counter_cache_if_it_exists
|
471
|
+
author = authors(:david)
|
472
|
+
author.stubs(:read_attribute).with('comments_count').returns(100)
|
473
|
+
assert_equal 100, author.comments.size
|
474
|
+
assert !author.comments.loaded?
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
447
478
|
def test_adding_junk_to_has_many_through_should_raise_type_mismatch
|
448
479
|
assert_raise(ActiveRecord::AssociationTypeMismatch) { posts(:thinking).tags << "Uhh what now?" }
|
449
480
|
end
|
@@ -452,8 +483,8 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
452
483
|
tags = posts(:thinking).tags
|
453
484
|
assert_equal tags, posts(:thinking).tags.push(tags(:general))
|
454
485
|
end
|
455
|
-
|
456
|
-
def
|
486
|
+
|
487
|
+
def test_delete_associate_when_deleting_from_has_many_through_with_nonstandard_id
|
457
488
|
count = books(:awdr).references.count
|
458
489
|
references_before = books(:awdr).references
|
459
490
|
book = Book.create!(:name => 'Getting Real')
|
@@ -466,7 +497,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
466
497
|
assert_equal(count, book_awdr.references(true).size)
|
467
498
|
assert_equal(references_before.sort, book_awdr.references.sort)
|
468
499
|
end
|
469
|
-
|
500
|
+
|
470
501
|
def test_delete_associate_when_deleting_from_has_many_through
|
471
502
|
count = posts(:thinking).tags.count
|
472
503
|
tags_before = posts(:thinking).tags
|