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.

Files changed (106) hide show
  1. data/CHANGELOG +581 -0
  2. data/README +361 -0
  3. data/RUNNING_UNIT_TESTS +36 -0
  4. data/dev-utils/eval_debugger.rb +9 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/associations.rb +87 -0
  7. data/examples/shared_setup.rb +15 -0
  8. data/examples/validation.rb +88 -0
  9. data/install.rb +60 -0
  10. data/lib/active_record.rb +48 -0
  11. data/lib/active_record/aggregations.rb +165 -0
  12. data/lib/active_record/associations.rb +536 -0
  13. data/lib/active_record/associations/association_collection.rb +70 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -0
  15. data/lib/active_record/associations/has_many_association.rb +104 -0
  16. data/lib/active_record/base.rb +985 -0
  17. data/lib/active_record/callbacks.rb +337 -0
  18. data/lib/active_record/connection_adapters/abstract_adapter.rb +326 -0
  19. data/lib/active_record/connection_adapters/mysql_adapter.rb +131 -0
  20. data/lib/active_record/connection_adapters/postgresql_adapter.rb +177 -0
  21. data/lib/active_record/connection_adapters/sqlite_adapter.rb +107 -0
  22. data/lib/active_record/deprecated_associations.rb +70 -0
  23. data/lib/active_record/fixtures.rb +172 -0
  24. data/lib/active_record/observer.rb +71 -0
  25. data/lib/active_record/reflection.rb +126 -0
  26. data/lib/active_record/support/class_attribute_accessors.rb +43 -0
  27. data/lib/active_record/support/class_inheritable_attributes.rb +37 -0
  28. data/lib/active_record/support/clean_logger.rb +10 -0
  29. data/lib/active_record/support/inflector.rb +70 -0
  30. data/lib/active_record/transactions.rb +102 -0
  31. data/lib/active_record/validations.rb +205 -0
  32. data/lib/active_record/vendor/mysql.rb +1117 -0
  33. data/lib/active_record/vendor/simple.rb +702 -0
  34. data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
  35. data/lib/active_record/wrappings.rb +59 -0
  36. data/rakefile +122 -0
  37. data/test/abstract_unit.rb +16 -0
  38. data/test/aggregations_test.rb +34 -0
  39. data/test/all.sh +8 -0
  40. data/test/associations_test.rb +477 -0
  41. data/test/base_test.rb +513 -0
  42. data/test/class_inheritable_attributes_test.rb +33 -0
  43. data/test/connections/native_mysql/connection.rb +24 -0
  44. data/test/connections/native_postgresql/connection.rb +24 -0
  45. data/test/connections/native_sqlite/connection.rb +24 -0
  46. data/test/deprecated_associations_test.rb +336 -0
  47. data/test/finder_test.rb +67 -0
  48. data/test/fixtures/accounts/signals37 +3 -0
  49. data/test/fixtures/accounts/unknown +2 -0
  50. data/test/fixtures/auto_id.rb +4 -0
  51. data/test/fixtures/column_name.rb +3 -0
  52. data/test/fixtures/companies/first_client +6 -0
  53. data/test/fixtures/companies/first_firm +4 -0
  54. data/test/fixtures/companies/second_client +6 -0
  55. data/test/fixtures/company.rb +37 -0
  56. data/test/fixtures/company_in_module.rb +33 -0
  57. data/test/fixtures/course.rb +3 -0
  58. data/test/fixtures/courses/java +2 -0
  59. data/test/fixtures/courses/ruby +2 -0
  60. data/test/fixtures/customer.rb +30 -0
  61. data/test/fixtures/customers/david +6 -0
  62. data/test/fixtures/db_definitions/mysql.sql +96 -0
  63. data/test/fixtures/db_definitions/mysql2.sql +4 -0
  64. data/test/fixtures/db_definitions/postgresql.sql +113 -0
  65. data/test/fixtures/db_definitions/postgresql2.sql +4 -0
  66. data/test/fixtures/db_definitions/sqlite.sql +85 -0
  67. data/test/fixtures/db_definitions/sqlite2.sql +4 -0
  68. data/test/fixtures/default.rb +2 -0
  69. data/test/fixtures/developer.rb +8 -0
  70. data/test/fixtures/developers/david +2 -0
  71. data/test/fixtures/developers/jamis +2 -0
  72. data/test/fixtures/developers_projects/david_action_controller +2 -0
  73. data/test/fixtures/developers_projects/david_active_record +2 -0
  74. data/test/fixtures/developers_projects/jamis_active_record +2 -0
  75. data/test/fixtures/entrant.rb +3 -0
  76. data/test/fixtures/entrants/first +3 -0
  77. data/test/fixtures/entrants/second +3 -0
  78. data/test/fixtures/entrants/third +3 -0
  79. data/test/fixtures/fixture_database.sqlite +0 -0
  80. data/test/fixtures/fixture_database_2.sqlite +0 -0
  81. data/test/fixtures/movie.rb +5 -0
  82. data/test/fixtures/movies/first +2 -0
  83. data/test/fixtures/movies/second +2 -0
  84. data/test/fixtures/project.rb +3 -0
  85. data/test/fixtures/projects/action_controller +2 -0
  86. data/test/fixtures/projects/active_record +2 -0
  87. data/test/fixtures/reply.rb +21 -0
  88. data/test/fixtures/subscriber.rb +5 -0
  89. data/test/fixtures/subscribers/first +2 -0
  90. data/test/fixtures/subscribers/second +2 -0
  91. data/test/fixtures/topic.rb +20 -0
  92. data/test/fixtures/topics/first +9 -0
  93. data/test/fixtures/topics/second +8 -0
  94. data/test/fixtures_test.rb +20 -0
  95. data/test/inflector_test.rb +104 -0
  96. data/test/inheritance_test.rb +125 -0
  97. data/test/lifecycle_test.rb +110 -0
  98. data/test/modules_test.rb +21 -0
  99. data/test/multiple_db_test.rb +46 -0
  100. data/test/pk_test.rb +57 -0
  101. data/test/reflection_test.rb +78 -0
  102. data/test/thread_safety_test.rb +33 -0
  103. data/test/transactions_test.rb +83 -0
  104. data/test/unconnected_test.rb +24 -0
  105. data/test/validations_test.rb +126 -0
  106. metadata +166 -0
