dm-core 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/CHANGELOG +144 -0
  2. data/FAQ +74 -0
  3. data/MIT-LICENSE +22 -0
  4. data/QUICKLINKS +12 -0
  5. data/README +143 -0
  6. data/lib/dm-core.rb +213 -0
  7. data/lib/dm-core/adapters.rb +4 -0
  8. data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
  9. data/lib/dm-core/adapters/data_objects_adapter.rb +701 -0
  10. data/lib/dm-core/adapters/mysql_adapter.rb +132 -0
  11. data/lib/dm-core/adapters/postgres_adapter.rb +179 -0
  12. data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  13. data/lib/dm-core/associations.rb +172 -0
  14. data/lib/dm-core/associations/many_to_many.rb +138 -0
  15. data/lib/dm-core/associations/many_to_one.rb +101 -0
  16. data/lib/dm-core/associations/one_to_many.rb +275 -0
  17. data/lib/dm-core/associations/one_to_one.rb +61 -0
  18. data/lib/dm-core/associations/relationship.rb +116 -0
  19. data/lib/dm-core/associations/relationship_chain.rb +74 -0
  20. data/lib/dm-core/auto_migrations.rb +64 -0
  21. data/lib/dm-core/collection.rb +604 -0
  22. data/lib/dm-core/hook.rb +11 -0
  23. data/lib/dm-core/identity_map.rb +45 -0
  24. data/lib/dm-core/is.rb +16 -0
  25. data/lib/dm-core/logger.rb +233 -0
  26. data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  27. data/lib/dm-core/migrator.rb +29 -0
  28. data/lib/dm-core/model.rb +399 -0
  29. data/lib/dm-core/naming_conventions.rb +52 -0
  30. data/lib/dm-core/property.rb +611 -0
  31. data/lib/dm-core/property_set.rb +158 -0
  32. data/lib/dm-core/query.rb +590 -0
  33. data/lib/dm-core/repository.rb +159 -0
  34. data/lib/dm-core/resource.rb +618 -0
  35. data/lib/dm-core/scope.rb +35 -0
  36. data/lib/dm-core/support.rb +7 -0
  37. data/lib/dm-core/support/array.rb +13 -0
  38. data/lib/dm-core/support/assertions.rb +8 -0
  39. data/lib/dm-core/support/errors.rb +23 -0
  40. data/lib/dm-core/support/kernel.rb +7 -0
  41. data/lib/dm-core/support/symbol.rb +41 -0
  42. data/lib/dm-core/transaction.rb +267 -0
  43. data/lib/dm-core/type.rb +160 -0
  44. data/lib/dm-core/type_map.rb +80 -0
  45. data/lib/dm-core/types.rb +19 -0
  46. data/lib/dm-core/types/boolean.rb +7 -0
  47. data/lib/dm-core/types/discriminator.rb +32 -0
  48. data/lib/dm-core/types/object.rb +20 -0
  49. data/lib/dm-core/types/paranoid_boolean.rb +23 -0
  50. data/lib/dm-core/types/paranoid_datetime.rb +22 -0
  51. data/lib/dm-core/types/serial.rb +9 -0
  52. data/lib/dm-core/types/text.rb +10 -0
  53. data/spec/integration/association_spec.rb +1215 -0
  54. data/spec/integration/association_through_spec.rb +150 -0
  55. data/spec/integration/associations/many_to_many_spec.rb +171 -0
  56. data/spec/integration/associations/many_to_one_spec.rb +123 -0
  57. data/spec/integration/associations/one_to_many_spec.rb +66 -0
  58. data/spec/integration/auto_migrations_spec.rb +398 -0
  59. data/spec/integration/collection_spec.rb +1015 -0
  60. data/spec/integration/data_objects_adapter_spec.rb +32 -0
  61. data/spec/integration/model_spec.rb +68 -0
  62. data/spec/integration/mysql_adapter_spec.rb +85 -0
  63. data/spec/integration/postgres_adapter_spec.rb +732 -0
  64. data/spec/integration/property_spec.rb +224 -0
  65. data/spec/integration/query_spec.rb +376 -0
  66. data/spec/integration/repository_spec.rb +57 -0
  67. data/spec/integration/resource_spec.rb +324 -0
  68. data/spec/integration/sqlite3_adapter_spec.rb +352 -0
  69. data/spec/integration/sti_spec.rb +185 -0
  70. data/spec/integration/transaction_spec.rb +75 -0
  71. data/spec/integration/type_spec.rb +149 -0
  72. data/spec/lib/mock_adapter.rb +27 -0
  73. data/spec/spec_helper.rb +112 -0
  74. data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
  75. data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
  76. data/spec/unit/adapters/data_objects_adapter_spec.rb +627 -0
  77. data/spec/unit/adapters/postgres_adapter_spec.rb +125 -0
  78. data/spec/unit/associations/many_to_many_spec.rb +14 -0
  79. data/spec/unit/associations/many_to_one_spec.rb +138 -0
  80. data/spec/unit/associations/one_to_many_spec.rb +385 -0
  81. data/spec/unit/associations/one_to_one_spec.rb +7 -0
  82. data/spec/unit/associations/relationship_spec.rb +67 -0
  83. data/spec/unit/associations_spec.rb +205 -0
  84. data/spec/unit/auto_migrations_spec.rb +110 -0
  85. data/spec/unit/collection_spec.rb +174 -0
  86. data/spec/unit/data_mapper_spec.rb +21 -0
  87. data/spec/unit/identity_map_spec.rb +126 -0
  88. data/spec/unit/is_spec.rb +80 -0
  89. data/spec/unit/migrator_spec.rb +33 -0
  90. data/spec/unit/model_spec.rb +339 -0
  91. data/spec/unit/naming_conventions_spec.rb +28 -0
  92. data/spec/unit/property_set_spec.rb +96 -0
  93. data/spec/unit/property_spec.rb +447 -0
  94. data/spec/unit/query_spec.rb +485 -0
  95. data/spec/unit/repository_spec.rb +93 -0
  96. data/spec/unit/resource_spec.rb +557 -0
  97. data/spec/unit/scope_spec.rb +131 -0
  98. data/spec/unit/transaction_spec.rb +493 -0
  99. data/spec/unit/type_map_spec.rb +114 -0
  100. data/spec/unit/type_spec.rb +119 -0
  101. metadata +187 -0
