activerecord 1.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 +581 -0
- data/README +361 -0
- data/RUNNING_UNIT_TESTS +36 -0
- data/dev-utils/eval_debugger.rb +9 -0
- data/examples/associations.png +0 -0
- data/examples/associations.rb +87 -0
- data/examples/shared_setup.rb +15 -0
- data/examples/validation.rb +88 -0
- data/install.rb +60 -0
- data/lib/active_record.rb +48 -0
- data/lib/active_record/aggregations.rb +165 -0
- data/lib/active_record/associations.rb +536 -0
- data/lib/active_record/associations/association_collection.rb +70 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -0
- data/lib/active_record/associations/has_many_association.rb +104 -0
- data/lib/active_record/base.rb +985 -0
- data/lib/active_record/callbacks.rb +337 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +326 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +131 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +177 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +107 -0
- data/lib/active_record/deprecated_associations.rb +70 -0
- data/lib/active_record/fixtures.rb +172 -0
- data/lib/active_record/observer.rb +71 -0
- data/lib/active_record/reflection.rb +126 -0
- data/lib/active_record/support/class_attribute_accessors.rb +43 -0
- data/lib/active_record/support/class_inheritable_attributes.rb +37 -0
- data/lib/active_record/support/clean_logger.rb +10 -0
- data/lib/active_record/support/inflector.rb +70 -0
- data/lib/active_record/transactions.rb +102 -0
- data/lib/active_record/validations.rb +205 -0
- data/lib/active_record/vendor/mysql.rb +1117 -0
- data/lib/active_record/vendor/simple.rb +702 -0
- data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
- data/lib/active_record/wrappings.rb +59 -0
- data/rakefile +122 -0
- data/test/abstract_unit.rb +16 -0
- data/test/aggregations_test.rb +34 -0
- data/test/all.sh +8 -0
- data/test/associations_test.rb +477 -0
- data/test/base_test.rb +513 -0
- data/test/class_inheritable_attributes_test.rb +33 -0
- data/test/connections/native_mysql/connection.rb +24 -0
- data/test/connections/native_postgresql/connection.rb +24 -0
- data/test/connections/native_sqlite/connection.rb +24 -0
- data/test/deprecated_associations_test.rb +336 -0
- data/test/finder_test.rb +67 -0
- data/test/fixtures/accounts/signals37 +3 -0
- data/test/fixtures/accounts/unknown +2 -0
- data/test/fixtures/auto_id.rb +4 -0
- data/test/fixtures/column_name.rb +3 -0
- data/test/fixtures/companies/first_client +6 -0
- data/test/fixtures/companies/first_firm +4 -0
- data/test/fixtures/companies/second_client +6 -0
- data/test/fixtures/company.rb +37 -0
- data/test/fixtures/company_in_module.rb +33 -0
- data/test/fixtures/course.rb +3 -0
- data/test/fixtures/courses/java +2 -0
- data/test/fixtures/courses/ruby +2 -0
- data/test/fixtures/customer.rb +30 -0
- data/test/fixtures/customers/david +6 -0
- data/test/fixtures/db_definitions/mysql.sql +96 -0
- data/test/fixtures/db_definitions/mysql2.sql +4 -0
- data/test/fixtures/db_definitions/postgresql.sql +113 -0
- data/test/fixtures/db_definitions/postgresql2.sql +4 -0
- data/test/fixtures/db_definitions/sqlite.sql +85 -0
- data/test/fixtures/db_definitions/sqlite2.sql +4 -0
- data/test/fixtures/default.rb +2 -0
- data/test/fixtures/developer.rb +8 -0
- data/test/fixtures/developers/david +2 -0
- data/test/fixtures/developers/jamis +2 -0
- data/test/fixtures/developers_projects/david_action_controller +2 -0
- data/test/fixtures/developers_projects/david_active_record +2 -0
- data/test/fixtures/developers_projects/jamis_active_record +2 -0
- data/test/fixtures/entrant.rb +3 -0
- data/test/fixtures/entrants/first +3 -0
- data/test/fixtures/entrants/second +3 -0
- data/test/fixtures/entrants/third +3 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movie.rb +5 -0
- data/test/fixtures/movies/first +2 -0
- data/test/fixtures/movies/second +2 -0
- data/test/fixtures/project.rb +3 -0
- data/test/fixtures/projects/action_controller +2 -0
- data/test/fixtures/projects/active_record +2 -0
- data/test/fixtures/reply.rb +21 -0
- data/test/fixtures/subscriber.rb +5 -0
- data/test/fixtures/subscribers/first +2 -0
- data/test/fixtures/subscribers/second +2 -0
- data/test/fixtures/topic.rb +20 -0
- data/test/fixtures/topics/first +9 -0
- data/test/fixtures/topics/second +8 -0
- data/test/fixtures_test.rb +20 -0
- data/test/inflector_test.rb +104 -0
- data/test/inheritance_test.rb +125 -0
- data/test/lifecycle_test.rb +110 -0
- data/test/modules_test.rb +21 -0
- data/test/multiple_db_test.rb +46 -0
- data/test/pk_test.rb +57 -0
- data/test/reflection_test.rb +78 -0
- data/test/thread_safety_test.rb +33 -0
- data/test/transactions_test.rb +83 -0
- data/test/unconnected_test.rb +24 -0
- data/test/validations_test.rb +126 -0
- metadata +166 -0
Binary file
|
Binary file
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Reply < Topic
|
2
|
+
belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true
|
3
|
+
|
4
|
+
attr_accessible :title, :author_name, :author_email_address, :written_on, :content, :last_read
|
5
|
+
|
6
|
+
def validate
|
7
|
+
errors.add("title", "Empty") unless attribute_present? "title"
|
8
|
+
errors.add("content", "Empty") unless attribute_present? "content"
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate_on_create
|
12
|
+
errors.add("title", "is Wrong Create") if attribute_present?("title") && title == "Wrong Create"
|
13
|
+
if attribute_present?("title") && attribute_present?("content") && content == "Mismatch"
|
14
|
+
errors.add("title", "is Content Mismatch")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate_on_update
|
19
|
+
errors.add("title", "is Wrong Update") if attribute_present?("title") && title == "Wrong Update"
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Topic < ActiveRecord::Base
|
2
|
+
has_many :replies, :foreign_key => "parent_id"
|
3
|
+
serialize :content
|
4
|
+
|
5
|
+
before_create :default_written_on
|
6
|
+
before_destroy :destroy_children #'self.class.delete_all "parent_id = #{id}"'
|
7
|
+
|
8
|
+
def parent
|
9
|
+
self.class.find(parent_id)
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
def default_written_on
|
14
|
+
self.written_on = Time.now unless attribute_present?("written_on")
|
15
|
+
end
|
16
|
+
|
17
|
+
def destroy_children
|
18
|
+
self.class.delete_all "parent_id = #{id}"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class FixturesTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@fixtures = create_fixtures("topics")
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_attributes
|
9
|
+
assert_equal("The First Topic", @fixtures["first"]["title"])
|
10
|
+
assert_nil(@fixtures["second"]["author_email_address"])
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_inserts
|
14
|
+
firstRow = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'David'")
|
15
|
+
assert_equal("The First Topic", firstRow["title"])
|
16
|
+
|
17
|
+
secondRow = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'Mary'")
|
18
|
+
assert_nil(secondRow["author_email_address"])
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class InflectorTest < Test::Unit::TestCase
|
4
|
+
SingularToPlural = {
|
5
|
+
"search" => "searches",
|
6
|
+
"switch" => "switches",
|
7
|
+
"fix" => "fixes",
|
8
|
+
"box" => "boxes",
|
9
|
+
"process" => "processes",
|
10
|
+
"address" => "addresses",
|
11
|
+
"case" => "cases",
|
12
|
+
"stack" => "stacks",
|
13
|
+
|
14
|
+
"category" => "categories",
|
15
|
+
"query" => "queries",
|
16
|
+
"ability" => "abilities",
|
17
|
+
"agency" => "agencies",
|
18
|
+
|
19
|
+
"wife" => "wives",
|
20
|
+
"safe" => "saves",
|
21
|
+
"half" => "halves",
|
22
|
+
|
23
|
+
"salesperson" => "salespeople",
|
24
|
+
"person" => "people",
|
25
|
+
|
26
|
+
"spokesman" => "spokesmen",
|
27
|
+
"man" => "men",
|
28
|
+
"woman" => "women",
|
29
|
+
|
30
|
+
"basis" => "bases",
|
31
|
+
"diagnosis" => "diagnoses",
|
32
|
+
|
33
|
+
"datum" => "data",
|
34
|
+
"medium" => "media",
|
35
|
+
|
36
|
+
"node_child" => "node_children",
|
37
|
+
"child" => "children",
|
38
|
+
|
39
|
+
"experience" => "experiences",
|
40
|
+
"day" => "days",
|
41
|
+
|
42
|
+
"comment" => "comments",
|
43
|
+
"foobar" => "foobars"
|
44
|
+
}
|
45
|
+
|
46
|
+
CamelToUnderscore = {
|
47
|
+
"Product" => "product",
|
48
|
+
"SpecialGuest" => "special_guest",
|
49
|
+
"AbstractApplicationController" => "abstract_application_controller"
|
50
|
+
}
|
51
|
+
|
52
|
+
ClassNameToForeignKeyWithUnderscore = {
|
53
|
+
"Person" => "person_id",
|
54
|
+
"MyApplication::Billing::Account" => "account_id"
|
55
|
+
}
|
56
|
+
|
57
|
+
ClassNameToForeignKeyWithoutUnderscore = {
|
58
|
+
"Person" => "personid",
|
59
|
+
"MyApplication::Billing::Account" => "accountid"
|
60
|
+
}
|
61
|
+
|
62
|
+
def test_pluralize
|
63
|
+
SingularToPlural.each do |singular, plural|
|
64
|
+
assert_equal(plural, Inflector.pluralize(singular))
|
65
|
+
end
|
66
|
+
|
67
|
+
assert_equal("plurals", Inflector.pluralize("plurals"))
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_singularize
|
71
|
+
SingularToPlural.each do |singular, plural|
|
72
|
+
assert_equal(singular, Inflector.singularize(plural))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_camelize
|
77
|
+
CamelToUnderscore.each do |camel, underscore|
|
78
|
+
assert_equal(camel, Inflector.camelize(underscore))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_underscore
|
83
|
+
CamelToUnderscore.each do |camel, underscore|
|
84
|
+
assert_equal(underscore, Inflector.underscore(camel))
|
85
|
+
end
|
86
|
+
|
87
|
+
assert_equal "html_tidy", Inflector.underscore("HTMLTidy")
|
88
|
+
assert_equal "html_tidy_generator", Inflector.underscore("HTMLTidyGenerator")
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_demodulize
|
92
|
+
assert_equal "Account", Inflector.demodulize("MyApplication::Billing::Account")
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_foreign_key
|
96
|
+
ClassNameToForeignKeyWithUnderscore.each do |klass, foreign_key|
|
97
|
+
assert_equal(foreign_key, Inflector.foreign_key(klass))
|
98
|
+
end
|
99
|
+
|
100
|
+
ClassNameToForeignKeyWithoutUnderscore.each do |klass, foreign_key|
|
101
|
+
assert_equal(foreign_key, Inflector.foreign_key(klass, false))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/company'
|
3
|
+
|
4
|
+
|
5
|
+
class InheritanceTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@company_fixtures = create_fixtures "companies"
|
8
|
+
end
|
9
|
+
|
10
|
+
def switch_to_alt_inheritance_column
|
11
|
+
# we don't want misleading test results, so get rid of the values in the type column
|
12
|
+
Company.find_all(nil, "id").each do |c|
|
13
|
+
c['type'] = nil
|
14
|
+
c.save
|
15
|
+
end
|
16
|
+
|
17
|
+
def Company.inheritance_column() "ruby_type" end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_inheritance_find
|
21
|
+
assert Company.find(1).kind_of?(Firm), "37signals should be a firm"
|
22
|
+
assert Firm.find(1).kind_of?(Firm), "37signals should be a firm"
|
23
|
+
assert Company.find(2).kind_of?(Client), "Summit should be a client"
|
24
|
+
assert Client.find(2).kind_of?(Client), "Summit should be a client"
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_alt_inheritance_find
|
28
|
+
switch_to_alt_inheritance_column
|
29
|
+
test_inheritance_find
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_inheritance_find_all
|
33
|
+
companies = Company.find_all(nil, "id")
|
34
|
+
assert companies[0].kind_of?(Firm), "37signals should be a firm"
|
35
|
+
assert companies[1].kind_of?(Client), "Summit should be a client"
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_alt_inheritance_find_all
|
39
|
+
switch_to_alt_inheritance_column
|
40
|
+
test_inheritance_find_all
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_inheritance_save
|
44
|
+
firm = Firm.new
|
45
|
+
firm.name = "Next Angle"
|
46
|
+
firm.save
|
47
|
+
|
48
|
+
next_angle = Company.find(firm.id)
|
49
|
+
assert next_angle.kind_of?(Firm), "Next Angle should be a firm"
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_alt_inheritance_save
|
53
|
+
switch_to_alt_inheritance_column
|
54
|
+
test_inheritance_save
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_inheritance_condition
|
58
|
+
assert_equal 3, Company.find_all.length
|
59
|
+
assert_equal 1, Firm.find_all.length
|
60
|
+
assert_equal 2, Client.find_all.length
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_alt_inheritance_condition
|
64
|
+
switch_to_alt_inheritance_column
|
65
|
+
test_inheritance_condition
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_finding_incorrect_type_data
|
69
|
+
assert_raises(ActiveRecord::RecordNotFound) { Firm.find(2) }
|
70
|
+
assert_nothing_raised { Firm.find(1) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_alt_finding_incorrect_type_data
|
74
|
+
switch_to_alt_inheritance_column
|
75
|
+
test_finding_incorrect_type_data
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_update_all_within_inheritance
|
79
|
+
Client.update_all "name = 'I am a client'"
|
80
|
+
assert_equal "I am a client", Client.find_all.first.name
|
81
|
+
assert_equal "37signals", Firm.find_all.first.name
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_alt_update_all_within_inheritance
|
85
|
+
switch_to_alt_inheritance_column
|
86
|
+
test_update_all_within_inheritance
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_destroy_all_within_inheritance
|
90
|
+
Client.destroy_all
|
91
|
+
assert_equal 0, Client.find_all.length
|
92
|
+
assert_equal 1, Firm.find_all.length
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_alt_destroy_all_within_inheritance
|
96
|
+
switch_to_alt_inheritance_column
|
97
|
+
test_destroy_all_within_inheritance
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_find_first_within_inheritance
|
101
|
+
assert_kind_of Firm, Company.find_first("name = '37signals'")
|
102
|
+
assert_kind_of Firm, Firm.find_first("name = '37signals'")
|
103
|
+
assert_nil Client.find_first("name = '37signals'")
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_alt_find_first_within_inheritance
|
107
|
+
switch_to_alt_inheritance_column
|
108
|
+
test_find_first_within_inheritance
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_complex_inheritance
|
112
|
+
very_special_client = VerySpecialClient.create("name" => "veryspecial")
|
113
|
+
assert_equal very_special_client, VerySpecialClient.find_first("name = 'veryspecial'")
|
114
|
+
assert_equal very_special_client, SpecialClient.find_first("name = 'veryspecial'")
|
115
|
+
assert_equal very_special_client, Company.find_first("name = 'veryspecial'")
|
116
|
+
assert_equal very_special_client, Client.find_first("name = 'veryspecial'")
|
117
|
+
assert_equal 1, Client.find_all("name = 'Summit'").size
|
118
|
+
assert_equal very_special_client, Client.find(very_special_client.id)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_alt_complex_inheritance
|
122
|
+
switch_to_alt_inheritance_column
|
123
|
+
test_complex_inheritance
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# require File.dirname(__FILE__) + '/../dev-utils/eval_debugger'
|
2
|
+
require 'abstract_unit'
|
3
|
+
require 'fixtures/topic'
|
4
|
+
require 'fixtures/developer'
|
5
|
+
|
6
|
+
class Topic; def after_find() end end
|
7
|
+
class Developer; def after_find() end end
|
8
|
+
|
9
|
+
class TopicManualObserver
|
10
|
+
include Singleton
|
11
|
+
|
12
|
+
attr_reader :action, :object, :callbacks
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
Topic.add_observer(self)
|
16
|
+
@callbacks = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def update(callback_method, object)
|
20
|
+
@callbacks << { "callback_method" => callback_method, "object" => object }
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_been_notified?
|
24
|
+
!@callbacks.empty?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class TopicaObserver < ActiveRecord::Observer
|
29
|
+
def self.observed_class() Topic end
|
30
|
+
|
31
|
+
attr_reader :topic
|
32
|
+
|
33
|
+
def after_find(topic)
|
34
|
+
@topic = topic
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class TopicObserver < ActiveRecord::Observer
|
39
|
+
attr_reader :topic
|
40
|
+
|
41
|
+
def after_find(topic)
|
42
|
+
@topic = topic
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class MultiObserver < ActiveRecord::Observer
|
47
|
+
attr_reader :record
|
48
|
+
|
49
|
+
def self.observed_class() [ Topic, Developer ] end
|
50
|
+
|
51
|
+
def after_find(record)
|
52
|
+
@record = record
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class LifecycleTest < Test::Unit::TestCase
|
58
|
+
def setup
|
59
|
+
@topics, @developers = create_fixtures("topics", "developers")
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_before_destroy
|
63
|
+
assert_equal 2, Topic.count
|
64
|
+
Topic.find(1).destroy
|
65
|
+
assert_equal 0, Topic.count
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_after_save
|
69
|
+
topic_observer = TopicManualObserver.instance
|
70
|
+
|
71
|
+
topic = Topic.find(1)
|
72
|
+
topic.title = "hello"
|
73
|
+
topic.save
|
74
|
+
|
75
|
+
assert topic_observer.has_been_notified?
|
76
|
+
assert_equal :after_save, topic_observer.callbacks.last["callback_method"]
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_observer_update_on_save
|
80
|
+
topic_observer = TopicManualObserver.instance
|
81
|
+
|
82
|
+
topic = Topic.find(1)
|
83
|
+
assert topic_observer.has_been_notified?
|
84
|
+
assert_equal :after_find, topic_observer.callbacks.first["callback_method"]
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_auto_observer
|
88
|
+
topic_observer = TopicaObserver.instance
|
89
|
+
|
90
|
+
topic = Topic.find(1)
|
91
|
+
assert_equal topic_observer.topic.title, topic.title
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_infered_auto_observer
|
95
|
+
topic_observer = TopicObserver.instance
|
96
|
+
|
97
|
+
topic = Topic.find(1)
|
98
|
+
assert_equal topic_observer.topic.title, topic.title
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_observing_two_classes
|
102
|
+
multi_observer = MultiObserver.instance
|
103
|
+
|
104
|
+
topic = Topic.find(1)
|
105
|
+
assert_equal multi_observer.record.title, topic.title
|
106
|
+
|
107
|
+
developer = Developer.find(1)
|
108
|
+
assert_equal multi_observer.record.name, developer.name
|
109
|
+
end
|
110
|
+
end
|