datamapper-dm-core 0.9.11 → 0.10.0

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 (192) hide show
  1. data/.autotest +17 -14
  2. data/.gitignore +3 -1
  3. data/FAQ +6 -5
  4. data/History.txt +5 -39
  5. data/Manifest.txt +67 -76
  6. data/QUICKLINKS +1 -1
  7. data/README.txt +21 -15
  8. data/Rakefile +16 -15
  9. data/SPECS +2 -29
  10. data/TODO +1 -1
  11. data/dm-core.gemspec +11 -15
  12. data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
  13. data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
  14. data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
  15. data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
  16. data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
  17. data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
  18. data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
  19. data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
  20. data/lib/dm-core/adapters.rb +135 -16
  21. data/lib/dm-core/associations/many_to_many.rb +372 -90
  22. data/lib/dm-core/associations/many_to_one.rb +220 -73
  23. data/lib/dm-core/associations/one_to_many.rb +319 -255
  24. data/lib/dm-core/associations/one_to_one.rb +66 -53
  25. data/lib/dm-core/associations/relationship.rb +560 -158
  26. data/lib/dm-core/collection.rb +1104 -381
  27. data/lib/dm-core/core_ext/kernel.rb +12 -0
  28. data/lib/dm-core/core_ext/symbol.rb +10 -0
  29. data/lib/dm-core/identity_map.rb +4 -34
  30. data/lib/dm-core/migrations.rb +1283 -0
  31. data/lib/dm-core/model/descendant_set.rb +81 -0
  32. data/lib/dm-core/model/hook.rb +45 -0
  33. data/lib/dm-core/model/is.rb +32 -0
  34. data/lib/dm-core/model/property.rb +248 -0
  35. data/lib/dm-core/model/relationship.rb +335 -0
  36. data/lib/dm-core/model/scope.rb +90 -0
  37. data/lib/dm-core/model.rb +570 -369
  38. data/lib/dm-core/property.rb +753 -280
  39. data/lib/dm-core/property_set.rb +141 -98
  40. data/lib/dm-core/query/conditions/comparison.rb +814 -0
  41. data/lib/dm-core/query/conditions/operation.rb +247 -0
  42. data/lib/dm-core/query/direction.rb +43 -0
  43. data/lib/dm-core/query/operator.rb +42 -0
  44. data/lib/dm-core/query/path.rb +102 -0
  45. data/lib/dm-core/query/sort.rb +45 -0
  46. data/lib/dm-core/query.rb +974 -492
  47. data/lib/dm-core/repository.rb +147 -107
  48. data/lib/dm-core/resource.rb +644 -429
  49. data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
  50. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
  51. data/lib/dm-core/support/chainable.rb +20 -0
  52. data/lib/dm-core/support/deprecate.rb +12 -0
  53. data/lib/dm-core/support/equalizer.rb +23 -0
  54. data/lib/dm-core/support/logger.rb +13 -0
  55. data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
  56. data/lib/dm-core/transaction.rb +333 -92
  57. data/lib/dm-core/type.rb +98 -60
  58. data/lib/dm-core/types/boolean.rb +1 -1
  59. data/lib/dm-core/types/discriminator.rb +34 -20
  60. data/lib/dm-core/types/object.rb +7 -4
  61. data/lib/dm-core/types/paranoid_boolean.rb +11 -9
  62. data/lib/dm-core/types/paranoid_datetime.rb +11 -9
  63. data/lib/dm-core/types/serial.rb +3 -3
  64. data/lib/dm-core/types/text.rb +3 -4
  65. data/lib/dm-core/version.rb +1 -1
  66. data/lib/dm-core.rb +106 -110
  67. data/script/performance.rb +102 -109
  68. data/script/profile.rb +169 -38
  69. data/spec/lib/adapter_helpers.rb +105 -0
  70. data/spec/lib/collection_helpers.rb +18 -0
  71. data/spec/lib/counter_adapter.rb +34 -0
  72. data/spec/lib/pending_helpers.rb +27 -0
  73. data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
  74. data/spec/public/associations/many_to_many_spec.rb +193 -0
  75. data/spec/public/associations/many_to_one_spec.rb +73 -0
  76. data/spec/public/associations/one_to_many_spec.rb +77 -0
  77. data/spec/public/associations/one_to_one_spec.rb +156 -0
  78. data/spec/public/collection_spec.rb +65 -0
  79. data/spec/public/model/relationship_spec.rb +924 -0
  80. data/spec/public/model_spec.rb +159 -0
  81. data/spec/public/property_spec.rb +829 -0
  82. data/spec/public/resource_spec.rb +71 -0
  83. data/spec/public/sel_spec.rb +44 -0
  84. data/spec/public/setup_spec.rb +145 -0
  85. data/spec/public/shared/association_collection_shared_spec.rb +317 -0
  86. data/spec/public/shared/collection_shared_spec.rb +1723 -0
  87. data/spec/public/shared/finder_shared_spec.rb +1619 -0
  88. data/spec/public/shared/resource_shared_spec.rb +924 -0
  89. data/spec/public/shared/sel_shared_spec.rb +112 -0
  90. data/spec/public/transaction_spec.rb +129 -0
  91. data/spec/public/types/discriminator_spec.rb +130 -0
  92. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  93. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  94. data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
  95. data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
  96. data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
  97. data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
  98. data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
  99. data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
  100. data/spec/semipublic/associations/relationship_spec.rb +194 -0
  101. data/spec/semipublic/associations_spec.rb +177 -0
  102. data/spec/semipublic/collection_spec.rb +142 -0
  103. data/spec/semipublic/property_spec.rb +61 -0
  104. data/spec/semipublic/query/conditions_spec.rb +528 -0
  105. data/spec/semipublic/query/path_spec.rb +443 -0
  106. data/spec/semipublic/query_spec.rb +2626 -0
  107. data/spec/semipublic/resource_spec.rb +47 -0
  108. data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
  109. data/spec/spec.opts +3 -1
  110. data/spec/spec_helper.rb +80 -57
  111. data/tasks/ci.rb +19 -31
  112. data/tasks/dm.rb +43 -48
  113. data/tasks/doc.rb +8 -11
  114. data/tasks/gemspec.rb +5 -5
  115. data/tasks/hoe.rb +15 -16
  116. data/tasks/install.rb +8 -10
  117. metadata +72 -93
  118. data/lib/dm-core/associations/relationship_chain.rb +0 -81
  119. data/lib/dm-core/associations.rb +0 -207
  120. data/lib/dm-core/auto_migrations.rb +0 -105
  121. data/lib/dm-core/dependency_queue.rb +0 -32
  122. data/lib/dm-core/hook.rb +0 -11
  123. data/lib/dm-core/is.rb +0 -16
  124. data/lib/dm-core/logger.rb +0 -232
  125. data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
  126. data/lib/dm-core/migrator.rb +0 -29
  127. data/lib/dm-core/scope.rb +0 -58
  128. data/lib/dm-core/support/array.rb +0 -13
  129. data/lib/dm-core/support/assertions.rb +0 -8
  130. data/lib/dm-core/support/errors.rb +0 -23
  131. data/lib/dm-core/support/kernel.rb +0 -11
  132. data/lib/dm-core/support/symbol.rb +0 -41
  133. data/lib/dm-core/support.rb +0 -7
  134. data/lib/dm-core/type_map.rb +0 -80
  135. data/lib/dm-core/types.rb +0 -19
  136. data/script/all +0 -4
  137. data/spec/integration/association_spec.rb +0 -1382
  138. data/spec/integration/association_through_spec.rb +0 -203
  139. data/spec/integration/associations/many_to_many_spec.rb +0 -449
  140. data/spec/integration/associations/many_to_one_spec.rb +0 -163
  141. data/spec/integration/associations/one_to_many_spec.rb +0 -188
  142. data/spec/integration/auto_migrations_spec.rb +0 -413
  143. data/spec/integration/collection_spec.rb +0 -1073
  144. data/spec/integration/data_objects_adapter_spec.rb +0 -32
  145. data/spec/integration/dependency_queue_spec.rb +0 -46
  146. data/spec/integration/model_spec.rb +0 -197
  147. data/spec/integration/mysql_adapter_spec.rb +0 -85
  148. data/spec/integration/postgres_adapter_spec.rb +0 -731
  149. data/spec/integration/property_spec.rb +0 -253
  150. data/spec/integration/query_spec.rb +0 -514
  151. data/spec/integration/repository_spec.rb +0 -61
  152. data/spec/integration/resource_spec.rb +0 -513
  153. data/spec/integration/sqlite3_adapter_spec.rb +0 -352
  154. data/spec/integration/sti_spec.rb +0 -273
  155. data/spec/integration/strategic_eager_loading_spec.rb +0 -156
  156. data/spec/integration/transaction_spec.rb +0 -75
  157. data/spec/integration/type_spec.rb +0 -275
  158. data/spec/lib/logging_helper.rb +0 -18
  159. data/spec/lib/mock_adapter.rb +0 -27
  160. data/spec/lib/model_loader.rb +0 -100
  161. data/spec/lib/publicize_methods.rb +0 -28
  162. data/spec/models/content.rb +0 -16
  163. data/spec/models/vehicles.rb +0 -34
  164. data/spec/models/zoo.rb +0 -48
  165. data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
  166. data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
  167. data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
  168. data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
  169. data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
  170. data/spec/unit/associations/many_to_many_spec.rb +0 -32
  171. data/spec/unit/associations/many_to_one_spec.rb +0 -159
  172. data/spec/unit/associations/one_to_many_spec.rb +0 -393
  173. data/spec/unit/associations/one_to_one_spec.rb +0 -7
  174. data/spec/unit/associations/relationship_spec.rb +0 -71
  175. data/spec/unit/associations_spec.rb +0 -242
  176. data/spec/unit/auto_migrations_spec.rb +0 -111
  177. data/spec/unit/collection_spec.rb +0 -182
  178. data/spec/unit/data_mapper_spec.rb +0 -35
  179. data/spec/unit/identity_map_spec.rb +0 -126
  180. data/spec/unit/is_spec.rb +0 -80
  181. data/spec/unit/migrator_spec.rb +0 -33
  182. data/spec/unit/model_spec.rb +0 -321
  183. data/spec/unit/naming_conventions_spec.rb +0 -36
  184. data/spec/unit/property_set_spec.rb +0 -90
  185. data/spec/unit/property_spec.rb +0 -753
  186. data/spec/unit/query_spec.rb +0 -571
  187. data/spec/unit/repository_spec.rb +0 -93
  188. data/spec/unit/resource_spec.rb +0 -649
  189. data/spec/unit/scope_spec.rb +0 -142
  190. data/spec/unit/transaction_spec.rb +0 -493
  191. data/spec/unit/type_map_spec.rb +0 -114
  192. data/spec/unit/type_spec.rb +0 -119