@@ -0,0 +1,224 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ gem 'fastercsv', '>=1.2.3'
4
+ require 'fastercsv'
5
+
6
+ if ADAPTER
7
+ describe DataMapper::Property, "with #{ADAPTER}" do
8
+ describe " tracking strategies" do
9
+ before :all do
10
+ class Actor
11
+ include DataMapper::Resource
12
+
13
+ property :id, Serial
14
+ property :name, String, :track => :set # :track default is :get for mutable types
15
+ property :notes, DataMapper::Types::Text
16
+ property :age, Integer # :track default is :set for mutable types
17
+ property :rating, Integer
18
+ property :location, String
19
+ property :lead, TrueClass, :track => :load
20
+ property :cv, Object # :track should be :hash
21
+ property :agent, String, :track => :hash # :track only Object#hash value on :load.
22
+ # Potentially faster, but less safe, so use judiciously, when the odds of a hash-collision are low.
23
+ end
24
+ end
25
+
26
+ before do
27
+ Actor.auto_migrate!(ADAPTER)
28
+ end
29
+
30
+ it "should set up tracking information" do
31
+ Actor.properties[:name].track.should == :set
32
+ Actor.properties[:location].track.should == :get
33
+ Actor.properties[:rating].track.should == :set
34
+ Actor.properties[:lead].track.should == :load
35
+ Actor.properties[:cv].track.should == :hash
36
+ Actor.properties[:agent].track.should == :hash
37
+ end
38
+
39
+ it "should track on :set" do
40
+ repository(ADAPTER) do
41
+ bob = Actor.new(:name => 'bob')
42
+ bob.save
43
+
44
+ bob.original_values.should_not have_key(:name)
45
+ bob.dirty?.should == false
46
+
47
+ bob.name = "Bob"
48
+ bob.original_values.should have_key(:name)
49
+ bob.original_values[:name].should == 'bob'
50
+ bob.dirty?.should == true
51
+ end
52
+ end
53
+
54
+ it "should track on :get" do
55
+ repository(ADAPTER) do
56
+ jon = Actor.new(:name => 'jon', :location => 'dallas')
57
+ jon.save
58
+
59
+ jon.location
60
+ jon.original_values.should have_key(:location)
61
+ jon.original_values[:location].should == 'dallas'
62
+
63
+ jon.dirty?.should be_false
64
+ jon.save.should be_false
65
+
66
+ jon.location.upcase!
67
+ jon.location.should == 'DALLAS'
68
+ jon.original_values[:location].should == 'dallas'
69
+
70
+ jon.dirty?.should be_true
71
+ jon.save.should be_true
72
+
73
+ jon.location << '!'
74
+ jon.original_values[:location].should == 'DALLAS'
75
+ jon.dirty?.should be_true
76
+ end
77
+ end
78
+
79
+ it "should track on :load" do
80
+ repository(ADAPTER) do
81
+ jan = Actor.create!(:name => 'jan', :lead => true)
82
+ jan.lead = false
83
+ jan.original_values[:lead].should be_true
84
+ jan.dirty?.should == true
85
+ end
86
+ repository(ADAPTER) do
87
+ jan = Actor.first
88
+ jan.original_values.should have_key(:lead)
89
+ jan.original_values[:lead].should be_true
90
+ jan.dirty?.should == false
91
+ end
92
+ end
93
+
94
+ it "should track on :hash" do
95
+ cv = { 2005 => "Othello" }
96
+ repository(ADAPTER) do
97
+ tom = Actor.create!(:name => 'tom', :cv => cv)
98
+ end
99
+ repository(ADAPTER) do
100
+ tom = Actor.first(:name => 'tom')
101
+ tom.cv.merge!({2006 => "Macbeth"})
102
+
103
+ tom.original_values.should have_key(:cv)
104
+ # tom.original_values[:cv].should == cv.hash
105
+ tom.cv.should == { 2005 => "Othello", 2006 => "Macbeth" }
106
+ tom.dirty?.should == true
107
+ end
108
+ end
109
+
110
+ it "should track with lazy text fields (#342)" do
111
+ repository(ADAPTER) do
112
+ tim = Actor.create!(:name => 'tim')
113
+ end
114
+ repository(ADAPTER) do
115
+ tim = Actor.first(:name => 'tim')
116
+ tim.notes # make sure they're loaded...
117
+ tim.dirty?.should be_false
118
+ tim.save.should be_false
119
+ tim.notes = "Testing"
120
+ tim.dirty?.should be_true
121
+ tim.save
122
+ end
123
+ repository(ADAPTER) do
124
+ tim = Actor.first(:name => 'tim')
125
+ tim.notes.should == "Testing"
126
+ end
127
+ end
128
+ end
129
+
130
+ describe "lazy loading" do
131
+ before :all do
132
+ class RowBoat
133
+ include DataMapper::Resource
134
+ property :id, Serial
135
+ property :notes, String, :lazy => [:notes]
136
+ property :trip_report, String, :lazy => [:notes,:trip]
137
+ property :miles, Integer, :lazy => [:trip]
138
+ end
139
+ end
140
+
141
+ before do
142
+ RowBoat.auto_migrate!(ADAPTER)
143
+
144
+ repository(ADAPTER) do
145
+ RowBoat.create!(:id => 1, :notes=>'Note',:trip_report=>'Report',:miles=>23)
146
+ RowBoat.create!(:id => 2, :notes=>'Note',:trip_report=>'Report',:miles=>23)
147
+ RowBoat.create!(:id => 3, :notes=>'Note',:trip_report=>'Report',:miles=>23)
148
+ end
149
+ end
150
+
151
+ it "should lazy load in context" do
152
+ result = repository(ADAPTER) { RowBoat.all.to_a }
153
+
154
+ result[0].attribute_loaded?(:notes).should be_false
155
+ result[0].attribute_loaded?(:trip_report).should be_false
156
+ result[1].attribute_loaded?(:notes).should be_false
157
+
158
+ result[0].notes.should_not be_nil
159
+
160
+ result[1].attribute_loaded?(:notes).should be_true
161
+ result[1].attribute_loaded?(:trip_report).should be_true
162
+ result[1].attribute_loaded?(:miles).should be_false
163
+
164
+ result = repository(ADAPTER) { RowBoat.all.to_a }
165
+
166
+ result[0].attribute_loaded?(:trip_report).should be_false
167
+ result[0].attribute_loaded?(:miles).should be_false
168
+
169
+ result[1].trip_report.should_not be_nil
170
+ result[2].attribute_loaded?(:miles).should be_true
171
+ end
172
+ end
173
+
174
+ describe 'defaults' do
175
+ before :all do
176
+ class Catamaran
177
+ include DataMapper::Resource
178
+ property :id, Serial
179
+ property :name, String
180
+
181
+ # Boolean
182
+ property :could_be_bool0, TrueClass, :default => true
183
+ property :could_be_bool1, TrueClass, :default => false
184
+ end
185
+
186
+ repository(ADAPTER){ Catamaran.auto_migrate!(ADAPTER) }
187
+ end
188
+
189
+ before :each do
190
+ @cat = Catamaran.new
191
+ end
192
+
193
+ it "should have defaults" do
194
+ @cat.could_be_bool0.should == true
195
+ @cat.could_be_bool1.should_not be_nil
196
+ @cat.could_be_bool1.should == false
197
+
198
+ @cat.name = 'Mary Mayweather'
199
+
200
+ repository(ADAPTER) do
201
+ @cat.save
202
+
203
+ cat = Catamaran.first
204
+ cat.could_be_bool0.should == true
205
+ cat.could_be_bool1.should_not be_nil
206
+ cat.could_be_bool1.should == false
207
+ cat.destroy
208
+ end
209
+
210
+ end
211
+
212
+ it "should have defaults even with creates" do
213
+ repository(ADAPTER) do
214
+ Catamaran.create!(:name => 'Jingle All The Way')
215
+ cat = Catamaran.first
216
+ cat.name.should == 'Jingle All The Way'
217
+ cat.could_be_bool0.should == true
218
+ cat.could_be_bool1.should_not be_nil
219
+ cat.could_be_bool1.should == false
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,376 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ if ADAPTER
4
+ describe DataMapper::Query, "with #{ADAPTER}" do
5
+ describe 'when ordering' do
6
+ before :all do
7
+ class SailBoat
8
+ include DataMapper::Resource
9
+ property :id, Serial
10
+ property :name, String
11
+ property :port, String
12
+ end
13
+ end
14
+
15
+ before do
16
+ SailBoat.auto_migrate!(ADAPTER)
17
+
18
+ repository(ADAPTER) do
19
+ SailBoat.create!(:name => 'A', :port => 'C')
20
+ SailBoat.create!(:name => 'B', :port => 'B')
21
+ SailBoat.create!(:name => 'C', :port => 'A')
22
+ end
23
+ end
24
+
25
+ it "should find by conditions" do
26
+ lambda do
27
+ repository(ADAPTER) do
28
+ SailBoat.first(:conditions => ['name = ?', 'B'])
29
+ end
30
+ end.should_not raise_error
31
+
32
+ lambda do
33
+ repository(ADAPTER) do
34
+ SailBoat.first(:conditions => ['name = ?', 'A'])
35
+ end
36
+ end.should_not raise_error
37
+ end
38
+
39
+ it "should find by conditions passed in as hash" do
40
+ repository(ADAPTER) do
41
+ SailBoat.create!(:name => "couldbe@email.com", :port => 'wee')
42
+
43
+ find = SailBoat.first(:name => 'couldbe@email.com')
44
+ find.name.should == 'couldbe@email.com'
45
+
46
+ find = SailBoat.first(:name => 'couldbe@email.com', :port.not => nil)
47
+ find.should_not be_nil
48
+ find.port.should_not be_nil
49
+ find.name.should == 'couldbe@email.com'
50
+ end
51
+ end
52
+
53
+ it "should find by conditions passed in a range" do
54
+ repository(ADAPTER) do
55
+ find = SailBoat.all(:id => 0..2)
56
+ find.should_not be_nil
57
+ find.should have(2).entries
58
+
59
+ find = SailBoat.all(:id.not => 0..2)
60
+ find.should have(1).entries
61
+ end
62
+ end
63
+
64
+ it "should order results" do
65
+ repository(ADAPTER) do
66
+ result = SailBoat.all(:order => [
67
+ DataMapper::Query::Direction.new(SailBoat.properties[:name], :asc)
68
+ ])
69
+ result[0].id.should == 1
70
+
71
+ result = SailBoat.all(:order => [
72
+ DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
73
+ ])
74
+ result[0].id.should == 3
75
+
76
+ result = SailBoat.all(:order => [
77
+ DataMapper::Query::Direction.new(SailBoat.properties[:name], :asc),
78
+ DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
79
+ ])
80
+ result[0].id.should == 1
81
+
82
+ result = SailBoat.all(:order => [
83
+ SailBoat.properties[:name],
84
+ DataMapper::Query::Direction.new(SailBoat.properties[:port], :asc)
85
+ ])
86
+ result[0].id.should == 1
87
+
88
+ result = SailBoat.all(:order => [:name])
89
+ result[0].id.should == 1
90
+
91
+ result = SailBoat.all(:order => [:name.desc])
92
+ result[0].id.should == 3
93
+ end
94
+ end
95
+ end
96
+
97
+ describe 'when sub-selecting' do
98
+ before :all do
99
+ class Permission
100
+ include DataMapper::Resource
101
+ property :id, Serial
102
+ property :user_id, Integer
103
+ property :resource_id, Integer
104
+ property :resource_type, String
105
+ property :token, String
106
+ end
107
+
108
+ class SailBoat
109
+ include DataMapper::Resource
110
+ property :id, Serial
111
+ property :name, String
112
+ property :port, String
113
+ property :captain, String
114
+ end
115
+ end
116
+
117
+ before do
118
+ Permission.auto_migrate!(ADAPTER)
119
+ SailBoat.auto_migrate!(ADAPTER)
120
+
121
+ repository(ADAPTER) do
122
+ SailBoat.create!(:id => 1, :name => "Fantasy I", :port => "Cape Town", :captain => 'Joe')
123
+ SailBoat.create!(:id => 2, :name => "Royal Flush II", :port => "Cape Town", :captain => 'James')
124
+ SailBoat.create!(:id => 3, :name => "Infringer III", :port => "Cape Town", :captain => 'Jason')
125
+
126
+ #User 1 permission -- read boat 1 & 2
127
+ Permission.create!(:id => 1, :user_id => 1, :resource_id => 1, :resource_type => 'SailBoat', :token => 'READ')
128
+ Permission.create!(:id => 2, :user_id => 1, :resource_id => 2, :resource_type => 'SailBoat', :token => 'READ')
129
+
130
+ #User 2 permission -- read boat 2 & 3
131
+ Permission.create!(:id => 3, :user_id => 2, :resource_id => 2, :resource_type => 'SailBoat', :token => 'READ')
132
+ Permission.create!(:id => 4, :user_id => 2, :resource_id => 3, :resource_type => 'SailBoat', :token => 'READ')
133
+ end
134
+ end
135
+
136
+ it 'should accept a DM::Query as a value of a condition' do
137
+ # User 1
138
+ acl = DataMapper::Query.new(repository(ADAPTER), Permission, :user_id => 1, :resource_type => 'SailBoat', :token => 'READ', :fields => [ :resource_id ])
139
+ query = { :port => 'Cape Town', :id => acl, :captain.like => 'J%', :order => [ :id ] }
140
+ boats = repository(ADAPTER) { SailBoat.all(query) }
141
+ boats.should have(2).entries
142
+ boats.entries[0].id.should == 1
143
+ boats.entries[1].id.should == 2
144
+
145
+ # User 2
146
+ acl = DataMapper::Query.new(repository(ADAPTER), Permission, :user_id => 2, :resource_type => 'SailBoat', :token => 'READ', :fields => [ :resource_id ])
147
+ query = { :port => 'Cape Town', :id => acl, :captain.like => 'J%', :order => [ :id ] }
148
+ boats = repository(ADAPTER) { SailBoat.all(query) }
149
+
150
+ boats.should have(2).entries
151
+ boats.entries[0].id.should == 2
152
+ boats.entries[1].id.should == 3
153
+ end
154
+
155
+ it 'when value is NOT IN another query' do
156
+ # Boats that User 1 Cannot see
157
+ acl = DataMapper::Query.new(repository(ADAPTER), Permission, :user_id => 1, :resource_type => 'SailBoat', :token => 'READ', :fields => [:resource_id])
158
+ query = { :port => 'Cape Town', :id.not => acl, :captain.like => 'J%' }
159
+ boats = repository(ADAPTER) { SailBoat.all(query) }
160
+ boats.should have(1).entries
161
+ boats.entries[0].id.should == 3
162
+ end
163
+ end # describe sub-selecting
164
+
165
+ describe 'when linking associated objects' do
166
+ before :all do
167
+ class Region
168
+ include DataMapper::Resource
169
+ property :id, Serial
170
+ property :name, String
171
+
172
+ def self.default_repository_name
173
+ ADAPTER
174
+ end
175
+ end
176
+
177
+ class Factory
178
+ include DataMapper::Resource
179
+ property :id, Serial
180
+ property :region_id, Integer
181
+ property :name, String
182
+
183
+ repository(:mock) do
184
+ property :land, String
185
+ end
186
+
187
+ belongs_to :region
188
+
189
+ def self.default_repository_name
190
+ ADAPTER
191
+ end
192
+ end
193
+
194
+ class Vehicle
195
+ include DataMapper::Resource
196
+ property :id, Serial
197
+ property :factory_id, Integer
198
+ property :name, String
199
+
200
+ belongs_to :factory
201
+
202
+ def self.default_repository_name
203
+ ADAPTER
204
+ end
205
+ end
206
+
207
+ module Namespace
208
+ class Region
209
+ include DataMapper::Resource
210
+ property :id, Serial
211
+ property :name, String
212
+
213
+ def self.default_repository_name
214
+ ADAPTER
215
+ end
216
+ end
217
+
218
+ class Factory
219
+ include DataMapper::Resource
220
+ property :id, Serial
221
+ property :region_id, Integer
222
+ property :name, String
223
+
224
+ repository(:mock) do
225
+ property :land, String
226
+ end
227
+
228
+ belongs_to :region
229
+
230
+ def self.default_repository_name
231
+ ADAPTER
232
+ end
233
+ end
234
+
235
+ class Vehicle
236
+ include DataMapper::Resource
237
+ property :id, Serial
238
+ property :factory_id, Integer
239
+ property :name, String
240
+
241
+ belongs_to :factory
242
+
243
+ def self.default_repository_name
244
+ ADAPTER
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ before do
251
+ Region.auto_migrate!
252
+ Factory.auto_migrate!
253
+ Vehicle.auto_migrate!
254
+
255
+ Region.new(:id=>1, :name=>'North West').save
256
+ Factory.new(:id=>2000, :region_id=>1, :name=>'North West Plant').save
257
+ Vehicle.new(:id=>1, :factory_id=>2000, :name=>'10 ton delivery truck').save
258
+
259
+ Namespace::Region.auto_migrate!
260
+ Namespace::Factory.auto_migrate!
261
+ Namespace::Vehicle.auto_migrate!
262
+
263
+ Namespace::Region.new(:id=>1, :name=>'North West').save
264
+ Namespace::Factory.new(:id=>2000, :region_id=>1, :name=>'North West Plant').save
265
+ Namespace::Vehicle.new(:id=>1, :factory_id=>2000, :name=>'10 ton delivery truck').save
266
+ end
267
+
268
+ it 'should require that all properties in :fields and all :links come from the same repository' #do
269
+ # land = Factory.properties(:mock)[:land]
270
+ # fields = []
271
+ # Vehicle.properties(ADAPTER).map do |property|
272
+ # fields << property
273
+ # end
274
+ # fields << land
275
+ #
276
+ # lambda{
277
+ # begin
278
+ # results = repository(ADAPTER) { Vehicle.all(:links => [:factory], :fields => fields) }
279
+ # rescue RuntimeError
280
+ # $!.message.should == "Property Factory.land not available in repository #{ADAPTER}"
281
+ # raise $!
282
+ # end
283
+ # }.should raise_error(RuntimeError)
284
+ #end
285
+
286
+ it 'should accept a DM::Assoc::Relationship as a link' do
287
+ factory = DataMapper::Associations::Relationship.new(
288
+ :factory,
289
+ ADAPTER,
290
+ 'Vehicle',
291
+ 'Factory',
292
+ { :child_key => [ :factory_id ], :parent_key => [ :id ] }
293
+ )
294
+ results = repository(ADAPTER) { Vehicle.all(:links => [factory]) }
295
+ results.should have(1).entries
296
+ end
297
+
298
+ it 'should accept a symbol of an association name as a link' do
299
+ results = repository(ADAPTER) { Vehicle.all(:links => [:factory]) }
300
+ results.should have(1).entries
301
+ end
302
+
303
+ it 'should accept a string of an association name as a link' do
304
+ results = repository(ADAPTER) { Vehicle.all(:links => ['factory']) }
305
+ results.should have(1).entries
306
+ end
307
+
308
+ it 'should accept a mixture of items as a set of links' do
309
+ region = DataMapper::Associations::Relationship.new(
310
+ :region,
311
+ ADAPTER,
312
+ 'Factory',
313
+ 'Region',
314
+ { :child_key => [ :region_id ], :parent_key => [ :id ] }
315
+ )
316
+ results = repository(ADAPTER) { Vehicle.all(:links => ['factory',region]) }
317
+ results.should have(1).entries
318
+ end
319
+
320
+ it 'should only accept a DM::Assoc::Relationship, String & Symbol as a link' do
321
+ lambda{
322
+ DataMapper::Query.new(repository(ADAPTER), Vehicle, :links => [1])
323
+ }.should raise_error(ArgumentError)
324
+ end
325
+
326
+ it 'should have a association by the name of the Symbol or String' do
327
+ lambda{
328
+ DataMapper::Query.new(repository(ADAPTER), Vehicle, :links=>['Sailing'])
329
+ }.should raise_error(ArgumentError)
330
+
331
+ lambda{
332
+ DataMapper::Query.new(repository(ADAPTER), Vehicle, :links=>[:sailing])
333
+ }.should raise_error(ArgumentError)
334
+ end
335
+
336
+ it 'should create an n-level query path' do
337
+ Vehicle.factory.region.model.should == Region
338
+ Vehicle.factory.region.name.property.should == Region.properties(Region.repository.name)[:name]
339
+ end
340
+
341
+ it 'should accept a DM::QueryPath as the key to a condition' do
342
+ vehicle = Vehicle.first(Vehicle.factory.region.name => 'North West')
343
+ vehicle.name.should == '10 ton delivery truck'
344
+
345
+ vehicle = Namespace::Vehicle.first(Namespace::Vehicle.factory.region.name => 'North West')
346
+ vehicle.name.should == '10 ton delivery truck'
347
+ end
348
+
349
+ it "should accept a string representing a DM::QueryPath as they key to a condition" do
350
+ vehicle = Vehicle.first("factory.region.name" => 'North West')
351
+ vehicle.name.should == '10 ton delivery truck'
352
+ end
353
+
354
+ it 'should auto generate the link if a DM::Property from a different resource is in the :fields option'
355
+
356
+ it 'should create links with composite keys'
357
+
358
+ it 'should eager load associations' do
359
+ repository(ADAPTER) do
360
+ vehicle = Vehicle.first(:includes => [Vehicle.factory])
361
+ end
362
+ end
363
+
364
+ it "should behave when using mocks" do
365
+ class Group
366
+ include DataMapper::Resource
367
+ property :id, Serial
368
+ property :name, String
369
+ end
370
+
371
+ Group.should_receive(:all).with(:order => [:id.asc])
372
+ Group.all(:order => [:id.asc])
373
+ end
374
+ end # describe links
375
+ end # DM::Query
376
+ end