datamapper 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/CHANGELOG +5 -1
  2. data/FAQ +96 -0
  3. data/QUICKLINKS +12 -0
  4. data/README +57 -155
  5. data/environment.rb +61 -43
  6. data/example.rb +30 -12
  7. data/lib/data_mapper.rb +6 -1
  8. data/lib/data_mapper/adapters/abstract_adapter.rb +0 -57
  9. data/lib/data_mapper/adapters/data_object_adapter.rb +203 -97
  10. data/lib/data_mapper/adapters/mysql_adapter.rb +4 -0
  11. data/lib/data_mapper/adapters/postgresql_adapter.rb +7 -1
  12. data/lib/data_mapper/adapters/sql/coersion.rb +3 -2
  13. data/lib/data_mapper/adapters/sql/commands/load_command.rb +29 -10
  14. data/lib/data_mapper/adapters/sql/mappings/associations_set.rb +4 -0
  15. data/lib/data_mapper/adapters/sql/mappings/column.rb +13 -9
  16. data/lib/data_mapper/adapters/sql/mappings/conditions.rb +172 -0
  17. data/lib/data_mapper/adapters/sql/mappings/table.rb +43 -17
  18. data/lib/data_mapper/adapters/sqlite3_adapter.rb +9 -2
  19. data/lib/data_mapper/associations.rb +75 -3
  20. data/lib/data_mapper/associations/belongs_to_association.rb +70 -36
  21. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +195 -86
  22. data/lib/data_mapper/associations/has_many_association.rb +168 -61
  23. data/lib/data_mapper/associations/has_n_association.rb +23 -3
  24. data/lib/data_mapper/attributes.rb +73 -0
  25. data/lib/data_mapper/auto_migrations.rb +2 -6
  26. data/lib/data_mapper/base.rb +5 -9
  27. data/lib/data_mapper/database.rb +4 -3
  28. data/lib/data_mapper/embedded_value.rb +66 -30
  29. data/lib/data_mapper/identity_map.rb +1 -3
  30. data/lib/data_mapper/is/tree.rb +121 -0
  31. data/lib/data_mapper/migration.rb +155 -0
  32. data/lib/data_mapper/persistence.rb +532 -218
  33. data/lib/data_mapper/property.rb +306 -0
  34. data/lib/data_mapper/query.rb +164 -0
  35. data/lib/data_mapper/support/blank.rb +2 -2
  36. data/lib/data_mapper/support/connection_pool.rb +5 -6
  37. data/lib/data_mapper/support/enumerable.rb +3 -3
  38. data/lib/data_mapper/support/errors.rb +10 -1
  39. data/lib/data_mapper/support/inflector.rb +174 -238
  40. data/lib/data_mapper/support/object.rb +54 -0
  41. data/lib/data_mapper/support/serialization.rb +19 -1
  42. data/lib/data_mapper/support/string.rb +7 -16
  43. data/lib/data_mapper/support/symbol.rb +3 -15
  44. data/lib/data_mapper/support/typed_set.rb +68 -0
  45. data/lib/data_mapper/types/base.rb +44 -0
  46. data/lib/data_mapper/types/string.rb +34 -0
  47. data/lib/data_mapper/validations/number_validator.rb +40 -0
  48. data/lib/data_mapper/validations/string_validator.rb +20 -0
  49. data/lib/data_mapper/validations/validator.rb +13 -0
  50. data/performance.rb +26 -1
  51. data/profile_data_mapper.rb +1 -1
  52. data/rakefile.rb +42 -2
  53. data/spec/acts_as_tree_spec.rb +11 -3
  54. data/spec/adapters/data_object_adapter_spec.rb +31 -0
  55. data/spec/associations/belongs_to_association_spec.rb +98 -0
  56. data/spec/associations/has_and_belongs_to_many_association_spec.rb +377 -0
  57. data/spec/associations/has_many_association_spec.rb +337 -0
  58. data/spec/attributes_spec.rb +23 -1
  59. data/spec/auto_migrations_spec.rb +86 -29
  60. data/spec/callbacks_spec.rb +107 -0
  61. data/spec/column_spec.rb +5 -2
  62. data/spec/count_command_spec.rb +33 -1
  63. data/spec/database_spec.rb +18 -0
  64. data/spec/dependency_spec.rb +4 -2
  65. data/spec/embedded_value_spec.rb +8 -8
  66. data/spec/fixtures/people.yaml +1 -1
  67. data/spec/fixtures/projects.yaml +10 -1
  68. data/spec/fixtures/tasks.yaml +6 -0
  69. data/spec/fixtures/tasks_tasks.yaml +2 -0
  70. data/spec/fixtures/tomatoes.yaml +1 -0
  71. data/spec/is_a_tree_spec.rb +149 -0
  72. data/spec/load_command_spec.rb +71 -9
  73. data/spec/magic_columns_spec.rb +17 -2
  74. data/spec/migration_spec.rb +267 -0
  75. data/spec/models/animal.rb +1 -1
  76. data/spec/models/candidate.rb +8 -0
  77. data/spec/models/career.rb +1 -1
  78. data/spec/models/chain.rb +8 -0
  79. data/spec/models/comment.rb +1 -1
  80. data/spec/models/exhibit.rb +1 -1
  81. data/spec/models/fence.rb +7 -0
  82. data/spec/models/fruit.rb +2 -2
  83. data/spec/models/job.rb +8 -0
  84. data/spec/models/person.rb +2 -3
  85. data/spec/models/post.rb +1 -1
  86. data/spec/models/project.rb +21 -1
  87. data/spec/models/section.rb +1 -1
  88. data/spec/models/serializer.rb +1 -1
  89. data/spec/models/task.rb +9 -0
  90. data/spec/models/tomato.rb +27 -0
  91. data/spec/models/user.rb +8 -2
  92. data/spec/models/zoo.rb +2 -7
  93. data/spec/paranoia_spec.rb +1 -1
  94. data/spec/{base_spec.rb → persistence_spec.rb} +207 -18
  95. data/spec/postgres_spec.rb +48 -6
  96. data/spec/property_spec.rb +90 -9
  97. data/spec/query_spec.rb +71 -5
  98. data/spec/save_command_spec.rb +11 -0
  99. data/spec/spec_helper.rb +14 -11
  100. data/spec/support/blank_spec.rb +8 -0
  101. data/spec/support/inflector_spec.rb +41 -0
  102. data/spec/support/object_spec.rb +9 -0
  103. data/spec/{serialization_spec.rb → support/serialization_spec.rb} +1 -1
  104. data/spec/support/silence_spec.rb +15 -0
  105. data/spec/{support_spec.rb → support/string_spec.rb} +3 -3
  106. data/spec/support/struct_spec.rb +12 -0
  107. data/spec/support/typed_set_spec.rb +66 -0
  108. data/spec/table_spec.rb +3 -3
  109. data/spec/types/string.rb +81 -0
  110. data/spec/validates_uniqueness_of_spec.rb +17 -0
  111. data/spec/validations/number_validator.rb +59 -0
  112. data/spec/validations/string_validator.rb +14 -0
  113. metadata +59 -17
  114. data/do_performance.rb +0 -153
  115. data/lib/data_mapper/support/active_record_impersonation.rb +0 -103
  116. data/lib/data_mapper/support/weak_hash.rb +0 -46
  117. data/spec/active_record_impersonation_spec.rb +0 -129
  118. data/spec/associations_spec.rb +0 -232
  119. data/spec/conditions_spec.rb +0 -49
  120. data/spec/has_many_association_spec.rb +0 -173
  121. data/spec/models/animals_exhibit.rb +0 -8
