datamapper 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/CHANGELOG +16 -1
  2. data/README +10 -8
  3. data/environment.rb +1 -1
  4. data/example.rb +13 -5
  5. data/lib/data_mapper.rb +2 -0
  6. data/lib/data_mapper/adapters/abstract_adapter.rb +61 -0
  7. data/lib/data_mapper/adapters/data_object_adapter.rb +33 -6
  8. data/lib/data_mapper/adapters/mysql_adapter.rb +5 -0
  9. data/lib/data_mapper/adapters/postgresql_adapter.rb +12 -0
  10. data/lib/data_mapper/adapters/sql/commands/load_command.rb +6 -14
  11. data/lib/data_mapper/adapters/sql/mappings/column.rb +37 -26
  12. data/lib/data_mapper/adapters/sql/mappings/table.rb +50 -8
  13. data/lib/data_mapper/associations.rb +4 -5
  14. data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +2 -2
  15. data/lib/data_mapper/associations/has_many_association.rb +40 -13
  16. data/lib/data_mapper/associations/has_n_association.rb +1 -1
  17. data/lib/data_mapper/base.rb +5 -448
  18. data/lib/data_mapper/callbacks.rb +12 -2
  19. data/lib/data_mapper/context.rb +4 -0
  20. data/lib/data_mapper/database.rb +1 -1
  21. data/lib/data_mapper/identity_map.rb +2 -2
  22. data/lib/data_mapper/persistence.rb +538 -0
  23. data/lib/data_mapper/support/active_record_impersonation.rb +21 -3
  24. data/lib/data_mapper/support/errors.rb +2 -0
  25. data/lib/data_mapper/support/serialization.rb +7 -10
  26. data/lib/data_mapper/support/struct.rb +7 -0
  27. data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +11 -4
  28. data/performance.rb +23 -10
  29. data/rakefile.rb +1 -1
  30. data/spec/active_record_impersonation_spec.rb +2 -6
  31. data/spec/acts_as_tree_spec.rb +3 -1
  32. data/spec/associations_spec.rb +40 -160
  33. data/spec/attributes_spec.rb +1 -1
  34. data/spec/base_spec.rb +41 -13
  35. data/spec/callbacks_spec.rb +32 -0
  36. data/spec/coersion_spec.rb +1 -1
  37. data/spec/column_spec.rb +22 -12
  38. data/spec/dependency_spec.rb +5 -3
  39. data/spec/embedded_value_spec.rb +33 -17
  40. data/spec/has_many_association_spec.rb +173 -0
  41. data/spec/legacy_spec.rb +2 -2
  42. data/spec/load_command_spec.rb +59 -7
  43. data/spec/models/animal.rb +6 -2
  44. data/spec/models/animals_exhibit.rb +3 -1
  45. data/spec/models/career.rb +2 -1
  46. data/spec/models/comment.rb +3 -1
  47. data/spec/models/exhibit.rb +3 -1
  48. data/spec/models/fruit.rb +3 -1
  49. data/spec/models/person.rb +10 -1
  50. data/spec/models/post.rb +3 -1
  51. data/spec/models/project.rb +3 -1
  52. data/spec/models/section.rb +3 -1
  53. data/spec/models/serializer.rb +3 -1
  54. data/spec/models/user.rb +3 -1
  55. data/spec/models/zoo.rb +3 -1
  56. data/spec/paranoia_spec.rb +3 -1
  57. data/spec/postgres_spec.rb +54 -0
  58. data/spec/save_command_spec.rb +9 -5
  59. data/spec/schema_spec.rb +0 -91
  60. data/spec/single_table_inheritance_spec.rb +8 -0
  61. data/spec/table_spec.rb +46 -0
  62. data/spec/validates_uniqueness_of_spec.rb +19 -1
  63. metadata +8 -10
  64. data/lib/data_mapper/associations/has_one_association.rb +0 -77
  65. data/plugins/dataobjects/do_rb +0 -0
data/spec/legacy_spec.rb CHANGED
@@ -8,8 +8,8 @@ describe 'Legacy mappings' do
8
8
 
9
9
  it('should allow custom foreign-key mappings') do
10
10
  database do