@@ -0,0 +1,4 @@
1
+ CREATE TABLE 'courses' (
2
+ 'id' INTEGER NOT NULL PRIMARY KEY,
3
+ 'name' VARCHAR(255) NOT NULL
4
+ );
@@ -0,0 +1,2 @@
1
+ class Default < ActiveRecord::Base
2
+ end
@@ -0,0 +1,8 @@
1
+ class Developer < ActiveRecord::Base
2
+ has_and_belongs_to_many :projects
3
+
4
+ protected
5
+ def validate
6
+ errors.add_on_boundry_breaking("name", 3..20)
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ id => 1
2
+ name => David
@@ -0,0 +1,2 @@
1
+ id => 2
2
+ name => Jamis
@@ -0,0 +1,2 @@
1
+ developer_id => 1
2
+ project_id => 2
@@ -0,0 +1,2 @@
1
+ developer_id => 1
2
+ project_id => 1
@@ -0,0 +1,2 @@
1
+ developer_id => 2
2
+ project_id => 1
@@ -0,0 +1,3 @@
1
+ class Entrant < ActiveRecord::Base
2
+ belongs_to :course
3
+ end
@@ -0,0 +1,3 @@
1
+ id => 1
2
+ course_id => 1
3
+ name => Ruby Developer
@@ -0,0 +1,3 @@
1
+ id => 2
2
+ course_id => 1
3
+ name => Ruby Guru
@@ -0,0 +1,3 @@
1
+ id => 3
2
+ course_id => 2
3
+ name => Java Lover
@@ -0,0 +1,5 @@
1
+ class Movie < ActiveRecord::Base
2
+ def self.primary_key
3
+ "movieid"
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ movieid => 1
2
+ name => Terminator
@@ -0,0 +1,2 @@
1
+ movieid => 2
2
+ name => Gladiator
@@ -0,0 +1,3 @@
1
+ class Project < ActiveRecord::Base
2
+ has_and_belongs_to_many :developers
3
+ end
@@ -0,0 +1,2 @@
1
+ id => 2
2
+ name => Active Record
@@ -0,0 +1,2 @@
1
+ id => 1
2
+ name => Active Record
@@ -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,5 @@
1
+ class Subscriber < ActiveRecord::Base
2
+ def self.primary_key
3
+ "nick"
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ nick => alterself
2
+ name => Luke Holden
@@ -0,0 +1,2 @@
1
+ nick => webster132
2
+ name => David Heinemeier Hansson
@@ -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,9 @@
1
+ id => 1
2
+ title => The First Topic
3
+ author_name => David
4
+ author_email_address => david@loudthinking.com
5
+ written_on => 2003-07-16 15:28
6
+ last_read => 2004-04-15
7
+ content => Have a nice day
8
+ approved => 0
9
+ replies_count => 0
@@ -0,0 +1,8 @@
1
+ id => 2
2
+ title => The Second Topic
3
+ author_name => Mary
4
+ written_on => 2003-07-15 15:28
5
+ content => Have a great day!
6
+ approved => 1
7
+ replies_count => 2
8
+ parent_id => 1
@@ -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