datamapper 0.2.4 → 0.2.5

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 (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