11
- Fruit[:name => 'Watermelon'].devourer_of_souls.should == Animal[:name => 'Cup']
12
- Animal[:name => 'Cup'].favourite_fruit.should == Fruit[:name => 'Watermelon']
11
+ Fruit.first(:name => 'Watermelon').devourer_of_souls.should == Animal.first(:name => 'Cup')
12
+ Animal.first(:name => 'Cup').favourite_fruit.should == Fruit.first(:name => 'Watermelon')
13
13
  end
14
14
  end
15
15
 
@@ -5,6 +5,11 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
5
5
  before(:all) do
6
6
  fixtures(:zoos)
7
7
  fixtures(:animals)
8
+ fixtures(:people)
9
+ end
10
+
11
+ after(:all) do
12
+ fixtures(:people)
8
13
  end
9
14
 
10
15
  def loader_for(klass, options = {})
@@ -109,7 +114,7 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
109
114
  zebra = Animal.first(:name => 'Zebra')
110
115
  zebra.name.should == 'Zebra'
111
116
 
112
- elephant = Animal[:name => 'Elephant']
117
+ elephant = Animal.first(:name => 'Elephant')
113
118
  elephant.name.should == 'Elephant'
114
119
 
115
120
  aged = Person.all(:age => 29)
@@ -122,18 +127,18 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
122
127
 
123
128
  it 'should not find deleted objects' do
124
129
  database do
125
- wally = Animal[:name => 'Whale']
130
+ wally = Animal.first(:name => 'Whale')
126
131
  wally.new_record?.should == false
127
132
  wally.destroy!.should == true
128
133
 
129
- wallys_evil_twin = Animal[:name => 'Whale']
134
+ wallys_evil_twin = Animal.first(:name => 'Whale')
130
135
  wallys_evil_twin.should == nil
131
136
 
132
137
  wally.new_record?.should == true
133
138
  wally.save
134
139
  wally.new_record?.should == false
135
140
 
136
- Animal[:name => 'Whale'].should == wally
141
+ Animal.first(:name => 'Whale').should == wally
137
142
  end
138
143
  end
139
144
 
@@ -160,6 +165,22 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
160
165
  Zoo.find(1).should be_a_kind_of(Zoo)
161
166
  end
162
167
 
168
+ # TICKET: http://wm.lighthouseapp.com/projects/4819-datamapper/tickets/90
169
+ it "should return a CLEAN object" do
170
+ Animal[2].should_not be_dirty
171
+ Animal.first(:name => 'Cup').should_not be_dirty
172
+ end
173
+
174
+ it "should retrieve altered integer columns correctly" do
175
+ pending "see http://wm.lighthouseapp.com/projects/4819-datamapper/tickets/95"
176
+ sam = Person.first
177
+ sam.age = 6471561394
178
+ sam.save
179
+ sam.reload
180
+ sam.original_values[:age].should == 6471561394
181
+ sam.age.should == 6471561394
182
+ end
183
+
163
184
  it "should be able to search on UTF-8 strings" do
164
185
  Zoo.create(:name => 'Danish Vowels: Smoot!') # øø
165
186
  Zoo.first(:name.like => '%Smoot%').should be_a_kind_of(Zoo)
@@ -175,9 +196,11 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
175
196
  end
176
197
 
177
198
  # See the comment in dataobjects_spec for why this is failing
178
- it "should return nil when finding by id, and the id is not present and/or invalid" do
179
- Zoo.find(nil).should be_nil
180
- end
199
+ unless ENV["ADAPTER"] == "mysql"
200
+ it "should return nil when finding by id, and the id is not present and/or invalid" do
201
+ Zoo.find(nil).should be_nil
202
+ end
203
+ end
181
204
 
182
205
  it "should return in order" do
183
206
  fixtures(:posts)
@@ -188,6 +211,35 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
188
211
  two.title.should eql('Two')
189
212
  one.next.next.previous.previous.next.previous.next.next.title.should eql('Three')
190
213
  end