@@ -1,5 +1,53 @@
1
1
  require File.dirname(__FILE__) + "/spec_helper"
2
2
 
3
+ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
4
+
5
+ def conditions_for(klass, options = {})
6
+ database_context = database(:mock)
7
+ DataMapper::Adapters::Sql::Commands::LoadCommand.new(
8
+ database_context.adapter, database_context, klass, options
9
+ ).conditions
10
+ end
11
+
12
+ it 'empty? should be false if conditions are present' do
13
+ conditions_for(Zoo, :name => 'Galveston').should_not be_empty
14
+ end
15
+
16
+ it 'should map implicit option names to field names' do
17
+ conditions_for(Zoo, :name => 'Galveston').should eql([["`name` = ?", 'Galveston']])
18
+ end
19
+
20
+ it 'should qualify with table name when using a join' do
21
+ conditions_for(Zoo, :name => 'Galveston', :include => :exhibits).should eql([["`zoos`.`name` = ?", 'Galveston']])
22
+ end
23
+
24
+ it 'should use Symbol::Operator to determine operator' do
25
+ conditions_for(Person, :age.gt => 28).should eql([["`age` > ?", 28]])
26
+ conditions_for(Person, :age.gte => 28).should eql([["`age` >= ?", 28]])
27
+
28
+ conditions_for(Person, :age.lt => 28).should eql([["`age` < ?", 28]])
29
+ conditions_for(Person, :age.lte => 28).should eql([["`age` <= ?", 28]])
30
+
31
+ conditions_for(Person, :age.not => 28).should eql([["`age` <> ?", 28]])
32
+ conditions_for(Person, :age.eql => 28).should eql([["`age` = ?", 28]])
33
+
34
+ conditions_for(Person, :name.like => 'S%').should eql([["`name` LIKE ?", 'S%']])
35
+
36
+ conditions_for(Person, :age.in => [ 28, 29 ]).should eql([["`age` IN ?", [ 28, 29 ]]])
37
+ end
38
+
39
+ it 'should use an IN clause for an Array' do
40
+ conditions_for(Person, :age => [ 28, 29 ]).should eql([["`age` IN ?", [ 28, 29 ]]])
41
+ end
42
+
43
+ it 'should use "not" for not-equal operations' do
44
+ conditions_for(Person, :name.not => 'Bob').should eql([["`name` <> ?", 'Bob']])
45
+ conditions_for(Person, :name.not => nil).should eql([["`name` IS NOT ?", nil]])
46
+ conditions_for(Person, :name.not => ['Sam', 'Bob']).should eql([["`name` NOT IN ?", ['Sam', 'Bob']]])
47
+ end
48
+
49
+ end
50
+
3
51
  describe DataMapper::Adapters::Sql::Commands::LoadCommand do
