activerecord 1.11.1 → 1.12.1
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 +198 -0
- data/lib/active_record.rb +19 -14
- data/lib/active_record/acts/list.rb +8 -6
- data/lib/active_record/acts/tree.rb +33 -10
- data/lib/active_record/aggregations.rb +1 -7
- data/lib/active_record/associations.rb +151 -82
- data/lib/active_record/associations/association_collection.rb +25 -0
- data/lib/active_record/associations/association_proxy.rb +9 -8
- data/lib/active_record/associations/belongs_to_association.rb +19 -5
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +44 -69
- data/lib/active_record/associations/has_many_association.rb +6 -14
- data/lib/active_record/associations/has_one_association.rb +5 -3
- data/lib/active_record/base.rb +344 -130
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +128 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +104 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +249 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +245 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +29 -464
- data/lib/active_record/connection_adapters/db2_adapter.rb +40 -10
- data/lib/active_record/connection_adapters/mysql_adapter.rb +131 -60
- data/lib/active_record/connection_adapters/oci_adapter.rb +106 -26
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +211 -62
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +193 -44
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +24 -15
- data/lib/active_record/fixtures.rb +47 -24
- data/lib/active_record/migration.rb +34 -5
- data/lib/active_record/observer.rb +32 -2
- data/lib/active_record/query_cache.rb +12 -11
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +84 -0
- data/lib/active_record/transactions.rb +1 -3
- data/lib/active_record/validations.rb +40 -26
- data/lib/active_record/vendor/mysql.rb +6 -0
- data/lib/active_record/version.rb +9 -0
- data/rakefile +5 -16
- data/test/abstract_unit.rb +6 -11
- data/test/adapter_test.rb +58 -0
- data/test/ar_schema_test.rb +33 -0
- data/test/association_callbacks_test.rb +14 -0
- data/test/associations_go_eager_test.rb +56 -14
- data/test/associations_test.rb +245 -25
- data/test/base_test.rb +205 -34
- data/test/binary_test.rb +25 -42
- data/test/callbacks_test.rb +75 -0
- data/test/conditions_scoping_test.rb +136 -0
- data/test/connections/native_mysql/connection.rb +0 -4
- data/test/connections/native_sqlite3/in_memory_connection.rb +17 -0
- data/test/copy_table_sqlite.rb +64 -0
- data/test/deprecated_associations_test.rb +7 -6
- data/test/deprecated_finder_test.rb +3 -3
- data/test/finder_test.rb +33 -3
- data/test/fixtures/accounts.yml +5 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/category.rb +11 -1
- data/test/fixtures/comment.rb +22 -2
- data/test/fixtures/comments.yml +6 -0
- data/test/fixtures/companies.yml +15 -0
- data/test/fixtures/company.rb +24 -1
- data/test/fixtures/db_definitions/db2.drop.sql +5 -1
- data/test/fixtures/db_definitions/db2.sql +15 -1
- data/test/fixtures/db_definitions/mysql.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql.sql +17 -2
- data/test/fixtures/db_definitions/oci.drop.sql +37 -5
- data/test/fixtures/db_definitions/oci.sql +47 -4
- data/test/fixtures/db_definitions/oci2.drop.sql +1 -1
- data/test/fixtures/db_definitions/oci2.sql +2 -2
- data/test/fixtures/db_definitions/postgresql.drop.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +33 -4
- data/test/fixtures/db_definitions/sqlite.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite.sql +16 -2
- data/test/fixtures/db_definitions/sqlserver.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver.sql +16 -2
- data/test/fixtures/developer.rb +1 -1
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/mixins.yml +11 -1
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/post.rb +4 -0
- data/test/fixtures/posts.yml +7 -0
- data/test/fixtures/project.rb +1 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +2 -4
- data/test/fixtures/topics.yml +2 -2
- data/test/fixtures_test.rb +79 -7
- data/test/inheritance_test.rb +2 -2
- data/test/lifecycle_test.rb +14 -6
- data/test/migration_test.rb +164 -6
- data/test/mixin_test.rb +78 -2
- data/test/pk_test.rb +25 -1
- data/test/readonly_test.rb +31 -0
- data/test/reflection_test.rb +4 -1
- data/test/schema_dumper_test.rb +19 -0
- data/test/schema_test_postgresql.rb +3 -2
- data/test/synonym_test_oci.rb +17 -0
- data/test/threaded_connections_test.rb +2 -1
- data/test/transactions_test.rb +109 -10
- data/test/validations_test.rb +70 -42
- metadata +25 -5
- data/test/fixtures/associations.png +0 -0
- data/test/thread_safety_test.rb +0 -36
@@ -0,0 +1,84 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# This class is used to dump the database schema for some connection to some
|
3
|
+
# output format (i.e., ActiveRecord::Schema).
|
4
|
+
class SchemaDumper #:nodoc:
|
5
|
+
private_class_method :new
|
6
|
+
|
7
|
+
def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
|
8
|
+
new(connection).dump(stream)
|
9
|
+
stream
|
10
|
+
end
|
11
|
+
|
12
|
+
def dump(stream)
|
13
|
+
header(stream)
|
14
|
+
tables(stream)
|
15
|
+
trailer(stream)
|
16
|
+
stream
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def initialize(connection)
|
22
|
+
@connection = connection
|
23
|
+
@types = @connection.native_database_types
|
24
|
+
@info = @connection.select_one("SELECT * FROM schema_info") rescue nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def header(stream)
|
28
|
+
define_params = @info ? ":version => #{@info['version']}" : ""
|
29
|
+
|
30
|
+
stream.puts <<HEADER
|
31
|
+
# This file is autogenerated. Instead of editing this file, please use the
|
32
|
+
# migrations feature of ActiveRecord to incrementally modify your database, and
|
33
|
+
# then regenerate this schema definition.
|
34
|
+
|
35
|
+
ActiveRecord::Schema.define(#{define_params}) do
|
36
|
+
|
37
|
+
HEADER
|
38
|
+
end
|
39
|
+
|
40
|
+
def trailer(stream)
|
41
|
+
stream.puts "end"
|
42
|
+
end
|
43
|
+
|
44
|
+
def tables(stream)
|
45
|
+
@connection.tables.sort.each do |tbl|
|
46
|
+
next if tbl == "schema_info"
|
47
|
+
table(tbl, stream)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def table(table, stream)
|
52
|
+
columns = @connection.columns(table)
|
53
|
+
|
54
|
+
stream.print " create_table #{table.inspect}"
|
55
|
+
stream.print ", :id => false" if !columns.detect { |c| c.name == "id" }
|
56
|
+
stream.print ", :force => true"
|
57
|
+
stream.puts " do |t|"
|
58
|
+
|
59
|
+
columns.each do |column|
|
60
|
+
next if column.name == "id"
|
61
|
+
stream.print " t.column #{column.name.inspect}, #{column.type.inspect}"
|
62
|
+
stream.print ", :limit => #{column.limit.inspect}" if column.limit != @types[column.type][:limit]
|
63
|
+
stream.print ", :default => #{column.default.inspect}" if !column.default.nil?
|
64
|
+
stream.print ", :null => false" if !column.null
|
65
|
+
stream.puts
|
66
|
+
end
|
67
|
+
|
68
|
+
stream.puts " end"
|
69
|
+
stream.puts
|
70
|
+
|
71
|
+
indexes(table, stream)
|
72
|
+
end
|
73
|
+
|
74
|
+
def indexes(table, stream)
|
75
|
+
indexes = @connection.indexes(table)
|
76
|
+
indexes.each do |index|
|
77
|
+
stream.print " add_index #{index.table.inspect}, #{index.columns.inspect}, :name => #{index.name.inspect}"
|
78
|
+
stream.print ", :unique => true" if index.unique
|
79
|
+
stream.puts
|
80
|
+
end
|
81
|
+
stream.puts unless indexes.empty?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -81,9 +81,7 @@ module ActiveRecord
|
|
81
81
|
# Tribute: Object-level transactions are implemented by Transaction::Simple by Austin Ziegler.
|
82
82
|
module ClassMethods
|
83
83
|
def transaction(*objects, &block)
|
84
|
-
previous_handler = trap('TERM')
|
85
|
-
raise TransactionError, "Transaction aborted"
|
86
|
-
end
|
84
|
+
previous_handler = trap('TERM') { raise TransactionError, "Transaction aborted" }
|
87
85
|
lock_mutex
|
88
86
|
|
89
87
|
begin
|
@@ -21,8 +21,8 @@ module ActiveRecord
|
|
21
21
|
:too_short => "is too short (min is %d characters)",
|
22
22
|
:wrong_length => "is the wrong length (should be %d characters)",
|
23
23
|
:taken => "has already been taken",
|
24
|
-
:not_a_number => "is not a number"
|
25
|
-
|
24
|
+
:not_a_number => "is not a number"
|
25
|
+
}
|
26
26
|
|
27
27
|
# Holds a hash with all the default error messages, such that they can be replaced by your own copy or localizations.
|
28
28
|
cattr_accessor :default_error_messages
|
@@ -179,7 +179,8 @@ module ActiveRecord
|
|
179
179
|
# person.count # => 2
|
180
180
|
# person.errors.on "last_name" # => "can't be empty"
|
181
181
|
# person.errors.on "phone_number" # => "has invalid format"
|
182
|
-
# person.each_full { |msg| puts msg }
|
182
|
+
# person.errors.each_full { |msg| puts msg }
|
183
|
+
# # => "Last name can't be empty\n" +
|
183
184
|
# "Phone number has invalid format"
|
184
185
|
#
|
185
186
|
# person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" }
|
@@ -398,9 +399,11 @@ module ActiveRecord
|
|
398
399
|
# method, proc or string should return or evaluate to a true or false value.
|
399
400
|
def validates_length_of(*attrs)
|
400
401
|
# Merge given options with defaults.
|
401
|
-
options = {
|
402
|
-
|
403
|
-
|
402
|
+
options = {
|
403
|
+
:too_long => ActiveRecord::Errors.default_error_messages[:too_long],
|
404
|
+
:too_short => ActiveRecord::Errors.default_error_messages[:too_short],
|
405
|
+
:wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length]
|
406
|
+
}.merge(DEFAULT_VALIDATION_OPTIONS)
|
404
407
|
options.update(attrs.pop.symbolize_keys) if attrs.last.is_a?(Hash)
|
405
408
|
|
406
409
|
# Ensure that one and only one range option is specified.
|
@@ -418,24 +421,31 @@ module ActiveRecord
|
|
418
421
|
option = range_options.first
|
419
422
|
option_value = options[range_options.first]
|
420
423
|
|
421
|
-
# Declare different validations per option.
|
422
|
-
validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
|
423
|
-
message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
|
424
|
-
|
425
424
|
case option
|
426
425
|
when :within, :in
|
427
|
-
raise ArgumentError,
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
426
|
+
raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range)
|
427
|
+
|
428
|
+
too_short = options[:too_short] % option_value.begin
|
429
|
+
too_long = options[:too_long] % option_value.end
|
430
|
+
|
431
|
+
validates_each(attrs, options) do |record, attr, value|
|
432
|
+
if value.nil? or value.size < option_value.begin
|
433
|
+
record.errors.add(attr, too_short)
|
434
|
+
elsif value.size > option_value.end
|
435
|
+
record.errors.add(attr, too_long)
|
436
|
+
end
|
437
|
+
end
|
433
438
|
when :is, :minimum, :maximum
|
434
|
-
raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
|
435
|
-
|
436
|
-
|
439
|
+
raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
|
440
|
+
|
441
|
+
# Declare different validations per option.
|
442
|
+
validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
|
443
|
+
message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
|
444
|
+
|
445
|
+
message = (options[:message] || options[message_options[option]]) % option_value
|
446
|
+
|
437
447
|
validates_each(attrs, options) do |record, attr, value|
|
438
|
-
record.errors.add(attr, message)
|
448
|
+
record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
|
439
449
|
end
|
440
450
|
end
|
441
451
|
end
|
@@ -588,7 +598,7 @@ module ActiveRecord
|
|
588
598
|
|
589
599
|
validates_each(attr_names, configuration) do |record, attr_name, value|
|
590
600
|
record.errors.add(attr_name, configuration[:message]) unless
|
591
|
-
(value.is_a?(Array) ? value : [value]).
|
601
|
+
(value.is_a?(Array) ? value : [value]).all? { |r| r.nil? or r.valid? }
|
592
602
|
end
|
593
603
|
end
|
594
604
|
|
@@ -604,7 +614,7 @@ module ActiveRecord
|
|
604
614
|
# * <tt>message</tt> - A custom error message (default is: "is not a number")
|
605
615
|
# * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
|
606
616
|
# * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false)
|
607
|
-
# * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float
|
617
|
+
# * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float columns empty strings are converted to nil
|
608
618
|
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
609
619
|
# occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
|
610
620
|
# method, proc or string should return or evaluate to a true or false value.
|
@@ -647,7 +657,12 @@ module ActiveRecord
|
|
647
657
|
# The validation process on save can be skipped by passing false. The regular Base#save method is
|
648
658
|
# replaced with this when the validations module is mixed in, which it is by default.
|
649
659
|
def save_with_validation(perform_validation = true)
|
650
|
-
if perform_validation && valid? || !perform_validation
|
660
|
+
if perform_validation && valid? || !perform_validation
|
661
|
+
save_without_validation
|
662
|
+
true
|
663
|
+
else
|
664
|
+
false
|
665
|
+
end
|
651
666
|
end
|
652
667
|
|
653
668
|
# Attempts to save the record just like Base.save but will raise a RecordInvalid exception instead of returning false
|
@@ -660,7 +675,7 @@ module ActiveRecord
|
|
660
675
|
# This is especially useful for boolean flags on existing records. The regular +update_attribute+ method
|
661
676
|
# in Base is replaced with this when the validations module is mixed in, which it is by default.
|
662
677
|
def update_attribute_with_validation_skipping(name, value)
|
663
|
-
|
678
|
+
send(name.to_s + '=', value)
|
664
679
|
save(false)
|
665
680
|
end
|
666
681
|
|
@@ -684,8 +699,7 @@ module ActiveRecord
|
|
684
699
|
|
685
700
|
# Returns the Errors object that holds all information about attribute error messages.
|
686
701
|
def errors
|
687
|
-
@errors
|
688
|
-
@errors
|
702
|
+
@errors ||= Errors.new(self)
|
689
703
|
end
|
690
704
|
|
691
705
|
protected
|
@@ -1022,6 +1022,9 @@ class Mysql
|
|
1022
1022
|
end
|
1023
1023
|
@sock.sync = true
|
1024
1024
|
buf.join
|
1025
|
+
rescue
|
1026
|
+
errno = Error::CR_SERVER_LOST
|
1027
|
+
raise Error::new(errno, Error::err(errno))
|
1025
1028
|
end
|
1026
1029
|
|
1027
1030
|
def write(data)
|
@@ -1039,6 +1042,9 @@ class Mysql
|
|
1039
1042
|
@pkt_nr = @pkt_nr + 1 & 0xff
|
1040
1043
|
@sock.sync = true
|
1041
1044
|
@sock.flush
|
1045
|
+
rescue
|
1046
|
+
errno = Error::CR_SERVER_LOST
|
1047
|
+
raise Error::new(errno, Error::err(errno))
|
1042
1048
|
end
|
1043
1049
|
|
1044
1050
|
def close()
|
data/rakefile
CHANGED
@@ -5,10 +5,11 @@ require 'rake/rdoctask'
|
|
5
5
|
require 'rake/packagetask'
|
6
6
|
require 'rake/gempackagetask'
|
7
7
|
require 'rake/contrib/rubyforgepublisher'
|
8
|
+
require File.join(File.dirname(__FILE__), 'lib', 'active_record', 'version')
|
8
9
|
|
9
10
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
10
11
|
PKG_NAME = 'activerecord'
|
11
|
-
PKG_VERSION =
|
12
|
+
PKG_VERSION = ActiveRecord::Version::STRING + PKG_BUILD
|
12
13
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
13
14
|
|
14
15
|
RELEASE_NAME = "REL #{PKG_VERSION}"
|
@@ -22,23 +23,11 @@ PKG_FILES = FileList[
|
|
22
23
|
|
23
24
|
|
24
25
|
desc "Default Task"
|
25
|
-
task :default => [ :
|
26
|
+
task :default => [ :test_mysql, :test_sqlite, :test_postgresql ]
|
26
27
|
|
27
28
|
# Run the unit tests
|
28
29
|
|
29
|
-
|
30
|
-
t.libs << "test" << "test/connections/native_mysql"
|
31
|
-
t.pattern = 'test/*_test{,_mysql}.rb'
|
32
|
-
t.verbose = true
|
33
|
-
}
|
34
|
-
|
35
|
-
Rake::TestTask.new("test_mysql_ruby") { |t|
|
36
|
-
t.libs << "test" << "test/connections/native_mysql"
|
37
|
-
t.pattern = 'test/*_test{,_mysql}.rb'
|
38
|
-
t.verbose = true
|
39
|
-
}
|
40
|
-
|
41
|
-
for adapter in %w( postgresql sqlite sqlite3 sqlserver sqlserver_odbc db2 oci )
|
30
|
+
for adapter in %w( mysql postgresql sqlite sqlite3 sqlserver sqlserver_odbc db2 oci )
|
42
31
|
Rake::TestTask.new("test_#{adapter}") { |t|
|
43
32
|
t.libs << "test" << "test/connections/native_#{adapter}"
|
44
33
|
t.pattern = "test/*_test{,_#{adapter}}.rb"
|
@@ -82,7 +71,7 @@ spec = Gem::Specification.new do |s|
|
|
82
71
|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
83
72
|
end
|
84
73
|
|
85
|
-
s.add_dependency('activesupport', '= 1.
|
74
|
+
s.add_dependency('activesupport', '= 1.2.1' + PKG_BUILD)
|
86
75
|
|
87
76
|
s.files.delete "test/fixtures/fixture_database.sqlite"
|
88
77
|
s.files.delete "test/fixtures/fixture_database_2.sqlite"
|
data/test/abstract_unit.rb
CHANGED
@@ -9,16 +9,11 @@ require 'active_support/breakpoint'
|
|
9
9
|
require 'connection'
|
10
10
|
|
11
11
|
class Test::Unit::TestCase #:nodoc:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
13
|
+
self.use_instantiated_fixtures = false
|
14
|
+
self.use_transactional_fixtures = (ENV['AR_NO_TX_FIXTURES'] != "yes")
|
15
|
+
|
16
|
+
def create_fixtures(*table_names, &block)
|
17
|
+
Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names, &block)
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
|
22
|
-
Test::Unit::TestCase.use_instantiated_fixtures = false
|
23
|
-
Test::Unit::TestCase.use_transactional_fixtures = (ENV['AR_TX_FIXTURES'] == "yes")
|
24
|
-
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class AdapterTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@connection = ActiveRecord::Base.connection
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_tables
|
9
|
+
if @connection.respond_to?(:tables)
|
10
|
+
tables = @connection.tables
|
11
|
+
assert tables.include?("accounts")
|
12
|
+
assert tables.include?("authors")
|
13
|
+
assert tables.include?("tasks")
|
14
|
+
assert tables.include?("topics")
|
15
|
+
else
|
16
|
+
warn "#{@connection.class} does not respond to #tables"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_indexes
|
21
|
+
if @connection.respond_to?(:indexes)
|
22
|
+
indexes = @connection.indexes("accounts")
|
23
|
+
assert indexes.empty?
|
24
|
+
|
25
|
+
@connection.add_index :accounts, :firm_id
|
26
|
+
indexes = @connection.indexes("accounts")
|
27
|
+
assert_equal "accounts", indexes.first.table
|
28
|
+
assert_equal "accounts_firm_id_index", indexes.first.name
|
29
|
+
assert !indexes.first.unique
|
30
|
+
assert_equal ["firm_id"], indexes.first.columns
|
31
|
+
else
|
32
|
+
warn "#{@connection.class} does not respond to #indexes"
|
33
|
+
end
|
34
|
+
|
35
|
+
ensure
|
36
|
+
@connection.remove_index :accounts, :firm_id rescue nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# test resetting sequences in odd tables in postgreSQL
|
40
|
+
if ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!)
|
41
|
+
require 'fixtures/movie'
|
42
|
+
require 'fixtures/subscriber'
|
43
|
+
def test_reset_empty_table_with_custom_pk
|
44
|
+
Movie.delete_all
|
45
|
+
Movie.connection.reset_pk_sequence! 'movies'
|
46
|
+
assert_equal 1, Movie.create(:name => 'fight club').id
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_reset_table_with_non_integer_pk
|
50
|
+
Subscriber.delete_all
|
51
|
+
Subscriber.connection.reset_pk_sequence! 'subscribers'
|
52
|
+
|
53
|
+
sub = Subscriber.new(:name => 'robert drake')
|
54
|
+
sub.id = 'bob drake'
|
55
|
+
assert sub.save!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require "#{File.dirname(__FILE__)}/../lib/active_record/schema"
|
3
|
+
|
4
|
+
if ActiveRecord::Base.connection.supports_migrations?
|
5
|
+
|
6
|
+
class ActiveRecordSchemaTest < Test::Unit::TestCase
|
7
|
+
self.use_transactional_fixtures = false
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@connection = ActiveRecord::Base.connection
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
@connection.drop_table :fruits rescue nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_schema_define
|
18
|
+
ActiveRecord::Schema.define(:version => 7) do
|
19
|
+
create_table :fruits do |t|
|
20
|
+
t.column :color, :string
|
21
|
+
t.column :size, :string
|
22
|
+
t.column :texture, :string
|
23
|
+
t.column :flavor, :string
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_nothing_raised { @connection.select_all "SELECT * FROM fruits" }
|
28
|
+
assert_nothing_raised { @connection.select_all "SELECT * FROM schema_info" }
|
29
|
+
assert_equal 7, @connection.select_one("SELECT version FROM schema_info")['version'].to_i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -83,6 +83,20 @@ class AssociationCallbacksTest < Test::Unit::TestCase
|
|
83
83
|
assert_equal ["before_removing#{david.id}", "after_removing#{david.id}", "before_removing#{jamis.id}",
|
84
84
|
"after_removing#{jamis.id}"], activerecord.developers_log
|
85
85
|
end
|
86
|
+
|
87
|
+
def test_has_and_belongs_to_many_remove_callback_on_clear
|
88
|
+
activerecord = projects(:active_record)
|
89
|
+
assert activerecord.developers_log.empty?
|
90
|
+
if activerecord.developers_with_callbacks.size == 0
|
91
|
+
activerecord.developers << developers(:david)
|
92
|
+
activerecord.developers << developers(:jamis)
|
93
|
+
activerecord.reload
|
94
|
+
assert activerecord.developers_with_callbacks.size == 2
|
95
|
+
end
|
96
|
+
log_array = activerecord.developers_with_callbacks.collect {|d| ["before_removing#{d.id}","after_removing#{d.id}"]}.flatten.sort
|
97
|
+
assert activerecord.developers_with_callbacks.clear
|
98
|
+
assert_equal log_array, activerecord.developers_log.sort
|
99
|
+
end
|
86
100
|
|
87
101
|
def test_dont_add_if_before_callback_raises_exception
|
88
102
|
assert !@david.unchangable_posts.include?(@authorless)
|
@@ -20,14 +20,19 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
20
20
|
assert post.comments.include?(comments(:greetings))
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_loading_conditions_with_or
|
24
|
+
posts = authors(:david).posts.find(:all, :include => :comments, :conditions => "comments.body like 'Normal%' OR comments.type = 'SpecialComment'")
|
25
|
+
assert_nil posts.detect { |p| p.author_id != authors(:david).id },
|
26
|
+
"expected to find only david's posts"
|
27
|
+
end
|
28
|
+
|
23
29
|
def test_with_ordering
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
assert_equal posts(:welcome), posts[5]
|
30
|
+
list = Post.find(:all, :include => :comments, :order => "posts.id DESC")
|
31
|
+
[:eager_other, :sti_habtm, :sti_post_and_comments, :sti_comments,
|
32
|
+
:authorless, :thinking, :welcome
|
33
|
+
].each_with_index do |post, index|
|
34
|
+
assert_equal posts(post), list[index]
|
35
|
+
end
|
31
36
|
end
|
32
37
|
|
33
38
|
def test_loading_with_multiple_associations
|
@@ -48,32 +53,32 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
48
53
|
|
49
54
|
def test_eager_association_loading_with_belongs_to
|
50
55
|
comments = Comment.find(:all, :include => :post)
|
51
|
-
assert_equal
|
56
|
+
assert_equal 10, comments.length
|
52
57
|
titles = comments.map { |c| c.post.title }
|
53
58
|
assert titles.include?(posts(:welcome).title)
|
54
59
|
assert titles.include?(posts(:sti_post_and_comments).title)
|
55
60
|
end
|
56
61
|
|
57
62
|
def test_eager_association_loading_with_belongs_to_and_limit
|
58
|
-
comments = Comment.find(:all, :include => :post, :limit => 5)
|
63
|
+
comments = Comment.find(:all, :include => :post, :limit => 5, :order => 'comments.id')
|
59
64
|
assert_equal 5, comments.length
|
60
65
|
assert_equal [1,2,3,5,6], comments.collect { |c| c.id }
|
61
66
|
end
|
62
67
|
|
63
68
|
def test_eager_association_loading_with_belongs_to_and_limit_and_conditions
|
64
|
-
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3)
|
69
|
+
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :order => 'comments.id')
|
65
70
|
assert_equal 3, comments.length
|
66
71
|
assert_equal [5,6,7], comments.collect { |c| c.id }
|
67
72
|
end
|
68
73
|
|
69
74
|
def test_eager_association_loading_with_belongs_to_and_limit_and_offset
|
70
|
-
comments = Comment.find(:all, :include => :post, :limit => 3, :offset => 2)
|
75
|
+
comments = Comment.find(:all, :include => :post, :limit => 3, :offset => 2, :order => 'comments.id')
|
71
76
|
assert_equal 3, comments.length
|
72
77
|
assert_equal [3,5,6], comments.collect { |c| c.id }
|
73
78
|
end
|
74
79
|
|
75
80
|
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions
|
76
|
-
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :offset => 1)
|
81
|
+
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id')
|
77
82
|
assert_equal 3, comments.length
|
78
83
|
assert_equal [6,7,8], comments.collect { |c| c.id }
|
79
84
|
end
|
@@ -90,8 +95,35 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
90
95
|
assert_equal [], posts
|
91
96
|
end
|
92
97
|
|
93
|
-
def
|
94
|
-
|
98
|
+
def test_eager_with_has_many_and_limit
|
99
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2)
|
100
|
+
assert_equal 2, posts.size
|
101
|
+
assert_equal 3, posts.inject(0) { |sum, post| sum += post.comments.size }
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_eager_with_has_many_and_limit_with_no_results
|
105
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'")
|
106
|
+
assert_equal 0, posts.size
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_eager_with_has_and_belongs_to_many_and_limit
|
110
|
+
posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3)
|
111
|
+
assert_equal 3, posts.size
|
112
|
+
assert_equal 2, posts[0].categories.size
|
113
|
+
assert_equal 1, posts[1].categories.size
|
114
|
+
assert_equal 0, posts[2].categories.size
|
115
|
+
assert posts[0].categories.include?(categories(:technology))
|
116
|
+
assert posts[1].categories.include?(categories(:general))
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
|
120
|
+
assert_raises(ArgumentError) do
|
121
|
+
posts = authors(:david).posts.find(:all,
|
122
|
+
:include => :comments,
|
123
|
+
:conditions => "comments.body like 'Normal%' OR comments.type = 'SpecialComment'",
|
124
|
+
:limit => 2
|
125
|
+
)
|
126
|
+
end
|
95
127
|
end
|
96
128
|
|
97
129
|
def test_eager_association_loading_with_habtm
|
@@ -136,12 +168,22 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
136
168
|
end
|
137
169
|
|
138
170
|
def test_eager_with_invalid_association_reference
|
171
|
+
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
172
|
+
post = Post.find(6, :include=> :monkeys )
|
173
|
+
}
|
139
174
|
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
140
175
|
post = Post.find(6, :include=>[ :monkeys ])
|
141
176
|
}
|
177
|
+
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
178
|
+
post = Post.find(6, :include=>[ 'monkeys' ])
|
179
|
+
}
|
142
180
|
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
|
143
181
|
post = Post.find(6, :include=>[ :monkeys, :elephants ])
|
144
182
|
}
|
145
183
|
end
|
146
184
|
|
185
|
+
def test_eager_with_valid_association_as_string_not_symbol
|
186
|
+
assert_nothing_raised { Post.find(:all, :include => 'comments') }
|
187
|
+
end
|
188
|
+
|
147
189
|
end
|