datamapper 0.2.3 → 0.2.4
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.
- 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