214
+
215
+ it "should iterate in batches" do
216
+
217
+ total = Animal.count
218
+ count = 0
219
+
220
+ Animal.each(:name.not => nil) do |animal|
221
+ count += 1
222
+ end
223
+
224
+ count.should == total
225
+ end
226
+
227
+ it "should get the right object back" do
228
+ a = Animal.first(:name => 'Cup')
229
+ Animal.get(a.id).should == a
230
+
231
+ b = Person.first(:name => 'Amy')
232
+ Person.get(b.id).should == b
233
+
234
+ c = Person.first(:name => 'Bob')
235
+ Person.get(c.id).should == c
236
+
237
+ database.execute("UPDATE people SET type = ? WHERE name = ?", nil, "Bob")
238
+
239
+ d = Person.first(:name => 'Bob')
240
+ Person.get(d.id).should == d
241
+ end
242
+
191
243
  end
192
244
 
193
245
  =begin
@@ -1,8 +1,12 @@
1
- class Animal < DataMapper::Base
2
- property :name, :string, :default => "No Name"
1
+ class Animal #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
4
+ property :name, :string, :default => "No Name", :index => :unique
3
5
  property :notes, :text
4
6
  property :nice, :boolean
5
7
 
6
8
  has_one :favourite_fruit, :class => 'Fruit', :foreign_key => 'devourer_id'
7
9
  has_and_belongs_to_many :exhibits
10
+
11
+ DEFAULT_LIMIT = 5
8
12
  end
@@ -1,6 +1,8 @@
1
1
  # This is just here to get around the fact I use a Class to load
2
2
  # fixtures right now.
3
- class AnimalsExhibit < DataMapper::Base
3
+ class AnimalsExhibit #< DataMapper::Base
4
+ include DataMapper::Persistence
5
+
4
6
  property :animal_id, :integer, :key => true
5
7
  property :exhibit_id, :integer, :key => true
6
8
  end
@@ -1,4 +1,5 @@
1
- class Career < DataMapper::Base
1
+ class Career #< DataMapper::Base
2
+ include DataMapper::Persistence
2
3
 
3
4
  property :name, :string, :key => true
4
5
 
@@ -1,4 +1,6 @@
1
- class Comment < DataMapper::Base
1
+ class Comment #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :comment, :text, :lazy => false
3
5
  belongs_to :author, :class => 'User', :foreign_key => 'user_id'
4
6
  end
@@ -1,4 +1,6 @@
1
- class Exhibit < DataMapper::Base
1
+ class Exhibit #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :name, :string
3
5
 
4
6
  begin
data/spec/models/fruit.rb CHANGED
@@ -1,4 +1,6 @@
1
- class Fruit < DataMapper::Base
1
+ class Fruit #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  set_table_name 'fruit'
3
5
  property :name, :string, :column => 'fruit_name'
4
6
 
@@ -1,4 +1,6 @@
1
- class Person < DataMapper::Base
1
+ class Person #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :name, :string
3
5
  property :age, :integer
4
6
  property :occupation, :string
@@ -19,4 +21,11 @@ class Person < DataMapper::Base
19
21
  end
20
22
 
21
23
  belongs_to :career
24
+
25
+ before_save :before_save_callback
26
+
27
+ def before_save_callback
28
+ @notes = "Lorem ipsum dolor sit amet"
29
+ end
30
+
22
31
  end
data/spec/models/post.rb CHANGED
@@ -1,4 +1,6 @@
1
- class Post < DataMapper::Base
1
+ class Post #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :title, :string
3
5
  property :created_at, :datetime
4
6
 
@@ -1,4 +1,6 @@
1
- class Project < DataMapper::Base
1
+ class Project #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :title, :string
3
5
  property :description, :string
4
6
 
@@ -1,4 +1,6 @@
1
- class Section < DataMapper::Base
1
+ class Section #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :title, :string
3
5
  property :created_at, :datetime
4
6
 
@@ -1,3 +1,5 @@
1
- class Serializer < DataMapper::Base
1
+ class Serializer #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :content, :object, :lazy => false
3
5
  end
data/spec/models/user.rb CHANGED
@@ -1,4 +1,6 @@
1
- class User < DataMapper::Base
1
+ class User #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :name, :string
3
5
  has_many :comments, :class => 'Comment', :foreign_key => 'user_id'
4
6
  end
