activerecord 1.13.2 → 1.14.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 +452 -10
- data/RUNNING_UNIT_TESTS +1 -1
- data/lib/active_record.rb +5 -2
- data/lib/active_record/acts/list.rb +1 -1
- data/lib/active_record/acts/tree.rb +29 -25
- data/lib/active_record/aggregations.rb +3 -2
- data/lib/active_record/associations.rb +783 -337
- data/lib/active_record/associations/association_collection.rb +7 -12
- data/lib/active_record/associations/association_proxy.rb +62 -24
- data/lib/active_record/associations/belongs_to_association.rb +27 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +38 -38
- data/lib/active_record/associations/has_many_association.rb +61 -56
- data/lib/active_record/associations/has_many_through_association.rb +144 -0
- data/lib/active_record/associations/has_one_association.rb +22 -16
- data/lib/active_record/base.rb +482 -182
- data/lib/active_record/calculations.rb +225 -0
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +162 -47
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +21 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +34 -2
- data/lib/active_record/connection_adapters/db2_adapter.rb +107 -61
- data/lib/active_record/connection_adapters/mysql_adapter.rb +29 -6
- data/lib/active_record/connection_adapters/openbase_adapter.rb +349 -0
- data/lib/active_record/connection_adapters/{oci_adapter.rb → oracle_adapter.rb} +125 -59
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +24 -21
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +47 -8
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +36 -16
- data/lib/active_record/connection_adapters/sybase_adapter.rb +684 -0
- data/lib/active_record/fixtures.rb +42 -17
- data/lib/active_record/locking.rb +36 -15
- data/lib/active_record/migration.rb +111 -8
- data/lib/active_record/observer.rb +25 -1
- data/lib/active_record/reflection.rb +103 -41
- data/lib/active_record/schema.rb +2 -2
- data/lib/active_record/schema_dumper.rb +55 -18
- data/lib/active_record/timestamp.rb +6 -6
- data/lib/active_record/validations.rb +65 -40
- data/lib/active_record/vendor/db2.rb +10 -5
- data/lib/active_record/vendor/simple.rb +693 -702
- data/lib/active_record/version.rb +2 -2
- data/rakefile +4 -4
- data/test/aaa_create_tables_test.rb +25 -6
- data/test/abstract_unit.rb +39 -1
- data/test/adapter_test.rb +31 -4
- data/test/associations_cascaded_eager_loading_test.rb +106 -0
- data/test/associations_go_eager_test.rb +85 -16
- data/test/associations_join_model_test.rb +338 -0
- data/test/associations_test.rb +129 -50
- data/test/base_test.rb +204 -49
- data/test/binary_test.rb +1 -1
- data/test/calculations_test.rb +169 -0
- data/test/callbacks_test.rb +5 -23
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -0
- data/test/connections/native_openbase/connection.rb +22 -0
- data/test/connections/{native_oci → native_oracle}/connection.rb +7 -9
- data/test/connections/native_sqlite/connection.rb +1 -1
- data/test/connections/native_sqlite3/connection.rb +1 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -0
- data/test/connections/native_sybase/connection.rb +24 -0
- data/test/defaults_test.rb +18 -0
- data/test/deprecated_associations_test.rb +2 -2
- data/test/deprecated_finder_test.rb +0 -6
- data/test/finder_test.rb +26 -23
- data/test/fixtures/accounts.yml +10 -0
- data/test/fixtures/author.rb +31 -6
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_posts.yml +4 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +11 -0
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +17 -5
- data/test/fixtures/company_in_module.rb +19 -5
- data/test/fixtures/db_definitions/db2.drop.sql +3 -0
- data/test/fixtures/db_definitions/db2.sql +121 -100
- data/test/fixtures/db_definitions/db22.sql +2 -2
- data/test/fixtures/db_definitions/firebird.drop.sql +4 -0
- data/test/fixtures/db_definitions/firebird.sql +26 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +3 -0
- data/test/fixtures/db_definitions/mysql.sql +21 -1
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +282 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/{oci.drop.sql → oracle.drop.sql} +6 -0
- data/test/fixtures/db_definitions/{oci.sql → oracle.sql} +25 -4
- data/test/fixtures/db_definitions/{oci2.drop.sql → oracle2.drop.sql} +0 -0
- data/test/fixtures/db_definitions/{oci2.sql → oracle2.sql} +0 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +22 -1
- data/test/fixtures/db_definitions/schema.rb +32 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlite.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +23 -3
- data/test/fixtures/db_definitions/sybase.drop.sql +31 -0
- data/test/fixtures/db_definitions/sybase.sql +204 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developers.yml +6 -1
- data/test/fixtures/developers_projects.yml +4 -0
- data/test/fixtures/funny_jokes.yml +14 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/mixin.rb +1 -1
- data/test/fixtures/person.rb +4 -1
- data/test/fixtures/post.rb +26 -1
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +2 -1
- data/test/fixtures/tag.rb +5 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/tasks.yml +2 -2
- data/test/fixtures/topic.rb +2 -2
- data/test/fixtures/topics.yml +1 -0
- data/test/fixtures_test.rb +47 -13
- data/test/inheritance_test.rb +2 -2
- data/test/locking_test.rb +15 -1
- data/test/method_scoping_test.rb +248 -13
- data/test/migration_test.rb +68 -11
- data/test/mixin_nested_set_test.rb +1 -1
- data/test/modules_test.rb +6 -1
- data/test/readonly_test.rb +1 -1
- data/test/reflection_test.rb +63 -9
- data/test/schema_dumper_test.rb +41 -0
- data/test/{synonym_test_oci.rb → synonym_test_oracle.rb} +1 -1
- data/test/threaded_connections_test.rb +10 -0
- data/test/unconnected_test.rb +12 -5
- data/test/validations_test.rb +197 -10
- metadata +295 -260
- data/test/fixtures/db_definitions/create_oracle_db.bat +0 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +0 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
data/rakefile
CHANGED
@@ -27,7 +27,7 @@ task :default => [ :test_mysql, :test_sqlite, :test_postgresql ]
|
|
27
27
|
|
28
28
|
# Run the unit tests
|
29
29
|
|
30
|
-
for adapter in %w( mysql postgresql sqlite sqlite3 firebird sqlserver sqlserver_odbc db2
|
30
|
+
for adapter in %w( mysql postgresql sqlite sqlite3 firebird sqlserver sqlserver_odbc db2 oracle sybase openbase )
|
31
31
|
Rake::TestTask.new("test_#{adapter}") { |t|
|
32
32
|
t.libs << "test" << "test/connections/native_#{adapter}"
|
33
33
|
t.pattern = "test/*_test{,_#{adapter}}.rb"
|
@@ -59,7 +59,7 @@ task :build_postgresql_databases do
|
|
59
59
|
%x( createdb activerecord_unittest )
|
60
60
|
%x( createdb activerecord_unittest2 )
|
61
61
|
%x( psql activerecord_unittest -f #{File.join(SCHEMA_PATH, 'postgresql.sql')} )
|
62
|
-
%x( psql
|
62
|
+
%x( psql activerecord_unittest2 -f #{File.join(SCHEMA_PATH, 'postgresql2.sql')} )
|
63
63
|
end
|
64
64
|
|
65
65
|
desc 'Drop the PostgreSQL test databases'
|
@@ -76,7 +76,7 @@ task :rebuild_postgresql_databases => [:drop_postgresql_databases, :build_postgr
|
|
76
76
|
Rake::RDocTask.new { |rdoc|
|
77
77
|
rdoc.rdoc_dir = 'doc'
|
78
78
|
rdoc.title = "Active Record -- Object-relation mapping put on rails"
|
79
|
-
rdoc.options << '--line-numbers --inline-source
|
79
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
80
80
|
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
81
81
|
rdoc.rdoc_files.include('README', 'RUNNING_UNIT_TESTS', 'CHANGELOG')
|
82
82
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
@@ -106,7 +106,7 @@ spec = Gem::Specification.new do |s|
|
|
106
106
|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
107
107
|
end
|
108
108
|
|
109
|
-
s.add_dependency('activesupport', '= 1.
|
109
|
+
s.add_dependency('activesupport', '= 1.3.0' + PKG_BUILD)
|
110
110
|
|
111
111
|
s.files.delete "test/fixtures/fixture_database.sqlite"
|
112
112
|
s.files.delete "test/fixtures/fixture_database_2.sqlite"
|
@@ -1,7 +1,9 @@
|
|
1
1
|
# The filename begins with "aaa" to ensure this is the first test.
|
2
2
|
require 'abstract_unit'
|
3
3
|
|
4
|
-
class
|
4
|
+
class AAACreateTablesTest < Test::Unit::TestCase
|
5
|
+
self.use_transactional_fixtures = false
|
6
|
+
|
5
7
|
def setup
|
6
8
|
@base_path = "#{File.dirname(__FILE__)}/fixtures/db_definitions"
|
7
9
|
end
|
@@ -10,6 +12,11 @@ class CreateTablesTest < Test::Unit::TestCase
|
|
10
12
|
recreate ActiveRecord::Base
|
11
13
|
assert true
|
12
14
|
end
|
15
|
+
|
16
|
+
def test_load_schema
|
17
|
+
eval(File.read("#{File.dirname(__FILE__)}/fixtures/db_definitions/schema.rb"))
|
18
|
+
assert true
|
19
|
+
end
|
13
20
|
|
14
21
|
def test_drop_and_create_courses_table
|
15
22
|
recreate Course, '2'
|
@@ -25,11 +32,23 @@ class CreateTablesTest < Test::Unit::TestCase
|
|
25
32
|
end
|
26
33
|
|
27
34
|
def execute_sql_file(path, connection)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
35
|
+
# OpenBase has a different format for sql files
|
36
|
+
if current_adapter?(:OpenBaseAdapter) then
|
37
|
+
File.read(path).split("go").each_with_index do |sql, i|
|
38
|
+
begin
|
39
|
+
# OpenBase does not support comments embedded in sql
|
40
|
+
connection.execute(sql,"SQL statement ##{i}") unless sql.blank?
|
41
|
+
rescue ActiveRecord::StatementInvalid
|
42
|
+
#$stderr.puts "warning: #{$!}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
else
|
46
|
+
File.read(path).split(';').each_with_index do |sql, i|
|
47
|
+
begin
|
48
|
+
connection.execute("\n\n-- statement ##{i}\n#{sql}\n") unless sql.blank?
|
49
|
+
rescue ActiveRecord::StatementInvalid
|
50
|
+
#$stderr.puts "warning: #{$!}"
|
51
|
+
end
|
33
52
|
end
|
34
53
|
end
|
35
54
|
end
|
data/test/abstract_unit.rb
CHANGED
@@ -16,7 +16,36 @@ class Test::Unit::TestCase #:nodoc:
|
|
16
16
|
self.use_transactional_fixtures = (ENV['AR_NO_TX_FIXTURES'] != "yes")
|
17
17
|
|
18
18
|
def create_fixtures(*table_names, &block)
|
19
|
-
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names, &block)
|
19
|
+
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names, {}, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_date_from_db(expected, actual, message = nil)
|
23
|
+
# SQL Server doesn't have a separate column type just for dates,
|
24
|
+
# so the time is in the string and incorrectly formatted
|
25
|
+
if current_adapter?(:SQLServerAdapter)
|
26
|
+
assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
|
27
|
+
elsif current_adapter?(:SybaseAdapter)
|
28
|
+
assert_equal expected.to_s, actual.to_date.to_s, message
|
29
|
+
else
|
30
|
+
assert_equal expected.to_s, actual.to_s, message
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_queries(num = 1)
|
35
|
+
ActiveRecord::Base.connection.class.class_eval do
|
36
|
+
self.query_count = 0
|
37
|
+
alias_method :execute, :execute_with_query_counting
|
38
|
+
end
|
39
|
+
yield
|
40
|
+
ensure
|
41
|
+
ActiveRecord::Base.connection.class.class_eval do
|
42
|
+
alias_method :execute, :execute_without_query_counting
|
43
|
+
end
|
44
|
+
assert_equal num, ActiveRecord::Base.connection.query_count, "#{ActiveRecord::Base.connection.query_count} instead of #{num} queries were executed."
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_no_queries(&block)
|
48
|
+
assert_queries(0, &block)
|
20
49
|
end
|
21
50
|
end
|
22
51
|
|
@@ -25,5 +54,14 @@ def current_adapter?(type)
|
|
25
54
|
ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters.const_get(type))
|
26
55
|
end
|
27
56
|
|
57
|
+
ActiveRecord::Base.connection.class.class_eval do
|
58
|
+
cattr_accessor :query_count
|
59
|
+
alias_method :execute_without_query_counting, :execute
|
60
|
+
def execute_with_query_counting(sql, name = nil)
|
61
|
+
self.query_count += 1
|
62
|
+
execute_without_query_counting(sql, name)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
28
66
|
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
29
67
|
#ActiveRecord::Base.colorize_logging = false
|
data/test/adapter_test.rb
CHANGED
@@ -18,14 +18,18 @@ class AdapterTest < Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_indexes
|
21
|
+
idx_name = "accounts_idx"
|
22
|
+
|
21
23
|
if @connection.respond_to?(:indexes)
|
22
24
|
indexes = @connection.indexes("accounts")
|
23
25
|
assert indexes.empty?
|
24
26
|
|
25
|
-
@connection.add_index :accounts, :firm_id
|
27
|
+
@connection.add_index :accounts, :firm_id, :name => idx_name
|
26
28
|
indexes = @connection.indexes("accounts")
|
27
29
|
assert_equal "accounts", indexes.first.table
|
28
|
-
|
30
|
+
# OpenBase does not have the concept of a named index
|
31
|
+
# Indexes are merely properties of columns.
|
32
|
+
assert_equal idx_name, indexes.first.name unless current_adapter?(:OpenBaseAdapter)
|
29
33
|
assert !indexes.first.unique
|
30
34
|
assert_equal ["firm_id"], indexes.first.columns
|
31
35
|
else
|
@@ -33,7 +37,29 @@ class AdapterTest < Test::Unit::TestCase
|
|
33
37
|
end
|
34
38
|
|
35
39
|
ensure
|
36
|
-
@connection.remove_index
|
40
|
+
@connection.remove_index(:accounts, :name => idx_name) rescue nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_current_database
|
44
|
+
if @connection.respond_to?(:current_database)
|
45
|
+
assert_equal "activerecord_unittest", @connection.current_database
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_table_alias
|
50
|
+
def @connection.test_table_alias_length() 10; end
|
51
|
+
class << @connection
|
52
|
+
alias_method :old_table_alias_length, :table_alias_length
|
53
|
+
alias_method :table_alias_length, :test_table_alias_length
|
54
|
+
end
|
55
|
+
|
56
|
+
assert_equal 'posts', @connection.table_alias_for('posts')
|
57
|
+
assert_equal 'posts_comm', @connection.table_alias_for('posts_comments')
|
58
|
+
assert_equal 'dbo_posts', @connection.table_alias_for('dbo.posts')
|
59
|
+
|
60
|
+
class << @connection
|
61
|
+
alias_method :table_alias_length, :old_table_alias_length
|
62
|
+
end
|
37
63
|
end
|
38
64
|
|
39
65
|
# test resetting sequences in odd tables in postgreSQL
|
@@ -52,7 +78,8 @@ class AdapterTest < Test::Unit::TestCase
|
|
52
78
|
|
53
79
|
sub = Subscriber.new(:name => 'robert drake')
|
54
80
|
sub.id = 'bob drake'
|
55
|
-
|
81
|
+
assert_nothing_raised { sub.save! }
|
56
82
|
end
|
57
83
|
end
|
84
|
+
|
58
85
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'active_record/acts/list'
|
3
|
+
require 'fixtures/post'
|
4
|
+
require 'fixtures/comment'
|
5
|
+
require 'fixtures/author'
|
6
|
+
require 'fixtures/category'
|
7
|
+
require 'fixtures/categorization'
|
8
|
+
require 'fixtures/mixin'
|
9
|
+
require 'fixtures/company'
|
10
|
+
require 'fixtures/topic'
|
11
|
+
require 'fixtures/reply'
|
12
|
+
|
13
|
+
class CascadedEagerLoadingTest < Test::Unit::TestCase
|
14
|
+
fixtures :authors, :mixins, :companies, :posts, :categorizations, :topics
|
15
|
+
|
16
|
+
def test_eager_association_loading_with_cascaded_two_levels
|
17
|
+
authors = Author.find(:all, :include=>{:posts=>:comments}, :order=>"authors.id")
|
18
|
+
assert_equal 2, authors.size
|
19
|
+
assert_equal 5, authors[0].posts.size
|
20
|
+
assert_equal 1, authors[1].posts.size
|
21
|
+
assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_eager_association_loading_with_cascaded_two_levels_and_one_level
|
25
|
+
authors = Author.find(:all, :include=>[{:posts=>:comments}, :categorizations], :order=>"authors.id")
|
26
|
+
assert_equal 2, authors.size
|
27
|
+
assert_equal 5, authors[0].posts.size
|
28
|
+
assert_equal 1, authors[1].posts.size
|
29
|
+
assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
|
30
|
+
assert_equal 1, authors[0].categorizations.size
|
31
|
+
assert_equal 1, authors[1].categorizations.size
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_eager_association_loading_with_cascaded_two_levels_with_two_has_many_associations
|
35
|
+
authors = Author.find(:all, :include=>{:posts=>[:comments, :categorizations]}, :order=>"authors.id")
|
36
|
+
assert_equal 2, authors.size
|
37
|
+
assert_equal 5, authors[0].posts.size
|
38
|
+
assert_equal 1, authors[1].posts.size
|
39
|
+
assert_equal 9, authors[0].posts.collect{|post| post.comments.size }.inject(0){|sum,i| sum+i}
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_eager_association_loading_with_cascaded_two_levels_and_self_table_reference
|
43
|
+
authors = Author.find(:all, :include=>{:posts=>[:comments, :author]}, :order=>"authors.id")
|
44
|
+
assert_equal 2, authors.size
|
45
|
+
assert_equal 5, authors[0].posts.size
|
46
|
+
assert_equal authors(:david).name, authors[0].name
|
47
|
+
assert_equal [authors(:david).name], authors[0].posts.collect{|post| post.author.name}.uniq
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_eager_association_loading_with_cascaded_two_levels_with_condition
|
51
|
+
authors = Author.find(:all, :include=>{:posts=>:comments}, :conditions=>"authors.id=1", :order=>"authors.id")
|
52
|
+
assert_equal 1, authors.size
|
53
|
+
assert_equal 5, authors[0].posts.size
|
54
|
+
end
|
55
|
+
|
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
|
+
def test_eager_association_loading_with_cascaded_three_levels_by_ping_pong
|
67
|
+
firms = Firm.find(:all, :include=>{:account=>{:firm=>:account}}, :order=>"companies.id")
|
68
|
+
assert_equal 2, firms.size
|
69
|
+
assert_equal firms.first.account, firms.first.account.firm.account
|
70
|
+
assert_equal companies(:first_firm).account, assert_no_queries { firms.first.account.firm.account }
|
71
|
+
assert_equal companies(:first_firm).account.firm.account, assert_no_queries { firms.first.account.firm.account }
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_eager_association_loading_with_has_many_sti
|
75
|
+
topics = Topic.find(:all, :include => :replies, :order => 'topics.id')
|
76
|
+
assert_equal [topics(:first), topics(:second)], topics
|
77
|
+
assert_no_queries do
|
78
|
+
assert_equal 1, topics[0].replies.size
|
79
|
+
assert_equal 0, topics[1].replies.size
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_eager_association_loading_with_belongs_to_sti
|
84
|
+
replies = Reply.find(:all, :include => :topic, :order => 'topics.id')
|
85
|
+
assert_equal [topics(:second)], replies
|
86
|
+
assert_equal topics(:first), assert_no_queries { replies.first.topic }
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_eager_association_loading_with_multiple_stis_and_order
|
90
|
+
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')
|
91
|
+
assert_equal authors(:david), author
|
92
|
+
assert_no_queries do
|
93
|
+
author.posts.first.special_comments
|
94
|
+
author.posts.first.very_special_comment
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_eager_association_loading_of_stis_with_multiple_references
|
99
|
+
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')
|
100
|
+
assert_equal [authors(:david)], authors
|
101
|
+
assert_no_queries do
|
102
|
+
authors.first.posts.first.special_comments.first.post.special_comments
|
103
|
+
authors.first.posts.first.special_comments.first.post.very_special_comment
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -4,10 +4,12 @@ require 'fixtures/comment'
|
|
4
4
|
require 'fixtures/author'
|
5
5
|
require 'fixtures/category'
|
6
6
|
require 'fixtures/company'
|
7
|
+
require 'fixtures/person'
|
8
|
+
require 'fixtures/reader'
|
7
9
|
|
8
10
|
class EagerAssociationTest < Test::Unit::TestCase
|
9
11
|
fixtures :posts, :comments, :authors, :categories, :categories_posts,
|
10
|
-
:companies, :accounts
|
12
|
+
:companies, :accounts, :tags, :people, :readers
|
11
13
|
|
12
14
|
def test_loading_with_one_association
|
13
15
|
posts = Post.find(:all, :include => :comments)
|
@@ -90,17 +92,26 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
90
92
|
end
|
91
93
|
|
92
94
|
def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations
|
93
|
-
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1)
|
95
|
+
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :order => 'posts.id')
|
94
96
|
assert_equal 1, posts.length
|
95
|
-
assert_equal [
|
97
|
+
assert_equal [1], posts.collect { |p| p.id }
|
96
98
|
end
|
97
99
|
|
98
100
|
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations
|
99
|
-
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :offset => 1)
|
100
|
-
assert_equal
|
101
|
-
assert_equal [], posts
|
101
|
+
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id')
|
102
|
+
assert_equal 1, posts.length
|
103
|
+
assert_equal [2], posts.collect { |p| p.id }
|
102
104
|
end
|
103
105
|
|
106
|
+
def test_eager_with_has_many_through
|
107
|
+
posts_with_comments = people(:michael).posts.find(:all, :include => :comments )
|
108
|
+
posts_with_author = people(:michael).posts.find(:all, :include => :author )
|
109
|
+
posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ])
|
110
|
+
assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum += post.comments.size }
|
111
|
+
assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
|
112
|
+
assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
|
113
|
+
end
|
114
|
+
|
104
115
|
def test_eager_with_has_many_and_limit
|
105
116
|
posts = Post.find(:all, :order => 'posts.id asc', :include => [ :author, :comments ], :limit => 2)
|
106
117
|
assert_equal 2, posts.size
|
@@ -120,9 +131,11 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
120
131
|
end
|
121
132
|
|
122
133
|
def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
|
123
|
-
|
124
|
-
|
125
|
-
|
134
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
|
135
|
+
assert_equal 2, posts.size
|
136
|
+
|
137
|
+
count = Post.count(:include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
|
138
|
+
assert_equal count, posts.size
|
126
139
|
end
|
127
140
|
|
128
141
|
def test_eager_with_has_many_and_limit_with_no_results
|
@@ -141,13 +154,19 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
141
154
|
end
|
142
155
|
|
143
156
|
def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
157
|
+
posts = authors(:david).posts.find(:all,
|
158
|
+
:include => :comments,
|
159
|
+
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
|
160
|
+
:limit => 2
|
161
|
+
)
|
162
|
+
assert_equal 2, posts.size
|
163
|
+
|
164
|
+
count = Post.count(
|
165
|
+
:include => [ :comments, :author ],
|
166
|
+
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
|
167
|
+
:limit => 2
|
168
|
+
)
|
169
|
+
assert_equal count, posts.size
|
151
170
|
end
|
152
171
|
|
153
172
|
def test_eager_association_loading_with_habtm
|
@@ -205,7 +224,57 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
205
224
|
post = Post.find(6, :include=>[ :monkeys, :elephants ])
|
206
225
|
}
|
207
226
|
end
|
227
|
+
|
228
|
+
def find_all_ordered(className, include=nil)
|
229
|
+
className.find(:all, :order=>"#{className.table_name}.#{className.primary_key}", :include=>include)
|
230
|
+
end
|
208
231
|
|
232
|
+
def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm
|
233
|
+
# Eager includes of has many and habtm associations aren't necessarily sorted in the same way
|
234
|
+
def assert_equal_after_sort(item1, item2, item3 = nil)
|
235
|
+
assert_equal(item1.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id})
|
236
|
+
assert_equal(item3.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) if item3
|
237
|
+
end
|
238
|
+
# Test regular association, association with conditions, association with
|
239
|
+
# STI, and association with conditions assured not to be true
|
240
|
+
post_types = [:posts, :hello_posts, :special_posts, :nonexistent_posts]
|
241
|
+
# test both has_many and has_and_belongs_to_many
|
242
|
+
[Author, Category].each do |className|
|
243
|
+
d1 = find_all_ordered(className)
|
244
|
+
# test including all post types at once
|
245
|
+
d2 = find_all_ordered(className, post_types)
|
246
|
+
d1.each_index do |i|
|
247
|
+
assert_equal(d1[i], d2[i])
|
248
|
+
assert_equal_after_sort(d1[i].posts, d2[i].posts)
|
249
|
+
post_types[1..-1].each do |post_type|
|
250
|
+
# test including post_types together
|
251
|
+
d3 = find_all_ordered(className, [:posts, post_type])
|
252
|
+
assert_equal(d1[i], d3[i])
|
253
|
+
assert_equal_after_sort(d1[i].posts, d3[i].posts)
|
254
|
+
assert_equal_after_sort(d1[i].send(post_type), d2[i].send(post_type), d3[i].send(post_type))
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_eager_with_multiple_associations_with_same_table_has_one
|
261
|
+
d1 = find_all_ordered(Firm)
|
262
|
+
d2 = find_all_ordered(Firm, :account)
|
263
|
+
d1.each_index do |i|
|
264
|
+
assert_equal(d1[i], d2[i])
|
265
|
+
assert_equal(d1[i].account, d2[i].account)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_eager_with_multiple_associations_with_same_table_belongs_to
|
270
|
+
firm_types = [:firm, :firm_with_basic_id, :firm_with_other_name, :firm_with_condition]
|
271
|
+
d1 = find_all_ordered(Client)
|
272
|
+
d2 = find_all_ordered(Client, firm_types)
|
273
|
+
d1.each_index do |i|
|
274
|
+
assert_equal(d1[i], d2[i])
|
275
|
+
firm_types.each { |type| assert_equal(d1[i].send(type), d2[i].send(type)) }
|
276
|
+
end
|
277
|
+
end
|
209
278
|
def test_eager_with_valid_association_as_string_not_symbol
|
210
279
|
assert_nothing_raised { Post.find(:all, :include => 'comments') }
|
211
280
|
end
|