@@ -0,0 +1,2626 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ require 'ostruct'
4
+
5
+ # TODO: make some of specs for Query.new shared. the assertions and
6
+ # normalizations should happen for Query#update, Query#relative and
7
+ # Query#merge and should probably be in shared specs
8
+
9
+ # class methods
10
+ describe DataMapper::Query do
11
+ before :all do
12
+ class ::Password < DataMapper::Type
13
+ primitive String
14
+ length 40
15
+ end
16
+
17
+ class ::User
18
+ include DataMapper::Resource
19
+
20
+ property :name, String, :key => true
21
+ property :password, Password
22
+ property :balance, BigDecimal
23
+
24
+ belongs_to :referrer, self, :nullable => true
25
+ has n, :referrals, self, :inverse => :referrer
26
+ end
27
+
28
+ @repository = DataMapper::Repository.new(:default)
29
+ @model = User
30
+
31
+ @fields = [ :name ].freeze
32
+ @links = [ :referrer ].freeze
33
+ @conditions = { :name => 'Dan Kubb' }
34
+ @offset = 0
35
+ @limit = 1
36
+ @order = [ :name ].freeze
37
+ @unique = false
38
+ @add_reversed = false
39
+ @reload = false
40
+
41
+ @options = {
42
+ :fields => @fields,
43
+ :links => @links,
44
+ :conditions => @conditions,
45
+ :offset => @offset,
46
+ :limit => @limit,
47
+ :order => @order,
48
+ :unique => @unique,
49
+ :add_reversed => @add_reversed,
50
+ :reload => @reload,
51
+ }
52
+ end
53
+
54
+ it { DataMapper::Query.should respond_to(:new) }
55
+
56
+ describe '.new' do
57
+ describe 'with a repository' do
58
+ describe 'that is valid' do
59
+ before :all do
60
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
61
+ end
62
+
63
+ it { @return.should be_kind_of(DataMapper::Query) }
64
+
65
+ it 'should set the repository' do
66
+ @return.repository.should == @repository
67
+ end
68
+ end
69
+
70
+ describe 'that is invalid' do
71
+ it 'should raise an exception' do
72
+ lambda {
73
+ DataMapper::Query.new('invalid', @model, @options)
74
+ }.should raise_error(ArgumentError, '+repository+ should be DataMapper::Repository, but was String')
75
+ end
76
+ end
77
+ end
78
+
79
+ describe 'with a model' do
80
+ describe 'that is valid' do
81
+ before :all do
82
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
83
+ end
84
+
85
+ it { @return.should be_kind_of(DataMapper::Query) }
86
+
87
+ it 'should set the model' do
88
+ @return.model.should == @model
89
+ end
90
+ end
91
+
92
+ describe 'that is invalid' do
93
+ it 'should raise an exception' do
94
+ lambda {
95
+ DataMapper::Query.new(@repository, 'invalid', @options)
96
+ }.should raise_error(ArgumentError, '+model+ should be DataMapper::Model, but was String')
97
+ end
98
+ end
99
+ end
100
+
101
+ describe 'with a fields option' do
102
+ describe 'that is an Array containing a Symbol' do
103
+ before :all do
104
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
105
+ end
106
+
107
+ it { @return.should be_kind_of(DataMapper::Query) }
108
+
109
+ it 'should set the fields' do
110
+ @return.fields.should == @model.properties.values_at(*@fields)
111
+ end
112
+ end
113
+
114
+ describe 'that is an Array containing a String' do
115
+ before :all do
116
+ @options[:fields] = [ 'name' ]
117
+
118
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
119
+ end
120
+
121
+ it { @return.should be_kind_of(DataMapper::Query) }
122
+
123
+ it 'should set the fields' do
124
+ @return.fields.should == @model.properties.values_at('name')
125
+ end
126
+ end
127
+
128
+ describe 'that is an Array containing a Property' do
129
+ before :all do
130
+ @options[:fields] = @model.properties.values_at(:name)
131
+
132
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
133
+ end
134
+
135
+ it { @return.should be_kind_of(DataMapper::Query) }
136
+
137
+ it 'should set the fields' do
138
+ @return.fields.should == @model.properties.values_at(:name)
139
+ end
140
+ end
141
+
142
+ describe 'that is an Array containing a Property from an ancestor' do
143
+ before :all do
144
+ class ::Contact < User; end
145
+
146
+ @options[:fields] = User.properties.values_at(:name)
147
+
148
+ @return = DataMapper::Query.new(@repository, Contact, @options.freeze)
149
+ end
150
+
151
+ it { @return.should be_kind_of(DataMapper::Query) }
152
+
153
+ it 'should set the fields' do
154
+ @return.fields.should == User.properties.values_at(:name)
155
+ end
156
+ end
157
+
158
+ describe 'that is missing' do
159
+ before :all do
160
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:fields).freeze)
161
+ end
162
+
163
+ it { @return.should be_kind_of(DataMapper::Query) }
164
+
165
+ it 'should set fields to the model default properties' do
166
+ @return.fields.should == @model.properties.defaults
167
+ end
168
+ end
169
+
170
+ describe 'that is invalid' do
171
+ it 'should raise an exception' do
172
+ lambda {
173
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => :name))
174
+ }.should raise_error(ArgumentError, '+options[:fields]+ should be Array, but was Symbol')
175
+ end
176
+ end
177
+
178
+ describe 'that is an empty Array and the unique option is false' do
179
+ it 'should raise an exception' do
180
+ lambda {
181
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [], :unique => false))
182
+ }.should raise_error(ArgumentError, '+options[:fields]+ should not be empty if +options[:unique]+ is false')
183
+ end
184
+ end
185
+
186
+ describe 'that is an Array containing an unknown Symbol' do
187
+ it 'should raise an exception' do
188
+ lambda {
189
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ :unknown ]))
190
+ }.should raise_error(ArgumentError, "+options[:fields]+ entry :unknown does not map to a property in #{@model}")
191
+ end
192
+ end
193
+
194
+ describe 'that is an Array containing an unknown String' do
195
+ it 'should raise an exception' do
196
+ lambda {
197
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ 'unknown' ]))
198
+ }.should raise_error(ArgumentError, "+options[:fields]+ entry \"unknown\" does not map to a property in #{@model}")
199
+ end
200
+ end
201
+
202
+ describe 'that is an Array containing an invalid object' do
203
+ it 'should raise an exception' do
204
+ lambda {
205
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ 1 ]))
206
+ }.should raise_error(ArgumentError, '+options[:fields]+ entry 1 of an unsupported object Fixnum')
207
+ end
208
+ end
209
+
210
+ describe 'that is an Array containing an unknown Property' do
211
+ it 'should raise an exception' do
212
+ lambda {
213
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ DataMapper::Property.new(@model, :unknown, String) ]))
214
+ }.should raise_error(ArgumentError, "+options[:field]+ entry :unknown does not map to a property in #{@model}")
215
+ end
216
+ end
217
+ end
218
+
219
+ describe 'with a links option' do
220
+ describe 'that is an Array containing a Symbol' do
221
+ before :all do
222
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
223
+ end
224
+
225
+ it { @return.should be_kind_of(DataMapper::Query) }
226
+
227
+ it 'should set the links' do
228
+ @return.links.should == @model.relationships.values_at(*@links)
229
+ end
230
+ end
231
+
232
+ describe 'that is an Array containing a String' do
233
+ before :all do
234
+ @options[:links] = [ 'referrer' ]
235
+
236
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
237
+ end
238
+
239
+ it { @return.should be_kind_of(DataMapper::Query) }
240
+
241
+ it 'should set the links' do
242
+ @return.links.should == @model.relationships.values_at('referrer')
243
+ end
244
+ end
245
+
246
+ describe 'that is an Array containing a Relationship' do
247
+ before :all do
248
+ @options[:links] = @model.relationships.values_at(:referrer)
249
+
250
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
251
+ end
252
+
253
+ it { @return.should be_kind_of(DataMapper::Query) }
254
+
255
+ it 'should set the links' do
256
+ @return.links.should == @model.relationships.values_at(:referrer)
257
+ end
258
+ end
259
+
260
+ describe 'that is missing' do
261
+ before :all do
262
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:links).freeze)
263
+ end
264
+
265
+ it { @return.should be_kind_of(DataMapper::Query) }
266
+
267
+ it 'should set links to an empty Array' do
268
+ @return.links.should == []
269
+ end
270
+ end
271
+
272
+ describe 'that is invalid' do
273
+ it 'should raise an exception' do
274
+ lambda {
275
+ DataMapper::Query.new(@repository, @model, @options.update(:links => :referral))
276
+ }.should raise_error(ArgumentError, '+options[:links]+ should be Array, but was Symbol')
277
+ end
278
+ end
279
+
280
+ describe 'that is an empty Array' do
281
+ it 'should raise an exception' do
282
+ lambda {
283
+ DataMapper::Query.new(@repository, @model, @options.update(:links => []))
284
+ }.should raise_error(ArgumentError, '+options[:links]+ should not be empty')
285
+ end
286
+ end
287
+
288
+ describe 'that is an Array containing an unknown Symbol' do
289
+ it 'should raise an exception' do
290
+ lambda {
291
+ DataMapper::Query.new(@repository, @model, @options.update(:links => [ :unknown ]))
292
+ }.should raise_error(ArgumentError, "+options[:links]+ entry :unknown does not map to a relationship in #{@model}")
293
+ end
294
+ end
295
+
296
+ describe 'that is an Array containing an unknown String' do
297
+ it 'should raise an exception' do
298
+ lambda {
299
+ DataMapper::Query.new(@repository, @model, @options.update(:links => [ 'unknown' ]))
300
+ }.should raise_error(ArgumentError, "+options[:links]+ entry \"unknown\" does not map to a relationship in #{@model}")
301
+ end
302
+ end
303
+
304
+ describe 'that is an Array containing an invalid object' do
305
+ it 'should raise an exception' do
306
+ lambda {
307
+ DataMapper::Query.new(@repository, @model, @options.update(:links => [ 1 ]))
308
+ }.should raise_error(ArgumentError, '+options[:links]+ entry 1 of an unsupported object Fixnum')
309
+ end
310
+ end
311
+ end
312
+
313
+ describe 'with a conditions option' do
314
+ describe 'that is a valid Hash' do
315
+ describe 'with the Property key' do
316
+ before :all do
317
+ @options[:conditions] = { @model.properties[:name] => 'Dan Kubb' }
318
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
319
+ end
320
+
321
+ it { @return.should be_kind_of(DataMapper::Query) }
322
+
323
+ it 'should set the conditions' do
324
+ @return.conditions.should ==
325
+ DataMapper::Query::Conditions::Operation.new(
326
+ :and,
327
+ DataMapper::Query::Conditions::Comparison.new(
328
+ :eql,
329
+ @model.properties[:name],
330
+ 'Dan Kubb'
331
+ )
332
+ )
333
+ end
334
+
335
+ it 'should be valid' do
336
+ @return.should be_valid
337
+ end
338
+ end
339
+
340
+ describe 'with the Symbol key mapping to a Property' do
341
+ before :all do
342
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
343
+ end
344
+
345
+ it { @return.should be_kind_of(DataMapper::Query) }
346
+
347
+ it 'should set the conditions' do
348
+ @return.conditions.should ==
349
+ DataMapper::Query::Conditions::Operation.new(
350
+ :and,
351
+ DataMapper::Query::Conditions::Comparison.new(
352
+ :eql,
353
+ @model.properties[:name],
354
+ 'Dan Kubb'
355
+ )
356
+ )
357
+ end
358
+
359
+ it 'should be valid' do
360
+ @return.should be_valid
361
+ end
362
+ end
363
+
364
+ describe 'with the String key mapping to a Property' do
365
+ before :all do
366
+ @options[:conditions] = { 'name' => 'Dan Kubb' }
367
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
368
+ end
369
+
370
+ it { @return.should be_kind_of(DataMapper::Query) }
371
+
372
+ it 'should set the conditions' do
373
+ @return.conditions.should ==
374
+ DataMapper::Query::Conditions::Operation.new(
375
+ :and,
376
+ DataMapper::Query::Conditions::Comparison.new(
377
+ :eql,
378
+ @model.properties[:name],
379
+ 'Dan Kubb'
380
+ )
381
+ )
382
+ end
383
+
384
+ it 'should be valid' do
385
+ @return.should be_valid
386
+ end
387
+ end
388
+
389
+ supported_by :all do
390
+ describe 'with the Symbol key mapping to a Relationship' do
391
+ before :all do
392
+ @user = @model.create(:name => 'Dan Kubb')
393
+
394
+ @options[:conditions] = { :referrer => @user }
395
+
396
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
397
+ end
398
+
399
+ it { @return.should be_kind_of(DataMapper::Query) }
400
+
401
+ it 'should set the conditions' do
402
+ @return.conditions.should ==
403
+ DataMapper::Query::Conditions::Operation.new(
404
+ :and,
405
+ DataMapper::Query::Conditions::Comparison.new(
406
+ :eql,
407
+ @model.relationships[:referrer],
408
+ @user
409
+ )
410
+ )
411
+ end
412
+
413
+ it 'should be valid' do
414
+ @return.should be_valid
415
+ end
416
+ end
417
+
418
+ describe 'with the String key mapping to a Relationship' do
419
+ before :all do
420
+ @user = @model.create(:name => 'Dan Kubb')
421
+
422
+ @options[:conditions] = { 'referrer' => @user }
423
+
424
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
425
+ end
426
+
427
+ it { @return.should be_kind_of(DataMapper::Query) }
428
+
429
+ it 'should set the conditions' do
430
+ @return.conditions.should ==
431
+ DataMapper::Query::Conditions::Operation.new(
432
+ :and,
433
+ DataMapper::Query::Conditions::Comparison.new(
434
+ :eql,
435
+ @model.relationships['referrer'],
436
+ @user
437
+ )
438
+ )
439
+ end
440
+
441
+ it 'should be valid' do
442
+ @return.should be_valid
443
+ end
444
+ end
445
+
446
+ describe 'with the Symbol key mapping to a Relationship and a nil value' do
447
+ before :all do
448
+ @options[:conditions] = { :referrer => nil }
449
+
450
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
451
+ end
452
+
453
+ it { @return.should be_kind_of(DataMapper::Query) }
454
+
455
+ it 'should set the conditions' do
456
+ @return.conditions.should ==
457
+ DataMapper::Query::Conditions::Operation.new(
458
+ :and,
459
+ DataMapper::Query::Conditions::Comparison.new(
460
+ :eql,
461
+ @model.relationships[:referrer],
462
+ nil
463
+ )
464
+ )
465
+ end
466
+
467
+ it 'should be valid' do
468
+ @return.should be_valid
469
+ end
470
+ end
471
+
472
+ describe 'with the Symbol key mapping to a Relationship and an empty Array' do
473
+ before :all do
474
+ @options[:conditions] = { :referrer => [] }
475
+
476
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
477
+ end
478
+
479
+ it { @return.should be_kind_of(DataMapper::Query) }
480
+
481
+ it 'should set the conditions' do
482
+ @return.conditions.should ==
483
+ DataMapper::Query::Conditions::Operation.new(
484
+ :and,
485
+ DataMapper::Query::Conditions::Comparison.new(
486
+ :in,
487
+ @model.relationships[:referrer],
488
+ []
489
+ )
490
+ )
491
+ end
492
+
493
+ it 'should be invalid' do
494
+ @return.should_not be_valid
495
+ end
496
+ end
497
+ end
498
+
499
+ describe 'with the Query::Operator key' do
500
+ before :all do
501
+ @options[:conditions] = { :name.gte => 'Dan Kubb' }
502
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
503
+ end
504
+
505
+ it { @return.should be_kind_of(DataMapper::Query) }
506
+
507
+ it 'should set the conditions' do
508
+ @return.conditions.should ==
509
+ DataMapper::Query::Conditions::Operation.new(
510
+ :and,
511
+ DataMapper::Query::Conditions::Comparison.new(
512
+ :gte,
513
+ @model.properties[:name],
514
+ 'Dan Kubb'
515
+ )
516
+ )
517
+ end
518
+
519
+ it 'should be valid' do
520
+ @return.should be_valid
521
+ end
522
+ end
523
+
524
+ describe 'with the Query::Path key' do
525
+ before :all do
526
+ @options[:conditions] = { @model.referrer.name => 'Dan Kubb' }
527
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
528
+ end
529
+
530
+ it { @return.should be_kind_of(DataMapper::Query) }
531
+
532
+ it 'should set the conditions' do
533
+ @return.conditions.should ==
534
+ DataMapper::Query::Conditions::Operation.new(
535
+ :and,
536
+ DataMapper::Query::Conditions::Comparison.new(
537
+ :eql,
538
+ @model.referrer.name,
539
+ 'Dan Kubb'
540
+ )
541
+ )
542
+ end
543
+
544
+ it 'should set the links' do
545
+ @return.links.should == [ @model.relationships[:referrals], @model.relationships[:referrer] ]
546
+ end
547
+
548
+ it 'should be valid' do
549
+ @return.should be_valid
550
+ end
551
+ end
552
+
553
+ describe 'with the String key mapping to a Query::Path' do
554
+ before :all do
555
+ @options[:conditions] = { 'referrer.name' => 'Dan Kubb' }
556
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
557
+ end
558
+
559
+ it { @return.should be_kind_of(DataMapper::Query) }
560
+
561
+ it 'should set the conditions' do
562
+ @return.conditions.should ==
563
+ DataMapper::Query::Conditions::Operation.new(
564
+ :and,
565
+ DataMapper::Query::Conditions::Comparison.new(
566
+ :eql,
567
+ @model.referrer.name,
568
+ 'Dan Kubb'
569
+ )
570
+ )
571
+ end
572
+
573
+ it 'should set the links' do
574
+ @return.links.should == [ @model.relationships[:referrals], @model.relationships[:referrer] ]
575
+ end
576
+
577
+ it 'should be valid' do
578
+ @return.should be_valid
579
+ end
580
+ end
581
+
582
+ describe 'with a Proc value' do
583
+ before :all do
584
+ @options[:conditions] = { :name => lambda { 'Dan Kubb' } }
585
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
586
+ end
587
+
588
+ it { @return.should be_kind_of(DataMapper::Query) }
589
+
590
+ it 'should set the conditions' do
591
+ @return.conditions.should ==
592
+ DataMapper::Query::Conditions::Operation.new(
593
+ :and,
594
+ DataMapper::Query::Conditions::Comparison.new(
595
+ :eql,
596
+ @model.properties[:name],
597
+ 'Dan Kubb'
598
+ )
599
+ )
600
+ end
601
+
602
+ it 'should be valid' do
603
+ @return.should be_valid
604
+ end
605
+ end
606
+
607
+ describe 'with an Array with 1 entry' do
608
+ before :all do
609
+ @options[:conditions] = { :name => [ 'Dan Kubb' ] }
610
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
611
+ end
612
+
613
+ it { @return.should be_kind_of(DataMapper::Query) }
614
+
615
+ it 'should set the conditions' do
616
+ pending do
617
+ @return.conditions.should ==
618
+ DataMapper::Query::Conditions::Operation.new(
619
+ :and,
620
+ DataMapper::Query::Conditions::Comparison.new(
621
+ :eql,
622
+ @model.properties[:name],
623
+ 'Dan Kubb'
624
+ )
625
+ )
626
+ end
627
+ end
628
+
629
+ it 'should be valid' do
630
+ @return.should be_valid
631
+ end
632
+ end
633
+
634
+ describe 'with an Array with duplicate entries' do
635
+ before :all do
636
+ @options[:conditions] = { :name => [ 'John Doe', 'Dan Kubb', 'John Doe' ] }
637
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
638
+ end
639
+
640
+ it { @return.should be_kind_of(DataMapper::Query) }
641
+
642
+ it 'should set the conditions' do
643
+ @return.conditions.should ==
644
+ DataMapper::Query::Conditions::Operation.new(
645
+ :and,
646
+ DataMapper::Query::Conditions::Comparison.new(
647
+ :in,
648
+ @model.properties[:name],
649
+ [ 'John Doe', 'Dan Kubb' ]
650
+ )
651
+ )
652
+ end
653
+
654
+ it 'should be valid' do
655
+ @return.should be_valid
656
+ end
657
+ end
658
+
659
+ describe 'with a custom Property' do
660
+ before :all do
661
+ @options[:conditions] = { :password => 'password' }
662
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
663
+ end
664
+
665
+ it { @return.should be_kind_of(DataMapper::Query) }
666
+
667
+ it 'should set the conditions' do
668
+ @return.conditions.should ==
669
+ DataMapper::Query::Conditions::Operation.new(
670
+ :and,
671
+ DataMapper::Query::Conditions::Comparison.new(
672
+ :eql,
673
+ @model.properties[:password],
674
+ 'password'
675
+ )
676
+ )
677
+ end
678
+
679
+ it 'should be valid' do
680
+ @return.should be_valid
681
+ end
682
+ end
683
+
684
+ describe 'with a Symbol for a String property' do
685
+ before :all do
686
+ @options[:conditions] = { :name => 'Dan Kubb'.to_sym }
687
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
688
+ end
689
+
690
+ it { @return.should be_kind_of(DataMapper::Query) }
691
+
692
+ it 'should set the conditions' do
693
+ @return.conditions.should ==
694
+ DataMapper::Query::Conditions::Operation.new(
695
+ :and,
696
+ DataMapper::Query::Conditions::Comparison.new(
697
+ :eql,
698
+ @model.properties[:name],
699
+ 'Dan Kubb' # typecast value
700
+ )
701
+ )
702
+ end
703
+
704
+ it 'should be valid' do
705
+ @return.should be_valid
706
+ end
707
+ end
708
+
709
+ describe 'with a Float for a BigDecimal property' do
710
+ before :all do
711
+ @options[:conditions] = { :balance => 50.5 }
712
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
713
+ end
714
+
715
+ it { @return.should be_kind_of(DataMapper::Query) }
716
+
717
+ it 'should set the conditions' do
718
+ @return.conditions.should ==
719
+ DataMapper::Query::Conditions::Operation.new(
720
+ :and,
721
+ DataMapper::Query::Conditions::Comparison.new(
722
+ :eql,
723
+ @model.properties[:balance],
724
+ BigDecimal('50.5') # typecast value
725
+ )
726
+ )
727
+ end
728
+
729
+ it 'should be valid' do
730
+ @return.should be_valid
731
+ end
732
+ end
733
+ end
734
+
735
+ describe 'that is a valid Array' do
736
+ before :all do
737
+ @options[:conditions] = [ 'name = ?', 'Dan Kubb' ]
738
+
739
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
740
+ end
741
+
742
+ it { @return.should be_kind_of(DataMapper::Query) }
743
+
744
+ it 'should set the conditions' do
745
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
746
+ end
747
+
748
+ it 'should be valid' do
749
+ @return.should be_valid
750
+ end
751
+ end
752
+
753
+ describe 'that is missing' do
754
+ before :all do
755
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:conditions).freeze)
756
+ end
757
+
758
+ it { @return.should be_kind_of(DataMapper::Query) }
759
+
760
+ it 'should set conditions to nil by default' do
761
+ @return.conditions.should be_nil
762
+ end
763
+
764
+ it 'should be valid' do
765
+ @return.should be_valid
766
+ end
767
+ end
768
+
769
+ describe 'that is invalid' do
770
+ it 'should raise an exception' do
771
+ lambda {
772
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => 'invalid'))
773
+ }.should raise_error(ArgumentError, '+options[:conditions]+ should be DataMapper::Query::Conditions::AbstractOperation or DataMapper::Query::Conditions::AbstractComparison or Hash or Array, but was String')
774
+ end
775
+ end
776
+
777
+ describe 'that is an empty Array' do
778
+ it 'should raise an exception' do
779
+ lambda {
780
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => []))
781
+ }.should raise_error(ArgumentError, '+options[:conditions]+ should not be empty')
782
+ end
783
+ end
784
+
785
+ describe 'that is an Array with a blank statement' do
786
+ it 'should raise an exception' do
787
+ lambda {
788
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => [ ' ' ]))
789
+ }.should raise_error(ArgumentError, '+options[:conditions]+ should have a statement for the first entry')
790
+ end
791
+ end
792
+
793
+ describe 'that is a Hash with a Symbol key that is not for a Property in the model' do
794
+ it 'should raise an exception' do
795
+ lambda {
796
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { :unknown => 1 }))
797
+ }.should raise_error(ArgumentError, "condition :unknown does not map to a property or relationship in #{@model}")
798
+ end
799
+ end
800
+
801
+ describe 'that is a Hash with a String key that is not for a Property in the model' do
802
+ it 'should raise an exception' do
803
+ lambda {
804
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { 'unknown' => 1 }))
805
+ }.should raise_error(ArgumentError, "condition \"unknown\" does not map to a property or relationship in #{@model}")
806
+ end
807
+ end
808
+
809
+ describe 'that is a Hash with a Query::Operator key that is not for a Property in the model' do
810
+ it 'should raise an exception' do
811
+ lambda {
812
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { :unknown.asc => 1 }))
813
+ }.should raise_error(ArgumentError, 'condition #<DataMapper::Query::Operator @target=:unknown @operator=:asc> used an invalid operator asc')
814
+ end
815
+ end
816
+
817
+ describe 'that is a Hash with a not operator that has an empty Array' do
818
+ it 'should raise an exception' do
819
+ lambda {
820
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { :name.not => [] }))
821
+ }.should raise_error(ArgumentError, 'Cannot use \'not\' operator with a bind value that is an empty Array for #<DataMapper::Query::Operator @target=:name @operator=:not>')
822
+ end
823
+ end
824
+
825
+ describe 'that is a Hash with a key of a type that is not permitted' do
826
+ it 'should raise an exception' do
827
+ lambda {
828
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { 1 => 1 }))
829
+ }.should raise_error(ArgumentError, 'condition 1 of an unsupported object Fixnum')
830
+ end
831
+ end
832
+ end
833
+
834
+ describe 'with an offset option' do
835
+ describe 'that is valid' do
836
+ before :all do
837
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
838
+ end
839
+
840
+ it { @return.should be_kind_of(DataMapper::Query) }
841
+
842
+ it 'should set the offset' do
843
+ @return.offset.should == @offset
844
+ end
845
+ end
846
+
847
+ describe 'that is missing' do
848
+ before :all do
849
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:offset).freeze)
850
+ end
851
+
852
+ it { @return.should be_kind_of(DataMapper::Query) }
853
+
854
+ it 'should set offset to 0' do
855
+ @return.offset.should == 0
856
+ end
857
+ end
858
+
859
+ describe 'that is invalid' do
860
+ it 'should raise an exception' do
861
+ lambda {
862
+ DataMapper::Query.new(@repository, @model, @options.update(:offset => '0'))
863
+ }.should raise_error(ArgumentError, '+options[:offset]+ should be Integer, but was String')
864
+ end
865
+ end
866
+
867
+ describe 'that is less than 0' do
868
+ it 'should raise an exception' do
869
+ lambda {
870
+ DataMapper::Query.new(@repository, @model, @options.update(:offset => -1))
871
+ }.should raise_error(ArgumentError, '+options[:offset]+ must be greater than or equal to 0, but was -1')
872
+ end
873
+ end
874
+
875
+ describe 'that is greater than 0 and a nil limit' do
876
+ it 'should raise an exception' do
877
+ lambda {
878
+ DataMapper::Query.new(@repository, @model, @options.except(:limit).update(:offset => 1))
879
+ }.should raise_error(ArgumentError, '+options[:offset]+ cannot be greater than 0 if limit is not specified')
880
+ end
881
+ end
882
+ end
883
+
884
+ describe 'with a limit option' do
885
+ describe 'that is valid' do
886
+ before :all do
887
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
888
+ end
889
+
890
+ it { @return.should be_kind_of(DataMapper::Query) }
891
+
892
+ it 'should set the limit' do
893
+ @return.limit.should == @limit
894
+ end
895
+ end
896
+
897
+ describe 'that is missing' do
898
+ before :all do
899
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:limit).freeze)
900
+ end
901
+
902
+ it { @return.should be_kind_of(DataMapper::Query) }
903
+
904
+ it 'should set limit to nil' do
905
+ @return.limit.should be_nil
906
+ end
907
+ end
908
+
909
+ describe 'that is invalid' do
910
+ it 'should raise an exception' do
911
+ lambda {
912
+ DataMapper::Query.new(@repository, @model, @options.update(:limit => '1'))
913
+ }.should raise_error(ArgumentError, '+options[:limit]+ should be Integer, but was String')
914
+ end
915
+ end
916
+
917
+ describe 'that is less than 0' do
918
+ it 'should raise an exception' do
919
+ lambda {
920
+ DataMapper::Query.new(@repository, @model, @options.update(:limit => -1))
921
+ }.should raise_error(ArgumentError, '+options[:limit]+ must be greater than or equal to 0, but was -1')
922
+ end
923
+ end
924
+ end
925
+
926
+ describe 'with an order option' do
927
+ describe 'that is an Array containing a Symbol' do
928
+ before :all do
929
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
930
+ end
931
+
932
+ it { @return.should be_kind_of(DataMapper::Query) }
933
+
934
+ it 'should set the order' do
935
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
936
+ end
937
+ end
938
+
939
+ describe 'that is an Array containing a String' do
940
+ before :all do
941
+ @options[:order] = [ 'name' ]
942
+
943
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
944
+ end
945
+
946
+ it { @return.should be_kind_of(DataMapper::Query) }
947
+
948
+ it 'should set the order' do
949
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
950
+ end
951
+ end
952
+
953
+ describe 'that is an Array containing a Property' do
954
+ before :all do
955
+ @options[:order] = @model.properties.values_at(:name)
956
+
957
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
958
+ end
959
+
960
+ it { @return.should be_kind_of(DataMapper::Query) }
961
+
962
+ it 'should set the order' do
963
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
964
+ end
965
+ end
966
+
967
+ describe 'that is an Array containing a Property from an ancestor' do
968
+ before :all do
969
+ class ::Contact < User; end
970
+
971
+ @options[:order] = User.properties.values_at(:name)
972
+
973
+ @return = DataMapper::Query.new(@repository, Contact, @options.freeze)
974
+ end
975
+
976
+ it { @return.should be_kind_of(DataMapper::Query) }
977
+
978
+ it 'should set the order' do
979
+ @return.order.should == [ DataMapper::Query::Direction.new(User.properties[:name]) ]
980
+ end
981
+ end
982
+
983
+ describe 'that is an Array containing an Operator' do
984
+ before :all do
985
+ @options[:order] = [ :name.asc ]
986
+
987
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
988
+ end
989
+
990
+ it { @return.should be_kind_of(DataMapper::Query) }
991
+
992
+ it 'should set the order' do
993
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :asc) ]
994
+ end
995
+ end
996
+
997
+ describe 'that is an Array containing an Query::Direction' do
998
+ before :all do
999
+ @options[:order] = [ DataMapper::Query::Direction.new(@model.properties[:name], :asc) ]
1000
+
1001
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1002
+ end
1003
+
1004
+ it { @return.should be_kind_of(DataMapper::Query) }
1005
+
1006
+ it 'should set the order' do
1007
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :asc) ]
1008
+ end
1009
+ end
1010
+
1011
+ describe 'that is an Array containing an Query::Direction with a Property from an ancestor' do
1012
+ before :all do
1013
+ class ::Contact < User; end
1014
+
1015
+ @options[:order] = [ DataMapper::Query::Direction.new(User.properties[:name], :asc) ]
1016
+
1017
+ @return = DataMapper::Query.new(@repository, Contact, @options.freeze)
1018
+ end
1019
+
1020
+ it { @return.should be_kind_of(DataMapper::Query) }
1021
+
1022
+ it 'should set the order' do
1023
+ @return.order.should == [ DataMapper::Query::Direction.new(User.properties[:name], :asc) ]
1024
+ end
1025
+ end
1026
+
1027
+ describe 'that is missing' do
1028
+ before :all do
1029
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:order).freeze)
1030
+ end
1031
+
1032
+ it { @return.should be_kind_of(DataMapper::Query) }
1033
+
1034
+ it 'should set order to the model default order' do
1035
+ @return.order.should == @model.default_order(@repository.name)
1036
+ end
1037
+ end
1038
+
1039
+ describe 'that is invalid' do
1040
+ it 'should raise an exception' do
1041
+ lambda {
1042
+ DataMapper::Query.new(@repository, @model, @options.update(:order => :name))
1043
+ }.should raise_error(ArgumentError, '+options[:order]+ should be Array, but was Symbol')
1044
+ end
1045
+ end
1046
+
1047
+ describe 'that is an empty Array and the fields option contains a non-operator' do
1048
+ it 'should raise an exception' do
1049
+ lambda {
1050
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [], :fields => [ :name ]))
1051
+ }.should raise_error(ArgumentError, '+options[:order]+ should not be empty if +options[:fields] contains a non-operator')
1052
+ end
1053
+ end
1054
+
1055
+ describe 'that is an Array containing an unknown String' do
1056
+ it 'should raise an exception' do
1057
+ lambda {
1058
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ 'unknown' ]))
1059
+ }.should raise_error(ArgumentError, "+options[:order]+ entry \"unknown\" does not map to a property in #{@model}")
1060
+ end
1061
+ end
1062
+
1063
+ describe 'that is an Array containing an invalid object' do
1064
+ it 'should raise an exception' do
1065
+ lambda {
1066
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ 1 ]))
1067
+ }.should raise_error(ArgumentError, '+options[:order]+ entry 1 of an unsupported object Fixnum')
1068
+ end
1069
+ end
1070
+
1071
+ describe 'that contains a Query::Direction with a property that is not part of the model' do
1072
+ before :all do
1073
+ @property = DataMapper::Property.new(@model, :unknown, String)
1074
+ @direction = DataMapper::Query::Direction.new(@property, :desc)
1075
+ end
1076
+
1077
+ it 'should raise an exception' do
1078
+ lambda {
1079
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ @direction ]))
1080
+ }.should raise_error(ArgumentError, "+options[:order]+ entry :unknown does not map to a property in #{@model}")
1081
+ end
1082
+ end
1083
+
1084
+ describe 'that contains a Query::Operator with a target that is not part of the model' do
1085
+ it 'should raise an exception' do
1086
+ lambda {
1087
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ :unknown.desc ]))
1088
+ }.should raise_error(ArgumentError, "+options[:order]+ entry :unknown does not map to a property in #{@model}")
1089
+ end
1090
+ end
1091
+
1092
+ describe 'that contains a Query::Operator with an unknown operator' do
1093
+ it 'should raise an exception' do
1094
+ lambda {
1095
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ :name.gt ]))
1096
+ }.should raise_error(ArgumentError, '+options[:order]+ entry #<DataMapper::Query::Operator @target=:name @operator=:gt> used an invalid operator gt')
1097
+ end
1098
+ end
1099
+
1100
+ describe 'that contains a Property that is not part of the model' do
1101
+ before :all do
1102
+ @property = DataMapper::Property.new(@model, :unknown, String)
1103
+ end
1104
+
1105
+ it 'should raise an exception' do
1106
+ lambda {
1107
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ @property ]))
1108
+ }.should raise_error(ArgumentError, "+options[:order]+ entry :unknown does not map to a property in #{@model}")
1109
+ end
1110
+ end
1111
+
1112
+ describe 'that contains a Symbol that is not for a Property in the model' do
1113
+ it 'should raise an exception' do
1114
+ lambda {
1115
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ :unknown ]))
1116
+ }.should raise_error(ArgumentError, "+options[:order]+ entry :unknown does not map to a property in #{@model}")
1117
+ end
1118
+ end
1119
+
1120
+ describe 'that contains a String that is not for a Property in the model' do
1121
+ it 'should raise an exception' do
1122
+ lambda {
1123
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ 'unknown' ]))
1124
+ }.should raise_error(ArgumentError, "+options[:order]+ entry \"unknown\" does not map to a property in #{@model}")
1125
+ end
1126
+ end
1127
+ end
1128
+
1129
+ describe 'with a unique option' do
1130
+ describe 'that is valid' do
1131
+ before :all do
1132
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1133
+ end
1134
+
1135
+ it { @return.should be_kind_of(DataMapper::Query) }
1136
+
1137
+ it 'should set the unique? flag' do
1138
+ @return.unique?.should == @unique
1139
+ end
1140
+ end
1141
+
1142
+ describe 'that is missing' do
1143
+ before :all do
1144
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:unique).freeze)
1145
+ end
1146
+
1147
+ it { @return.should be_kind_of(DataMapper::Query) }
1148
+
1149
+ it 'should set the query to not be unique' do
1150
+ @return.should_not be_unique
1151
+ end
1152
+ end
1153
+
1154
+ describe 'that is invalid' do
1155
+ it 'should raise an exception' do
1156
+ lambda {
1157
+ DataMapper::Query.new(@repository, @model, @options.update(:unique => nil))
1158
+ }.should raise_error(ArgumentError, '+options[:unique]+ should be true or false, but was nil')
1159
+ end
1160
+ end
1161
+ end
1162
+
1163
+ describe 'with an add_reversed option' do
1164
+ describe 'that is valid' do
1165
+ before :all do
1166
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1167
+ end
1168
+
1169
+ it { @return.should be_kind_of(DataMapper::Query) }
1170
+
1171
+ it 'should set the add_reversed? flag' do
1172
+ @return.add_reversed?.should == @add_reversed
1173
+ end
1174
+ end
1175
+
1176
+ describe 'that is missing' do
1177
+ before :all do
1178
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:add_reversed).freeze)
1179
+ end
1180
+
1181
+ it { @return.should be_kind_of(DataMapper::Query) }
1182
+
1183
+ it 'should set the query to not add in reverse order' do
1184
+ # TODO: think about renaming the flag to not sound 'clumsy'
1185
+ @return.should_not be_add_reversed
1186
+ end
1187
+ end
1188
+
1189
+ describe 'that is invalid' do
1190
+ it 'should raise an exception' do
1191
+ lambda {
1192
+ DataMapper::Query.new(@repository, @model, @options.update(:add_reversed => nil))
1193
+ }.should raise_error(ArgumentError, '+options[:add_reversed]+ should be true or false, but was nil')
1194
+ end
1195
+ end
1196
+ end
1197
+
1198
+ describe 'with a reload option' do
1199
+ describe 'that is valid' do
1200
+ before :all do
1201
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1202
+ end
1203
+
1204
+ it { @return.should be_kind_of(DataMapper::Query) }
1205
+
1206
+ it 'should set the reload? flag' do
1207
+ @return.reload?.should == @reload
1208
+ end
1209
+ end
1210
+
1211
+ describe 'that is missing' do
1212
+ before :all do
1213
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:reload).freeze)
1214
+ end
1215
+
1216
+ it { @return.should be_kind_of(DataMapper::Query) }
1217
+
1218
+ it 'should set the query to not reload' do
1219
+ @return.should_not be_reload
1220
+ end
1221
+ end
1222
+
1223
+ describe 'that is invalid' do
1224
+ it 'should raise an exception' do
1225
+ lambda {
1226
+ DataMapper::Query.new(@repository, @model, @options.update(:reload => nil))
1227
+ }.should raise_error(ArgumentError, '+options[:reload]+ should be true or false, but was nil')
1228
+ end
1229
+ end
1230
+ end
1231
+
1232
+ describe 'with options' do
1233
+ describe 'that are unknown' do
1234
+ before :all do
1235
+ @options.update(@options.delete(:conditions))
1236
+
1237
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1238
+ end
1239
+
1240
+ it { @return.should be_kind_of(DataMapper::Query) }
1241
+
1242
+ it 'should set the conditions' do
1243
+ @return.conditions.should ==
1244
+ DataMapper::Query::Conditions::Operation.new(
1245
+ :and,
1246
+ DataMapper::Query::Conditions::Comparison.new(
1247
+ :eql,
1248
+ @model.properties[:name],
1249
+ @conditions[:name]
1250
+ )
1251
+ )
1252
+ end
1253
+ end
1254
+
1255
+ describe 'that are invalid' do
1256
+ it 'should raise an exception' do
1257
+ lambda {
1258
+ DataMapper::Query.new(@repository, @model, 'invalid')
1259
+ }.should raise_error(ArgumentError, '+options+ should be Hash, but was String')
1260
+ end
1261
+ end
1262
+ end
1263
+
1264
+ describe 'with no options' do
1265
+ before :all do
1266
+ @return = DataMapper::Query.new(@repository, @model)
1267
+ end
1268
+
1269
+ it { @return.should be_kind_of(DataMapper::Query) }
1270
+
1271
+ it 'should set options to an empty Hash' do
1272
+ @return.options.should == {}
1273
+ end
1274
+ end
1275
+ end
1276
+ end
1277
+
1278
+ # instance methods
1279
+ describe DataMapper::Query do
1280
+ before :all do
1281
+ class ::User
1282
+ include DataMapper::Resource
1283
+
1284
+ property :name, String, :key => true
1285
+ property :citizenship, String
1286
+
1287
+ belongs_to :referrer, self, :nullable => true
1288
+ has n, :referrals, self, :inverse => :referrer
1289
+
1290
+ # TODO: figure out a way to remove this
1291
+ assert_valid
1292
+ end
1293
+
1294
+ @repository = DataMapper::Repository.new(:default)
1295
+ @model = User
1296
+ @options = { :limit => 3 }
1297
+ @query = DataMapper::Query.new(@repository, @model, @options)
1298
+ @original = @query
1299
+ end
1300
+
1301
+ before :all do
1302
+ @other_options = {
1303
+ :fields => [ @model.properties[:name] ].freeze,
1304
+ :links => [ @model.relationships[:referrer] ].freeze,
1305
+ :conditions => [ 'name = ?', 'Dan Kubb' ].freeze,
1306
+ :offset => 1,
1307
+ :limit => 2,
1308
+ :order => [ DataMapper::Query::Direction.new(@model.properties[:name], :desc) ].freeze,
1309
+ :unique => true,
1310
+ :add_reversed => true,
1311
+ :reload => true,
1312
+ }
1313
+ end
1314
+
1315
+ it { @query.should respond_to(:==) }
1316
+
1317
+ describe '#==' do
1318
+ describe 'when other is equal' do
1319
+ before :all do
1320
+ @return = @query == @query
1321
+ end
1322
+
1323
+ it { @return.should be_true }
1324
+ end
1325
+
1326
+ describe 'when other is equivalent' do
1327
+ before :all do
1328
+ @return = @query == @query.dup
1329
+ end
1330
+
1331
+ it { @return.should be_true }
1332
+ end
1333
+
1334
+ DataMapper::Query::OPTIONS.each do |name|
1335
+ describe "when other has an inequalvalent #{name}" do
1336
+ before :all do
1337
+ @return = @query == @query.merge(name => @other_options[name])
1338
+ end
1339
+
1340
+ it { @return.should be_false }
1341
+ end
1342
+ end
1343
+
1344
+ describe 'when other is a different type of object that can be compared, and is equivalent' do
1345
+ before :all do
1346
+ @other = OpenStruct.new(
1347
+ :repository => @query.repository,
1348
+ :model => @query.model,
1349
+ :sorted_fields => @query.sorted_fields,
1350
+ :links => @query.links,
1351
+ :conditions => @query.conditions,
1352
+ :order => @query.order,
1353
+ :limit => @query.limit,
1354
+ :offset => @query.offset,
1355
+ :reload? => @query.reload?,
1356
+ :unique? => @query.unique?,
1357
+ :add_reversed? => @query.add_reversed?
1358
+ )
1359
+
1360
+ @return = @query == @other
1361
+ end
1362
+
1363
+ it { @return.should be_true }
1364
+ end
1365
+
1366
+ describe 'when other is a different type of object that can be compared, and is not equivalent' do
1367
+ before :all do
1368
+ @other = OpenStruct.new(
1369
+ :repository => @query.repository,
1370
+ :model => @query.model,
1371
+ :sorted_fields => @query.sorted_fields,
1372
+ :links => @query.links,
1373
+ :conditions => @query.conditions,
1374
+ :order => @query.order,
1375
+ :limit => @query.limit,
1376
+ :offset => @query.offset,
1377
+ :reload? => true,
1378
+ :unique? => @query.unique?,
1379
+ :add_reversed? => @query.add_reversed?
1380
+ )
1381
+
1382
+ @return = @query == @other
1383
+ end
1384
+
1385
+ it { @return.should be_false }
1386
+ end
1387
+
1388
+ describe 'when other is a different type of object that cannot be compared' do
1389
+ before :all do
1390
+ @return = @query == 'invalid'
1391
+ end
1392
+
1393
+ it { @return.should be_false }
1394
+ end
1395
+ end
1396
+
1397
+ it { @query.should respond_to(:conditions) }
1398
+
1399
+ describe '#conditions' do
1400
+ before :all do
1401
+ @query.update(:name => 'Dan Kubb')
1402
+
1403
+ @return = @query.conditions
1404
+ end
1405
+
1406
+ it { @return.should be_kind_of(DataMapper::Query::Conditions::AndOperation) }
1407
+
1408
+ it 'should return expected value' do
1409
+ @return.should ==
1410
+ DataMapper::Query::Conditions::Operation.new(
1411
+ :and,
1412
+ DataMapper::Query::Conditions::Comparison.new(
1413
+ :eql,
1414
+ @model.properties[:name],
1415
+ 'Dan Kubb'
1416
+ )
1417
+ )
1418
+ end
1419
+ end
1420
+
1421
+ it { @query.should respond_to(:dup) }
1422
+
1423
+ describe '#dup' do
1424
+ it 'should be awesome'
1425
+ end
1426
+
1427
+ it { @query.should respond_to(:eql?) }
1428
+
1429
+ describe '#eql?' do
1430
+ describe 'when other is equal' do
1431
+ before :all do
1432
+ @return = @query.eql?(@query)
1433
+ end
1434
+
1435
+ it { @return.should be_true }
1436
+ end
1437
+
1438
+ describe 'when other is eql' do
1439
+ before :all do
1440
+ @return = @query.eql?(@query.dup)
1441
+ end
1442
+
1443
+ it { @return.should be_true }
1444
+ end
1445
+
1446
+ DataMapper::Query::OPTIONS.each do |name|
1447
+ describe "when other has an not eql #{name}" do
1448
+ before :all do
1449
+ @return = @query.eql?(@query.merge(name => @other_options[name]))
1450
+ end
1451
+
1452
+ it { @return.should be_false }
1453
+ end
1454
+ end
1455
+
1456
+ describe 'when other is a different type of object' do
1457
+ before :all do
1458
+ @other = OpenStruct.new(
1459
+ :repository => @query.repository,
1460
+ :model => @query.model,
1461
+ :sorted_fields => @query.sorted_fields,
1462
+ :links => @query.links,
1463
+ :conditions => @query.conditions,
1464
+ :order => @query.order,
1465
+ :limit => @query.limit,
1466
+ :offset => @query.offset,
1467
+ :reload? => @query.reload?,
1468
+ :unique? => @query.unique?,
1469
+ :add_reversed? => @query.add_reversed?
1470
+ )
1471
+
1472
+ @return = @query.eql?(@other)
1473
+ end
1474
+
1475
+ it { @return.should be_false }
1476
+ end
1477
+ end
1478
+
1479
+ it { @query.should respond_to(:fields) }
1480
+
1481
+ describe '#fields' do
1482
+ before :all do
1483
+ @return = @query.fields
1484
+ end
1485
+
1486
+ it { @return.should be_kind_of(Array) }
1487
+
1488
+ it 'should return expected value' do
1489
+ @return.should == [ @model.properties[:name], @model.properties[:citizenship], @model.properties[:referrer_name] ]
1490
+ end
1491
+ end
1492
+
1493
+ it { @query.should respond_to(:filter_records) }
1494
+
1495
+ supported_by :all do
1496
+ describe '#filter_records' do
1497
+ before :all do
1498
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
1499
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
1500
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
1501
+
1502
+ @records = [ @john, @sam, @dan ]
1503
+
1504
+ @query.update(:name.not => @sam['name'])
1505
+
1506
+ @return = @query.filter_records(@records)
1507
+ end
1508
+
1509
+ it 'should return Enumerable' do
1510
+ @return.should be_kind_of(Enumerable)
1511
+ end
1512
+
1513
+ it 'should not be the records provided' do
1514
+ @return.should_not equal(@records)
1515
+ end
1516
+
1517
+ it 'should return expected values' do
1518
+ @return.should == [ @dan, @john ]
1519
+ end
1520
+ end
1521
+ end
1522
+
1523
+ it { @query.should respond_to(:inspect) }
1524
+
1525
+ describe '#inspect' do
1526
+ before :all do
1527
+ @return = @query.inspect
1528
+ end
1529
+
1530
+ it 'should return expected value' do
1531
+ @return.should == <<-INSPECT.compress_lines
1532
+ #<DataMapper::Query
1533
+ @repository=:default
1534
+ @model=User
1535
+ @fields=[#<DataMapper::Property @model=User @name=:name>, #<DataMapper::Property @model=User @name=:citizenship>, #<DataMapper::Property @model=User @name=:referrer_name>]
1536
+ @links=[]
1537
+ @conditions=nil
1538
+ @order=[#<DataMapper::Query::Direction @target=#<DataMapper::Property @model=User @name=:name> @operator=:asc>]
1539
+ @limit=3
1540
+ @offset=0
1541
+ @reload=false
1542
+ @unique=false>
1543
+ INSPECT
1544
+ end
1545
+ end
1546
+
1547
+ it { @query.should respond_to(:limit) }
1548
+
1549
+ describe '#limit' do
1550
+ before :all do
1551
+ @return = @query.limit
1552
+ end
1553
+
1554
+ it { @return.should be_kind_of(Integer) }
1555
+
1556
+ it 'should return expected value' do
1557
+ @return.should == 3
1558
+ end
1559
+ end
1560
+
1561
+ it { @query.should respond_to(:limit_records) }
1562
+
1563
+ supported_by :all do
1564
+ describe '#limit_records' do
1565
+ before :all do
1566
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
1567
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
1568
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
1569
+
1570
+ @records = [ @john, @sam, @dan ]
1571
+
1572
+ @query.update(:limit => 1, :offset => 1)
1573
+
1574
+ @return = @query.limit_records(@records)
1575
+ end
1576
+
1577
+ it 'should return Enumerable' do
1578
+ @return.should be_kind_of(Enumerable)
1579
+ end
1580
+
1581
+ it 'should not be the records provided' do
1582
+ @return.should_not equal(@records)
1583
+ end
1584
+
1585
+ it 'should return expected values' do
1586
+ @return.should == [ @sam ]
1587
+ end
1588
+ end
1589
+ end
1590
+
1591
+ it { @query.should respond_to(:links) }
1592
+
1593
+ describe '#links' do
1594
+ before :all do
1595
+ @return = @query.links
1596
+ end
1597
+
1598
+ it { @return.should be_kind_of(Array) }
1599
+
1600
+ it { @return.should be_empty }
1601
+ end
1602
+
1603
+ it { @query.should respond_to(:match_records) }
1604
+
1605
+ supported_by :all do
1606
+ describe '#match_records' do
1607
+ before :all do
1608
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
1609
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
1610
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
1611
+
1612
+ @records = [ @john, @sam, @dan ]
1613
+
1614
+ @query.update(:name.not => @sam['name'])
1615
+
1616
+ @return = @query.match_records(@records)
1617
+ end
1618
+
1619
+ it 'should return Enumerable' do
1620
+ @return.should be_kind_of(Enumerable)
1621
+ end
1622
+
1623
+ it 'should not be the records provided' do
1624
+ @return.should_not equal(@records)
1625
+ end
1626
+
1627
+ it 'should return expected values' do
1628
+ @return.should == [ @john, @dan ]
1629
+ end
1630
+ end
1631
+ end
1632
+
1633
+ it { @query.should respond_to(:merge) }
1634
+
1635
+ describe '#merge' do
1636
+ describe "with a Hash" do
1637
+ before(:each) do
1638
+ @return = @query.merge({ :limit => 202 })
1639
+ end
1640
+
1641
+ it "does not affect the receiver" do
1642
+ @query.options[:limit].should == 3
1643
+ end
1644
+ end
1645
+
1646
+ describe "with a Query" do
1647
+ before(:each) do
1648
+ @other = DataMapper::Query.new(@repository, @model, @options.update(@other_options))
1649
+ @return = @query.merge(@other)
1650
+ end
1651
+
1652
+ it "does not affect the receiver" do
1653
+ @query.options[:limit].should == 3
1654
+ end
1655
+ end
1656
+ end
1657
+
1658
+ it { @query.should respond_to(:model) }
1659
+
1660
+ describe '#model' do
1661
+ before :all do
1662
+ @return = @query.model
1663
+ end
1664
+
1665
+ it { @return.should be_kind_of(Class) }
1666
+
1667
+ it 'should return expected value' do
1668
+ @return.should == @model
1669
+ end
1670
+ end
1671
+
1672
+ it { @query.should respond_to(:offset) }
1673
+
1674
+ describe '#offset' do
1675
+ before :all do
1676
+ @return = @query.offset
1677
+ end
1678
+
1679
+ it { @return.should be_kind_of(Integer) }
1680
+
1681
+ it 'should return expected value' do
1682
+ @return.should == 0
1683
+ end
1684
+ end
1685
+
1686
+ it { @query.should respond_to(:order) }
1687
+
1688
+ describe '#order' do
1689
+ before :all do
1690
+ @return = @query.order
1691
+ end
1692
+
1693
+ it { @return.should be_kind_of(Array) }
1694
+
1695
+ it 'should return expected value' do
1696
+ @return.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
1697
+ end
1698
+ end
1699
+
1700
+ it { @query.should respond_to(:raw?) }
1701
+
1702
+ describe '#raw?' do
1703
+ describe 'when the query contains raw conditions' do
1704
+ before :all do
1705
+ @query.update(:conditions => [ 'name = ?', 'Dan Kubb' ])
1706
+ end
1707
+
1708
+ it { @query.should be_raw }
1709
+ end
1710
+
1711
+ describe 'when the query does not contain raw conditions' do
1712
+ it { @query.should_not be_raw }
1713
+ end
1714
+ end
1715
+
1716
+ it { @query.should respond_to(:relative) }
1717
+
1718
+ describe '#relative' do
1719
+ describe 'with a Hash' do
1720
+ describe 'that is empty' do
1721
+ before :all do
1722
+ @return = @query.relative({})
1723
+ end
1724
+
1725
+ it { @return.should be_kind_of(DataMapper::Query) }
1726
+
1727
+ it 'should not return self' do
1728
+ @return.should_not equal(@query)
1729
+ end
1730
+
1731
+ it 'should return a copy' do
1732
+ @return.should be_eql(@query)
1733
+ end
1734
+ end
1735
+
1736
+ describe 'using a different repository as a Repository' do
1737
+ before :all do
1738
+ @repository = DataMapper::Repository.new(:other)
1739
+ @return = @query.relative(:repository => @repository)
1740
+ end
1741
+
1742
+ it { @return.should be_kind_of(DataMapper::Query) }
1743
+
1744
+ it 'should not return self' do
1745
+ @return.should_not equal(@original)
1746
+ end
1747
+
1748
+ it 'should set the repository' do
1749
+ @return.repository.should equal(@repository)
1750
+ end
1751
+ end
1752
+
1753
+ describe 'using a different repository as a Symbol' do
1754
+ before :all do
1755
+ @other_adapter = DataMapper.setup(:other, :adapter => :in_memory)
1756
+
1757
+ @return = @query.relative(:repository => :other)
1758
+ end
1759
+
1760
+ after :all do
1761
+ DataMapper::Repository.adapters.delete(@other_adapter.name)
1762
+ end
1763
+
1764
+ it { @return.should be_kind_of(DataMapper::Query) }
1765
+
1766
+ it 'should not return self' do
1767
+ @return.should_not equal(@original)
1768
+ end
1769
+
1770
+ it 'should set the repository' do
1771
+ @return.repository.should == DataMapper::Repository.new(:other)
1772
+ end
1773
+ end
1774
+
1775
+ describe 'using different options' do
1776
+ before :all do
1777
+ @return = @query.relative(@other_options)
1778
+ end
1779
+
1780
+ it { @return.should be_kind_of(DataMapper::Query) }
1781
+
1782
+ it 'should not return self' do
1783
+ @return.should_not equal(@original)
1784
+ end
1785
+
1786
+ it 'should update the fields' do
1787
+ @return.fields.should == @other_options[:fields]
1788
+ end
1789
+
1790
+ it 'should update the links' do
1791
+ @return.links.should == @other_options[:links]
1792
+ end
1793
+
1794
+ it 'should update the conditions' do
1795
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
1796
+ end
1797
+
1798
+ it 'should update the offset' do
1799
+ @return.offset.should == @other_options[:offset]
1800
+ end
1801
+
1802
+ it 'should update the limit' do
1803
+ @return.limit.should == @other_options[:limit]
1804
+ end
1805
+
1806
+ it 'should update the order' do
1807
+ @return.order.should == @other_options[:order]
1808
+ end
1809
+
1810
+ it 'should update the unique' do
1811
+ @return.unique?.should == @other_options[:unique]
1812
+ end
1813
+
1814
+ it 'should update the add_reversed' do
1815
+ @return.add_reversed?.should == @other_options[:add_reversed]
1816
+ end
1817
+
1818
+ it 'should update the reload' do
1819
+ @return.reload?.should == @other_options[:reload]
1820
+ end
1821
+ end
1822
+
1823
+ describe 'using extra options' do
1824
+ before :all do
1825
+ @options = { :name => 'Dan Kubb' }
1826
+
1827
+ @return = @query.relative(@options)
1828
+ end
1829
+
1830
+ it { @return.should be_kind_of(DataMapper::Query) }
1831
+
1832
+ it 'should not return self' do
1833
+ @return.should_not equal(@original)
1834
+ end
1835
+
1836
+ it 'should update the conditions' do
1837
+ @return.conditions.should ==
1838
+ DataMapper::Query::Conditions::Operation.new(
1839
+ :and,
1840
+ DataMapper::Query::Conditions::Comparison.new(
1841
+ :eql,
1842
+ @model.properties[:name],
1843
+ @options[:name]
1844
+ )
1845
+ )
1846
+ end
1847
+ end
1848
+
1849
+ describe 'using an offset when query offset is greater than 0' do
1850
+ before :all do
1851
+ @query = @query.update(:offset => 1, :limit => 2)
1852
+
1853
+ @return = @query.relative(:offset => 1)
1854
+ end
1855
+
1856
+ it { @return.should be_kind_of(DataMapper::Query) }
1857
+
1858
+ it 'should not return self' do
1859
+ @return.should_not equal(@original)
1860
+ end
1861
+
1862
+ it 'should update the offset to be relative to the original offset' do
1863
+ @return.offset.should == 2
1864
+ end
1865
+ end
1866
+
1867
+ describe 'using an limit when query limit specified' do
1868
+ before :all do
1869
+ @query = @query.update(:offset => 1, :limit => 2)
1870
+
1871
+ @return = @query.relative(:limit => 1)
1872
+ end
1873
+
1874
+ it { @return.should be_kind_of(DataMapper::Query) }
1875
+
1876
+ it 'should not return self' do
1877
+ @return.should_not equal(@original)
1878
+ end
1879
+
1880
+ it 'should update the limit' do
1881
+ @return.limit.should == 1
1882
+ end
1883
+ end
1884
+ end
1885
+ end
1886
+
1887
+ it { @query.should respond_to(:reload?) }
1888
+
1889
+ describe '#reload?' do
1890
+ describe 'when the query should reload' do
1891
+ before :all do
1892
+ @query.update(:reload => true)
1893
+ end
1894
+
1895
+ it { @query.should be_reload }
1896
+ end
1897
+
1898
+ describe 'when the query should not reload' do
1899
+ it { @query.should_not be_reload }
1900
+ end
1901
+ end
1902
+
1903
+ it { @query.should respond_to(:repository) }
1904
+
1905
+ describe '#repository' do
1906
+ before :all do
1907
+ @return = @query.repository
1908
+ end
1909
+
1910
+ it { @return.should be_kind_of(DataMapper::Repository) }
1911
+
1912
+ it 'should return expected value' do
1913
+ @return.should == @repository
1914
+ end
1915
+ end
1916
+
1917
+ it { @query.should respond_to(:reverse) }
1918
+
1919
+ describe '#reverse' do
1920
+ before :all do
1921
+ @return = @query.reverse
1922
+ end
1923
+
1924
+ it { @return.should be_kind_of(DataMapper::Query) }
1925
+
1926
+ it 'should copy the Query' do
1927
+ @return.should_not equal(@original)
1928
+ end
1929
+
1930
+ # TODO: push this into dup spec
1931
+ it 'should not reference original order' do
1932
+ @return.order.should_not equal(@original.order)
1933
+ end
1934
+
1935
+ it 'should have a reversed order' do
1936
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :desc) ]
1937
+ end
1938
+
1939
+ [ :repository, :model, :fields, :links, :conditions, :offset, :limit, :unique?, :add_reversed?, :reload? ].each do |attribute|
1940
+ it "should have an equivalent #{attribute}" do
1941
+ @return.send(attribute).should == @original.send(attribute)
1942
+ end
1943
+ end
1944
+ end
1945
+
1946
+ it { @query.should respond_to(:reverse!) }
1947
+
1948
+ describe '#reverse!' do
1949
+ before :all do
1950
+ @return = @query.reverse!
1951
+ end
1952
+
1953
+ it { @return.should be_kind_of(DataMapper::Query) }
1954
+
1955
+ it { @return.should equal(@original) }
1956
+
1957
+ it 'should have a reversed order' do
1958
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :desc) ]
1959
+ end
1960
+ end
1961
+
1962
+ [ :slice, :[] ].each do |method|
1963
+ it { @query.should respond_to(method) }
1964
+
1965
+ describe "##{method}" do
1966
+ describe 'with a positive offset' do
1967
+ before :all do
1968
+ @query = @query.update(:offset => 1, :limit => 2)
1969
+
1970
+ @return = @query.send(method, 1)
1971
+ end
1972
+
1973
+ it { @return.should be_kind_of(DataMapper::Query) }
1974
+
1975
+ it 'should not return self' do
1976
+ @return.should_not equal(@original)
1977
+ end
1978
+
1979
+ it 'should update the offset to be relative to the original offset' do
1980
+ @return.offset.should == 2
1981
+ end
1982
+
1983
+ it 'should update the limit to 1' do
1984
+ @return.limit.should == 1
1985
+ end
1986
+ end
1987
+
1988
+ describe 'with a positive offset and length' do
1989
+ before :all do
1990
+ @query = @query.update(:offset => 1, :limit => 2)
1991
+
1992
+ @return = @query.send(method, 1, 1)
1993
+ end
1994
+
1995
+ it { @return.should be_kind_of(DataMapper::Query) }
1996
+
1997
+ it 'should not return self' do
1998
+ @return.should_not equal(@original)
1999
+ end
2000
+
2001
+ it 'should update the offset to be relative to the original offset' do
2002
+ @return.offset.should == 2
2003
+ end
2004
+
2005
+ it 'should update the limit' do
2006
+ @return.limit.should == 1
2007
+ end
2008
+ end
2009
+
2010
+ describe 'with a positive range' do
2011
+ before :all do
2012
+ @query = @query.update(:offset => 1, :limit => 3)
2013
+
2014
+ @return = @query.send(method, 1..2)
2015
+ end
2016
+
2017
+ it { @return.should be_kind_of(DataMapper::Query) }
2018
+
2019
+ it 'should not return self' do
2020
+ @return.should_not equal(@original)
2021
+ end
2022
+
2023
+ it 'should update the offset to be relative to the original offset' do
2024
+ @return.offset.should == 2
2025
+ end
2026
+
2027
+ it 'should update the limit' do
2028
+ @return.limit.should == 2
2029
+ end
2030
+ end
2031
+
2032
+ describe 'with a negative offset' do
2033
+ before :all do
2034
+ @query = @query.update(:offset => 1, :limit => 2)
2035
+
2036
+ @return = @query.send(method, -1)
2037
+ end
2038
+
2039
+ it { @return.should be_kind_of(DataMapper::Query) }
2040
+
2041
+ it 'should not return self' do
2042
+ @return.should_not equal(@original)
2043
+ end
2044
+
2045
+ it 'should update the offset to be relative to the original offset' do
2046
+ pending "TODO: update Query##{method} handle negative offset" do
2047
+ @return.offset.should == 2
2048
+ end
2049
+ end
2050
+
2051
+ it 'should update the limit to 1' do
2052
+ @return.limit.should == 1
2053
+ end
2054
+ end
2055
+
2056
+ describe 'with a negative offset and length' do
2057
+ before :all do
2058
+ @query = @query.update(:offset => 1, :limit => 2)
2059
+
2060
+ @return = @query.send(method, -1, 1)
2061
+ end
2062
+
2063
+ it { @return.should be_kind_of(DataMapper::Query) }
2064
+
2065
+ it 'should not return self' do
2066
+ @return.should_not equal(@original)
2067
+ end
2068
+
2069
+ it 'should update the offset to be relative to the original offset' do
2070
+ pending "TODO: update Query##{method} handle negative offset and length" do
2071
+ @return.offset.should == 2
2072
+ end
2073
+ end
2074
+
2075
+ it 'should update the limit to 1' do
2076
+ @return.limit.should == 1
2077
+ end
2078
+ end
2079
+
2080
+ describe 'with a negative range' do
2081
+ before :all do
2082
+ @query = @query.update(:offset => 1, :limit => 3)
2083
+
2084
+ rescue_if "TODO: update Query##{method} handle negative range" do
2085
+ @return = @query.send(method, -2..-1)
2086
+ end
2087
+ end
2088
+
2089
+ before do
2090
+ pending_if "TODO: update Query##{method} handle negative range", !defined?(@return)
2091
+ end
2092
+
2093
+ it { @return.should be_kind_of(DataMapper::Query) }
2094
+
2095
+ it 'should not return self' do
2096
+ @return.should_not equal(@original)
2097
+ end
2098
+
2099
+ it 'should update the offset to be relative to the original offset' do
2100
+ @return.offset.should == 2
2101
+ end
2102
+
2103
+ it 'should update the limit to 1' do
2104
+ @return.limit.should == 2
2105
+ end
2106
+ end
2107
+
2108
+ describe 'with an offset not within range' do
2109
+ before :all do
2110
+ @query = @query.update(:offset => 1, :limit => 3)
2111
+ end
2112
+
2113
+ it 'should raise an exception' do
2114
+ lambda {
2115
+ @query.send(method, 12)
2116
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2117
+ end
2118
+ end
2119
+
2120
+ describe 'with an offset and length not within range' do
2121
+ before :all do
2122
+ @query = @query.update(:offset => 1, :limit => 3)
2123
+ end
2124
+
2125
+ it 'should raise an exception' do
2126
+ lambda {
2127
+ @query.send(method, 12, 1)
2128
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2129
+ end
2130
+ end
2131
+
2132
+ describe 'with a range not within range' do
2133
+ before :all do
2134
+ @query = @query.update(:offset => 1, :limit => 3)
2135
+ end
2136
+
2137
+ it 'should raise an exception' do
2138
+ lambda {
2139
+ @query.send(method, 12..12)
2140
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2141
+ end
2142
+ end
2143
+
2144
+ describe 'with invalid arguments' do
2145
+ it 'should raise an exception' do
2146
+ lambda {
2147
+ @query.send(method, 'invalid')
2148
+ }.should raise_error(ArgumentError, 'arguments may be 1 or 2 Integers, or 1 Range object, was: ["invalid"]')
2149
+ end
2150
+ end
2151
+ end
2152
+ end
2153
+
2154
+ it { @query.should respond_to(:slice!) }
2155
+
2156
+ describe '#slice!' do
2157
+ describe 'with a positive offset' do
2158
+ before :all do
2159
+ @query = @query.update(:offset => 1, :limit => 2)
2160
+
2161
+ @return = @query.slice!(1)
2162
+ end
2163
+
2164
+ it { @return.should be_kind_of(DataMapper::Query) }
2165
+
2166
+ it 'should return self' do
2167
+ @return.should equal(@original)
2168
+ end
2169
+
2170
+ it 'should update the offset to be relative to the original offset' do
2171
+ @return.offset.should == 2
2172
+ end
2173
+
2174
+ it 'should update the limit to 1' do
2175
+ @return.limit.should == 1
2176
+ end
2177
+ end
2178
+
2179
+ describe 'with a positive offset and length' do
2180
+ before :all do
2181
+ @query = @query.update(:offset => 1, :limit => 2)
2182
+
2183
+ @return = @query.slice!(1, 1)
2184
+ end
2185
+
2186
+ it { @return.should be_kind_of(DataMapper::Query) }
2187
+
2188
+ it 'should return self' do
2189
+ @return.should equal(@original)
2190
+ end
2191
+
2192
+ it 'should update the offset to be relative to the original offset' do
2193
+ @return.offset.should == 2
2194
+ end
2195
+
2196
+ it 'should update the limit' do
2197
+ @return.limit.should == 1
2198
+ end
2199
+ end
2200
+
2201
+ describe 'with a positive range' do
2202
+ before :all do
2203
+ @query = @query.update(:offset => 1, :limit => 3)
2204
+
2205
+ @return = @query.slice!(1..2)
2206
+ end
2207
+
2208
+ it { @return.should be_kind_of(DataMapper::Query) }
2209
+
2210
+ it 'should return self' do
2211
+ @return.should equal(@original)
2212
+ end
2213
+
2214
+ it 'should update the offset to be relative to the original offset' do
2215
+ @return.offset.should == 2
2216
+ end
2217
+
2218
+ it 'should update the limit' do
2219
+ @return.limit.should == 2
2220
+ end
2221
+ end
2222
+
2223
+ describe 'with a negative offset' do
2224
+ before :all do
2225
+ @query = @query.update(:offset => 1, :limit => 2)
2226
+
2227
+ @return = @query.slice!(-1)
2228
+ end
2229
+
2230
+ it { @return.should be_kind_of(DataMapper::Query) }
2231
+
2232
+ it 'should return self' do
2233
+ @return.should equal(@original)
2234
+ end
2235
+
2236
+ it 'should update the offset to be relative to the original offset' do
2237
+ pending 'TODO: update Query#slice! handle negative offset' do
2238
+ @return.offset.should == 2
2239
+ end
2240
+ end
2241
+
2242
+ it 'should update the limit to 1' do
2243
+ @return.limit.should == 1
2244
+ end
2245
+ end
2246
+
2247
+ describe 'with a negative offset and length' do
2248
+ before :all do
2249
+ @query = @query.update(:offset => 1, :limit => 2)
2250
+
2251
+ @return = @query.slice!(-1, 1)
2252
+ end
2253
+
2254
+ it { @return.should be_kind_of(DataMapper::Query) }
2255
+
2256
+ it 'should return self' do
2257
+ @return.should equal(@original)
2258
+ end
2259
+
2260
+ it 'should update the offset to be relative to the original offset' do
2261
+ pending 'TODO: update Query#slice! handle negative offset and length' do
2262
+ @return.offset.should == 2
2263
+ end
2264
+ end
2265
+
2266
+ it 'should update the limit to 1' do
2267
+ @return.limit.should == 1
2268
+ end
2269
+ end
2270
+
2271
+ describe 'with a negative range' do
2272
+ before :all do
2273
+ @query = @query.update(:offset => 1, :limit => 3)
2274
+
2275
+ rescue_if 'TODO: update Query#slice! handle negative range' do
2276
+ @return = @query.slice!(-2..-1)
2277
+ end
2278
+ end
2279
+
2280
+ before do
2281
+ pending_if 'TODO: update Query#slice! handle negative range', !defined?(@return)
2282
+ end
2283
+
2284
+ it { @return.should be_kind_of(DataMapper::Query) }
2285
+
2286
+ it 'should return self' do
2287
+ @return.should equal(@original)
2288
+ end
2289
+
2290
+ it 'should update the offset to be relative to the original offset' do
2291
+ @return.offset.should == 2
2292
+ end
2293
+
2294
+ it 'should update the limit to 1' do
2295
+ @return.limit.should == 2
2296
+ end
2297
+ end
2298
+
2299
+ describe 'with an offset not within range' do
2300
+ before :all do
2301
+ @query = @query.update(:offset => 1, :limit => 3)
2302
+ end
2303
+
2304
+ it 'should raise an exception' do
2305
+ lambda {
2306
+ @query.slice!(12)
2307
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2308
+ end
2309
+ end
2310
+
2311
+ describe 'with an offset and length not within range' do
2312
+ before :all do
2313
+ @query = @query.update(:offset => 1, :limit => 3)
2314
+ end
2315
+
2316
+ it 'should raise an exception' do
2317
+ lambda {
2318
+ @query.slice!(12, 1)
2319
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2320
+ end
2321
+ end
2322
+
2323
+ describe 'with a range not within range' do
2324
+ before :all do
2325
+ @query = @query.update(:offset => 1, :limit => 3)
2326
+ end
2327
+
2328
+ it 'should raise an exception' do
2329
+ lambda {
2330
+ @query.slice!(12..12)
2331
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2332
+ end
2333
+ end
2334
+
2335
+ describe 'with invalid arguments' do
2336
+ it 'should raise an exception' do
2337
+ lambda {
2338
+ @query.slice!('invalid')
2339
+ }.should raise_error(ArgumentError, 'arguments may be 1 or 2 Integers, or 1 Range object, was: ["invalid"]')
2340
+ end
2341
+ end
2342
+ end
2343
+
2344
+ it { @query.should respond_to(:sort_records) }
2345
+
2346
+ supported_by :all do
2347
+ describe '#sort_records' do
2348
+ before :all do
2349
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
2350
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
2351
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
2352
+
2353
+ @records = [ @john, @sam, @dan ]
2354
+
2355
+ @query.update(:order => [ :name ])
2356
+
2357
+ @return = @query.sort_records(@records)
2358
+ end
2359
+
2360
+ it 'should return Enumerable' do
2361
+ @return.should be_kind_of(Enumerable)
2362
+ end
2363
+
2364
+ it 'should not be the records provided' do
2365
+ @return.should_not equal(@records)
2366
+ end
2367
+
2368
+ it 'should return expected values' do
2369
+ @return.should == [ @dan, @john, @sam ]
2370
+ end
2371
+ end
2372
+ end
2373
+
2374
+ it { @query.should respond_to(:unique?) }
2375
+
2376
+ describe '#unique?' do
2377
+ describe 'when the query is unique' do
2378
+ before :all do
2379
+ @query.update(:unique => true)
2380
+ end
2381
+
2382
+ it { @query.should be_unique }
2383
+ end
2384
+
2385
+ describe 'when the query is not unique' do
2386
+ it { @query.should_not be_unique }
2387
+ end
2388
+ end
2389
+
2390
+ it { @query.should respond_to(:update) }
2391
+
2392
+ describe '#update' do
2393
+ describe 'with a Query' do
2394
+ describe 'that is equivalent' do
2395
+ before :all do
2396
+ @other = DataMapper::Query.new(@repository, @model, @options)
2397
+
2398
+ @return = @query.update(@other)
2399
+ end
2400
+
2401
+ it { @return.should be_kind_of(DataMapper::Query) }
2402
+
2403
+ it { @return.should equal(@original) }
2404
+ end
2405
+
2406
+ describe 'that has conditions set' do
2407
+ before :all do
2408
+ @and_operation = DataMapper::Query::Conditions::Operation.new(:and)
2409
+ @or_operation = DataMapper::Query::Conditions::Operation.new(:or)
2410
+
2411
+ @and_operation << DataMapper::Query::Conditions::Comparison.new(:eql,User.name,"Dan Kubb")
2412
+ @and_operation << DataMapper::Query::Conditions::Comparison.new(:eql,User.citizenship,"Canada")
2413
+
2414
+ @or_operation << DataMapper::Query::Conditions::Comparison.new(:eql,User.name,"Ted Han")
2415
+ @or_operation << DataMapper::Query::Conditions::Comparison.new(:eql,User.citizenship,"USA")
2416
+ @query_one = DataMapper::Query.new(@repository, @model, {:conditions=>@and_operation})
2417
+ @query_two = DataMapper::Query.new(@repository, @model, {:conditions=>@or_operation})
2418
+
2419
+ @conditions = @query_one.merge(@query_two).conditions
2420
+ end
2421
+
2422
+ it { @conditions.should == (@and_operation << @or_operation) }
2423
+ end
2424
+
2425
+ describe 'that is for an ancestor model' do
2426
+ before :all do
2427
+ class ::Contact < User; end
2428
+
2429
+ @query = DataMapper::Query.new(@repository, Contact, @options)
2430
+ @original = @query
2431
+
2432
+ @other = DataMapper::Query.new(@repository, User, @options)
2433
+
2434
+ @return = @query.update(@other)
2435
+ end
2436
+
2437
+ it { @return.should be_kind_of(DataMapper::Query) }
2438
+
2439
+ it { @return.should equal(@original) }
2440
+ end
2441
+
2442
+ describe 'using a different repository' do
2443
+ it 'should raise an exception' do
2444
+ lambda {
2445
+ @query.update(DataMapper::Query.new(DataMapper::Repository.new(:other), User))
2446
+ }.should raise_error(ArgumentError, '+other+ DataMapper::Query must be for the default repository, not other')
2447
+ end
2448
+ end
2449
+
2450
+ describe 'using a different model' do
2451
+ before :all do
2452
+ class ::Clone
2453
+ include DataMapper::Resource
2454
+
2455
+ property :name, String, :key => true
2456
+ end
2457
+ end
2458
+
2459
+ it 'should raise an exception' do
2460
+ lambda {
2461
+ @query.update(DataMapper::Query.new(@repository, Clone))
2462
+ }.should raise_error(ArgumentError, '+other+ DataMapper::Query must be for the User model, not Clone')
2463
+ end
2464
+ end
2465
+
2466
+ describe 'using different options' do
2467
+ before :all do
2468
+ @other = DataMapper::Query.new(@repository, @model, @options.update(@other_options))
2469
+
2470
+ @return = @query.update(@other)
2471
+ end
2472
+
2473
+ it { @return.should be_kind_of(DataMapper::Query) }
2474
+
2475
+ it { @return.should equal(@original) }
2476
+
2477
+ it 'should update the fields' do
2478
+ @return.fields.should == @options[:fields]
2479
+ end
2480
+
2481
+ it 'should update the links' do
2482
+ @return.links.should == @options[:links]
2483
+ end
2484
+
2485
+ it 'should update the conditions' do
2486
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
2487
+ end
2488
+
2489
+ it 'should update the offset' do
2490
+ @return.offset.should == @options[:offset]
2491
+ end
2492
+
2493
+ it 'should update the limit' do
2494
+ @return.limit.should == @options[:limit]
2495
+ end
2496
+
2497
+ it 'should update the order' do
2498
+ @return.order.should == @options[:order]
2499
+ end
2500
+
2501
+ it 'should update the unique' do
2502
+ @return.unique?.should == @options[:unique]
2503
+ end
2504
+
2505
+ it 'should update the add_reversed' do
2506
+ @return.add_reversed?.should == @options[:add_reversed]
2507
+ end
2508
+
2509
+ it 'should update the reload' do
2510
+ @return.reload?.should == @options[:reload]
2511
+ end
2512
+ end
2513
+
2514
+ describe 'using extra options' do
2515
+ before :all do
2516
+ @options.update(:name => 'Dan Kubb')
2517
+ @other = DataMapper::Query.new(@repository, @model, @options)
2518
+
2519
+ @return = @query.update(@other)
2520
+ end
2521
+
2522
+ it { @return.should be_kind_of(DataMapper::Query) }
2523
+
2524
+ it { @return.should equal(@original) }
2525
+
2526
+ it 'should update the conditions' do
2527
+ @return.conditions.should ==
2528
+ DataMapper::Query::Conditions::Operation.new(
2529
+ :and,
2530
+ DataMapper::Query::Conditions::Comparison.new(
2531
+ :eql,
2532
+ @model.properties[:name],
2533
+ @options[:name]
2534
+ )
2535
+ )
2536
+ end
2537
+ end
2538
+ end
2539
+
2540
+ describe 'with a Hash' do
2541
+ describe 'that is empty' do
2542
+ before :all do
2543
+ @copy = @query.dup
2544
+ @return = @query.update({})
2545
+ end
2546
+
2547
+ it { @return.should be_kind_of(DataMapper::Query) }
2548
+
2549
+ it { @return.should equal(@original) }
2550
+
2551
+ it 'should not change the Query' do
2552
+ @return.should == @copy
2553
+ end
2554
+ end
2555
+
2556
+ describe 'using different options' do
2557
+ before :all do
2558
+ @return = @query.update(@other_options)
2559
+ end
2560
+
2561
+ it { @return.should be_kind_of(DataMapper::Query) }
2562
+
2563
+ it { @return.should equal(@original) }
2564
+
2565
+ it 'should update the fields' do
2566
+ @return.fields.should == @other_options[:fields]
2567
+ end
2568
+
2569
+ it 'should update the links' do
2570
+ @return.links.should == @other_options[:links]
2571
+ end
2572
+
2573
+ it 'should update the conditions' do
2574
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
2575
+ end
2576
+
2577
+ it 'should update the offset' do
2578
+ @return.offset.should == @other_options[:offset]
2579
+ end
2580
+
2581
+ it 'should update the limit' do
2582
+ @return.limit.should == @other_options[:limit]
2583
+ end
2584
+
2585
+ it 'should update the order' do
2586
+ @return.order.should == @other_options[:order]
2587
+ end
2588
+
2589
+ it 'should update the unique' do
2590
+ @return.unique?.should == @other_options[:unique]
2591
+ end
2592
+
2593
+ it 'should update the add_reversed' do
2594
+ @return.add_reversed?.should == @other_options[:add_reversed]
2595
+ end
2596
+
2597
+ it 'should update the reload' do
2598
+ @return.reload?.should == @other_options[:reload]
2599
+ end
2600
+ end
2601
+
2602
+ describe 'using extra options' do
2603
+ before :all do
2604
+ @options = { :name => 'Dan Kubb' }
2605
+
2606
+ @return = @query.update(@options)
2607
+ end
2608
+
2609
+ it { @return.should be_kind_of(DataMapper::Query) }
2610
+
2611
+ it { @return.should equal(@original) }
2612
+
2613
+ it 'should update the conditions' do
2614
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(
2615
+ :and,
2616
+ DataMapper::Query::Conditions::Comparison.new(:eql,
2617
+ @model.properties[:name],
2618
+ @options[:name]
2619
+ )
2620
+ )
2621
+ #@return.conditions.should == [ [ :eql, @model.properties[:name], @options[:name] ] ]
2622
+ end
2623
+ end
2624
+ end
2625
+ end
2626
+ end