data/spec/models/zoo.rb CHANGED
@@ -1,4 +1,6 @@
1
- class Zoo < DataMapper::Base
1
+ class Zoo #< DataMapper::Base
2
+ include DataMapper::Persistence
3
+
2
4
  property :name, :string
3
5
  property :notes, :text
4
6
  property :updated_at, :datetime
@@ -3,7 +3,9 @@ require File.dirname(__FILE__) + "/spec_helper"
3
3
  describe 'Paranoia' do
4
4
 
5
5
  before(:all) do
6
- class Scared < DataMapper::Base
6
+ class Scared
7
+ include DataMapper::Persistence
8
+
7
9
  property :name, :string
8
10
  property :deleted_at, :datetime
9
11
  end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ # Only run these specs when the ADAPTER env-variable is set to 'postgresql'
4
+ # You will probably need to set the DATABASE and USERNAME vars as well.
5
+ if ENV['ADAPTER'] == 'postgresql'
6
+
7
+ describe DataMapper::Adapters::PostgresqlAdapter::Mappings::Column do
8
+ it "should be able to set check-constraints on columns" do
9
+ mappings = DataMapper::Adapters::PostgresqlAdapter::Mappings
10
+ table = mappings::Table.new(database(:mock).adapter, "Zebu")
11
+ column = mappings::Column.new(database(:mock).adapter, table, :age,
12
+ :integer, 1, { :check => "age > 18"})
13
+ column.to_long_form.should match(/CHECK \(age > 18\)/)
14
+ end
15
+ end
16
+
17
+ describe DataMapper::Adapters::PostgresqlAdapter::Mappings::Table do
18
+
19
+ before(:all) do
20
+ class Cage < DataMapper::Base
21
+ set_table_name "cages"
22
+ property :name, :string
23
+ end
24
+
25
+ class CageInSchema < DataMapper::Base
26
+ set_table_name "my_schema.cages"
27
+ property :name, :string
28
+ end
29
+ end
30
+
31
+ it "should return a quoted table name for a simple table" do
32
+ table_sql = database.adapter.table(Cage).to_sql
33
+ table_sql.should == "\"cages\""
34
+ end
35
+
36
+ it "should return a quoted schema and table name for a table which specifies a schema" do
37
+ table_sql = database.adapter.table(CageInSchema).to_sql
38
+ table_sql.should == "\"my_schema\".\"cages\""
39
+ end
40
+
41
+ it "should search only the specified schema if qualified" do
42
+ database.save(Cage)
43
+ database.adapter.table(CageInSchema).exists?.should == false
44
+ database.save(CageInSchema)
45
+ database.adapter.table(CageInSchema).exists?.should == true
46
+ end
47
+
48
+ after do
49
+ database.adapter.execute("DROP SCHEMA my_schema CASCADE") rescue nil
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -2,16 +2,20 @@ require File.dirname(__FILE__) + "/spec_helper"
2
2
 
3
3
  describe "Save Commands" do
4
4
 
5
+ before(:all) do
6
+ fixtures(:zoos)
7
+ end
8
+
5
9
  it "should create a new row" do
6
10
  total = Zoo.all.length
7
11
  Zoo.create({ :name => 'bob' })
8
- zoo = Zoo[:name => 'bob']
12
+ zoo = Zoo.first(:name => 'bob')
9
13
  zoo.name.should == 'bob'
10
14
  Zoo.all.length.should == total+1
11
15
  end
12
16
 
13
17
  it "should update an existing row" do
14
- dallas = Zoo[:name => 'Dallas']
18
+ dallas = Zoo.first(:name => 'Dallas')
15
19
  dallas.name = 'bob'
16
20
  dallas.save
17
21
  dallas.name = 'Dallas'
@@ -25,15 +29,15 @@ describe "Save Commands" do
25
29
 
26
30
  it "should stamp association on save" do
27
31
  database do
28
- dallas = Zoo[:name => 'Dallas']
32
+ dallas = Zoo.first(:name => 'Dallas')
29
33
  dallas.exhibits << Exhibit.new(:name => 'Flying Monkeys')
30
34
  dallas.save
