datamapper 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/example.rb +5 -5
- data/lib/data_mapper/adapters/abstract_adapter.rb +2 -2
- data/lib/data_mapper/adapters/data_object_adapter.rb +141 -147
- data/lib/data_mapper/adapters/mysql_adapter.rb +14 -1
- data/lib/data_mapper/adapters/postgresql_adapter.rb +123 -18
- data/lib/data_mapper/adapters/sql/coersion.rb +21 -9
- data/lib/data_mapper/adapters/sql/commands/load_command.rb +36 -19
- data/lib/data_mapper/adapters/sql/mappings/column.rb +111 -17
- data/lib/data_mapper/adapters/sql/mappings/schema.rb +27 -0
- data/lib/data_mapper/adapters/sql/mappings/table.rb +256 -29
- data/lib/data_mapper/adapters/sqlite3_adapter.rb +93 -8
- data/lib/data_mapper/associations/belongs_to_association.rb +53 -54
- data/lib/data_mapper/associations/has_and_belongs_to_many_association.rb +157 -25
- data/lib/data_mapper/associations/has_many_association.rb +45 -15
- data/lib/data_mapper/associations/has_n_association.rb +79 -20
- data/lib/data_mapper/associations/has_one_association.rb +2 -2
- data/lib/data_mapper/associations/reference.rb +1 -1
- data/lib/data_mapper/auto_migrations.rb +40 -0
- data/lib/data_mapper/base.rb +201 -98
- data/lib/data_mapper/context.rb +16 -10
- data/lib/data_mapper/database.rb +22 -11
- data/lib/data_mapper/dependency_queue.rb +28 -0
- data/lib/data_mapper/embedded_value.rb +61 -17
- data/lib/data_mapper/property.rb +4 -0
- data/lib/data_mapper/support/active_record_impersonation.rb +13 -5
- data/lib/data_mapper/support/errors.rb +5 -0
- data/lib/data_mapper/support/serialization.rb +8 -4
- data/lib/data_mapper/validatable_extensions/errors.rb +12 -0
- data/lib/data_mapper/validatable_extensions/macros.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validatable_instance_methods.rb +62 -0
- data/lib/data_mapper/validatable_extensions/validation_base.rb +18 -0
- data/lib/data_mapper/validatable_extensions/validations/formats/email.rb +43 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_acceptance_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_confirmation_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_each.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_format_of.rb +28 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_length_of.rb +15 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_numericality_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_presence_of.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_true_for.rb +7 -0
- data/lib/data_mapper/validatable_extensions/validations/validates_uniqueness_of.rb +33 -0
- data/lib/data_mapper/validations.rb +20 -0
- data/lib/data_mapper.rb +39 -34
- data/performance.rb +24 -18
- data/plugins/dataobjects/do_rb +0 -0
- data/rakefile.rb +12 -2
- data/spec/active_record_impersonation_spec.rb +133 -0
- data/spec/acts_as_tree_spec.rb +25 -9
- data/spec/associations_spec.rb +124 -4
- data/spec/attributes_spec.rb +13 -0
- data/spec/auto_migrations_spec.rb +44 -0
- data/spec/base_spec.rb +189 -1
- data/spec/column_spec.rb +85 -7
- data/spec/conditions_spec.rb +2 -2
- data/spec/dependency_spec.rb +25 -0
- data/spec/embedded_value_spec.rb +123 -3
- data/spec/fixtures/animals.yaml +1 -0
- data/spec/fixtures/careers.yaml +5 -0
- data/spec/fixtures/comments.yaml +1 -0
- data/spec/fixtures/people.yaml +14 -9
- data/spec/fixtures/projects.yaml +4 -0
- data/spec/fixtures/sections.yaml +5 -0
- data/spec/fixtures/serializers.yaml +6 -0
- data/spec/fixtures/users.yaml +1 -0
- data/spec/load_command_spec.rb +5 -4
- data/spec/mock_adapter.rb +2 -2
- data/spec/models/animal.rb +2 -1
- data/spec/models/animals_exhibit.rb +2 -2
- data/spec/models/career.rb +6 -0
- data/spec/models/comment.rb +4 -0
- data/spec/models/exhibit.rb +4 -0
- data/spec/models/person.rb +3 -13
- data/spec/models/project.rb +1 -1
- data/spec/models/serializer.rb +3 -0
- data/spec/models/user.rb +4 -0
- data/spec/models/zoo.rb +8 -1
- data/spec/natural_key_spec.rb +36 -0
- data/spec/paranoia_spec.rb +36 -0
- data/spec/property_spec.rb +70 -0
- data/spec/schema_spec.rb +10 -2
- data/spec/serialization_spec.rb +6 -3
- data/spec/serialize_spec.rb +19 -0
- data/spec/single_table_inheritance_spec.rb +7 -1
- data/spec/spec_helper.rb +26 -8
- data/spec/table_spec.rb +33 -0
- data/spec/validates_confirmation_of_spec.rb +20 -4
- data/spec/validates_format_of_spec.rb +22 -8
- data/spec/validates_length_of_spec.rb +26 -13
- data/spec/validates_uniqueness_of_spec.rb +18 -5
- data/spec/validations_spec.rb +55 -10
- data/tasks/fixtures.rb +13 -7
- metadata +189 -153
- data/lib/data_mapper/validations/confirmation_validator.rb +0 -53
- data/lib/data_mapper/validations/contextual_validations.rb +0 -50
- data/lib/data_mapper/validations/format_validator.rb +0 -85
- data/lib/data_mapper/validations/formats/email.rb +0 -78
- data/lib/data_mapper/validations/generic_validator.rb +0 -22
- data/lib/data_mapper/validations/length_validator.rb +0 -76
- data/lib/data_mapper/validations/required_field_validator.rb +0 -41
- data/lib/data_mapper/validations/unique_validator.rb +0 -56
- data/lib/data_mapper/validations/validation_errors.rb +0 -37
- data/lib/data_mapper/validations/validation_helper.rb +0 -77
- data/plugins/dataobjects/REVISION +0 -1
- data/plugins/dataobjects/Rakefile +0 -9
- data/plugins/dataobjects/do.rb +0 -348
- data/plugins/dataobjects/do_mysql.rb +0 -212
- data/plugins/dataobjects/do_postgres.rb +0 -196
- data/plugins/dataobjects/do_sqlite3.rb +0 -157
- data/plugins/dataobjects/spec/do_spec.rb +0 -150
- data/plugins/dataobjects/spec/spec_helper.rb +0 -81
- data/plugins/dataobjects/swig_mysql/extconf.rb +0 -45
- data/plugins/dataobjects/swig_mysql/mysql_c.c +0 -16602
- data/plugins/dataobjects/swig_mysql/mysql_c.i +0 -67
- data/plugins/dataobjects/swig_mysql/mysql_supp.i +0 -46
- data/plugins/dataobjects/swig_postgres/extconf.rb +0 -29
- data/plugins/dataobjects/swig_postgres/postgres_c.c +0 -8185
- data/plugins/dataobjects/swig_postgres/postgres_c.i +0 -73
- data/plugins/dataobjects/swig_sqlite/extconf.rb +0 -9
- data/plugins/dataobjects/swig_sqlite/sqlite3_c.c +0 -4725
- data/plugins/dataobjects/swig_sqlite/sqlite_c.i +0 -168
- data/tasks/drivers.rb +0 -20
data/spec/base_spec.rb
CHANGED
@@ -25,6 +25,13 @@ describe DataMapper::Base do
|
|
25
25
|
x.should be_dirty
|
26
26
|
end
|
27
27
|
|
28
|
+
it "should be dirty when set to nil" do
|
29
|
+
x = Person.create(:name => 'a')
|
30
|
+
x.should_not be_dirty
|
31
|
+
x.name = "asdfasfd"
|
32
|
+
x.should be_dirty
|
33
|
+
end
|
34
|
+
|
28
35
|
it "should return a diff" do
|
29
36
|
x = Person.new(:name => 'Sam', :age => 30, :occupation => 'Programmer')
|
30
37
|
y = Person.new(:name => 'Amy', :age => 21, :occupation => 'Programmer')
|
@@ -46,6 +53,30 @@ describe DataMapper::Base do
|
|
46
53
|
x.should_not be_dirty
|
47
54
|
end
|
48
55
|
|
56
|
+
it "should return the table for a given model" do
|
57
|
+
Person.table.should be_a_kind_of(DataMapper::Adapters::Sql::Mappings::Table)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should support boolean accessors" do
|
61
|
+
dolphin = Animal.first(:name => 'Dolphin')
|
62
|
+
dolphin.should be_nice
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be comparable" do
|
66
|
+
p1 = Person.create(:name => 'Sam')
|
67
|
+
p2 = Person[p1.id]
|
68
|
+
|
69
|
+
p1.should == p2
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should not be equal if attributes have changed" do
|
73
|
+
p1 = Person.create(:name => 'Sam')
|
74
|
+
p2 = Person[p1.id]
|
75
|
+
p2.name = "Paul"
|
76
|
+
|
77
|
+
p1.should_not == p2
|
78
|
+
end
|
79
|
+
|
49
80
|
end
|
50
81
|
|
51
82
|
describe 'A new record' do
|
@@ -71,4 +102,161 @@ describe 'A new record' do
|
|
71
102
|
@bob.id.should == nil
|
72
103
|
end
|
73
104
|
|
74
|
-
|
105
|
+
it "should not have dirty attributes when not dirty" do
|
106
|
+
x = Person.create(:name => 'a')
|
107
|
+
x.should_not be_dirty
|
108
|
+
x.dirty_attributes.should be_empty
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should only list attributes that have changed in the dirty attributes hash" do
|
112
|
+
x = Person.create(:name => 'a')
|
113
|
+
x.name = "asdfr"
|
114
|
+
x.should be_dirty
|
115
|
+
x.dirty_attributes.keys.should == [:name]
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should not have original_values when a new record" do
|
119
|
+
x = Person.new(:name => 'a')
|
120
|
+
x.original_values.should be_empty
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should have original_values after saved" do
|
124
|
+
x = Person.new(:name => 'a')
|
125
|
+
x.save
|
126
|
+
x.original_values.should_not be_empty
|
127
|
+
x.original_values.keys.should include(:name)
|
128
|
+
x.original_values[:name].should == 'a'
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should have original values when created" do
|
132
|
+
x = Person.create(:name => 'a')
|
133
|
+
x.original_values.should_not be_empty
|
134
|
+
x.original_values.keys.should include(:name)
|
135
|
+
x.original_values[:name].should == "a"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should have original values when loaded from the database" do
|
139
|
+
Person.create(:name => 'a')
|
140
|
+
x = Person[:name => 'a']
|
141
|
+
x.original_values.should_not be_empty
|
142
|
+
x.original_values.keys.should include(:name)
|
143
|
+
x.original_values[:name].should == "a"
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should reset the original values when not new, changed then saved" do
|
147
|
+
x = Person.create(:name => 'a')
|
148
|
+
x.should_not be_new_record
|
149
|
+
x.original_values[:name].should == "a"
|
150
|
+
x.name = "b"
|
151
|
+
x.save
|
152
|
+
x.original_values[:name].should == "b"
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should allow a value to be set to nil" do
|
156
|
+
x = Person.create(:name => 'a')
|
157
|
+
x.name = nil
|
158
|
+
x.save
|
159
|
+
x.reload!
|
160
|
+
x.name.should be_nil
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'Properties' do
|
166
|
+
|
167
|
+
it 'should default to public method visibility' do
|
168
|
+
class SoftwareEngineer < DataMapper::Base
|
169
|
+
set_table_name 'people'
|
170
|
+
property :name, :string
|
171
|
+
end
|
172
|
+
|
173
|
+
public_properties = SoftwareEngineer.public_instance_methods.select { |m| ["name", "name="].include?(m) }
|
174
|
+
public_properties.length.should == 2
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should respect protected property options' do
|
178
|
+
class SanitationEngineer < DataMapper::Base
|
179
|
+
set_table_name 'people'
|
180
|
+
property :name, :string, :reader => :protected
|
181
|
+
property :age, :integer, :writer => :protected
|
182
|
+
end
|
183
|
+
|
184
|
+
protected_properties = SanitationEngineer.protected_instance_methods.select { |m| ["name", "age="].include?(m) }
|
185
|
+
protected_properties.length.should == 2
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'should respect private property options' do
|
189
|
+
class ElectricalEngineer < DataMapper::Base
|
190
|
+
set_table_name 'people'
|
191
|
+
property :name, :string, :reader => :private
|
192
|
+
property :age, :integer, :writer => :private
|
193
|
+
end
|
194
|
+
|
195
|
+
private_properties = ElectricalEngineer.private_instance_methods.select { |m| ["name", "age="].include?(m) }
|
196
|
+
private_properties.length.should == 2
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should set both reader and writer visibiliy when accessor option is passed' do
|
200
|
+
class TrainEngineer < DataMapper::Base
|
201
|
+
property :name, :string, :accessor => :private
|
202
|
+
end
|
203
|
+
|
204
|
+
private_properties = TrainEngineer.private_instance_methods.select { |m| ["name", "name="].include?(m) }
|
205
|
+
private_properties.length.should == 2
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should only be listed in attributes if they have public getters' do
|
209
|
+
class SalesEngineer < DataMapper::Base
|
210
|
+
set_table_name 'people'
|
211
|
+
property :name, :string
|
212
|
+
property :age, :integer, :reader => :private
|
213
|
+
end
|
214
|
+
|
215
|
+
@sam = SalesEngineer[:name => 'Sam']
|
216
|
+
# note: id default key gets a public reader by default (but writer is protected)
|
217
|
+
@sam.attributes.should == {:id => @sam.id, :name => @sam.name}
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should not allow mass assignment if private or protected' do
|
221
|
+
class ChemicalEngineer < DataMapper::Base
|
222
|
+
set_table_name 'people'
|
223
|
+
property :name, :string, :writer => :private
|
224
|
+
property :age, :integer
|
225
|
+
end
|
226
|
+
|
227
|
+
@sam = ChemicalEngineer[:name => 'Sam']
|
228
|
+
@sam.attributes = {:name => 'frank', :age => 101}
|
229
|
+
@sam.age.should == 101
|
230
|
+
@sam.name.should == 'Sam'
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'should allow :protected to be passed as an alias for a public reader, protected writer' do
|
234
|
+
class CivilEngineer < DataMapper::Base
|
235
|
+
set_table_name 'people'
|
236
|
+
property :name, :string, :protected => true
|
237
|
+
end
|
238
|
+
|
239
|
+
CivilEngineer.public_instance_methods.should include("name")
|
240
|
+
CivilEngineer.protected_instance_methods.should include("name=")
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'should allow :private to be passed as an alias for a public reader, private writer' do
|
244
|
+
class AudioEngineer < DataMapper::Base
|
245
|
+
set_table_name 'people'
|
246
|
+
property :name, :string, :private => true
|
247
|
+
end
|
248
|
+
|
249
|
+
AudioEngineer.public_instance_methods.should include("name")
|
250
|
+
AudioEngineer.private_instance_methods.should include("name=")
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'should raise an error when invalid options are passsed' do
|
254
|
+
lambda do
|
255
|
+
class JumpyCow < DataMapper::Base
|
256
|
+
set_table_name 'animals'
|
257
|
+
property :name, :string, :laze => true
|
258
|
+
end
|
259
|
+
end.should raise_error(ArgumentError)
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
data/spec/column_spec.rb
CHANGED
@@ -2,22 +2,100 @@ require File.dirname(__FILE__) + "/spec_helper"
|
|
2
2
|
|
3
3
|
describe DataMapper::Adapters::Sql::Mappings::Column do
|
4
4
|
|
5
|
+
before(:all) do
|
6
|
+
fixtures(:zoos)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should only lazy loading text columns by default" do
|
10
|
+
table = database.table(Zoo)
|
11
|
+
table.columns.each do |column|
|
12
|
+
if column.type == :text
|
13
|
+
column.should be_lazy
|
14
|
+
else
|
15
|
+
column.should_not be_lazy
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
5
20
|
it "should be unique within a set" do
|
6
21
|
|
7
22
|
mappings = DataMapper::Adapters::Sql::Mappings
|
8
23
|
|
9
24
|
columns = SortedSet.new
|
10
|
-
|
11
|
-
|
12
|
-
columns << mappings::Column.new(database(:mock).adapter,
|
13
|
-
columns << mappings::Column.new(database(:mock).adapter,
|
25
|
+
|
26
|
+
table = mappings::Table.new(database(:mock).adapter, "Cow")
|
27
|
+
columns << mappings::Column.new(database(:mock).adapter, table, :one, :string, 1)
|
28
|
+
columns << mappings::Column.new(database(:mock).adapter, table, :two, :string, 2)
|
29
|
+
columns << mappings::Column.new(database(:mock).adapter, table, :three, :string, 3)
|
14
30
|
columns.should have(3).entries
|
15
31
|
|
16
|
-
columns << mappings::Column.new(database(:mock).adapter,
|
32
|
+
columns << mappings::Column.new(database(:mock).adapter, table, :two, :integer, 3)
|
17
33
|
columns.should have(3).entries
|
18
34
|
|
19
|
-
columns << mappings::Column.new(database(:mock).adapter,
|
35
|
+
columns << mappings::Column.new(database(:mock).adapter, table, :id, :integer, -1)
|
20
36
|
columns.should have(4).entries
|
21
37
|
end
|
22
38
|
|
23
|
-
|
39
|
+
it "should get its meta data from the database"
|
40
|
+
|
41
|
+
it "should be able to rename" do
|
42
|
+
table = database.table(Zoo)
|
43
|
+
name_column = table[:name]
|
44
|
+
|
45
|
+
lambda { database.query("SELECT name FROM zoos") }.should_not raise_error
|
46
|
+
lambda { database.query("SELECT moo FROM zoos") }.should raise_error
|
47
|
+
|
48
|
+
name_column.rename!(:moo).should eql(true)
|
49
|
+
name_column.name.should eql(:moo)
|
50
|
+
|
51
|
+
lambda { database.query("SELECT name FROM zoos") }.should raise_error
|
52
|
+
lambda { database.query("SELECT moo FROM zoos") }.should_not raise_error
|
53
|
+
|
54
|
+
name_column.rename!(:name)
|
55
|
+
name_column.name.should eql(:name)
|
56
|
+
|
57
|
+
lambda { database.query("SELECT name FROM zoos") }.should_not raise_error
|
58
|
+
lambda { database.query("SELECT moo FROM zoos") }.should raise_error
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should create, alter and drop a column" do
|
62
|
+
lambda { database.query("SELECT moo FROM zoos") }.should raise_error
|
63
|
+
|
64
|
+
database.logger.debug { 'MOO' * 10 }
|
65
|
+
|
66
|
+
table = database.table(Zoo)
|
67
|
+
Zoo.property(:moo, :string)
|
68
|
+
moo = table[:moo]
|
69
|
+
moo.create!
|
70
|
+
|
71
|
+
lambda { database.query("SELECT moo FROM zoos") }.should_not raise_error
|
72
|
+
|
73
|
+
zoo = Zoo.create(:name => 'columns', :moo => 'AAA')
|
74
|
+
zoo.moo.should eql('AAA')
|
75
|
+
|
76
|
+
zoo.moo = 4
|
77
|
+
zoo.save
|
78
|
+
zoo.reload!
|
79
|
+
zoo.moo.should eql('4')
|
80
|
+
|
81
|
+
moo.type = :integer
|
82
|
+
moo.alter!
|
83
|
+
zoo.reload!
|
84
|
+
zoo.moo.should eql(4)
|
85
|
+
|
86
|
+
moo.drop!
|
87
|
+
|
88
|
+
Zoo.send(:undef_method, :moo)
|
89
|
+
Zoo.send(:undef_method, :moo=)
|
90
|
+
|
91
|
+
lambda { database.query("SELECT moo FROM zoos") }.should raise_error
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should default the size of an integer column to 11" do
|
95
|
+
mappings = DataMapper::Adapters::Sql::Mappings
|
96
|
+
table = mappings::Table.new(database(:mock).adapter, "Zebu")
|
97
|
+
integer = mappings::Column.new(database(:mock).adapter, table, :age, :integer, 1)
|
98
|
+
integer.size.should == 11
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
data/spec/conditions_spec.rb
CHANGED
@@ -3,9 +3,9 @@ require File.dirname(__FILE__) + "/spec_helper"
|
|
3
3
|
describe DataMapper::Adapters::Sql::Commands::LoadCommand do
|
4
4
|
|
5
5
|
def conditions_for(klass, options = {})
|
6
|
-
|
6
|
+
database_context = database(:mock)
|
7
7
|
DataMapper::Adapters::Sql::Commands::LoadCommand.new(
|
8
|
-
|
8
|
+
database_context.adapter, database_context, klass, options
|
9
9
|
).conditions
|
10
10
|
end
|
11
11
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe DataMapper::Base do
|
4
|
+
|
5
|
+
it "should be able to add a dependency for a class not yet defined" do
|
6
|
+
|
7
|
+
$happy_cow_defined = false
|
8
|
+
|
9
|
+
DataMapper::Base.dependencies.add('HappyCow') do |klass|
|
10
|
+
klass.should eql(Object.const_get('HappyCow'))
|
11
|
+
database.table(klass).key.name.should eql(:name)
|
12
|
+
$happy_cow_defined = true
|
13
|
+
end
|
14
|
+
|
15
|
+
class HappyCow < DataMapper::Base
|
16
|
+
property :name, :string, :key => true
|
17
|
+
end
|
18
|
+
|
19
|
+
# Dependencies are not resolved until you try to access the key for a table...
|
20
|
+
database.table(HappyCow).key
|
21
|
+
|
22
|
+
raise 'Dependency not called for HappyCow :-(' unless $happy_cow_defined
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/spec/embedded_value_spec.rb
CHANGED
@@ -18,8 +18,128 @@ describe DataMapper::EmbeddedValue do
|
|
18
18
|
@bob.address.city_state_zip_code.should == 'Dallas, TX 75000'
|
19
19
|
end
|
20
20
|
|
21
|
-
it 'should
|
22
|
-
|
21
|
+
it 'should not require prefix' do
|
22
|
+
class PointyHeadedBoss < DataMapper::Base
|
23
|
+
set_table_name 'people'
|
24
|
+
property :name, :string
|
25
|
+
|
26
|
+
embed :address do
|
27
|
+
# don't provide a prefix option to embed
|
28
|
+
# so the column names of these properties gets nothing auto-prepended
|
29
|
+
property :address_street, :string
|
30
|
+
property :address_city, :string
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
@sam = PointyHeadedBoss[:name => 'Sam']
|
35
|
+
@sam.address.address_street.should == '1337 Duck Way'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should add convenience methods to the non-embedded base' do
|
39
|
+
class Employee < DataMapper::Base
|
40
|
+
set_table_name 'people'
|
41
|
+
property :name, :string
|
42
|
+
|
43
|
+
embed :address, :prefix => true do
|
44
|
+
property :street, :string
|
45
|
+
property :city, :string
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@sam = Employee[:name => 'Sam']
|
50
|
+
@sam.address_street.should == '1337 Duck Way'
|
23
51
|
end
|
52
|
+
|
53
|
+
it 'should support lazy loading of embedded properties' do
|
54
|
+
class Human < DataMapper::Base
|
55
|
+
set_table_name 'people'
|
56
|
+
property :name, :string
|
57
|
+
|
58
|
+
embed :address, :lazy => true, :prefix => true do
|
59
|
+
property :street, :string
|
60
|
+
property :city, :string
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
@sam = Human[:name => 'Sam']
|
65
|
+
@sam.address.street.should == '1337 Duck Way'
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should default to public method visibility for all' do
|
69
|
+
class SoftwareEngineer < DataMapper::Base
|
70
|
+
set_table_name 'people'
|
71
|
+
property :name, :string
|
72
|
+
|
73
|
+
embed :address, :prefix => true do
|
74
|
+
property :city, :string
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
@sam = SoftwareEngineer[:name => 'Sam']
|
79
|
+
public_properties = @sam.address.class.public_instance_methods.select { |m| ["city", "city="].include?(m) }
|
80
|
+
public_properties.length.should == 2
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should respect protected property options for all' do
|
84
|
+
class SanitationEngineer < DataMapper::Base
|
85
|
+
set_table_name 'people'
|
86
|
+
property :name, :string
|
87
|
+
|
88
|
+
embed :address, :reader => :protected, :prefix => true do
|
89
|
+
property :city, :string
|
90
|
+
property :street, :string
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
@sam = SanitationEngineer[:name => 'Sam']
|
95
|
+
protected_properties = @sam.address.class.protected_instance_methods.select { |m| ["city", "street"].include?(m) }
|
96
|
+
protected_properties.length.should == 2
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should respect private property options for all' do
|
100
|
+
class ElectricalEngineer < DataMapper::Base
|
101
|
+
set_table_name 'people'
|
102
|
+
property :name, :string, :reader => :private
|
103
|
+
|
104
|
+
embed :address, :writer => :private, :prefix => true do
|
105
|
+
property :city, :string
|
106
|
+
property :street, :string
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
@sam = ElectricalEngineer[:name => 'Sam']
|
111
|
+
private_properties = @sam.address.class.private_instance_methods.select { |m| ["city=", "street="].include?(m) }
|
112
|
+
private_properties.length.should == 2
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should set both reader and writer visibiliy for all when accessor option is passed' do
|
116
|
+
class TrainEngineer < DataMapper::Base
|
117
|
+
set_table_name 'people'
|
118
|
+
property :name, :string, :reader => :private
|
24
119
|
|
25
|
-
|
120
|
+
embed :address, :accessor => :private, :prefix => true do
|
121
|
+
property :city, :string
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
@sam = TrainEngineer[:name => 'Sam']
|
126
|
+
private_properties = @sam.address.class.private_instance_methods.select { |m| ["city", "city="].include?(m) }
|
127
|
+
private_properties.length.should == 2
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should allow individual properties to override method visibility options passed on the block' do
|
131
|
+
class ChemicalEngineer < DataMapper::Base
|
132
|
+
set_table_name 'people'
|
133
|
+
property :name, :string
|
134
|
+
|
135
|
+
embed :address, :accessor => :private, :prefix => true do
|
136
|
+
property :city, :string
|
137
|
+
property :street, :string, :accessor => :public
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
@sam = ChemicalEngineer[:name => 'Sam']
|
142
|
+
public_properties = @sam.address.class.public_instance_methods.select { |m| ["street", "street="].include?(m) }
|
143
|
+
public_properties.length.should == 2
|
144
|
+
end
|
145
|
+
end
|
data/spec/fixtures/animals.yaml
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
--- []
|
data/spec/fixtures/people.yaml
CHANGED
@@ -2,31 +2,36 @@
|
|
2
2
|
age: 29
|
3
3
|
occupation: Programmer
|
4
4
|
type: Person
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
address_street: 1337 Duck Way
|
6
|
+
address_city: Galveston
|
7
|
+
adresss_state: TX
|
8
|
+
address_zip_code: "75000"
|
9
9
|
notes:
|
10
10
|
date_of_birth: 2007-10-24
|
11
|
+
career_name: Programmer
|
11
12
|
- name: Amy
|
12
13
|
age: 28
|
13
14
|
occupation: Business Analyst Manager
|
14
15
|
type: Person
|
16
|
+
career_name: Business Analyst Manager
|
15
17
|
- name: Scott
|
16
18
|
age: 25
|
17
19
|
occupation: Programmer
|
18
20
|
type: SalesPerson
|
19
21
|
commission: 172
|
22
|
+
career_name: Programmer
|
20
23
|
- name: Josh
|
21
24
|
age: 23
|
22
25
|
occupation: Supervisor
|
23
26
|
type:
|
27
|
+
career_name: Supervisor
|
24
28
|
- name: Bob
|
25
29
|
age: 29
|
26
30
|
occupation: Peon
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
address_street: 123 Happy Ln.
|
32
|
+
address_city: Dallas
|
33
|
+
address_state: TX
|
34
|
+
address_zip_code: 75000
|
31
35
|
type: SalesPerson
|
32
|
-
commission: 40
|
36
|
+
commission: 40
|
37
|
+
career_name: Peon
|
@@ -0,0 +1 @@
|
|
1
|
+
--- []
|
data/spec/load_command_spec.rb
CHANGED
@@ -4,11 +4,12 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
|
|
4
4
|
|
5
5
|
before(:all) do
|
6
6
|
fixtures(:zoos)
|
7
|
+
fixtures(:animals)
|
7
8
|
end
|
8
9
|
|
9
10
|
def loader_for(klass, options = {})
|
10
|
-
|
11
|
-
DataMapper::Adapters::Sql::Commands::LoadCommand.new(
|
11
|
+
database_context = database(:mock)
|
12
|
+
DataMapper::Adapters::Sql::Commands::LoadCommand.new(database_context.adapter, database_context, klass, options)
|
12
13
|
end
|
13
14
|
|
14
15
|
it "should return a Struct for custom queries" do
|
@@ -41,7 +42,7 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
|
|
41
42
|
|
42
43
|
it "should join has and belongs to many associtions in the statement" do
|
43
44
|
loader_for(Animal, :include => :exhibits).to_parameterized_sql.first.should == <<-EOS.compress_lines
|
44
|
-
SELECT `animals`.`id`, `animals`.`name`,
|
45
|
+
SELECT `animals`.`id`, `animals`.`name`, `animals`.`nice`,
|
45
46
|
`exhibits`.`id`, `exhibits`.`name`, `exhibits`.`zoo_id`,
|
46
47
|
`animals_exhibits`.`animal_id`, `animals_exhibits`.`exhibit_id`
|
47
48
|
FROM `animals`
|
@@ -52,7 +53,7 @@ describe DataMapper::Adapters::Sql::Commands::LoadCommand do
|
|
52
53
|
|
53
54
|
it "should shallow-join unmapped tables for has-and-belongs-to-many in the statement" do
|
54
55
|
loader_for(Animal, :shallow_include => :exhibits).to_parameterized_sql.first.should == <<-EOS.compress_lines
|
55
|
-
SELECT `animals`.`id`, `animals`.`name`,
|
56
|
+
SELECT `animals`.`id`, `animals`.`name`, `animals`.`nice`,
|
56
57
|
`animals_exhibits`.`animal_id`, `animals_exhibits`.`exhibit_id`
|
57
58
|
FROM `animals`
|
58
59
|
JOIN `animals_exhibits` ON `animals_exhibits`.`animal_id` = `animals`.`id`
|
data/spec/mock_adapter.rb
CHANGED
@@ -7,10 +7,10 @@ class MockAdapter < DataMapper::Adapters::DataObjectAdapter
|
|
7
7
|
def delete(instance_or_klass, options = nil)
|
8
8
|
end
|
9
9
|
|
10
|
-
def save(
|
10
|
+
def save(database_context, instance)
|
11
11
|
end
|
12
12
|
|
13
|
-
def load(
|
13
|
+
def load(database_context, klass, options)
|
14
14
|
end
|
15
15
|
|
16
16
|
def table_exists?(name)
|
data/spec/models/animal.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
class Animal < DataMapper::Base
|
2
|
-
property :name, :string
|
2
|
+
property :name, :string, :default => "No Name"
|
3
3
|
property :notes, :text
|
4
|
+
property :nice, :boolean
|
4
5
|
|
5
6
|
has_one :favourite_fruit, :class => 'Fruit', :foreign_key => 'devourer_id'
|
6
7
|
has_and_belongs_to_many :exhibits
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# This is just here to get around the fact I use a Class to load
|
2
2
|
# fixtures right now.
|
3
3
|
class AnimalsExhibit < DataMapper::Base
|
4
|
-
property :animal_id, :integer, :key => true
|
5
|
-
property :exhibit_id, :integer
|
4
|
+
property :animal_id, :integer, :key => true
|
5
|
+
property :exhibit_id, :integer, :key => true
|
6
6
|
end
|
data/spec/models/exhibit.rb
CHANGED