4
52
 
5
53
  before(:all) do
@@ -202,14 +250,20 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
202
250
  end
203
251
  end
204
252
 
205
- it "should return in order" do
206
- fixtures(:posts)
207
-
208
- one = Post.first
209
- one.title.should eql('One')
210
- two = one.next
211
- two.title.should eql('Two')
212
- one.next.next.previous.previous.next.previous.next.next.title.should eql('Three')
253
+ # it "should return in order" do
254
+ # pending("This spec is silly, and nothing but trouble since it depends on the table's clustered index. :-p")
255
+ # fixtures(:posts)
256
+ #
257
+ # one = Post.first
258
+ # one.title.should eql('One')
259
+ # two = one.next
260
+ # two.title.should eql('Two')
261
+ # one.next.next.previous.previous.next.previous.next.next.title.should eql('Three')
262
+ # end
263
+
264
+ it "should allow both implicit :conditions and explicit in the same finder" do
265
+ cup = Animal.first(:name => 'Cup', :conditions => ['name <> ?', 'Frog'])
266
+ cup.should == Animal[cup.key]
213
267
  end
214
268
 
215
269
  it "should iterate in batches" do
@@ -221,7 +275,15 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
221
275
  count += 1
222
276
  end
223
277
 
224
- count.should == total
278
+ count.should == total
279
+
280
+ count = 0
281
+
282
+ Animal.each(:order => "id asc", :conditions => ["id > ? AND id < ?", 0, 9985], :limit => 2) do |animal|
283
+ count += 1
284
+ end
285
+
286
+ count.should == total
225
287
  end