31
- Exhibit[:name => 'Flying Monkeys'].zoo.should == dallas
35
+ Exhibit.first(:name => 'Flying Monkeys').zoo.should == dallas
32
36
  end
33
37
  end
34
38
 
35
39
  it "should be invalid if invalid associations are loaded" do
36
- miami = Zoo[:name => 'Miami']
40
+ miami = Zoo.first(:name => 'Miami')
37
41
  fish_fancy = Exhibit.new
38
42
  miami.exhibits << fish_fancy
39
43
  miami.should_not be_valid
data/spec/schema_spec.rb CHANGED
@@ -6,94 +6,3 @@ describe DataMapper::Adapters::Sql::Mappings::Schema do
6
6
  database.adapter.schema.database_tables.each { |table| table.should be_a_kind_of( DataMapper::Adapters::Sql::Mappings::Table ) }
7
7
  end
8
8
  end
9
-
10
-
11
- if ENV['ADAPTER'] == 'postgresql' && false
12
-
13
- describe DataMapper::Adapters::PostgresqlAdapter::Mappings::Table do
14
-
15
- before(:all) do
16
- class Cage < DataMapper::Base
17
- set_table_name "cages"
18
- property :name, :string
19
- end
20
-
21
- class CageInSchema < DataMapper::Base
22
- set_table_name "my_schema.cages"
23
- property :name, :string
24
- end
25
- end
26
-
27
- it "should return a quoted table name for a simple table" do
28
- table_sql = database.adapter.table(Cage).to_sql
29
- table_sql.should == "\"cages\""
30
- end
31
-
32
- it "should return a quoted schema and table name for a table which specifies a schema" do
33
- table_sql = database.adapter.table(CageInSchema).to_sql
34
- table_sql.should == "\"my_schema\".\"cages\""
35
- end
36
-
37
- it "should search only the specified schema if qualified" do
38
- database.save(Cage)
39
- database.adapter.table(CageInSchema).exists?.should == false
40
- database.save(CageInSchema)
41
- database.adapter.table(CageInSchema).exists?.should == true
42
- end
43
-
44
- after do
45
- database.adapter.execute("DROP SCHEMA my_schema CASCADE") rescue nil
46
- end
47
-
48
- end
49
-
50
- describe DataMapper::Adapters::PostgresqlAdapter::Commands::SaveCommand do
51
-
52
- before(:all) do
53
- class Cage < DataMapper::Base
54
- set_table_name "cages"
55
- property :name, :string
56
- end
57
-
58
- class CageInSchema < DataMapper::Base
59
- set_table_name "my_schema.cages"
60
- property :name, :string
61
- end
62
- end
63
-
64
- def table_mapping_for(klass)
65
- database_context = database
66
- DataMapper::Adapters::PostgresqlAdapter::Commands::SaveCommand.new(database_context.adapter, database_context, klass)
67
- end
68
-
69
- it "should create a schema if it doesn't already exist" do
70
- create_sql = table_mapping_for(CageInSchema).to_create_table_sql
71
- create_sql.should == <<-EOS.compress_lines
72
- CREATE SCHEMA "my_schema"; CREATE TABLE "my_schema"."cages" ("id" serial primary key, "name" varchar)
73
- EOS
74
- end
75
-
76
- it "shouldn't create a schema if it exists" do
77
- database.save(CageInSchema)
78
- create_sql = table_mapping_for(CageInSchema).to_create_table_sql
79
- create_sql.should == <<-EOS.compress_lines
80
- CREATE TABLE "my_schema"."cages" ("id" serial primary key, "name" varchar)
81
- EOS
82
- end
83
-
84
- it "basic crud should work in schemas" do
85
- database.save(CageInSchema)
86
- CageInSchema.find(:all).size.should == 0
87
- CageInSchema.create({ :name => 'bob' })
88
- CageInSchema.find(:all).size.should == 1
89
- cage = CageInSchema.first(:name => 'bob')
90
- cage.name.should == 'bob'
91
- cage.destroy!.should == true
92
- end
93
-
94
- after do
95
- database.adapter.execute("DROP SCHEMA my_schema CASCADE") rescue nil
96
- end
97
-
98
- end
99
- end