datamapper 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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