226
288
 
227
289
  it "should get the right object back" do
@@ -1,11 +1,26 @@
1
1
  require File.dirname(__FILE__) + "/spec_helper"
2
2
 
3
3
  describe "Magic Columns" do
4
-
4
+
5
5
  it "should update updated_at on save" do
6
6
  zoo = Zoo.new(:name => 'Mary')
7
7
  zoo.save
8
8
  zoo.updated_at.should be_a_kind_of(Time)
9
9
  end
10
-
10
+
11
+ it "should not update created_at when updating a model" do
12
+ section = Section.create(:title => "Mars")
13
+ old_created_at = section.created_at
14
+ section.update_attributes(:title => "Mars2!")
15
+ section.created_at.should eql(old_created_at)
16
+ end
17
+
18
+ it "should not set the created_at/on fields if already set on creation" do
19
+ section = Section.new(:title => "Mars")
20
+ fixed_created_at = Time::now - 2600
21
+ section.created_at = fixed_created_at
22
+ section.save
23
+ section.created_at.should eql(fixed_created_at)
24
+ end
25
+
11
26
  end
@@ -0,0 +1,267 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+ require File.dirname(__FILE__) + "/../lib/data_mapper/migration"
3
+
4
+ class MigrationUser
5
+ include DataMapper::Persistence
6
+
7
+ property :name, :string
8
+ property :login, :string
9
+
10
+ end
11
+
12
+ def check_schema
13
+ case ENV['ADAPTER']
14
+ when 'postgresql'
15
+ result = database.query("
16
+ SELECT table_name, column_name FROM information_schema.columns WHERE table_name = 'migration_users'
17
+ ").join(", ")
18
+ result.blank? ? nil : result
19
+ when 'mysql'
20
+ begin
21
+ database.query("SHOW CREATE TABLE migration_users")[0]["create table"]
22
+ rescue Exception => e
23
+ raise e unless e.message.match(/Table.*doesn\'t exist/)
24
+ end
25
+ else
26
+ database.query("
27
+ SELECT sql FROM
28
+ (SELECT * FROM sqlite_master UNION ALL
29
+ SELECT * FROM sqlite_temp_master)
30
+ WHERE name = 'migration_users'
31
+ ORDER BY substr(type,2,1), name
32
+ ")[0]
33
+ end
34
+ end
35
+
36
+ describe DataMapper::Migration do
37
+
38
+ class AddUsers < DataMapper::Migration
39
+ def self.up
40
+ table :migration_users do # sees that the users table does not exist and so creates the table
41
+ add :name, :string
42
+ add :login, :string
43
+ end
44
+ end
45
+
46
+ def self.down
47
+ table.drop :migration_users
48
+ end
49
+ end
50
+
51
+ class AddPasswordToUsers < DataMapper::Migration
52
+ def self.up
53
+ table :migration_users do
54
+ add :password, :string
55
+ end
56
+ end
57
+
58
+ def self.down
59
+ table :migration_users do
60
+ remove :password
61
+ end
62
+ end
63
+ end
64
+
65
+ class RenameLoginOnUsers < DataMapper::Migration
66
+ def self.up
67
+ table :migration_users do
68
+ rename :login, :username
69
+ end
70
+ end
71
+
72
+ def self.down
73
+ table :migration_users do
74
+ rename :username, :login
75
+ end
76
+ end
77
+ end
78
+
79
+ class AlterLoginOnUsers < DataMapper::Migration
80
+ def self.up
81
+ table :migration_users do
82
+ alter :login, :text, :nullable => false, :default => "username"
83
+ end
84
+ end
85
+
86
+ def self.down
87
+ table :migration_users do
88
+ alter :login, :string
89
+ end
90
+ end
91
+ end
92
+
93
+ it "should migrate up creating a table with its columns" do
94
+ AddUsers.migrate(:up)
95
+ database.table_exists?(MigrationUser).should be_true
96
+ check_schema.should match(/migration_users/)
97
+ check_schema.should match(/name|login/)
98
+ user = MigrationUser.new(:name => "test", :login => "username")
99
+ user.save.should be_true
100
+ MigrationUser.first.should == user
101
+ end
102
+
103
+ it "should migrate down deleting the created table" do
104
+ AddUsers.migrate(:down)
105
+ check_schema.should be_nil
106
+ database.table_exists?(MigrationUser).should == false
107
+ end
108
+
109
+ it "should migrate up altering a table to add a column" do
110
+ AddUsers.migrate(:up)
111
+ AddPasswordToUsers.migrate(:up)
112
+ table = database.table(MigrationUser)
113
+ table[:password].should_not be_nil
114
+ end
115
+
116
+ it "should migrate down altering a table to remove a column" do
117
+ check_schema.should match(/password/)
118
+ AddPasswordToUsers.migrate(:down)
119
+ check_schema.should_not match(/password/)
120
+ table = database.table(MigrationUser)
121
+ table[:password].should be_nil
122
+ AddUsers.migrate(:down)
123
+ end
124
+
125
+ it "should migrate up renaming a column" do
126
+ AddUsers.migrate(:up)
127
+ user = MigrationUser.create(:name => "Sam", :login => "sammy")
128
+ RenameLoginOnUsers.migrate(:up)
129
+ class MigrationUser
130
+ property :username, :string
131
+ end
132
+ check_schema.should match(/username/)
133
+ check_schema.should_not match(/login/)
134
+ MigrationUser.first.username.should == user.login
135
+ end
136
+
137
+ it "should migrate down renaming a column" do
138
+ user = MigrationUser.first
139
+ RenameLoginOnUsers.migrate(:down)
140
+ check_schema.should_not match(/username/)
141
+ check_schema.should match(/login/)
142
+ MigrationUser.first.login.should == user.username
143
+ AddUsers.migrate(:down)
144
+ end
145
+
146
+ it "should migrate up altering a column" do
147
+ AddUsers.migrate(:up)
148
+ AlterLoginOnUsers.migrate(:up)
149
+ column = database.table(MigrationUser)[:login]
150
+ column.type.should == :text
151
+ column.nullable?.should be_false
152
+ column.default.should == "username"
153
+ end
154
+
155
+ it "should migrate down altering a column" do
156
+ AlterLoginOnUsers.migrate(:down)
157
+ column = database.table(MigrationUser)[:login]
158
+ column.type.should == :string
159
+ column.nullable?.should be_true
160
+ column.default.should be_nil
161
+ AddUsers.migrate(:down)
162
+ end
163
+ end
164
+
165
+ describe "DataMapper::Migration [RAILS]" do
166
+ class RailsAddUsers < DataMapper::Migration
167
+ def self.up
168
+ create_table :migration_users do |t|
169
+ t.column :name, :string
170
+ t.column :login, :string
171
+ end
172
+ end
173
+
174
+ def self.down
175
+ drop_table :migration_users
176
+ end
177
+ end
178
+
179
+ class RailsAddPasswordToUsers < DataMapper::Migration
180
+ def self.up
181
+ add_column :migration_users, :password, :string
182
+ end
183
+
184
+ def self.down
185
+ remove_column :migration_users, :password
186
+ end
187
+ end
188
+
189
+ class RailsRenameLoginOnUsers < DataMapper::Migration
190
+ def self.up
191
+ rename_column :migration_users, :login, :username
192
+ end
193
+
194
+ def self.down
195
+ rename_column :migration_users, :username, :login
196
+ end
197
+ end
198
+
199
+ class RailsAlterLoginOnUsers < DataMapper::Migration
200
+ def self.up
201
+ change_column :migration_users, :login, :text, :nullable => false, :default => "username"
202
+ end
203
+
204
+ def self.down
205
+ change_column :migration_users, :login, :string
206
+ end
207
+ end
208
+
209
+ it "should migrate up creating a table with its columns" do
210
+ RailsAddUsers.migrate(:up)
211
+ database.table_exists?(MigrationUser).should be_true
212
+ check_schema.should match(/migration_users/)
213
+ check_schema.should match(/name|login/)
214
+ end
215
+
216
+ it "should migrate down deleting the created table" do
217
+ RailsAddUsers.migrate(:down)
218
+ database.table_exists?(MigrationUser).should be_false
219
+ check_schema.should be_nil
220
+ end
221
+
222
+ it "should migrate up altering a table to add a column" do
223
+ RailsAddUsers.migrate(:up)
224
+ RailsAddPasswordToUsers.migrate(:up)
225
+ check_schema.should match(/password/)
226
+ end
227
+
228
+ it "should migrate down altering a table to remove a column" do
229
+ RailsAddPasswordToUsers.migrate(:down)
230
+ check_schema.should_not match(/password/)
231
+ table = database.table(MigrationUser)
232
+ table[:password].should be_nil
233
+ RailsAddUsers.migrate(:down)
234
+ end
235
+
236
+ it "should migrate up renaming a column" do
237
+ RailsAddUsers.migrate(:up)
238
+ RailsRenameLoginOnUsers.migrate(:up)
239
+ check_schema.should match(/username/)
240
+ check_schema.should_not match(/login/)
241
+ end
242
+
243
+ it "should migrate down renaming a column" do
244
+ RailsRenameLoginOnUsers.migrate(:down)
245
+ check_schema.should match(/login/)
246
+ check_schema.should_not match(/username/)
247
+ RailsAddUsers.migrate(:down)
248
+ end
249
+
250
+ it "should migrate up altering a column" do
251
+ AddUsers.migrate(:up)
252
+ RailsAlterLoginOnUsers.migrate(:up)
253
+ column = database.table(MigrationUser)[:login]
254
+ column.type.should == :text
255
+ column.nullable?.should be_false
256
+ column.default.should == "username"
257
+ end
258
+
259
+ it "should migrate down altering a column" do
260
+ RailsAlterLoginOnUsers.migrate(:down)
261
+ column = database.table(MigrationUser)[:login]
262
+ column.type.should == :string
263
+ column.nullable?.should be_true
264
+ column.default.should be_nil
265
+ AddUsers.migrate(:down)
266
+ end
267
+ end
@@ -1,4 +1,4 @@
1
- class Animal #< DataMapper::Base
1
+ class Animal #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :name, :string, :default => "No Name", :index => :unique
@@ -0,0 +1,8 @@
1
+ class Candidate #< DataMapper::Base # please do not remove this
2
+ include DataMapper::Persistence
3
+
4
+ property :name, :string
5
+
6
+ belongs_to :job
7
+ has_and_belongs_to_many :applications, :class => 'Job', :join_table => "applications_candidates"
8
+ end
@@ -1,4 +1,4 @@
1
- class Career #< DataMapper::Base
1
+ class Career #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :name, :string, :key => true
@@ -0,0 +1,8 @@
1
+ class Chain #< DataMapper::Base # please do not remove this
2
+ include DataMapper::Persistence
3
+
4
+ property :name, :string
5
+
6
+ belongs_to :fence
7
+ #has_and_belongs_to_many :chains # do not remove this
8
+ end
@@ -1,4 +1,4 @@
1
- class Comment #< DataMapper::Base
1
+ class Comment #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :comment, :text, :lazy => false
@@ -1,4 +1,4 @@
1
- class Exhibit #< DataMapper::Base
1
+ class Exhibit #< DataMapper::Base # please do not remove this
2
2
  include DataMapper::Persistence
3
3
 
4
4
  property :name, :string
@@ -0,0 +1,7 @@
1
+ class Fence #< DataMapper::Base # please do not remove this
2
+ include DataMapper::Persistence
3
+
4
+ property :name, :string
5
+
6
+ #has_many :chains # do not remove
7
+ end