ardm-core 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (259) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +29 -0
  3. data/.document +5 -0
  4. data/.gitignore +35 -0
  5. data/.travis.yml +23 -0
  6. data/.yardopts +1 -0
  7. data/Gemfile +63 -0
  8. data/LICENSE +20 -0
  9. data/README.rdoc +237 -0
  10. data/Rakefile +4 -0
  11. data/VERSION +1 -0
  12. data/ardm-core.gemspec +25 -0
  13. data/lib/ardm-core.rb +1 -0
  14. data/lib/dm-core.rb +285 -0
  15. data/lib/dm-core/adapters.rb +222 -0
  16. data/lib/dm-core/adapters/abstract_adapter.rb +236 -0
  17. data/lib/dm-core/adapters/in_memory_adapter.rb +113 -0
  18. data/lib/dm-core/associations/many_to_many.rb +496 -0
  19. data/lib/dm-core/associations/many_to_one.rb +296 -0
  20. data/lib/dm-core/associations/one_to_many.rb +345 -0
  21. data/lib/dm-core/associations/one_to_one.rb +86 -0
  22. data/lib/dm-core/associations/relationship.rb +663 -0
  23. data/lib/dm-core/backwards.rb +13 -0
  24. data/lib/dm-core/collection.rb +1514 -0
  25. data/lib/dm-core/core_ext/kernel.rb +23 -0
  26. data/lib/dm-core/core_ext/pathname.rb +6 -0
  27. data/lib/dm-core/core_ext/symbol.rb +10 -0
  28. data/lib/dm-core/identity_map.rb +7 -0
  29. data/lib/dm-core/model.rb +869 -0
  30. data/lib/dm-core/model/hook.rb +102 -0
  31. data/lib/dm-core/model/is.rb +32 -0
  32. data/lib/dm-core/model/property.rb +253 -0
  33. data/lib/dm-core/model/relationship.rb +377 -0
  34. data/lib/dm-core/model/scope.rb +89 -0
  35. data/lib/dm-core/property.rb +839 -0
  36. data/lib/dm-core/property/binary.rb +22 -0
  37. data/lib/dm-core/property/boolean.rb +31 -0
  38. data/lib/dm-core/property/class.rb +24 -0
  39. data/lib/dm-core/property/date.rb +45 -0
  40. data/lib/dm-core/property/date_time.rb +44 -0
  41. data/lib/dm-core/property/decimal.rb +50 -0
  42. data/lib/dm-core/property/discriminator.rb +46 -0
  43. data/lib/dm-core/property/float.rb +28 -0
  44. data/lib/dm-core/property/integer.rb +32 -0
  45. data/lib/dm-core/property/lookup.rb +29 -0
  46. data/lib/dm-core/property/numeric.rb +40 -0
  47. data/lib/dm-core/property/object.rb +28 -0
  48. data/lib/dm-core/property/serial.rb +13 -0
  49. data/lib/dm-core/property/string.rb +50 -0
  50. data/lib/dm-core/property/text.rb +12 -0
  51. data/lib/dm-core/property/time.rb +46 -0
  52. data/lib/dm-core/property/typecast/numeric.rb +32 -0
  53. data/lib/dm-core/property/typecast/time.rb +33 -0
  54. data/lib/dm-core/property_set.rb +177 -0
  55. data/lib/dm-core/query.rb +1444 -0
  56. data/lib/dm-core/query/conditions/comparison.rb +910 -0
  57. data/lib/dm-core/query/conditions/operation.rb +720 -0
  58. data/lib/dm-core/query/direction.rb +36 -0
  59. data/lib/dm-core/query/operator.rb +35 -0
  60. data/lib/dm-core/query/path.rb +114 -0
  61. data/lib/dm-core/query/sort.rb +39 -0
  62. data/lib/dm-core/relationship_set.rb +72 -0
  63. data/lib/dm-core/repository.rb +226 -0
  64. data/lib/dm-core/resource.rb +1228 -0
  65. data/lib/dm-core/resource/persistence_state.rb +75 -0
  66. data/lib/dm-core/resource/persistence_state/clean.rb +40 -0
  67. data/lib/dm-core/resource/persistence_state/deleted.rb +30 -0
  68. data/lib/dm-core/resource/persistence_state/dirty.rb +96 -0
  69. data/lib/dm-core/resource/persistence_state/immutable.rb +34 -0
  70. data/lib/dm-core/resource/persistence_state/persisted.rb +29 -0
  71. data/lib/dm-core/resource/persistence_state/transient.rb +78 -0
  72. data/lib/dm-core/spec/lib/adapter_helpers.rb +54 -0
  73. data/lib/dm-core/spec/lib/collection_helpers.rb +20 -0
  74. data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
  75. data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
  76. data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
  77. data/lib/dm-core/spec/setup.rb +173 -0
  78. data/lib/dm-core/spec/shared/adapter_spec.rb +326 -0
  79. data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
  80. data/lib/dm-core/spec/shared/resource_spec.rb +1236 -0
  81. data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
  82. data/lib/dm-core/spec/shared/semipublic/property_spec.rb +134 -0
  83. data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
  84. data/lib/dm-core/support/assertions.rb +8 -0
  85. data/lib/dm-core/support/chainable.rb +18 -0
  86. data/lib/dm-core/support/deprecate.rb +12 -0
  87. data/lib/dm-core/support/descendant_set.rb +89 -0
  88. data/lib/dm-core/support/equalizer.rb +48 -0
  89. data/lib/dm-core/support/ext/array.rb +22 -0
  90. data/lib/dm-core/support/ext/blank.rb +25 -0
  91. data/lib/dm-core/support/ext/hash.rb +67 -0
  92. data/lib/dm-core/support/ext/module.rb +47 -0
  93. data/lib/dm-core/support/ext/object.rb +57 -0
  94. data/lib/dm-core/support/ext/string.rb +24 -0
  95. data/lib/dm-core/support/ext/try_dup.rb +12 -0
  96. data/lib/dm-core/support/hook.rb +402 -0
  97. data/lib/dm-core/support/inflections.rb +60 -0
  98. data/lib/dm-core/support/inflector/inflections.rb +211 -0
  99. data/lib/dm-core/support/inflector/methods.rb +151 -0
  100. data/lib/dm-core/support/lazy_array.rb +451 -0
  101. data/lib/dm-core/support/local_object_space.rb +12 -0
  102. data/lib/dm-core/support/logger.rb +199 -0
  103. data/lib/dm-core/support/mash.rb +176 -0
  104. data/lib/dm-core/support/naming_conventions.rb +90 -0
  105. data/lib/dm-core/support/ordered_set.rb +380 -0
  106. data/lib/dm-core/support/subject.rb +33 -0
  107. data/lib/dm-core/support/subject_set.rb +250 -0
  108. data/lib/dm-core/version.rb +3 -0
  109. data/script/performance.rb +275 -0
  110. data/script/profile.rb +218 -0
  111. data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
  112. data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +68 -0
  113. data/spec/public/associations/many_to_many_spec.rb +197 -0
  114. data/spec/public/associations/many_to_one_spec.rb +83 -0
  115. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
  116. data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
  117. data/spec/public/associations/one_to_many_spec.rb +81 -0
  118. data/spec/public/associations/one_to_one_spec.rb +176 -0
  119. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
  120. data/spec/public/collection_spec.rb +69 -0
  121. data/spec/public/finalize_spec.rb +76 -0
  122. data/spec/public/model/hook_spec.rb +246 -0
  123. data/spec/public/model/property_spec.rb +88 -0
  124. data/spec/public/model/relationship_spec.rb +1040 -0
  125. data/spec/public/model_spec.rb +458 -0
  126. data/spec/public/property/binary_spec.rb +41 -0
  127. data/spec/public/property/boolean_spec.rb +22 -0
  128. data/spec/public/property/class_spec.rb +28 -0
  129. data/spec/public/property/date_spec.rb +22 -0
  130. data/spec/public/property/date_time_spec.rb +22 -0
  131. data/spec/public/property/decimal_spec.rb +23 -0
  132. data/spec/public/property/discriminator_spec.rb +135 -0
  133. data/spec/public/property/float_spec.rb +22 -0
  134. data/spec/public/property/integer_spec.rb +22 -0
  135. data/spec/public/property/object_spec.rb +107 -0
  136. data/spec/public/property/serial_spec.rb +22 -0
  137. data/spec/public/property/string_spec.rb +22 -0
  138. data/spec/public/property/text_spec.rb +63 -0
  139. data/spec/public/property/time_spec.rb +22 -0
  140. data/spec/public/property_spec.rb +341 -0
  141. data/spec/public/resource_spec.rb +284 -0
  142. data/spec/public/sel_spec.rb +53 -0
  143. data/spec/public/setup_spec.rb +145 -0
  144. data/spec/public/shared/association_collection_shared_spec.rb +309 -0
  145. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  146. data/spec/public/shared/collection_shared_spec.rb +1669 -0
  147. data/spec/public/shared/finder_shared_spec.rb +1629 -0
  148. data/spec/rcov.opts +6 -0
  149. data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
  150. data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
  151. data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
  152. data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
  153. data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
  154. data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
  155. data/spec/semipublic/associations/relationship_spec.rb +200 -0
  156. data/spec/semipublic/associations_spec.rb +177 -0
  157. data/spec/semipublic/collection_spec.rb +110 -0
  158. data/spec/semipublic/model_spec.rb +96 -0
  159. data/spec/semipublic/property/binary_spec.rb +13 -0
  160. data/spec/semipublic/property/boolean_spec.rb +47 -0
  161. data/spec/semipublic/property/class_spec.rb +33 -0
  162. data/spec/semipublic/property/date_spec.rb +43 -0
  163. data/spec/semipublic/property/date_time_spec.rb +46 -0
  164. data/spec/semipublic/property/decimal_spec.rb +83 -0
  165. data/spec/semipublic/property/discriminator_spec.rb +19 -0
  166. data/spec/semipublic/property/float_spec.rb +82 -0
  167. data/spec/semipublic/property/integer_spec.rb +82 -0
  168. data/spec/semipublic/property/lookup_spec.rb +29 -0
  169. data/spec/semipublic/property/serial_spec.rb +13 -0
  170. data/spec/semipublic/property/string_spec.rb +13 -0
  171. data/spec/semipublic/property/text_spec.rb +31 -0
  172. data/spec/semipublic/property/time_spec.rb +50 -0
  173. data/spec/semipublic/property_spec.rb +114 -0
  174. data/spec/semipublic/query/conditions/comparison_spec.rb +1501 -0
  175. data/spec/semipublic/query/conditions/operation_spec.rb +1294 -0
  176. data/spec/semipublic/query/path_spec.rb +471 -0
  177. data/spec/semipublic/query_spec.rb +3777 -0
  178. data/spec/semipublic/resource/state/clean_spec.rb +88 -0
  179. data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
  180. data/spec/semipublic/resource/state/dirty_spec.rb +156 -0
  181. data/spec/semipublic/resource/state/immutable_spec.rb +105 -0
  182. data/spec/semipublic/resource/state/transient_spec.rb +162 -0
  183. data/spec/semipublic/resource/state_spec.rb +230 -0
  184. data/spec/semipublic/resource_spec.rb +23 -0
  185. data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
  186. data/spec/semipublic/shared/resource_shared_spec.rb +199 -0
  187. data/spec/semipublic/shared/resource_state_shared_spec.rb +79 -0
  188. data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
  189. data/spec/spec.opts +5 -0
  190. data/spec/spec_helper.rb +37 -0
  191. data/spec/support/core_ext/hash.rb +10 -0
  192. data/spec/support/core_ext/inheritable_attributes.rb +46 -0
  193. data/spec/support/properties/huge_integer.rb +17 -0
  194. data/spec/unit/array_spec.rb +23 -0
  195. data/spec/unit/blank_spec.rb +73 -0
  196. data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
  197. data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
  198. data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
  199. data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
  200. data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
  201. data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
  202. data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
  203. data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
  204. data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
  205. data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
  206. data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
  207. data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
  208. data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
  209. data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
  210. data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
  211. data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
  212. data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
  213. data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
  214. data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
  215. data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
  216. data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
  217. data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
  218. data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
  219. data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
  220. data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
  221. data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
  222. data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
  223. data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
  224. data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
  225. data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
  226. data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
  227. data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
  228. data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
  229. data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
  230. data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
  231. data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
  232. data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
  233. data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
  234. data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
  235. data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
  236. data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
  237. data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
  238. data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
  239. data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
  240. data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
  241. data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
  242. data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
  243. data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
  244. data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
  245. data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
  246. data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
  247. data/spec/unit/hash_spec.rb +28 -0
  248. data/spec/unit/hook_spec.rb +1235 -0
  249. data/spec/unit/lazy_array_spec.rb +1949 -0
  250. data/spec/unit/mash_spec.rb +312 -0
  251. data/spec/unit/module_spec.rb +71 -0
  252. data/spec/unit/object_spec.rb +38 -0
  253. data/spec/unit/try_dup_spec.rb +46 -0
  254. data/tasks/ci.rake +1 -0
  255. data/tasks/db.rake +11 -0
  256. data/tasks/spec.rake +38 -0
  257. data/tasks/yard.rake +9 -0
  258. data/tasks/yardstick.rake +19 -0
  259. metadata +491 -0
@@ -0,0 +1,3777 @@
1
+ require '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::Property::String
13
+ length 40
14
+ end
15
+
16
+ class ::User
17
+ include DataMapper::Resource
18
+
19
+ property :name, String, :key => true
20
+ property :password, Password
21
+ property :balance, Decimal, :precision => 5, :scale => 2
22
+
23
+ belongs_to :referrer, self, :required => false
24
+ has n, :referrals, self, :inverse => :referrer
25
+ end
26
+
27
+ @repository = DataMapper::Repository.new(:default)
28
+ @model = User
29
+
30
+ @fields = [ :name ].freeze
31
+ @links = [ :referrer ].freeze
32
+ @conditions = { :name => 'Dan Kubb' }
33
+ @offset = 0
34
+ @limit = 1
35
+ @order = [ :name ].freeze
36
+ @unique = false
37
+ @add_reversed = false
38
+ @reload = false
39
+
40
+ @options = {
41
+ :fields => @fields,
42
+ :links => @links,
43
+ :conditions => @conditions,
44
+ :offset => @offset,
45
+ :limit => @limit,
46
+ :order => @order,
47
+ :unique => @unique,
48
+ :add_reversed => @add_reversed,
49
+ :reload => @reload,
50
+ }
51
+ end
52
+
53
+ it { DataMapper::Query.should respond_to(:new) }
54
+
55
+ describe '.new' do
56
+ describe 'with a repository' do
57
+ describe 'that is valid' do
58
+ before :all do
59
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
60
+ end
61
+
62
+ it { @return.should be_kind_of(DataMapper::Query) }
63
+
64
+ it 'should set the repository' do
65
+ @return.repository.should == @repository
66
+ end
67
+ end
68
+
69
+ describe 'that is invalid' do
70
+ it 'should raise an exception' do
71
+ lambda {
72
+ DataMapper::Query.new('invalid', @model, @options)
73
+ }.should raise_error(ArgumentError, '+repository+ should be DataMapper::Repository, but was String')
74
+ end
75
+ end
76
+ end
77
+
78
+ describe 'with a model' do
79
+ describe 'that is valid' do
80
+ before :all do
81
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
82
+ end
83
+
84
+ it { @return.should be_kind_of(DataMapper::Query) }
85
+
86
+ it 'should set the model' do
87
+ @return.model.should == @model
88
+ end
89
+ end
90
+
91
+ describe 'that is invalid' do
92
+ it 'should raise an exception' do
93
+ lambda {
94
+ DataMapper::Query.new(@repository, 'invalid', @options)
95
+ }.should raise_error(ArgumentError, '+model+ should be DataMapper::Model, but was String')
96
+ end
97
+ end
98
+ end
99
+
100
+ describe 'with a fields option' do
101
+ describe 'that is an Array containing a Symbol' do
102
+ before :all do
103
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
104
+ end
105
+
106
+ it { @return.should be_kind_of(DataMapper::Query) }
107
+
108
+ it 'should set the fields' do
109
+ @return.fields.should == @model.properties.values_at(*@fields)
110
+ end
111
+ end
112
+
113
+ describe 'that is an Array containing a String' do
114
+ before :all do
115
+ @options[:fields] = [ 'name' ]
116
+
117
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
118
+ end
119
+
120
+ it { @return.should be_kind_of(DataMapper::Query) }
121
+
122
+ it 'should set the fields' do
123
+ @return.fields.should == @model.properties.values_at('name')
124
+ end
125
+ end
126
+
127
+ describe 'that is an Array containing a Property' do
128
+ before :all do
129
+ @options[:fields] = @model.properties.values_at(:name)
130
+
131
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
132
+ end
133
+
134
+ it { @return.should be_kind_of(DataMapper::Query) }
135
+
136
+ it 'should set the fields' do
137
+ @return.fields.should == @model.properties.values_at(:name)
138
+ end
139
+ end
140
+
141
+ describe 'that is an Array containing a Property from an ancestor' do
142
+ before :all do
143
+ class ::Contact < User; end
144
+
145
+ @options[:fields] = User.properties.values_at(:name)
146
+
147
+ @return = DataMapper::Query.new(@repository, Contact, @options.freeze)
148
+ end
149
+
150
+ it { @return.should be_kind_of(DataMapper::Query) }
151
+
152
+ it 'should set the fields' do
153
+ @return.fields.should == User.properties.values_at(:name)
154
+ end
155
+ end
156
+
157
+ describe 'that is missing' do
158
+ before :all do
159
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:fields).freeze)
160
+ end
161
+
162
+ it { @return.should be_kind_of(DataMapper::Query) }
163
+
164
+ it 'should set fields to the model default properties' do
165
+ @return.fields.should == @model.properties.defaults
166
+ end
167
+ end
168
+
169
+ describe 'that is invalid' do
170
+ it 'should raise an exception' do
171
+ lambda {
172
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => :name))
173
+ }.should raise_error(StandardError)
174
+ end
175
+ end
176
+
177
+ describe 'that is an Array containing an unknown Symbol' do
178
+ it 'should raise an exception' do
179
+ lambda {
180
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ :unknown ]))
181
+ }.should raise_error(ArgumentError, "+options[:fields]+ entry :unknown does not map to a property in #{@model}")
182
+ end
183
+ end
184
+
185
+ describe 'that is an Array containing an unknown String' do
186
+ it 'should raise an exception' do
187
+ lambda {
188
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ 'unknown' ]))
189
+ }.should raise_error(ArgumentError, "+options[:fields]+ entry \"unknown\" does not map to a property in #{@model}")
190
+ end
191
+ end
192
+
193
+ describe 'that is an Array containing an invalid object' do
194
+ it 'should raise an exception' do
195
+ lambda {
196
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ 1 ]))
197
+ }.should raise_error(ArgumentError, '+options[:fields]+ entry 1 of an unsupported object Fixnum')
198
+ end
199
+ end
200
+
201
+ describe 'that is an Array containing an unknown Property' do
202
+ it 'should raise an exception' do
203
+ lambda {
204
+ DataMapper::Query.new(@repository, @model, @options.update(:fields => [ DataMapper::Property::String.new(@model, :unknown) ]))
205
+ }.should raise_error(ArgumentError, "+options[:field]+ entry :unknown does not map to a property in #{@model}")
206
+ end
207
+ end
208
+ end
209
+
210
+ describe 'with a links option' do
211
+ describe 'that is an Array containing a Symbol' do
212
+ before :all do
213
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
214
+ end
215
+
216
+ it { @return.should be_kind_of(DataMapper::Query) }
217
+
218
+ it 'should set the links' do
219
+ @return.links.should == @model.relationships.values_at(*@links)
220
+ end
221
+ end
222
+
223
+ describe 'that is an Array containing a String' do
224
+ before :all do
225
+ @options[:links] = [ 'referrer' ]
226
+
227
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
228
+ end
229
+
230
+ it { @return.should be_kind_of(DataMapper::Query) }
231
+
232
+ it 'should set the links' do
233
+ @return.links.should == @model.relationships.values_at('referrer')
234
+ end
235
+ end
236
+
237
+ describe 'that is an Array containing a Relationship' do
238
+ before :all do
239
+ @options[:links] = @model.relationships.values_at(:referrer)
240
+
241
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
242
+ end
243
+
244
+ it { @return.should be_kind_of(DataMapper::Query) }
245
+
246
+ it 'should set the links' do
247
+ @return.links.should == @model.relationships.values_at(:referrer)
248
+ end
249
+ end
250
+
251
+ describe 'that is missing' do
252
+ before :all do
253
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:links).freeze)
254
+ end
255
+
256
+ it { @return.should be_kind_of(DataMapper::Query) }
257
+
258
+ it 'should set links to an empty Array' do
259
+ @return.links.should == []
260
+ end
261
+ end
262
+
263
+ describe 'that is invalid' do
264
+ it 'should raise an exception' do
265
+ lambda {
266
+ DataMapper::Query.new(@repository, @model, @options.update(:links => :referral))
267
+ }.should raise_error(StandardError)
268
+ end
269
+ end
270
+
271
+ describe 'that is an empty Array' do
272
+ it 'should raise an exception' do
273
+ lambda {
274
+ DataMapper::Query.new(@repository, @model, @options.update(:links => []))
275
+ }.should raise_error(ArgumentError, '+options[:links]+ should not be empty')
276
+ end
277
+ end
278
+
279
+ describe 'that is an Array containing an unknown Symbol' do
280
+ it 'should raise an exception' do
281
+ lambda {
282
+ DataMapper::Query.new(@repository, @model, @options.update(:links => [ :unknown ]))
283
+ }.should raise_error(ArgumentError, "+options[:links]+ entry :unknown does not map to a relationship in #{@model}")
284
+ end
285
+ end
286
+
287
+ describe 'that is an Array containing an unknown String' do
288
+ it 'should raise an exception' do
289
+ lambda {
290
+ DataMapper::Query.new(@repository, @model, @options.update(:links => [ 'unknown' ]))
291
+ }.should raise_error(ArgumentError, "+options[:links]+ entry \"unknown\" does not map to a relationship in #{@model}")
292
+ end
293
+ end
294
+
295
+ describe 'that is an Array containing an invalid object' do
296
+ it 'should raise an exception' do
297
+ lambda {
298
+ DataMapper::Query.new(@repository, @model, @options.update(:links => [ 1 ]))
299
+ }.should raise_error(ArgumentError, '+options[:links]+ entry 1 of an unsupported object Fixnum')
300
+ end
301
+ end
302
+ end
303
+
304
+ describe 'with a conditions option' do
305
+ describe 'that is a valid Hash' do
306
+ describe 'with the Property key' do
307
+ before :all do
308
+ @options[:conditions] = { @model.properties[:name] => 'Dan Kubb' }
309
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
310
+ end
311
+
312
+ it { @return.should be_kind_of(DataMapper::Query) }
313
+
314
+ it 'should set the conditions' do
315
+ @return.conditions.should ==
316
+ DataMapper::Query::Conditions::Operation.new(
317
+ :and,
318
+ DataMapper::Query::Conditions::Comparison.new(
319
+ :eql,
320
+ @model.properties[:name],
321
+ 'Dan Kubb'
322
+ )
323
+ )
324
+ end
325
+
326
+ it 'should be valid' do
327
+ @return.should be_valid
328
+ end
329
+ end
330
+
331
+ describe 'with the Symbol key mapping to a Property' do
332
+ before :all do
333
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
334
+ end
335
+
336
+ it { @return.should be_kind_of(DataMapper::Query) }
337
+
338
+ it 'should set the conditions' do
339
+ @return.conditions.should ==
340
+ DataMapper::Query::Conditions::Operation.new(
341
+ :and,
342
+ DataMapper::Query::Conditions::Comparison.new(
343
+ :eql,
344
+ @model.properties[:name],
345
+ 'Dan Kubb'
346
+ )
347
+ )
348
+ end
349
+
350
+ it 'should be valid' do
351
+ @return.should be_valid
352
+ end
353
+ end
354
+
355
+ describe 'with the String key mapping to a Property' do
356
+ before :all do
357
+ @options[:conditions] = { 'name' => 'Dan Kubb' }
358
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
359
+ end
360
+
361
+ it { @return.should be_kind_of(DataMapper::Query) }
362
+
363
+ it 'should set the conditions' do
364
+ @return.conditions.should ==
365
+ DataMapper::Query::Conditions::Operation.new(
366
+ :and,
367
+ DataMapper::Query::Conditions::Comparison.new(
368
+ :eql,
369
+ @model.properties[:name],
370
+ 'Dan Kubb'
371
+ )
372
+ )
373
+ end
374
+
375
+ it 'should be valid' do
376
+ @return.should be_valid
377
+ end
378
+ end
379
+
380
+ supported_by :all do
381
+ describe 'with the Symbol key mapping to a Relationship' do
382
+ before :all do
383
+ @user = @model.create(:name => 'Dan Kubb')
384
+
385
+ @options[:conditions] = { :referrer => @user }
386
+
387
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
388
+ end
389
+
390
+ it { @return.should be_kind_of(DataMapper::Query) }
391
+
392
+ it 'should set the conditions' do
393
+ @return.conditions.should ==
394
+ DataMapper::Query::Conditions::Operation.new(
395
+ :and,
396
+ DataMapper::Query::Conditions::Comparison.new(
397
+ :eql,
398
+ @model.relationships[:referrer],
399
+ @user
400
+ )
401
+ )
402
+ end
403
+
404
+ it 'should be valid' do
405
+ @return.should be_valid
406
+ end
407
+ end
408
+
409
+ describe 'with the String key mapping to a Relationship' do
410
+ before :all do
411
+ @user = @model.create(:name => 'Dan Kubb')
412
+
413
+ @options[:conditions] = { 'referrer' => @user }
414
+
415
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
416
+ end
417
+
418
+ it { @return.should be_kind_of(DataMapper::Query) }
419
+
420
+ it 'should set the conditions' do
421
+ @return.conditions.should ==
422
+ DataMapper::Query::Conditions::Operation.new(
423
+ :and,
424
+ DataMapper::Query::Conditions::Comparison.new(
425
+ :eql,
426
+ @model.relationships['referrer'],
427
+ @user
428
+ )
429
+ )
430
+ end
431
+
432
+ it 'should be valid' do
433
+ @return.should be_valid
434
+ end
435
+ end
436
+
437
+ describe 'with the Symbol key mapping to a Relationship and a nil value' do
438
+ before :all do
439
+ @options[:conditions] = { :referrer => nil }
440
+
441
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
442
+ end
443
+
444
+ it { @return.should be_kind_of(DataMapper::Query) }
445
+
446
+ it 'should set the conditions' do
447
+ @return.conditions.should ==
448
+ DataMapper::Query::Conditions::Operation.new(
449
+ :and,
450
+ DataMapper::Query::Conditions::Comparison.new(
451
+ :eql,
452
+ @model.relationships[:referrer],
453
+ nil
454
+ )
455
+ )
456
+ end
457
+
458
+ it 'should be valid' do
459
+ @return.should be_valid
460
+ end
461
+ end
462
+
463
+ describe 'with the Symbol key mapping to a Relationship and an empty Array' do
464
+ before :all do
465
+ @options[:conditions] = { :referrer => [] }
466
+
467
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
468
+ end
469
+
470
+ it { @return.should be_kind_of(DataMapper::Query) }
471
+
472
+ it 'should set the conditions' do
473
+ @return.conditions.should ==
474
+ DataMapper::Query::Conditions::Operation.new(
475
+ :and,
476
+ DataMapper::Query::Conditions::Comparison.new(
477
+ :in,
478
+ @model.relationships[:referrer],
479
+ []
480
+ )
481
+ )
482
+ end
483
+
484
+ it 'should be invalid' do
485
+ @return.should_not be_valid
486
+ end
487
+ end
488
+ end
489
+
490
+ describe 'with the Query::Operator key' do
491
+ before :all do
492
+ @options[:conditions] = { :name.gte => 'Dan Kubb' }
493
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
494
+ end
495
+
496
+ it { @return.should be_kind_of(DataMapper::Query) }
497
+
498
+ it 'should set the conditions' do
499
+ @return.conditions.should ==
500
+ DataMapper::Query::Conditions::Operation.new(
501
+ :and,
502
+ DataMapper::Query::Conditions::Comparison.new(
503
+ :gte,
504
+ @model.properties[:name],
505
+ 'Dan Kubb'
506
+ )
507
+ )
508
+ end
509
+
510
+ it 'should be valid' do
511
+ @return.should be_valid
512
+ end
513
+ end
514
+
515
+ describe 'with the Query::Path key' do
516
+ before :all do
517
+ @options[:conditions] = { @model.referrer.name => 'Dan Kubb' }
518
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
519
+ end
520
+
521
+ it { @return.should be_kind_of(DataMapper::Query) }
522
+
523
+ it 'should not set the conditions' do
524
+ pending do
525
+ @return.conditions.should be_nil
526
+ end
527
+ end
528
+
529
+ it 'should set the links' do
530
+ @return.links.should == [ @model.relationships[:referrals], @model.relationships[:referrer] ]
531
+ end
532
+
533
+ it 'should be valid' do
534
+ @return.should be_valid
535
+ end
536
+ end
537
+
538
+ describe 'with the String key mapping to a Query::Path' do
539
+ before :all do
540
+ @options[:conditions] = { 'referrer.name' => 'Dan Kubb' }
541
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
542
+ end
543
+
544
+ it { @return.should be_kind_of(DataMapper::Query) }
545
+
546
+ it 'should not set the conditions' do
547
+ pending do
548
+ @return.conditions.should be_nil
549
+ end
550
+ end
551
+
552
+ it 'should set the links' do
553
+ @return.links.should == [ @model.relationships[:referrals], @model.relationships[:referrer] ]
554
+ end
555
+
556
+ it 'should be valid' do
557
+ @return.should be_valid
558
+ end
559
+ end
560
+
561
+ describe 'with an Array with 1 entry' do
562
+ before :all do
563
+ @options[:conditions] = { :name => [ 'Dan Kubb' ] }
564
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
565
+ end
566
+
567
+ it { @return.should be_kind_of(DataMapper::Query) }
568
+
569
+ it 'should set the conditions' do
570
+ pending do
571
+ @return.conditions.should ==
572
+ DataMapper::Query::Conditions::Operation.new(
573
+ :and,
574
+ DataMapper::Query::Conditions::Comparison.new(
575
+ :eql,
576
+ @model.properties[:name],
577
+ 'Dan Kubb'
578
+ )
579
+ )
580
+ end
581
+ end
582
+
583
+ it 'should be valid' do
584
+ @return.should be_valid
585
+ end
586
+ end
587
+
588
+ describe 'with an Array with no entries' do
589
+ before :all do
590
+ @options[:conditions] = { :name => [] }
591
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
592
+ end
593
+
594
+ it { @return.should be_kind_of(DataMapper::Query) }
595
+
596
+ it 'should set the conditions' do
597
+ pending do
598
+ @return.conditions.should ==
599
+ DataMapper::Query::Conditions::Operation.new(
600
+ :and,
601
+ DataMapper::Query::Conditions::Comparison.new(
602
+ :eql,
603
+ @model.properties[:name],
604
+ 'Dan Kubb'
605
+ )
606
+ )
607
+ end
608
+ end
609
+
610
+ it 'should not be valid' do
611
+ @return.should_not be_valid
612
+ end
613
+ end
614
+
615
+ describe 'with an Array with duplicate entries' do
616
+ before :all do
617
+ @options[:conditions] = { :name => [ 'John Doe', 'Dan Kubb', 'John Doe' ] }
618
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
619
+ end
620
+
621
+ it { @return.should be_kind_of(DataMapper::Query) }
622
+
623
+ it 'should set the conditions' do
624
+ @return.conditions.should ==
625
+ DataMapper::Query::Conditions::Operation.new(
626
+ :and,
627
+ DataMapper::Query::Conditions::Comparison.new(
628
+ :in,
629
+ @model.properties[:name],
630
+ [ 'John Doe', 'Dan Kubb' ]
631
+ )
632
+ )
633
+ end
634
+
635
+ it 'should be valid' do
636
+ @return.should be_valid
637
+ end
638
+ end
639
+
640
+ describe 'with a Property subclass' do
641
+ before :all do
642
+ @options[:conditions] = { :password => 'password' }
643
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
644
+ end
645
+
646
+ it { @return.should be_kind_of(DataMapper::Query) }
647
+
648
+ it 'should set the conditions' do
649
+ @return.conditions.should ==
650
+ DataMapper::Query::Conditions::Operation.new(
651
+ :and,
652
+ DataMapper::Query::Conditions::Comparison.new(
653
+ :eql,
654
+ @model.properties[:password],
655
+ 'password'
656
+ )
657
+ )
658
+ end
659
+
660
+ it 'should be valid' do
661
+ @return.should be_valid
662
+ end
663
+ end
664
+
665
+ describe 'with a Symbol for a String property' do
666
+ before :all do
667
+ @options[:conditions] = { :name => 'Dan Kubb'.to_sym }
668
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
669
+ end
670
+
671
+ it { @return.should be_kind_of(DataMapper::Query) }
672
+
673
+ it 'should set the conditions' do
674
+ @return.conditions.should ==
675
+ DataMapper::Query::Conditions::Operation.new(
676
+ :and,
677
+ DataMapper::Query::Conditions::Comparison.new(
678
+ :eql,
679
+ @model.properties[:name],
680
+ 'Dan Kubb' # typecast value
681
+ )
682
+ )
683
+ end
684
+
685
+ it 'should be valid' do
686
+ @return.should be_valid
687
+ end
688
+ end
689
+
690
+ describe 'with a Float for a Decimal property' do
691
+ before :all do
692
+ @options[:conditions] = { :balance => 50.5 }
693
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
694
+ end
695
+
696
+ it { @return.should be_kind_of(DataMapper::Query) }
697
+
698
+ it 'should set the conditions' do
699
+ @return.conditions.should ==
700
+ DataMapper::Query::Conditions::Operation.new(
701
+ :and,
702
+ DataMapper::Query::Conditions::Comparison.new(
703
+ :eql,
704
+ @model.properties[:balance],
705
+ BigDecimal('50.5') # typecast value
706
+ )
707
+ )
708
+ end
709
+
710
+ it 'should be valid' do
711
+ @return.should be_valid
712
+ end
713
+ end
714
+ end
715
+
716
+ describe 'that is a valid Array' do
717
+ before :all do
718
+ @options[:conditions] = [ 'name = ?', 'Dan Kubb' ]
719
+
720
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
721
+ end
722
+
723
+ it { @return.should be_kind_of(DataMapper::Query) }
724
+
725
+ it 'should set the conditions' do
726
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
727
+ end
728
+
729
+ it 'should be valid' do
730
+ @return.should be_valid
731
+ end
732
+ end
733
+
734
+ describe 'that is missing' do
735
+ before :all do
736
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:conditions).freeze)
737
+ end
738
+
739
+ it { @return.should be_kind_of(DataMapper::Query) }
740
+
741
+ it 'should set conditions to nil by default' do
742
+ @return.conditions.should be_nil
743
+ end
744
+
745
+ it 'should be valid' do
746
+ @return.should be_valid
747
+ end
748
+ end
749
+
750
+ describe 'that is invalid' do
751
+ it 'should raise an exception' do
752
+ lambda {
753
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => 'invalid'))
754
+ }.should raise_error(ArgumentError, '+options[:conditions]+ should be DataMapper::Query::Conditions::AbstractOperation or DataMapper::Query::Conditions::AbstractComparison or Hash or Array, but was String')
755
+ end
756
+ end
757
+
758
+ describe 'that is an empty Array' do
759
+ it 'should raise an exception' do
760
+ lambda {
761
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => []))
762
+ }.should raise_error(ArgumentError, '+options[:conditions]+ should not be empty')
763
+ end
764
+ end
765
+
766
+ describe 'that is an Array with a blank statement' do
767
+ it 'should raise an exception' do
768
+ lambda {
769
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => [ ' ' ]))
770
+ }.should raise_error(ArgumentError, '+options[:conditions]+ should have a statement for the first entry')
771
+ end
772
+ end
773
+
774
+ describe 'that is a Hash with a Symbol key that is not for a Property in the model' do
775
+ it 'should raise an exception' do
776
+ lambda {
777
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { :unknown => 1 }))
778
+ }.should raise_error(ArgumentError, "condition :unknown does not map to a property or relationship in #{@model}")
779
+ end
780
+ end
781
+
782
+ describe 'that is a Hash with a String key that is not for a Property in the model' do
783
+ it 'should raise an exception' do
784
+ lambda {
785
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { 'unknown' => 1 }))
786
+ }.should raise_error(ArgumentError, "condition \"unknown\" does not map to a property or relationship in #{@model}")
787
+ end
788
+ end
789
+
790
+ describe 'that is a Hash with a String key that is a Path and not for a Relationship in the model' do
791
+ it 'should raise an exception' do
792
+ lambda {
793
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { 'unknown.id' => 1 }))
794
+ }.should raise_error(ArgumentError, "condition \"unknown.id\" does not map to a property or relationship in #{@model}")
795
+ end
796
+ end
797
+
798
+ describe 'that is a Hash with a Property that does not belong to the model' do
799
+ before do
800
+ Object.send(:remove_const, :Alternate) if Object.const_defined?(:Alternate)
801
+ @alternate_model = DataMapper::Model.new('Alternate') do
802
+ property :id, DataMapper::Property::Serial
803
+ end
804
+ end
805
+
806
+ it 'should raise an exception' do
807
+ lambda {
808
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { @alternate_model.properties[:id] => 1 }))
809
+ }.should raise_error(ArgumentError, "condition :id does not map to a property in #{@model}, but belongs to #{@alternate_model}")
810
+ end
811
+ end
812
+
813
+ describe 'that is a Hash with a Query::Operator key that is not for a Property in the model' do
814
+ it 'should raise an exception' do
815
+ lambda {
816
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { :unknown.asc => 1 }))
817
+ }.should raise_error(ArgumentError, 'condition #<DataMapper::Query::Operator @target=:unknown @operator=:asc> used an invalid operator asc')
818
+ end
819
+ end
820
+
821
+ describe 'that is a Hash with a key of a type that is not permitted' do
822
+ it 'should raise an exception' do
823
+ lambda {
824
+ DataMapper::Query.new(@repository, @model, @options.update(:conditions => { 1 => 1 }))
825
+ }.should raise_error(ArgumentError, 'condition 1 of an unsupported object Fixnum')
826
+ end
827
+ end
828
+ end
829
+
830
+ describe 'with an offset option' do
831
+ describe 'that is valid' do
832
+ before :all do
833
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
834
+ end
835
+
836
+ it { @return.should be_kind_of(DataMapper::Query) }
837
+
838
+ it 'should set the offset' do
839
+ @return.offset.should == @offset
840
+ end
841
+ end
842
+
843
+ describe 'that is missing' do
844
+ before :all do
845
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:offset).freeze)
846
+ end
847
+
848
+ it { @return.should be_kind_of(DataMapper::Query) }
849
+
850
+ it 'should set offset to 0' do
851
+ @return.offset.should == 0
852
+ end
853
+ end
854
+
855
+ describe 'that is invalid' do
856
+ it 'should raise an exception' do
857
+ lambda {
858
+ DataMapper::Query.new(@repository, @model, @options.update(:offset => '0'))
859
+ }.should raise_error(StandardError)
860
+ end
861
+ end
862
+
863
+ describe 'that is less than 0' do
864
+ it 'should raise an exception' do
865
+ lambda {
866
+ DataMapper::Query.new(@repository, @model, @options.update(:offset => -1))
867
+ }.should raise_error(ArgumentError, '+options[:offset]+ must be greater than or equal to 0, but was -1')
868
+ end
869
+ end
870
+
871
+ describe 'that is greater than 0 and a nil limit' do
872
+ it 'should raise an exception' do
873
+ lambda {
874
+ DataMapper::Query.new(@repository, @model, @options.except(:limit).update(:offset => 1))
875
+ }.should raise_error(ArgumentError, '+options[:offset]+ cannot be greater than 0 if limit is not specified')
876
+ end
877
+ end
878
+ end
879
+
880
+ describe 'with a limit option' do
881
+ describe 'that is valid' do
882
+ before :all do
883
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
884
+ end
885
+
886
+ it { @return.should be_kind_of(DataMapper::Query) }
887
+
888
+ it 'should set the limit' do
889
+ @return.limit.should == @limit
890
+ end
891
+ end
892
+
893
+ describe 'that is missing' do
894
+ before :all do
895
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:limit).freeze)
896
+ end
897
+
898
+ it { @return.should be_kind_of(DataMapper::Query) }
899
+
900
+ it 'should set limit to nil' do
901
+ @return.limit.should be_nil
902
+ end
903
+ end
904
+
905
+ describe 'that is invalid' do
906
+ it 'should raise an exception' do
907
+ lambda {
908
+ DataMapper::Query.new(@repository, @model, @options.update(:limit => '1'))
909
+ }.should raise_error(StandardError)
910
+ end
911
+ end
912
+
913
+ describe 'that is less than 0' do
914
+ it 'should raise an exception' do
915
+ lambda {
916
+ DataMapper::Query.new(@repository, @model, @options.update(:limit => -1))
917
+ }.should raise_error(ArgumentError, '+options[:limit]+ must be greater than or equal to 0, but was -1')
918
+ end
919
+ end
920
+ end
921
+
922
+ describe 'with an order option' do
923
+ describe 'that is a single Symbol' do
924
+ before :all do
925
+ @options[:order] = :name
926
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
927
+ end
928
+
929
+ it { @return.should be_kind_of(DataMapper::Query) }
930
+
931
+ it 'should set the order' do
932
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
933
+ end
934
+ end
935
+
936
+ describe 'that is a single String' do
937
+ before :all do
938
+ @options[:order] = 'name'
939
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
940
+ end
941
+
942
+ it { @return.should be_kind_of(DataMapper::Query) }
943
+
944
+ it 'should set the order' do
945
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
946
+ end
947
+ end
948
+
949
+ describe 'that is a single Property' do
950
+ before :all do
951
+ @options[:order] = @model.properties.values_at(:name)
952
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
953
+ end
954
+
955
+ it { @return.should be_kind_of(DataMapper::Query) }
956
+
957
+ it 'should set the order' do
958
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
959
+ end
960
+ end
961
+
962
+ describe 'that contains a Query::Direction with a property that is not part of the model' do
963
+ before :all do
964
+ @property = DataMapper::Property::String.new(@model, :unknown)
965
+ @direction = DataMapper::Query::Direction.new(@property, :desc)
966
+ @return = DataMapper::Query.new(@repository, @model, @options.update(:order => [ @direction ]))
967
+ end
968
+
969
+ it 'should set the order, since it may map to a joined model' do
970
+ @return.order.should == [ @direction ]
971
+ end
972
+ end
973
+
974
+ describe 'that contains a Property that is not part of the model' do
975
+ before :all do
976
+ @property = DataMapper::Property::String.new(@model, :unknown)
977
+ @return = DataMapper::Query.new(@repository, @model, @options.update(:order => [ @property ]))
978
+ end
979
+
980
+ it 'should set the order, since it may map to a joined model' do
981
+ @return.order.should == [ DataMapper::Query::Direction.new(@property) ]
982
+ end
983
+ end
984
+
985
+ describe 'that contains a Query::Path to a property on a linked model' do
986
+ before :all do
987
+ @property = @model.referrer.name
988
+ @return = DataMapper::Query.new(@repository, @model, @options.update(:order => [ @property ]))
989
+ end
990
+
991
+ it 'should set the order' do
992
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
993
+ end
994
+ end
995
+
996
+ describe 'that is an Array containing a Symbol' do
997
+ before :all do
998
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
999
+ end
1000
+
1001
+ it { @return.should be_kind_of(DataMapper::Query) }
1002
+
1003
+ it 'should set the order' do
1004
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
1005
+ end
1006
+ end
1007
+
1008
+ describe 'that is an Array containing a String' do
1009
+ before :all do
1010
+ @options[:order] = [ 'name' ]
1011
+
1012
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1013
+ end
1014
+
1015
+ it { @return.should be_kind_of(DataMapper::Query) }
1016
+
1017
+ it 'should set the order' do
1018
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
1019
+ end
1020
+ end
1021
+
1022
+ describe 'that is an Array containing a Property' do
1023
+ before :all do
1024
+ @options[:order] = @model.properties.values_at(:name)
1025
+
1026
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1027
+ end
1028
+
1029
+ it { @return.should be_kind_of(DataMapper::Query) }
1030
+
1031
+ it 'should set the order' do
1032
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
1033
+ end
1034
+ end
1035
+
1036
+ describe 'that is an Array containing a Property from an ancestor' do
1037
+ before :all do
1038
+ class ::Contact < User; end
1039
+
1040
+ @options[:order] = User.properties.values_at(:name)
1041
+
1042
+ @return = DataMapper::Query.new(@repository, Contact, @options.freeze)
1043
+ end
1044
+
1045
+ it { @return.should be_kind_of(DataMapper::Query) }
1046
+
1047
+ it 'should set the order' do
1048
+ @return.order.should == [ DataMapper::Query::Direction.new(User.properties[:name]) ]
1049
+ end
1050
+ end
1051
+
1052
+ describe 'that is an Array containing an Operator' do
1053
+ before :all do
1054
+ @options[:order] = [ :name.asc ]
1055
+
1056
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1057
+ end
1058
+
1059
+ it { @return.should be_kind_of(DataMapper::Query) }
1060
+
1061
+ it 'should set the order' do
1062
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :asc) ]
1063
+ end
1064
+ end
1065
+
1066
+ describe 'that is an Array containing an Query::Direction' do
1067
+ before :all do
1068
+ @options[:order] = [ DataMapper::Query::Direction.new(@model.properties[:name], :asc) ]
1069
+
1070
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1071
+ end
1072
+
1073
+ it { @return.should be_kind_of(DataMapper::Query) }
1074
+
1075
+ it 'should set the order' do
1076
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :asc) ]
1077
+ end
1078
+ end
1079
+
1080
+ describe 'that is an Array containing an Query::Direction with a Property from an ancestor' do
1081
+ before :all do
1082
+ class ::Contact < User; end
1083
+
1084
+ @options[:order] = [ DataMapper::Query::Direction.new(User.properties[:name], :asc) ]
1085
+
1086
+ @return = DataMapper::Query.new(@repository, Contact, @options.freeze)
1087
+ end
1088
+
1089
+ it { @return.should be_kind_of(DataMapper::Query) }
1090
+
1091
+ it 'should set the order' do
1092
+ @return.order.should == [ DataMapper::Query::Direction.new(User.properties[:name], :asc) ]
1093
+ end
1094
+ end
1095
+
1096
+ describe 'that is missing' do
1097
+ before :all do
1098
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:order).freeze)
1099
+ end
1100
+
1101
+ it { @return.should be_kind_of(DataMapper::Query) }
1102
+
1103
+ it 'should set order to the model default order' do
1104
+ @return.order.should == @model.default_order(@repository.name)
1105
+ end
1106
+ end
1107
+
1108
+ describe 'that is invalid' do
1109
+ it 'should raise an exception' do
1110
+ lambda {
1111
+ DataMapper::Query.new(@repository, @model, @options.update(:order => 'unknown'))
1112
+ }.should raise_error(ArgumentError, "+options[:order]+ entry \"unknown\" does not map to a property in #{@model}")
1113
+ end
1114
+ end
1115
+
1116
+ describe 'that is an empty Array and the fields option contains a non-operator' do
1117
+ it 'should raise an exception' do
1118
+ lambda {
1119
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [], :fields => [ :name ]))
1120
+ }.should raise_error(ArgumentError, '+options[:order]+ should not be empty if +options[:fields] contains a non-operator')
1121
+ end
1122
+ end
1123
+
1124
+ describe 'that is an Array containing an unknown String' do
1125
+ it 'should raise an exception' do
1126
+ lambda {
1127
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ 'unknown' ]))
1128
+ }.should raise_error(ArgumentError, "+options[:order]+ entry \"unknown\" does not map to a property in #{@model}")
1129
+ end
1130
+ end
1131
+
1132
+ describe 'that is an Array containing an invalid object' do
1133
+ it 'should raise an exception' do
1134
+ lambda {
1135
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ 1 ]))
1136
+ }.should raise_error(ArgumentError, '+options[:order]+ entry 1 of an unsupported object Fixnum')
1137
+ end
1138
+ end
1139
+
1140
+ describe 'that contains a Query::Operator with a target that is not part of the model' do
1141
+ it 'should raise an exception' do
1142
+ lambda {
1143
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ :unknown.desc ]))
1144
+ }.should raise_error(ArgumentError, "+options[:order]+ entry :unknown does not map to a property in #{@model}")
1145
+ end
1146
+ end
1147
+
1148
+ describe 'that contains a Query::Operator with an unknown operator' do
1149
+ it 'should raise an exception' do
1150
+ lambda {
1151
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ :name.gt ]))
1152
+ }.should raise_error(ArgumentError, '+options[:order]+ entry #<DataMapper::Query::Operator @target=:name @operator=:gt> used an invalid operator gt')
1153
+ end
1154
+ end
1155
+
1156
+ describe 'that contains a Symbol that is not for a Property in the model' do
1157
+ it 'should raise an exception' do
1158
+ lambda {
1159
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ :unknown ]))
1160
+ }.should raise_error(ArgumentError, "+options[:order]+ entry :unknown does not map to a property in #{@model}")
1161
+ end
1162
+ end
1163
+
1164
+ describe 'that contains a String that is not for a Property in the model' do
1165
+ it 'should raise an exception' do
1166
+ lambda {
1167
+ DataMapper::Query.new(@repository, @model, @options.update(:order => [ 'unknown' ]))
1168
+ }.should raise_error(ArgumentError, "+options[:order]+ entry \"unknown\" does not map to a property in #{@model}")
1169
+ end
1170
+ end
1171
+ end
1172
+
1173
+ describe 'with a unique option' do
1174
+ describe 'that is valid' do
1175
+ before :all do
1176
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1177
+ end
1178
+
1179
+ it { @return.should be_kind_of(DataMapper::Query) }
1180
+
1181
+ it 'should set the unique? flag' do
1182
+ @return.unique?.should == @unique
1183
+ end
1184
+ end
1185
+
1186
+ describe 'that is missing' do
1187
+ before :all do
1188
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:unique, :links).freeze)
1189
+ end
1190
+
1191
+ it { @return.should be_kind_of(DataMapper::Query) }
1192
+
1193
+ it 'should set the query to not be unique' do
1194
+ @return.should_not be_unique
1195
+ end
1196
+ end
1197
+
1198
+ describe 'that is invalid' do
1199
+ it 'should raise an exception' do
1200
+ lambda {
1201
+ DataMapper::Query.new(@repository, @model, @options.update(:unique => nil))
1202
+ }.should raise_error(ArgumentError, '+options[:unique]+ should be true or false, but was nil')
1203
+ end
1204
+ end
1205
+ end
1206
+
1207
+ describe 'with an add_reversed option' do
1208
+ describe 'that is valid' do
1209
+ before :all do
1210
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1211
+ end
1212
+
1213
+ it { @return.should be_kind_of(DataMapper::Query) }
1214
+
1215
+ it 'should set the add_reversed? flag' do
1216
+ @return.add_reversed?.should == @add_reversed
1217
+ end
1218
+ end
1219
+
1220
+ describe 'that is missing' do
1221
+ before :all do
1222
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:add_reversed).freeze)
1223
+ end
1224
+
1225
+ it { @return.should be_kind_of(DataMapper::Query) }
1226
+
1227
+ it 'should set the query to not add in reverse order' do
1228
+ # TODO: think about renaming the flag to not sound 'clumsy'
1229
+ @return.should_not be_add_reversed
1230
+ end
1231
+ end
1232
+
1233
+ describe 'that is invalid' do
1234
+ it 'should raise an exception' do
1235
+ lambda {
1236
+ DataMapper::Query.new(@repository, @model, @options.update(:add_reversed => nil))
1237
+ }.should raise_error(ArgumentError, '+options[:add_reversed]+ should be true or false, but was nil')
1238
+ end
1239
+ end
1240
+ end
1241
+
1242
+ describe 'with a reload option' do
1243
+ describe 'that is valid' do
1244
+ before :all do
1245
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1246
+ end
1247
+
1248
+ it { @return.should be_kind_of(DataMapper::Query) }
1249
+
1250
+ it 'should set the reload? flag' do
1251
+ @return.reload?.should == @reload
1252
+ end
1253
+ end
1254
+
1255
+ describe 'that is missing' do
1256
+ before :all do
1257
+ @return = DataMapper::Query.new(@repository, @model, @options.except(:reload).freeze)
1258
+ end
1259
+
1260
+ it { @return.should be_kind_of(DataMapper::Query) }
1261
+
1262
+ it 'should set the query to not reload' do
1263
+ @return.should_not be_reload
1264
+ end
1265
+ end
1266
+
1267
+ describe 'that is invalid' do
1268
+ it 'should raise an exception' do
1269
+ lambda {
1270
+ DataMapper::Query.new(@repository, @model, @options.update(:reload => nil))
1271
+ }.should raise_error(ArgumentError, '+options[:reload]+ should be true or false, but was nil')
1272
+ end
1273
+ end
1274
+ end
1275
+
1276
+ describe 'with options' do
1277
+ describe 'that are unknown' do
1278
+ before :all do
1279
+ @options.update(@options.delete(:conditions))
1280
+
1281
+ @return = DataMapper::Query.new(@repository, @model, @options.freeze)
1282
+ end
1283
+
1284
+ it { @return.should be_kind_of(DataMapper::Query) }
1285
+
1286
+ it 'should set the conditions' do
1287
+ @return.conditions.should ==
1288
+ DataMapper::Query::Conditions::Operation.new(
1289
+ :and,
1290
+ DataMapper::Query::Conditions::Comparison.new(
1291
+ :eql,
1292
+ @model.properties[:name],
1293
+ @conditions[:name]
1294
+ )
1295
+ )
1296
+ end
1297
+ end
1298
+
1299
+ describe 'that are invalid' do
1300
+ it 'should raise an exception' do
1301
+ lambda {
1302
+ DataMapper::Query.new(@repository, @model, 'invalid')
1303
+ }.should raise_error(StandardError)
1304
+ end
1305
+ end
1306
+ end
1307
+
1308
+ describe 'with no options' do
1309
+ before :all do
1310
+ @return = DataMapper::Query.new(@repository, @model)
1311
+ end
1312
+
1313
+ it { @return.should be_kind_of(DataMapper::Query) }
1314
+
1315
+ it 'should set options to an empty Hash' do
1316
+ @return.options.should == {}
1317
+ end
1318
+ end
1319
+ end
1320
+ end
1321
+
1322
+ # instance methods
1323
+ describe DataMapper::Query do
1324
+ before :all do
1325
+ class ::User
1326
+ include DataMapper::Resource
1327
+
1328
+ property :name, String, :key => true
1329
+ property :citizenship, String
1330
+
1331
+ belongs_to :referrer, self, :required => false
1332
+ has n, :referrals, self, :inverse => :referrer
1333
+ has n, :grandparents, self, :through => :referrals, :via => :referrer
1334
+ end
1335
+
1336
+ class ::Other
1337
+ include DataMapper::Resource
1338
+
1339
+ property :id, Serial
1340
+ end
1341
+
1342
+ # finalize the models
1343
+ DataMapper.finalize
1344
+
1345
+ @repository = DataMapper::Repository.new(:default)
1346
+ @model = User
1347
+ @options = { :limit => 3 }
1348
+ @query = DataMapper::Query.new(@repository, @model, @options)
1349
+ @original = @query
1350
+ end
1351
+
1352
+ before :all do
1353
+ @other_options = {
1354
+ :fields => [ @model.properties[:name] ].freeze,
1355
+ :links => [ @model.relationships[:referrer] ].freeze,
1356
+ :conditions => [ 'name = ?', 'Dan Kubb' ].freeze,
1357
+ :offset => 1,
1358
+ :limit => 2,
1359
+ :order => [ DataMapper::Query::Direction.new(@model.properties[:name], :desc) ].freeze,
1360
+ :unique => true,
1361
+ :add_reversed => true,
1362
+ :reload => true,
1363
+ }
1364
+ end
1365
+
1366
+ subject { @query }
1367
+
1368
+ it { should respond_to(:==) }
1369
+
1370
+ describe '#==' do
1371
+ describe 'when other is equal' do
1372
+ before :all do
1373
+ @return = @query == @query
1374
+ end
1375
+
1376
+ it { @return.should be(true) }
1377
+ end
1378
+
1379
+ describe 'when other is equivalent' do
1380
+ before :all do
1381
+ @return = @query == @query.dup
1382
+ end
1383
+
1384
+ it { @return.should be(true) }
1385
+ end
1386
+
1387
+ DataMapper::Query::OPTIONS.each do |name|
1388
+ describe "when other has an inequalvalent #{name}" do
1389
+ before :all do
1390
+ @return = @query == @query.merge(name => @other_options[name])
1391
+ end
1392
+
1393
+ it { @return.should be(false) }
1394
+ end
1395
+ end
1396
+
1397
+ describe 'when other is a different type of object that can be compared, and is equivalent' do
1398
+ before :all do
1399
+ @other = OpenStruct.new(
1400
+ :repository => @query.repository,
1401
+ :model => @query.model,
1402
+ :sorted_fields => @query.sorted_fields,
1403
+ :links => @query.links,
1404
+ :conditions => @query.conditions,
1405
+ :order => @query.order,
1406
+ :limit => @query.limit,
1407
+ :offset => @query.offset,
1408
+ :reload? => @query.reload?,
1409
+ :unique? => @query.unique?,
1410
+ :add_reversed? => @query.add_reversed?
1411
+ )
1412
+
1413
+ @return = @query == @other
1414
+ end
1415
+
1416
+ it { @return.should be(false) }
1417
+ end
1418
+
1419
+ describe 'when other is a different type of object that can be compared, and is not equivalent' do
1420
+ before :all do
1421
+ @other = OpenStruct.new(
1422
+ :repository => @query.repository,
1423
+ :model => @query.model,
1424
+ :sorted_fields => @query.sorted_fields,
1425
+ :links => @query.links,
1426
+ :conditions => @query.conditions,
1427
+ :order => @query.order,
1428
+ :limit => @query.limit,
1429
+ :offset => @query.offset,
1430
+ :reload? => true,
1431
+ :unique? => @query.unique?,
1432
+ :add_reversed? => @query.add_reversed?
1433
+ )
1434
+
1435
+ @return = @query == @other
1436
+ end
1437
+
1438
+ it { @return.should be(false) }
1439
+ end
1440
+
1441
+ describe 'when other is a different type of object that cannot be compared' do
1442
+ before :all do
1443
+ @return = @query == 'invalid'
1444
+ end
1445
+
1446
+ it { @return.should be(false) }
1447
+ end
1448
+ end
1449
+
1450
+ it { should respond_to(:conditions) }
1451
+
1452
+ describe '#conditions' do
1453
+ before :all do
1454
+ @query.update(:name => 'Dan Kubb')
1455
+
1456
+ @return = @query.conditions
1457
+ end
1458
+
1459
+ it { @return.should be_kind_of(DataMapper::Query::Conditions::AndOperation) }
1460
+
1461
+ it 'should return expected value' do
1462
+ @return.should ==
1463
+ DataMapper::Query::Conditions::Operation.new(
1464
+ :and,
1465
+ DataMapper::Query::Conditions::Comparison.new(
1466
+ :eql,
1467
+ @model.properties[:name],
1468
+ 'Dan Kubb'
1469
+ )
1470
+ )
1471
+ end
1472
+ end
1473
+
1474
+ [ :difference, :- ].each do |method|
1475
+ it { should respond_to(method) }
1476
+
1477
+ describe "##{method}" do
1478
+ supported_by :all do
1479
+ before :all do
1480
+ @key = @model.key(@repository.name)
1481
+
1482
+ @self_relationship = DataMapper::Associations::OneToMany::Relationship.new(
1483
+ :self,
1484
+ @model,
1485
+ @model,
1486
+ {
1487
+ :child_key => @key.map { |p| p.name },
1488
+ :parent_key => @key.map { |p| p.name },
1489
+ :child_repository_name => @repository.name,
1490
+ :parent_repository_name => @repository.name,
1491
+ }
1492
+ )
1493
+
1494
+ 10.times do |n|
1495
+ @model.create(:name => "#{@model} #{n}")
1496
+ end
1497
+ end
1498
+
1499
+ subject { @query.send(method, @other) }
1500
+
1501
+ describe 'with other matching everything' do
1502
+ before do
1503
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1504
+ @other = DataMapper::Query.new(@repository, @model)
1505
+
1506
+ @expected = DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
1507
+ end
1508
+
1509
+ it { should be_kind_of(DataMapper::Query) }
1510
+
1511
+ it { should_not equal(@query) }
1512
+
1513
+ it { should_not equal(@other) }
1514
+
1515
+ it 'should factor out the operation matching everything' do
1516
+ subject.conditions.should == @expected
1517
+ end
1518
+ end
1519
+
1520
+ describe 'with self matching everything' do
1521
+ before do
1522
+ @query = DataMapper::Query.new(@repository, @model)
1523
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1524
+
1525
+ @expected = DataMapper::Query::Conditions::Operation.new(:not,
1526
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
1527
+ )
1528
+ end
1529
+
1530
+ it { should be_kind_of(DataMapper::Query) }
1531
+
1532
+ it { should_not equal(@query) }
1533
+
1534
+ it { should_not equal(@other) }
1535
+
1536
+ it 'should factor out the operation matching everything, and negate the other' do
1537
+ subject.conditions.should == @expected
1538
+ end
1539
+ end
1540
+
1541
+ describe 'with self having a limit' do
1542
+ before do
1543
+ @query = DataMapper::Query.new(@repository, @model, :limit => 5)
1544
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1545
+
1546
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
1547
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
1548
+ DataMapper::Query::Conditions::Operation.new(:not,
1549
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
1550
+ )
1551
+ )
1552
+ end
1553
+
1554
+ it { should_not equal(@query) }
1555
+
1556
+ it { should_not equal(@other) }
1557
+
1558
+ it 'should put each query into a subquery and AND them together, and negate the other' do
1559
+ subject.conditions.should == @expected
1560
+ end
1561
+ end
1562
+
1563
+ describe 'with other having a limit' do
1564
+ before do
1565
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1566
+ @other = DataMapper::Query.new(@repository, @model, :limit => 5)
1567
+
1568
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
1569
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
1570
+ DataMapper::Query::Conditions::Operation.new(:not,
1571
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
1572
+ )
1573
+ )
1574
+ end
1575
+
1576
+ it { should_not equal(@query) }
1577
+
1578
+ it { should_not equal(@other) }
1579
+
1580
+ it 'should put each query into a subquery and AND them together, and negate the other' do
1581
+ subject.conditions.should == @expected
1582
+ end
1583
+ end
1584
+
1585
+ describe 'with self having an offset > 0' do
1586
+ before do
1587
+ @query = DataMapper::Query.new(@repository, @model, :offset => 5, :limit => 5)
1588
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1589
+
1590
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
1591
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
1592
+ DataMapper::Query::Conditions::Operation.new(:not,
1593
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
1594
+ )
1595
+ )
1596
+ end
1597
+
1598
+ it { should_not equal(@query) }
1599
+
1600
+ it { should_not equal(@other) }
1601
+
1602
+ it 'should put each query into a subquery and AND them together, and negate the other' do
1603
+ subject.conditions.should == @expected
1604
+ end
1605
+ end
1606
+
1607
+ describe 'with other having an offset > 0' do
1608
+ before do
1609
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1610
+ @other = DataMapper::Query.new(@repository, @model, :offset => 5, :limit => 5)
1611
+
1612
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
1613
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
1614
+ DataMapper::Query::Conditions::Operation.new(:not,
1615
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
1616
+ )
1617
+ )
1618
+ end
1619
+
1620
+ it { should_not equal(@query) }
1621
+
1622
+ it { should_not equal(@other) }
1623
+
1624
+ it 'should put each query into a subquery and AND them together, and negate the other' do
1625
+ subject.conditions.should == @expected
1626
+ end
1627
+ end
1628
+
1629
+ describe 'with self having links' do
1630
+ before :all do
1631
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
1632
+ end
1633
+
1634
+ before do
1635
+ @query = DataMapper::Query.new(@repository, @model, :links => [ :referrer ])
1636
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1637
+
1638
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
1639
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
1640
+ DataMapper::Query::Conditions::Operation.new(:not,
1641
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
1642
+ )
1643
+ )
1644
+ end
1645
+
1646
+ it { should_not equal(@query) }
1647
+
1648
+ it { should_not equal(@other) }
1649
+
1650
+ it 'should put each query into a subquery and AND them together, and negate the other query' do
1651
+ subject.conditions.should == @expected
1652
+ end
1653
+ end
1654
+
1655
+ describe 'with other having links' do
1656
+ before :all do
1657
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
1658
+ end
1659
+
1660
+ before do
1661
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
1662
+ @other = DataMapper::Query.new(@repository, @model, :links => [ :referrer ])
1663
+
1664
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
1665
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
1666
+ DataMapper::Query::Conditions::Operation.new(:not,
1667
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
1668
+ )
1669
+ )
1670
+ end
1671
+
1672
+ it { should_not equal(@query) }
1673
+
1674
+ it { should_not equal(@other) }
1675
+
1676
+ it 'should put each query into a subquery and AND them together, and negate the other query' do
1677
+ subject.conditions.should == @expected
1678
+ end
1679
+ end
1680
+
1681
+ describe 'with different conditions, no links/offset/limit' do
1682
+ before do
1683
+ property = @model.properties[:name]
1684
+
1685
+ @query = DataMapper::Query.new(@repository, @model, property.name => 'Dan Kubb')
1686
+ @other = DataMapper::Query.new(@repository, @model, property.name => 'John Doe')
1687
+
1688
+ @query.conditions.should_not == @other.conditions
1689
+
1690
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
1691
+ DataMapper::Query::Conditions::Comparison.new(:eql, property, 'Dan Kubb'),
1692
+ DataMapper::Query::Conditions::Operation.new(:not,
1693
+ DataMapper::Query::Conditions::Comparison.new(:eql, property, 'John Doe')
1694
+ )
1695
+ )
1696
+ end
1697
+
1698
+ it { should be_kind_of(DataMapper::Query) }
1699
+
1700
+ it { should_not equal(@query) }
1701
+
1702
+ it { should_not equal(@other) }
1703
+
1704
+ it 'should AND the conditions together, and negate the other query' do
1705
+ subject.conditions.should == @expected
1706
+ end
1707
+ end
1708
+
1709
+ describe 'with different fields' do
1710
+ before do
1711
+ @property = @model.properties[:name]
1712
+
1713
+ @query = DataMapper::Query.new(@repository, @model)
1714
+ @other = DataMapper::Query.new(@repository, @model, :fields => [ @property ])
1715
+
1716
+ @query.fields.should_not == @other.fields
1717
+ end
1718
+
1719
+ it { should be_kind_of(DataMapper::Query) }
1720
+
1721
+ it { should_not equal(@query) }
1722
+
1723
+ it { should_not equal(@other) }
1724
+
1725
+ it { subject.conditions.should == DataMapper::Query::Conditions::Operation.new(:and) }
1726
+
1727
+ it 'should use the other fields' do
1728
+ subject.fields.should == [ @property ]
1729
+ end
1730
+ end
1731
+
1732
+ describe 'with different order' do
1733
+ before do
1734
+ @property = @model.properties[:name]
1735
+
1736
+ @query = DataMapper::Query.new(@repository, @model)
1737
+ @other = DataMapper::Query.new(@repository, @model, :order => [ DataMapper::Query::Direction.new(@property, :desc) ])
1738
+
1739
+ @query.order.should_not == @other.order
1740
+ end
1741
+
1742
+ it { should be_kind_of(DataMapper::Query) }
1743
+
1744
+ it { should_not equal(@query) }
1745
+
1746
+ it { should_not equal(@other) }
1747
+
1748
+ it { subject.conditions.should == DataMapper::Query::Conditions::Operation.new(:and) }
1749
+
1750
+ it 'should use the other order' do
1751
+ subject.order.should == [ DataMapper::Query::Direction.new(@property, :desc) ]
1752
+ end
1753
+ end
1754
+
1755
+ describe 'with different unique' do
1756
+ before do
1757
+ @query = DataMapper::Query.new(@repository, @model)
1758
+ @other = DataMapper::Query.new(@repository, @model, :unique => true)
1759
+
1760
+ @query.unique?.should_not == @other.unique?
1761
+ end
1762
+
1763
+ it { should be_kind_of(DataMapper::Query) }
1764
+
1765
+ it { should_not equal(@query) }
1766
+
1767
+ it { should_not equal(@other) }
1768
+
1769
+ it { subject.conditions.should == DataMapper::Query::Conditions::Operation.new(:and) }
1770
+
1771
+ it 'should use the other unique' do
1772
+ subject.unique?.should == true
1773
+ end
1774
+ end
1775
+
1776
+ describe 'with different add_reversed' do
1777
+ before do
1778
+ @query = DataMapper::Query.new(@repository, @model)
1779
+ @other = DataMapper::Query.new(@repository, @model, :add_reversed => true)
1780
+
1781
+ @query.add_reversed?.should_not == @other.add_reversed?
1782
+ end
1783
+
1784
+ it { should be_kind_of(DataMapper::Query) }
1785
+
1786
+ it { should_not equal(@query) }
1787
+
1788
+ it { should_not equal(@other) }
1789
+
1790
+ it { subject.conditions.should == DataMapper::Query::Conditions::Operation.new(:and) }
1791
+
1792
+ it 'should use the other add_reversed' do
1793
+ subject.add_reversed?.should == true
1794
+ end
1795
+ end
1796
+
1797
+ describe 'with different reload' do
1798
+ before do
1799
+ @query = DataMapper::Query.new(@repository, @model)
1800
+ @other = DataMapper::Query.new(@repository, @model, :reload => true)
1801
+
1802
+ @query.reload?.should_not == @other.reload?
1803
+ end
1804
+
1805
+ it { should be_kind_of(DataMapper::Query) }
1806
+
1807
+ it { should_not equal(@query) }
1808
+
1809
+ it { should_not equal(@other) }
1810
+
1811
+ it { subject.conditions.should == DataMapper::Query::Conditions::Operation.new(:and) }
1812
+
1813
+ it 'should use the other reload' do
1814
+ subject.reload?.should == true
1815
+ end
1816
+ end
1817
+
1818
+ describe 'with different models' do
1819
+ before { @other = DataMapper::Query.new(@repository, Other) }
1820
+
1821
+ it { method(:subject).should raise_error(ArgumentError) }
1822
+ end
1823
+ end
1824
+ end
1825
+ end
1826
+
1827
+ it { should respond_to(:dup) }
1828
+
1829
+ describe '#dup' do
1830
+ before :all do
1831
+ @new = @query.dup
1832
+ end
1833
+
1834
+ it 'should return a Query' do
1835
+ @new.should be_kind_of(DataMapper::Query)
1836
+ end
1837
+
1838
+ it 'should not equal query' do
1839
+ @new.should_not equal(@query)
1840
+ end
1841
+
1842
+ it 'should eql query' do
1843
+ @new.should eql(@query)
1844
+ end
1845
+
1846
+ it 'should == query' do
1847
+ @new.should == @query
1848
+ end
1849
+ end
1850
+
1851
+ it { should respond_to(:eql?) }
1852
+
1853
+ describe '#eql?' do
1854
+ describe 'when other is equal' do
1855
+ before :all do
1856
+ @return = @query.eql?(@query)
1857
+ end
1858
+
1859
+ it { @return.should be(true) }
1860
+ end
1861
+
1862
+ describe 'when other is eql' do
1863
+ before :all do
1864
+ @return = @query.eql?(@query.dup)
1865
+ end
1866
+
1867
+ it { @return.should be(true) }
1868
+ end
1869
+
1870
+ DataMapper::Query::OPTIONS.each do |name|
1871
+ describe "when other has an not eql #{name}" do
1872
+ before :all do
1873
+ @return = @query.eql?(@query.merge(name => @other_options[name]))
1874
+ end
1875
+
1876
+ it { @return.should be(false) }
1877
+ end
1878
+ end
1879
+
1880
+ describe 'when other is a different type of object' do
1881
+ before :all do
1882
+ @other = OpenStruct.new(
1883
+ :repository => @query.repository,
1884
+ :model => @query.model,
1885
+ :sorted_fields => @query.sorted_fields,
1886
+ :links => @query.links,
1887
+ :conditions => @query.conditions,
1888
+ :order => @query.order,
1889
+ :limit => @query.limit,
1890
+ :offset => @query.offset,
1891
+ :reload? => @query.reload?,
1892
+ :unique? => @query.unique?,
1893
+ :add_reversed? => @query.add_reversed?
1894
+ )
1895
+
1896
+ @return = @query.eql?(@other)
1897
+ end
1898
+
1899
+ it { @return.should be(false) }
1900
+ end
1901
+ end
1902
+
1903
+ it { should respond_to(:fields) }
1904
+
1905
+ describe '#fields' do
1906
+ before :all do
1907
+ @return = @query.fields
1908
+ end
1909
+
1910
+ it { @return.should be_kind_of(Array) }
1911
+
1912
+ it 'should return expected value' do
1913
+ @return.should == [ @model.properties[:name], @model.properties[:citizenship], @model.properties[:referrer_name] ]
1914
+ end
1915
+ end
1916
+
1917
+ it { should respond_to(:filter_records) }
1918
+
1919
+ describe '#filter_records' do
1920
+ supported_by :all do
1921
+ before :all do
1922
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
1923
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
1924
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
1925
+
1926
+ @records = [ @john, @sam, @dan ]
1927
+
1928
+ @query.update(:name.not => @sam['name'])
1929
+
1930
+ @return = @query.filter_records(@records)
1931
+ end
1932
+
1933
+ it 'should return Enumerable' do
1934
+ @return.should be_kind_of(Enumerable)
1935
+ end
1936
+
1937
+ it 'should not be the records provided' do
1938
+ @return.should_not equal(@records)
1939
+ end
1940
+
1941
+ it 'should return expected values' do
1942
+ @return.should == [ @dan, @john ]
1943
+ end
1944
+ end
1945
+ end
1946
+
1947
+ it { should respond_to(:inspect) }
1948
+
1949
+ describe '#inspect' do
1950
+ before :all do
1951
+ @return = @query.inspect
1952
+ end
1953
+
1954
+ it 'should return expected value' do
1955
+ @return.should == DataMapper::Ext::String.compress_lines(<<-INSPECT)
1956
+ #<DataMapper::Query
1957
+ @repository=:default
1958
+ @model=User
1959
+ @fields=[#<DataMapper::Property::String @model=User @name=:name>, #<DataMapper::Property::String @model=User @name=:citizenship>, #<DataMapper::Property::String @model=User @name=:referrer_name>]
1960
+ @links=[]
1961
+ @conditions=nil
1962
+ @order=[#<DataMapper::Query::Direction @target=#<DataMapper::Property::String @model=User @name=:name> @operator=:asc>]
1963
+ @limit=3
1964
+ @offset=0
1965
+ @reload=false
1966
+ @unique=false>
1967
+ INSPECT
1968
+ end
1969
+ end
1970
+
1971
+ [ :intersection, :& ].each do |method|
1972
+ it { should respond_to(method) }
1973
+
1974
+ describe "##{method}" do
1975
+ supported_by :all do
1976
+ before :all do
1977
+ @key = @model.key(@repository.name)
1978
+
1979
+ @self_relationship = DataMapper::Associations::OneToMany::Relationship.new(
1980
+ :self,
1981
+ @model,
1982
+ @model,
1983
+ {
1984
+ :child_key => @key.map { |p| p.name },
1985
+ :parent_key => @key.map { |p| p.name },
1986
+ :child_repository_name => @repository.name,
1987
+ :parent_repository_name => @repository.name,
1988
+ }
1989
+ )
1990
+
1991
+ 10.times do |n|
1992
+ @model.create(:name => "#{@model} #{n}")
1993
+ end
1994
+ end
1995
+
1996
+ subject do
1997
+ result = @query.send(method, @other)
1998
+
1999
+ if @another
2000
+ result = result.send(method, @another)
2001
+ end
2002
+
2003
+ result
2004
+ end
2005
+
2006
+ describe 'with equivalent query' do
2007
+ before { @other = @query.dup }
2008
+
2009
+ it { should be_kind_of(DataMapper::Query) }
2010
+
2011
+ it { should_not equal(@query) }
2012
+
2013
+ it { should_not equal(@other) }
2014
+
2015
+ it { should == @query }
2016
+ end
2017
+
2018
+ describe 'with other matching everything' do
2019
+ before do
2020
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2021
+ @other = DataMapper::Query.new(@repository, @model)
2022
+ end
2023
+
2024
+ it { should be_kind_of(DataMapper::Query) }
2025
+
2026
+ it { should_not equal(@query) }
2027
+
2028
+ it { should_not equal(@other) }
2029
+
2030
+ it 'should factor out the operation matching everything' do
2031
+ pending 'TODO: compress Query#conditions for proper comparison' do
2032
+ should == DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2033
+ end
2034
+ end
2035
+ end
2036
+
2037
+ describe 'with self matching everything' do
2038
+ before do
2039
+ @query = DataMapper::Query.new(@repository, @model)
2040
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2041
+ @another = DataMapper::Query.new(@repository, @model, :citizenship => 'US')
2042
+ end
2043
+
2044
+ it { should be_kind_of(DataMapper::Query) }
2045
+
2046
+ it { should_not equal(@query) }
2047
+
2048
+ it { should_not equal(@other) }
2049
+
2050
+ it { should_not equal(@another) }
2051
+
2052
+ it 'should factor out the operation matching everything' do
2053
+ should == DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb', :citizenship => 'US')
2054
+ end
2055
+ end
2056
+
2057
+ describe 'with self having a limit' do
2058
+ before do
2059
+ @query = DataMapper::Query.new(@repository, @model, :limit => 5)
2060
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2061
+
2062
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
2063
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
2064
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
2065
+ )
2066
+ end
2067
+
2068
+ it { should_not equal(@query) }
2069
+
2070
+ it { should_not equal(@other) }
2071
+
2072
+ it 'should put each query into a subquery and AND them together' do
2073
+ subject.conditions.should == @expected
2074
+ end
2075
+ end
2076
+
2077
+ describe 'with other having a limit' do
2078
+ before do
2079
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2080
+ @other = DataMapper::Query.new(@repository, @model, :limit => 5)
2081
+
2082
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
2083
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
2084
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
2085
+ )
2086
+ end
2087
+
2088
+ it { should_not equal(@query) }
2089
+
2090
+ it { should_not equal(@other) }
2091
+
2092
+ it 'should put each query into a subquery and AND them together' do
2093
+ subject.conditions.should == @expected
2094
+ end
2095
+ end
2096
+
2097
+ describe 'with self having an offset > 0' do
2098
+ before do
2099
+ @query = DataMapper::Query.new(@repository, @model, :offset => 5, :limit => 5)
2100
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2101
+
2102
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
2103
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
2104
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
2105
+ )
2106
+ end
2107
+
2108
+ it { should_not equal(@query) }
2109
+
2110
+ it { should_not equal(@other) }
2111
+
2112
+ it 'should put each query into a subquery and AND them together' do
2113
+ subject.conditions.should == @expected
2114
+ end
2115
+ end
2116
+
2117
+ describe 'with other having an offset > 0' do
2118
+ before do
2119
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2120
+ @other = DataMapper::Query.new(@repository, @model, :offset => 5, :limit => 5)
2121
+
2122
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
2123
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
2124
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
2125
+ )
2126
+ end
2127
+
2128
+ it { should_not equal(@query) }
2129
+
2130
+ it { should_not equal(@other) }
2131
+
2132
+ it 'should put each query into a subquery and AND them together' do
2133
+ subject.conditions.should == @expected
2134
+ end
2135
+ end
2136
+
2137
+ describe 'with self having links' do
2138
+ before :all do
2139
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
2140
+ end
2141
+
2142
+ before do
2143
+ @query = DataMapper::Query.new(@repository, @model, :links => [ :referrer ])
2144
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2145
+
2146
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
2147
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
2148
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
2149
+ )
2150
+ end
2151
+
2152
+ it { should_not equal(@query) }
2153
+
2154
+ it { should_not equal(@other) }
2155
+
2156
+ it 'should put each query into a subquery and AND them together' do
2157
+ subject.conditions.should == @expected
2158
+ end
2159
+ end
2160
+
2161
+ describe 'with other having links' do
2162
+ before :all do
2163
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
2164
+ end
2165
+
2166
+ before do
2167
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
2168
+ @other = DataMapper::Query.new(@repository, @model, :links => [ :referrer ])
2169
+
2170
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
2171
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
2172
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
2173
+ )
2174
+ end
2175
+
2176
+ it { should_not equal(@query) }
2177
+
2178
+ it { should_not equal(@other) }
2179
+
2180
+ it 'should put each query into a subquery and AND them together' do
2181
+ subject.conditions.should == @expected
2182
+ end
2183
+ end
2184
+
2185
+ describe 'with different conditions, no links/offset/limit' do
2186
+ before do
2187
+ property = @model.properties[:name]
2188
+
2189
+ @query = DataMapper::Query.new(@repository, @model, property.name => 'Dan Kubb')
2190
+ @other = DataMapper::Query.new(@repository, @model, property.name => 'John Doe')
2191
+
2192
+ @query.conditions.should_not == @other.conditions
2193
+
2194
+ @expected = DataMapper::Query::Conditions::Operation.new(:and,
2195
+ DataMapper::Query::Conditions::Comparison.new(:eql, property, 'Dan Kubb'),
2196
+ DataMapper::Query::Conditions::Comparison.new(:eql, property, 'John Doe')
2197
+ )
2198
+ end
2199
+
2200
+ it { should be_kind_of(DataMapper::Query) }
2201
+
2202
+ it { should_not equal(@query) }
2203
+
2204
+ it { should_not equal(@other) }
2205
+
2206
+ it 'should AND the conditions together' do
2207
+ subject.conditions.should == @expected
2208
+ end
2209
+ end
2210
+
2211
+ describe 'with different fields' do
2212
+ before do
2213
+ @property = @model.properties[:name]
2214
+
2215
+ @query = DataMapper::Query.new(@repository, @model)
2216
+ @other = DataMapper::Query.new(@repository, @model, :fields => [ @property ])
2217
+
2218
+ @query.fields.should_not == @other.fields
2219
+ end
2220
+
2221
+ it { should be_kind_of(DataMapper::Query) }
2222
+
2223
+ it { should_not equal(@query) }
2224
+
2225
+ it { should_not equal(@other) }
2226
+
2227
+ it { subject.conditions.should be_nil }
2228
+
2229
+ it 'should use the other fields' do
2230
+ subject.fields.should == [ @property ]
2231
+ end
2232
+ end
2233
+
2234
+ describe 'with different order' do
2235
+ before do
2236
+ @property = @model.properties[:name]
2237
+
2238
+ @query = DataMapper::Query.new(@repository, @model)
2239
+ @other = DataMapper::Query.new(@repository, @model, :order => [ DataMapper::Query::Direction.new(@property, :desc) ])
2240
+
2241
+ @query.order.should_not == @other.order
2242
+ end
2243
+
2244
+ it { should be_kind_of(DataMapper::Query) }
2245
+
2246
+ it { should_not equal(@query) }
2247
+
2248
+ it { should_not equal(@other) }
2249
+
2250
+ it { subject.conditions.should be_nil }
2251
+
2252
+ it 'should use the other order' do
2253
+ subject.order.should == [ DataMapper::Query::Direction.new(@property, :desc) ]
2254
+ end
2255
+ end
2256
+
2257
+ describe 'with different unique' do
2258
+ before do
2259
+ @query = DataMapper::Query.new(@repository, @model)
2260
+ @other = DataMapper::Query.new(@repository, @model, :unique => true)
2261
+
2262
+ @query.unique?.should_not == @other.unique?
2263
+ end
2264
+
2265
+ it { should be_kind_of(DataMapper::Query) }
2266
+
2267
+ it { should_not equal(@query) }
2268
+
2269
+ it { should_not equal(@other) }
2270
+
2271
+ it { subject.conditions.should be_nil }
2272
+
2273
+ it 'should use the other unique' do
2274
+ subject.unique?.should == true
2275
+ end
2276
+ end
2277
+
2278
+ describe 'with different add_reversed' do
2279
+ before do
2280
+ @query = DataMapper::Query.new(@repository, @model)
2281
+ @other = DataMapper::Query.new(@repository, @model, :add_reversed => true)
2282
+
2283
+ @query.add_reversed?.should_not == @other.add_reversed?
2284
+ end
2285
+
2286
+ it { should be_kind_of(DataMapper::Query) }
2287
+
2288
+ it { should_not equal(@query) }
2289
+
2290
+ it { should_not equal(@other) }
2291
+
2292
+ it { subject.conditions.should be_nil }
2293
+
2294
+ it 'should use the other add_reversed' do
2295
+ subject.add_reversed?.should == true
2296
+ end
2297
+ end
2298
+
2299
+ describe 'with different reload' do
2300
+ before do
2301
+ @query = DataMapper::Query.new(@repository, @model)
2302
+ @other = DataMapper::Query.new(@repository, @model, :reload => true)
2303
+
2304
+ @query.reload?.should_not == @other.reload?
2305
+ end
2306
+
2307
+ it { should be_kind_of(DataMapper::Query) }
2308
+
2309
+ it { should_not equal(@query) }
2310
+
2311
+ it { should_not equal(@other) }
2312
+
2313
+ it 'should use the other reload' do
2314
+ subject.reload?.should == true
2315
+ end
2316
+ end
2317
+
2318
+ describe 'with different models' do
2319
+ before { @other = DataMapper::Query.new(@repository, Other) }
2320
+
2321
+ it { method(:subject).should raise_error(ArgumentError) }
2322
+ end
2323
+ end
2324
+ end
2325
+ end
2326
+
2327
+ it { should respond_to(:limit) }
2328
+
2329
+ describe '#limit' do
2330
+ before :all do
2331
+ @return = @query.limit
2332
+ end
2333
+
2334
+ it { @return.should be_kind_of(Integer) }
2335
+
2336
+ it 'should return expected value' do
2337
+ @return.should == 3
2338
+ end
2339
+ end
2340
+
2341
+ it { should respond_to(:limit_records) }
2342
+
2343
+ describe '#limit_records' do
2344
+ supported_by :all do
2345
+ before :all do
2346
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
2347
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
2348
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
2349
+
2350
+ @records = [ @john, @sam, @dan ]
2351
+
2352
+ @query.update(:limit => 1, :offset => 1)
2353
+
2354
+ @return = @query.limit_records(@records)
2355
+ end
2356
+
2357
+ it 'should return Enumerable' do
2358
+ @return.should be_kind_of(Enumerable)
2359
+ end
2360
+
2361
+ it 'should not be the records provided' do
2362
+ @return.should_not equal(@records)
2363
+ end
2364
+
2365
+ it 'should return expected values' do
2366
+ @return.should == [ @sam ]
2367
+ end
2368
+ end
2369
+ end
2370
+
2371
+ it { should respond_to(:links) }
2372
+
2373
+ describe '#links' do
2374
+ before :all do
2375
+ @return = @query.links
2376
+ end
2377
+
2378
+ it { @return.should be_kind_of(Array) }
2379
+
2380
+ it { @return.should be_empty }
2381
+ end
2382
+
2383
+ it { should respond_to(:match_records) }
2384
+
2385
+ describe '#match_records' do
2386
+ supported_by :all do
2387
+ before :all do
2388
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
2389
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
2390
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
2391
+
2392
+ @records = [ @john, @sam, @dan ]
2393
+
2394
+ @query.update(:name.not => @sam['name'])
2395
+
2396
+ @return = @query.match_records(@records)
2397
+ end
2398
+
2399
+ it 'should return Enumerable' do
2400
+ @return.should be_kind_of(Enumerable)
2401
+ end
2402
+
2403
+ it 'should not be the records provided' do
2404
+ @return.should_not equal(@records)
2405
+ end
2406
+
2407
+ it 'should return expected values' do
2408
+ @return.should == [ @john, @dan ]
2409
+ end
2410
+ end
2411
+ end
2412
+
2413
+ it { should respond_to(:merge) }
2414
+
2415
+ describe '#merge' do
2416
+ describe 'with a Hash' do
2417
+ before do
2418
+ @return = @query.merge({ :limit => 202 })
2419
+ end
2420
+
2421
+ it 'does not affect the receiver' do
2422
+ @query.options[:limit].should == 3
2423
+ end
2424
+ end
2425
+
2426
+ describe 'with a Query' do
2427
+ before do
2428
+ @other = DataMapper::Query.new(@repository, @model, @options.update(@other_options))
2429
+ @return = @query.merge(@other)
2430
+ end
2431
+
2432
+ it 'does not affect the receiver' do
2433
+ @query.options[:limit].should == 3
2434
+ end
2435
+ end
2436
+ end
2437
+
2438
+ it { should respond_to(:model) }
2439
+
2440
+ describe '#model' do
2441
+ before :all do
2442
+ @return = @query.model
2443
+ end
2444
+
2445
+ it { @return.should be_kind_of(Class) }
2446
+
2447
+ it 'should return expected value' do
2448
+ @return.should == @model
2449
+ end
2450
+ end
2451
+
2452
+ it { should respond_to(:offset) }
2453
+
2454
+ describe '#offset' do
2455
+ before :all do
2456
+ @return = @query.offset
2457
+ end
2458
+
2459
+ it { @return.should be_kind_of(Integer) }
2460
+
2461
+ it 'should return expected value' do
2462
+ @return.should == 0
2463
+ end
2464
+ end
2465
+
2466
+ it { should respond_to(:order) }
2467
+
2468
+ describe '#order' do
2469
+ before :all do
2470
+ @return = @query.order
2471
+ end
2472
+
2473
+ it { @return.should be_kind_of(Array) }
2474
+
2475
+ it 'should return expected value' do
2476
+ @return.should == [ DataMapper::Query::Direction.new(@model.properties[:name]) ]
2477
+ end
2478
+ end
2479
+
2480
+ it { should respond_to(:raw?) }
2481
+
2482
+ describe '#raw?' do
2483
+ describe 'when the query contains raw conditions' do
2484
+ before :all do
2485
+ @query.update(:conditions => [ 'name = ?', 'Dan Kubb' ])
2486
+ end
2487
+
2488
+ it { should be_raw }
2489
+ end
2490
+
2491
+ describe 'when the query does not contain raw conditions' do
2492
+ it { should_not be_raw }
2493
+ end
2494
+ end
2495
+
2496
+ it { should respond_to(:relative) }
2497
+
2498
+ describe '#relative' do
2499
+ describe 'with a Hash' do
2500
+ describe 'that is empty' do
2501
+ before :all do
2502
+ @return = @query.relative({})
2503
+ end
2504
+
2505
+ it { @return.should be_kind_of(DataMapper::Query) }
2506
+
2507
+ it 'should not return self' do
2508
+ @return.should_not equal(@query)
2509
+ end
2510
+
2511
+ it 'should return a copy' do
2512
+ @return.should be_eql(@query)
2513
+ end
2514
+ end
2515
+
2516
+ describe 'using different options' do
2517
+ before :all do
2518
+ @return = @query.relative(@other_options)
2519
+ end
2520
+
2521
+ it { @return.should be_kind_of(DataMapper::Query) }
2522
+
2523
+ it 'should not return self' do
2524
+ @return.should_not equal(@original)
2525
+ end
2526
+
2527
+ it 'should update the fields' do
2528
+ @return.fields.should == @other_options[:fields]
2529
+ end
2530
+
2531
+ it 'should update the links' do
2532
+ @return.links.should == @other_options[:links]
2533
+ end
2534
+
2535
+ it 'should update the conditions' do
2536
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
2537
+ end
2538
+
2539
+ it 'should update the offset' do
2540
+ @return.offset.should == @other_options[:offset]
2541
+ end
2542
+
2543
+ it 'should update the limit' do
2544
+ @return.limit.should == @other_options[:limit]
2545
+ end
2546
+
2547
+ it 'should update the order' do
2548
+ @return.order.should == @other_options[:order]
2549
+ end
2550
+
2551
+ it 'should update the unique' do
2552
+ @return.unique?.should == @other_options[:unique]
2553
+ end
2554
+
2555
+ it 'should update the add_reversed' do
2556
+ @return.add_reversed?.should == @other_options[:add_reversed]
2557
+ end
2558
+
2559
+ it 'should update the reload' do
2560
+ @return.reload?.should == @other_options[:reload]
2561
+ end
2562
+ end
2563
+
2564
+ describe 'using extra options' do
2565
+ before :all do
2566
+ @options = { :name => 'Dan Kubb' }
2567
+
2568
+ @return = @query.relative(@options)
2569
+ end
2570
+
2571
+ it { @return.should be_kind_of(DataMapper::Query) }
2572
+
2573
+ it 'should not return self' do
2574
+ @return.should_not equal(@original)
2575
+ end
2576
+
2577
+ it 'should update the conditions' do
2578
+ @return.conditions.should ==
2579
+ DataMapper::Query::Conditions::Operation.new(
2580
+ :and,
2581
+ DataMapper::Query::Conditions::Comparison.new(
2582
+ :eql,
2583
+ @model.properties[:name],
2584
+ @options[:name]
2585
+ )
2586
+ )
2587
+ end
2588
+ end
2589
+
2590
+ describe 'using an offset when query offset is greater than 0' do
2591
+ before :all do
2592
+ @query = @query.update(:offset => 1, :limit => 2)
2593
+
2594
+ @return = @query.relative(:offset => 1)
2595
+ end
2596
+
2597
+ it { @return.should be_kind_of(DataMapper::Query) }
2598
+
2599
+ it 'should not return self' do
2600
+ @return.should_not equal(@original)
2601
+ end
2602
+
2603
+ it 'should update the offset to be relative to the original offset' do
2604
+ @return.offset.should == 2
2605
+ end
2606
+ end
2607
+
2608
+ describe 'using an limit when query limit specified' do
2609
+ before :all do
2610
+ @query = @query.update(:offset => 1, :limit => 2)
2611
+
2612
+ @return = @query.relative(:limit => 1)
2613
+ end
2614
+
2615
+ it { @return.should be_kind_of(DataMapper::Query) }
2616
+
2617
+ it 'should not return self' do
2618
+ @return.should_not equal(@original)
2619
+ end
2620
+
2621
+ it 'should update the limit' do
2622
+ @return.limit.should == 1
2623
+ end
2624
+ end
2625
+ end
2626
+ end
2627
+
2628
+ it { should respond_to(:reload?) }
2629
+
2630
+ describe '#reload?' do
2631
+ describe 'when the query should reload' do
2632
+ before :all do
2633
+ @query.update(:reload => true)
2634
+ end
2635
+
2636
+ it { should be_reload }
2637
+ end
2638
+
2639
+ describe 'when the query should not reload' do
2640
+ it { should_not be_reload }
2641
+ end
2642
+ end
2643
+
2644
+ it { should respond_to(:repository) }
2645
+
2646
+ describe '#repository' do
2647
+ before :all do
2648
+ @return = @query.repository
2649
+ end
2650
+
2651
+ it { @return.should be_kind_of(DataMapper::Repository) }
2652
+
2653
+ it 'should return expected value' do
2654
+ @return.should == @repository
2655
+ end
2656
+ end
2657
+
2658
+ it { should respond_to(:reverse) }
2659
+
2660
+ describe '#reverse' do
2661
+ before :all do
2662
+ @return = @query.reverse
2663
+ end
2664
+
2665
+ it { @return.should be_kind_of(DataMapper::Query) }
2666
+
2667
+ it 'should copy the Query' do
2668
+ @return.should_not equal(@original)
2669
+ end
2670
+
2671
+ # TODO: push this into dup spec
2672
+ it 'should not reference original order' do
2673
+ @return.order.should_not equal(@original.order)
2674
+ end
2675
+
2676
+ it 'should have a reversed order' do
2677
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :desc) ]
2678
+ end
2679
+
2680
+ [ :repository, :model, :fields, :links, :conditions, :offset, :limit, :unique?, :add_reversed?, :reload? ].each do |attribute|
2681
+ it "should have an equivalent #{attribute}" do
2682
+ @return.send(attribute).should == @original.send(attribute)
2683
+ end
2684
+ end
2685
+ end
2686
+
2687
+ it { should respond_to(:reverse!) }
2688
+
2689
+ describe '#reverse!' do
2690
+ before :all do
2691
+ @return = @query.reverse!
2692
+ end
2693
+
2694
+ it { @return.should be_kind_of(DataMapper::Query) }
2695
+
2696
+ it { @return.should equal(@original) }
2697
+
2698
+ it 'should have a reversed order' do
2699
+ @return.order.should == [ DataMapper::Query::Direction.new(@model.properties[:name], :desc) ]
2700
+ end
2701
+ end
2702
+
2703
+ [ :slice, :[] ].each do |method|
2704
+ it { should respond_to(method) }
2705
+
2706
+ describe "##{method}" do
2707
+ describe 'with a positive offset' do
2708
+ before :all do
2709
+ @query = @query.update(:offset => 1, :limit => 2)
2710
+
2711
+ @return = @query.send(method, 1)
2712
+ end
2713
+
2714
+ it { @return.should be_kind_of(DataMapper::Query) }
2715
+
2716
+ it 'should not return self' do
2717
+ @return.should_not equal(@original)
2718
+ end
2719
+
2720
+ it 'should update the offset to be relative to the original offset' do
2721
+ @return.offset.should == 2
2722
+ end
2723
+
2724
+ it 'should update the limit to 1' do
2725
+ @return.limit.should == 1
2726
+ end
2727
+ end
2728
+
2729
+ describe 'with a positive offset and length' do
2730
+ before :all do
2731
+ @query = @query.update(:offset => 1, :limit => 2)
2732
+
2733
+ @return = @query.send(method, 1, 1)
2734
+ end
2735
+
2736
+ it { @return.should be_kind_of(DataMapper::Query) }
2737
+
2738
+ it 'should not return self' do
2739
+ @return.should_not equal(@original)
2740
+ end
2741
+
2742
+ it 'should update the offset to be relative to the original offset' do
2743
+ @return.offset.should == 2
2744
+ end
2745
+
2746
+ it 'should update the limit' do
2747
+ @return.limit.should == 1
2748
+ end
2749
+ end
2750
+
2751
+ describe 'with a positive range' do
2752
+ before :all do
2753
+ @query = @query.update(:offset => 1, :limit => 3)
2754
+
2755
+ @return = @query.send(method, 1..2)
2756
+ end
2757
+
2758
+ it { @return.should be_kind_of(DataMapper::Query) }
2759
+
2760
+ it 'should not return self' do
2761
+ @return.should_not equal(@original)
2762
+ end
2763
+
2764
+ it 'should update the offset to be relative to the original offset' do
2765
+ @return.offset.should == 2
2766
+ end
2767
+
2768
+ it 'should update the limit' do
2769
+ @return.limit.should == 2
2770
+ end
2771
+ end
2772
+
2773
+ describe 'with a negative offset' do
2774
+ before :all do
2775
+ @query = @query.update(:offset => 1, :limit => 2)
2776
+
2777
+ @return = @query.send(method, -1)
2778
+ end
2779
+
2780
+ it { @return.should be_kind_of(DataMapper::Query) }
2781
+
2782
+ it 'should not return self' do
2783
+ @return.should_not equal(@original)
2784
+ end
2785
+
2786
+ it 'should update the offset to be relative to the original offset' do
2787
+ pending "TODO: update Query##{method} handle negative offset" do
2788
+ @return.offset.should == 2
2789
+ end
2790
+ end
2791
+
2792
+ it 'should update the limit to 1' do
2793
+ @return.limit.should == 1
2794
+ end
2795
+ end
2796
+
2797
+ describe 'with a negative offset and length' do
2798
+ before :all do
2799
+ @query = @query.update(:offset => 1, :limit => 2)
2800
+
2801
+ @return = @query.send(method, -1, 1)
2802
+ end
2803
+
2804
+ it { @return.should be_kind_of(DataMapper::Query) }
2805
+
2806
+ it 'should not return self' do
2807
+ @return.should_not equal(@original)
2808
+ end
2809
+
2810
+ it 'should update the offset to be relative to the original offset' do
2811
+ pending "TODO: update Query##{method} handle negative offset and length" do
2812
+ @return.offset.should == 2
2813
+ end
2814
+ end
2815
+
2816
+ it 'should update the limit to 1' do
2817
+ @return.limit.should == 1
2818
+ end
2819
+ end
2820
+
2821
+ describe 'with a negative range' do
2822
+ before :all do
2823
+ @query = @query.update(:offset => 1, :limit => 3)
2824
+
2825
+ rescue_if "TODO: update Query##{method} handle negative range" do
2826
+ @return = @query.send(method, -2..-1)
2827
+ end
2828
+ end
2829
+
2830
+ before do
2831
+ pending_if "TODO: update Query##{method} handle negative range", !defined?(@return)
2832
+ end
2833
+
2834
+ it { @return.should be_kind_of(DataMapper::Query) }
2835
+
2836
+ it 'should not return self' do
2837
+ @return.should_not equal(@original)
2838
+ end
2839
+
2840
+ it 'should update the offset to be relative to the original offset' do
2841
+ @return.offset.should == 2
2842
+ end
2843
+
2844
+ it 'should update the limit to 1' do
2845
+ @return.limit.should == 2
2846
+ end
2847
+ end
2848
+
2849
+ describe 'with an offset not within range' do
2850
+ before :all do
2851
+ @query = @query.update(:offset => 1, :limit => 3)
2852
+ end
2853
+
2854
+ it 'should raise an exception' do
2855
+ lambda {
2856
+ @query.send(method, 12)
2857
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2858
+ end
2859
+ end
2860
+
2861
+ describe 'with an offset and length not within range' do
2862
+ before :all do
2863
+ @query = @query.update(:offset => 1, :limit => 3)
2864
+ end
2865
+
2866
+ it 'should raise an exception' do
2867
+ lambda {
2868
+ @query.send(method, 12, 1)
2869
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2870
+ end
2871
+ end
2872
+
2873
+ describe 'with a range not within range' do
2874
+ before :all do
2875
+ @query = @query.update(:offset => 1, :limit => 3)
2876
+ end
2877
+
2878
+ it 'should raise an exception' do
2879
+ lambda {
2880
+ @query.send(method, 12..12)
2881
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
2882
+ end
2883
+ end
2884
+
2885
+ describe 'with invalid arguments' do
2886
+ it 'should raise an exception' do
2887
+ lambda {
2888
+ @query.send(method, 'invalid')
2889
+ }.should raise_error(ArgumentError, 'arguments may be 1 or 2 Integers, or 1 Range object, was: ["invalid"]')
2890
+ end
2891
+ end
2892
+ end
2893
+ end
2894
+
2895
+ it { should respond_to(:slice!) }
2896
+
2897
+ describe '#slice!' do
2898
+ describe 'with a positive offset' do
2899
+ before :all do
2900
+ @query = @query.update(:offset => 1, :limit => 2)
2901
+
2902
+ @return = @query.slice!(1)
2903
+ end
2904
+
2905
+ it { @return.should be_kind_of(DataMapper::Query) }
2906
+
2907
+ it 'should return self' do
2908
+ @return.should equal(@original)
2909
+ end
2910
+
2911
+ it 'should update the offset to be relative to the original offset' do
2912
+ @return.offset.should == 2
2913
+ end
2914
+
2915
+ it 'should update the limit to 1' do
2916
+ @return.limit.should == 1
2917
+ end
2918
+ end
2919
+
2920
+ describe 'with a positive offset and length' do
2921
+ before :all do
2922
+ @query = @query.update(:offset => 1, :limit => 2)
2923
+
2924
+ @return = @query.slice!(1, 1)
2925
+ end
2926
+
2927
+ it { @return.should be_kind_of(DataMapper::Query) }
2928
+
2929
+ it 'should return self' do
2930
+ @return.should equal(@original)
2931
+ end
2932
+
2933
+ it 'should update the offset to be relative to the original offset' do
2934
+ @return.offset.should == 2
2935
+ end
2936
+
2937
+ it 'should update the limit' do
2938
+ @return.limit.should == 1
2939
+ end
2940
+ end
2941
+
2942
+ describe 'with a positive range' do
2943
+ before :all do
2944
+ @query = @query.update(:offset => 1, :limit => 3)
2945
+
2946
+ @return = @query.slice!(1..2)
2947
+ end
2948
+
2949
+ it { @return.should be_kind_of(DataMapper::Query) }
2950
+
2951
+ it 'should return self' do
2952
+ @return.should equal(@original)
2953
+ end
2954
+
2955
+ it 'should update the offset to be relative to the original offset' do
2956
+ @return.offset.should == 2
2957
+ end
2958
+
2959
+ it 'should update the limit' do
2960
+ @return.limit.should == 2
2961
+ end
2962
+ end
2963
+
2964
+ describe 'with a negative offset' do
2965
+ before :all do
2966
+ @query = @query.update(:offset => 1, :limit => 2)
2967
+
2968
+ @return = @query.slice!(-1)
2969
+ end
2970
+
2971
+ it { @return.should be_kind_of(DataMapper::Query) }
2972
+
2973
+ it 'should return self' do
2974
+ @return.should equal(@original)
2975
+ end
2976
+
2977
+ it 'should update the offset to be relative to the original offset' do
2978
+ pending 'TODO: update Query#slice! handle negative offset' do
2979
+ @return.offset.should == 2
2980
+ end
2981
+ end
2982
+
2983
+ it 'should update the limit to 1' do
2984
+ @return.limit.should == 1
2985
+ end
2986
+ end
2987
+
2988
+ describe 'with a negative offset and length' do
2989
+ before :all do
2990
+ @query = @query.update(:offset => 1, :limit => 2)
2991
+
2992
+ @return = @query.slice!(-1, 1)
2993
+ end
2994
+
2995
+ it { @return.should be_kind_of(DataMapper::Query) }
2996
+
2997
+ it 'should return self' do
2998
+ @return.should equal(@original)
2999
+ end
3000
+
3001
+ it 'should update the offset to be relative to the original offset' do
3002
+ pending 'TODO: update Query#slice! handle negative offset and length' do
3003
+ @return.offset.should == 2
3004
+ end
3005
+ end
3006
+
3007
+ it 'should update the limit to 1' do
3008
+ @return.limit.should == 1
3009
+ end
3010
+ end
3011
+
3012
+ describe 'with a negative range' do
3013
+ before :all do
3014
+ @query = @query.update(:offset => 1, :limit => 3)
3015
+
3016
+ rescue_if 'TODO: update Query#slice! handle negative range' do
3017
+ @return = @query.slice!(-2..-1)
3018
+ end
3019
+ end
3020
+
3021
+ before do
3022
+ pending_if 'TODO: update Query#slice! handle negative range', !defined?(@return)
3023
+ end
3024
+
3025
+ it { @return.should be_kind_of(DataMapper::Query) }
3026
+
3027
+ it 'should return self' do
3028
+ @return.should equal(@original)
3029
+ end
3030
+
3031
+ it 'should update the offset to be relative to the original offset' do
3032
+ @return.offset.should == 2
3033
+ end
3034
+
3035
+ it 'should update the limit to 1' do
3036
+ @return.limit.should == 2
3037
+ end
3038
+ end
3039
+
3040
+ describe 'with an offset not within range' do
3041
+ before :all do
3042
+ @query = @query.update(:offset => 1, :limit => 3)
3043
+ end
3044
+
3045
+ it 'should raise an exception' do
3046
+ lambda {
3047
+ @query.slice!(12)
3048
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
3049
+ end
3050
+ end
3051
+
3052
+ describe 'with an offset and length not within range' do
3053
+ before :all do
3054
+ @query = @query.update(:offset => 1, :limit => 3)
3055
+ end
3056
+
3057
+ it 'should raise an exception' do
3058
+ lambda {
3059
+ @query.slice!(12, 1)
3060
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
3061
+ end
3062
+ end
3063
+
3064
+ describe 'with a range not within range' do
3065
+ before :all do
3066
+ @query = @query.update(:offset => 1, :limit => 3)
3067
+ end
3068
+
3069
+ it 'should raise an exception' do
3070
+ lambda {
3071
+ @query.slice!(12..12)
3072
+ }.should raise_error(RangeError, 'offset 12 and limit 1 are outside allowed range')
3073
+ end
3074
+ end
3075
+
3076
+ describe 'with invalid arguments' do
3077
+ it 'should raise an exception' do
3078
+ lambda {
3079
+ @query.slice!('invalid')
3080
+ }.should raise_error(ArgumentError, 'arguments may be 1 or 2 Integers, or 1 Range object, was: ["invalid"]')
3081
+ end
3082
+ end
3083
+ end
3084
+
3085
+ it { should respond_to(:sort_records) }
3086
+
3087
+ describe '#sort_records' do
3088
+ supported_by :all do
3089
+ before :all do
3090
+ @john = { 'name' => 'John Doe', 'referrer_name' => nil }
3091
+ @sam = { 'name' => 'Sam Smoot', 'referrer_name' => nil }
3092
+ @dan = { 'name' => 'Dan Kubb', 'referrer_name' => 'Sam Smoot' }
3093
+
3094
+ @records = [ @john, @sam, @dan ]
3095
+
3096
+ @query.update(:order => [ :name ])
3097
+
3098
+ @return = @query.sort_records(@records)
3099
+ end
3100
+
3101
+ it 'should return Enumerable' do
3102
+ @return.should be_kind_of(Enumerable)
3103
+ end
3104
+
3105
+ it 'should not be the records provided' do
3106
+ @return.should_not equal(@records)
3107
+ end
3108
+
3109
+ it 'should return expected values' do
3110
+ @return.should == [ @dan, @john, @sam ]
3111
+ end
3112
+ end
3113
+ end
3114
+
3115
+ [ :union, :|, :+ ].each do |method|
3116
+ it { should respond_to(method) }
3117
+
3118
+ describe "##{method}" do
3119
+ supported_by :all do
3120
+ before :all do
3121
+ @key = @model.key(@repository.name)
3122
+
3123
+ @self_relationship = DataMapper::Associations::OneToMany::Relationship.new(
3124
+ :self,
3125
+ @model,
3126
+ @model,
3127
+ {
3128
+ :child_key => @key.map { |p| p.name },
3129
+ :parent_key => @key.map { |p| p.name },
3130
+ :child_repository_name => @repository.name,
3131
+ :parent_repository_name => @repository.name,
3132
+ }
3133
+ )
3134
+
3135
+ 10.times do |n|
3136
+ @model.create(:name => "#{@model} #{n}")
3137
+ end
3138
+ end
3139
+
3140
+ subject { @query.send(method, @other) }
3141
+
3142
+ describe 'with equivalent query' do
3143
+ before { @other = @query.dup }
3144
+
3145
+ it { should be_kind_of(DataMapper::Query) }
3146
+
3147
+ it { should_not equal(@query) }
3148
+
3149
+ it { should_not equal(@other) }
3150
+
3151
+ it { should == @query }
3152
+ end
3153
+
3154
+ describe 'with other matching everything' do
3155
+ before do
3156
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3157
+ @other = DataMapper::Query.new(@repository, @model)
3158
+ end
3159
+
3160
+ it { should be_kind_of(DataMapper::Query) }
3161
+
3162
+ it { should_not equal(@query) }
3163
+
3164
+ it { should_not equal(@other) }
3165
+
3166
+ it 'should match everything' do
3167
+ should == DataMapper::Query.new(@repository, @model)
3168
+ end
3169
+ end
3170
+
3171
+ describe 'with self matching everything' do
3172
+ before do
3173
+ @query = DataMapper::Query.new(@repository, @model)
3174
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3175
+ end
3176
+
3177
+ it { should be_kind_of(DataMapper::Query) }
3178
+
3179
+ it { should_not equal(@query) }
3180
+
3181
+ it { should_not equal(@other) }
3182
+
3183
+ it 'should match everything' do
3184
+ should == DataMapper::Query.new(@repository, @model)
3185
+ end
3186
+ end
3187
+
3188
+ describe 'with self having a limit' do
3189
+ before do
3190
+ @query = DataMapper::Query.new(@repository, @model, :limit => 5)
3191
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3192
+
3193
+ @expected = DataMapper::Query::Conditions::Operation.new(:or,
3194
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
3195
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
3196
+ )
3197
+ end
3198
+
3199
+ it { should_not equal(@query) }
3200
+
3201
+ it { should_not equal(@other) }
3202
+
3203
+ it 'should put each query into a subquery and OR them together' do
3204
+ subject.conditions.should == @expected
3205
+ end
3206
+ end
3207
+
3208
+ describe 'with other having a limit' do
3209
+ before do
3210
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3211
+ @other = DataMapper::Query.new(@repository, @model, :limit => 5)
3212
+
3213
+ @expected = DataMapper::Query::Conditions::Operation.new(:or,
3214
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
3215
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
3216
+ )
3217
+ end
3218
+
3219
+ it { should_not equal(@query) }
3220
+
3221
+ it { should_not equal(@other) }
3222
+
3223
+ it 'should put each query into a subquery and OR them together' do
3224
+ subject.conditions.should == @expected
3225
+ end
3226
+ end
3227
+
3228
+ describe 'with self having an offset > 0' do
3229
+ before do
3230
+ @query = DataMapper::Query.new(@repository, @model, :offset => 5, :limit => 5)
3231
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3232
+
3233
+ @expected = DataMapper::Query::Conditions::Operation.new(:or,
3234
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
3235
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
3236
+ )
3237
+ end
3238
+
3239
+ it { should_not equal(@query) }
3240
+
3241
+ it { should_not equal(@other) }
3242
+
3243
+ it 'should put each query into a subquery and OR them together' do
3244
+ subject.conditions.should == @expected
3245
+ end
3246
+ end
3247
+
3248
+ describe 'with other having an offset > 0' do
3249
+ before do
3250
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3251
+ @other = DataMapper::Query.new(@repository, @model, :offset => 5, :limit => 5)
3252
+
3253
+ @expected = DataMapper::Query::Conditions::Operation.new(:or,
3254
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
3255
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
3256
+ )
3257
+ end
3258
+
3259
+ it { should_not equal(@query) }
3260
+
3261
+ it { should_not equal(@other) }
3262
+
3263
+ it 'should put each query into a subquery and OR them together' do
3264
+ subject.conditions.should == @expected
3265
+ end
3266
+ end
3267
+
3268
+ describe 'with self having links' do
3269
+ before :all do
3270
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
3271
+ end
3272
+
3273
+ before do
3274
+ @query = DataMapper::Query.new(@repository, @model, :links => [ :referrer ])
3275
+ @other = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3276
+
3277
+ @expected = DataMapper::Query::Conditions::Operation.new(:or,
3278
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@query.merge(:fields => @key))),
3279
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb')
3280
+ )
3281
+ end
3282
+
3283
+ it { should_not equal(@query) }
3284
+
3285
+ it { should_not equal(@other) }
3286
+
3287
+ it 'should put each query into a subquery and OR them together' do
3288
+ subject.conditions.should == @expected
3289
+ end
3290
+ end
3291
+
3292
+ describe 'with other having links' do
3293
+ before :all do
3294
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
3295
+ end
3296
+
3297
+ before do
3298
+ @query = DataMapper::Query.new(@repository, @model, :name => 'Dan Kubb')
3299
+ @other = DataMapper::Query.new(@repository, @model, :links => [ :referrer ])
3300
+
3301
+ @expected = DataMapper::Query::Conditions::Operation.new(:or,
3302
+ DataMapper::Query::Conditions::Comparison.new(:eql, @model.properties[:name], 'Dan Kubb'),
3303
+ DataMapper::Query::Conditions::Comparison.new(:in, @self_relationship, @model.all(@other.merge(:fields => @key)))
3304
+ )
3305
+ end
3306
+
3307
+ it { should_not equal(@query) }
3308
+
3309
+ it { should_not equal(@other) }
3310
+
3311
+ it 'should put each query into a subquery and OR them together' do
3312
+ subject.conditions.should == @expected
3313
+ end
3314
+ end
3315
+
3316
+ describe 'with different conditions, no links/offset/limit' do
3317
+ before do
3318
+ property = @model.properties[:name]
3319
+
3320
+ @query = DataMapper::Query.new(@repository, @model, property.name => 'Dan Kubb')
3321
+ @other = DataMapper::Query.new(@repository, @model, property.name => 'John Doe')
3322
+
3323
+ @query.conditions.should_not == @other.conditions
3324
+
3325
+ @expected = DataMapper::Query::Conditions::Operation.new(:or,
3326
+ DataMapper::Query::Conditions::Comparison.new(:eql, property, 'Dan Kubb'),
3327
+ DataMapper::Query::Conditions::Comparison.new(:eql, property, 'John Doe')
3328
+ )
3329
+ end
3330
+
3331
+ it { should be_kind_of(DataMapper::Query) }
3332
+
3333
+ it { should_not equal(@query) }
3334
+
3335
+ it { should_not equal(@other) }
3336
+
3337
+ it 'should OR the conditions together' do
3338
+ subject.conditions.should == @expected
3339
+ end
3340
+ end
3341
+
3342
+ describe 'with different fields' do
3343
+ before do
3344
+ @property = @model.properties[:name]
3345
+
3346
+ @query = DataMapper::Query.new(@repository, @model)
3347
+ @other = DataMapper::Query.new(@repository, @model, :fields => [ @property ])
3348
+
3349
+ @query.fields.should_not == @other.fields
3350
+ end
3351
+
3352
+ it { should be_kind_of(DataMapper::Query) }
3353
+
3354
+ it { should_not equal(@query) }
3355
+
3356
+ it { should_not equal(@other) }
3357
+
3358
+ it { subject.conditions.should be_nil }
3359
+
3360
+ it 'should use the other fields' do
3361
+ subject.fields.should == [ @property ]
3362
+ end
3363
+ end
3364
+
3365
+ describe 'with different order' do
3366
+ before do
3367
+ @property = @model.properties[:name]
3368
+
3369
+ @query = DataMapper::Query.new(@repository, @model)
3370
+ @other = DataMapper::Query.new(@repository, @model, :order => [ DataMapper::Query::Direction.new(@property, :desc) ])
3371
+
3372
+ @query.order.should_not == @other.order
3373
+ end
3374
+
3375
+ it { should be_kind_of(DataMapper::Query) }
3376
+
3377
+ it { should_not equal(@query) }
3378
+
3379
+ it { should_not equal(@other) }
3380
+
3381
+ it { subject.conditions.should be_nil }
3382
+
3383
+ it 'should use the other order' do
3384
+ subject.order.should == [ DataMapper::Query::Direction.new(@property, :desc) ]
3385
+ end
3386
+ end
3387
+
3388
+ describe 'with different unique' do
3389
+ before do
3390
+ @query = DataMapper::Query.new(@repository, @model)
3391
+ @other = DataMapper::Query.new(@repository, @model, :unique => true)
3392
+
3393
+ @query.unique?.should_not == @other.unique?
3394
+ end
3395
+
3396
+ it { should be_kind_of(DataMapper::Query) }
3397
+
3398
+ it { should_not equal(@query) }
3399
+
3400
+ it { should_not equal(@other) }
3401
+
3402
+ it { subject.conditions.should be_nil }
3403
+
3404
+ it 'should use the other unique' do
3405
+ subject.unique?.should == true
3406
+ end
3407
+ end
3408
+
3409
+ describe 'with different add_reversed' do
3410
+ before do
3411
+ @query = DataMapper::Query.new(@repository, @model)
3412
+ @other = DataMapper::Query.new(@repository, @model, :add_reversed => true)
3413
+
3414
+ @query.add_reversed?.should_not == @other.add_reversed?
3415
+ end
3416
+
3417
+ it { should be_kind_of(DataMapper::Query) }
3418
+
3419
+ it { should_not equal(@query) }
3420
+
3421
+ it { should_not equal(@other) }
3422
+
3423
+ it { subject.conditions.should be_nil }
3424
+
3425
+ it 'should use the other add_reversed' do
3426
+ subject.add_reversed?.should == true
3427
+ end
3428
+ end
3429
+
3430
+ describe 'with different reload' do
3431
+ before do
3432
+ @query = DataMapper::Query.new(@repository, @model)
3433
+ @other = DataMapper::Query.new(@repository, @model, :reload => true)
3434
+
3435
+ @query.reload?.should_not == @other.reload?
3436
+ end
3437
+
3438
+ it { should be_kind_of(DataMapper::Query) }
3439
+
3440
+ it { should_not equal(@query) }
3441
+
3442
+ it { should_not equal(@other) }
3443
+
3444
+ it { subject.conditions.should be_nil }
3445
+
3446
+ it 'should use the other reload' do
3447
+ subject.reload?.should == true
3448
+ end
3449
+ end
3450
+
3451
+ describe 'with different models' do
3452
+ before { @other = DataMapper::Query.new(@repository, Other) }
3453
+
3454
+ it { method(:subject).should raise_error(ArgumentError) }
3455
+ end
3456
+ end
3457
+ end
3458
+ end
3459
+
3460
+ it { should respond_to(:unique?) }
3461
+
3462
+ describe '#unique?' do
3463
+ describe 'when the query is unique' do
3464
+ before :all do
3465
+ @query.update(:unique => true)
3466
+ end
3467
+
3468
+ it { should be_unique }
3469
+ end
3470
+
3471
+ describe 'when the query is not unique' do
3472
+ it { should_not be_unique }
3473
+ end
3474
+
3475
+ describe 'when links are provided, but unique is not specified' do
3476
+ before :all do
3477
+ @query.should_not be_unique
3478
+ @query.update(:links => [ :referrer ])
3479
+ end
3480
+
3481
+ it { should be_unique }
3482
+ end
3483
+
3484
+ describe 'when links are provided, but unique is false' do
3485
+ before :all do
3486
+ @query.should_not be_unique
3487
+ @query.update(:links => [ :referrer ], :unique => false)
3488
+ end
3489
+
3490
+ it { should_not be_unique }
3491
+ end
3492
+ end
3493
+
3494
+ it { should respond_to(:update) }
3495
+
3496
+ describe '#update' do
3497
+ describe 'with a Query' do
3498
+ describe 'that is equivalent' do
3499
+ before :all do
3500
+ @other = DataMapper::Query.new(@repository, @model, @options)
3501
+
3502
+ @return = @query.update(@other)
3503
+ end
3504
+
3505
+ it { @return.should be_kind_of(DataMapper::Query) }
3506
+
3507
+ it { @return.should equal(@original) }
3508
+ end
3509
+
3510
+ describe 'that has conditions set' do
3511
+ before :all do
3512
+ @and_operation = DataMapper::Query::Conditions::Operation.new(:and)
3513
+ @or_operation = DataMapper::Query::Conditions::Operation.new(:or)
3514
+
3515
+ @and_operation << DataMapper::Query::Conditions::Comparison.new(:eql, User.properties[:name], 'Dan Kubb')
3516
+ @and_operation << DataMapper::Query::Conditions::Comparison.new(:eql, User.properties[:citizenship],'Canada')
3517
+
3518
+ @or_operation << DataMapper::Query::Conditions::Comparison.new(:eql, User.properties[:name], 'Ted Han')
3519
+ @or_operation << DataMapper::Query::Conditions::Comparison.new(:eql, User.properties[:citizenship], 'USA')
3520
+
3521
+ @query_one = DataMapper::Query.new(@repository, @model, :conditions => @and_operation)
3522
+ @query_two = DataMapper::Query.new(@repository, @model, :conditions => @or_operation)
3523
+
3524
+ @conditions = @query_one.merge(@query_two).conditions
3525
+ end
3526
+
3527
+ it { @conditions.should == DataMapper::Query::Conditions::Operation.new(:and, @and_operation, @or_operation) }
3528
+ end
3529
+
3530
+ describe 'that is for an ancestor model' do
3531
+ before :all do
3532
+ class ::Contact < User; end
3533
+
3534
+ @query = DataMapper::Query.new(@repository, Contact, @options)
3535
+ @original = @query
3536
+
3537
+ @other = DataMapper::Query.new(@repository, User, @options)
3538
+
3539
+ @return = @query.update(@other)
3540
+ end
3541
+
3542
+ it { @return.should be_kind_of(DataMapper::Query) }
3543
+
3544
+ it { @return.should equal(@original) }
3545
+ end
3546
+
3547
+ describe 'using a different repository' do
3548
+ it 'should raise an exception' do
3549
+ lambda {
3550
+ @query.update(DataMapper::Query.new(DataMapper::Repository.new(:other), User))
3551
+ }.should raise_error(ArgumentError, '+other+ DataMapper::Query must be for the default repository, not other')
3552
+ end
3553
+ end
3554
+
3555
+ describe 'using a different model' do
3556
+ before :all do
3557
+ class ::Clone
3558
+ include DataMapper::Resource
3559
+
3560
+ property :name, String, :key => true
3561
+ end
3562
+ end
3563
+
3564
+ it 'should raise an exception' do
3565
+ lambda {
3566
+ @query.update(DataMapper::Query.new(@repository, Clone))
3567
+ }.should raise_error(ArgumentError, '+other+ DataMapper::Query must be for the User model, not Clone')
3568
+ end
3569
+ end
3570
+
3571
+ describe 'using different options' do
3572
+ before :all do
3573
+ @other = DataMapper::Query.new(@repository, @model, @options.update(@other_options))
3574
+
3575
+ @return = @query.update(@other)
3576
+ end
3577
+
3578
+ it { @return.should be_kind_of(DataMapper::Query) }
3579
+
3580
+ it { @return.should equal(@original) }
3581
+
3582
+ it 'should update the fields' do
3583
+ @return.fields.should == @options[:fields]
3584
+ end
3585
+
3586
+ it 'should update the links' do
3587
+ @return.links.should == @options[:links]
3588
+ end
3589
+
3590
+ it 'should update the conditions' do
3591
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
3592
+ end
3593
+
3594
+ it 'should update the offset' do
3595
+ @return.offset.should == @options[:offset]
3596
+ end
3597
+
3598
+ it 'should update the limit' do
3599
+ @return.limit.should == @options[:limit]
3600
+ end
3601
+
3602
+ it 'should update the order' do
3603
+ @return.order.should == @options[:order]
3604
+ end
3605
+
3606
+ it 'should update the unique' do
3607
+ @return.unique?.should == @options[:unique]
3608
+ end
3609
+
3610
+ it 'should update the add_reversed' do
3611
+ @return.add_reversed?.should == @options[:add_reversed]
3612
+ end
3613
+
3614
+ it 'should update the reload' do
3615
+ @return.reload?.should == @options[:reload]
3616
+ end
3617
+ end
3618
+
3619
+ describe 'using extra options' do
3620
+ before :all do
3621
+ @options.update(:name => 'Dan Kubb')
3622
+ @other = DataMapper::Query.new(@repository, @model, @options)
3623
+
3624
+ @return = @query.update(@other)
3625
+ end
3626
+
3627
+ it { @return.should be_kind_of(DataMapper::Query) }
3628
+
3629
+ it { @return.should equal(@original) }
3630
+
3631
+ it 'should update the conditions' do
3632
+ @return.conditions.should ==
3633
+ DataMapper::Query::Conditions::Operation.new(
3634
+ :and,
3635
+ DataMapper::Query::Conditions::Comparison.new(
3636
+ :eql,
3637
+ @model.properties[:name],
3638
+ @options[:name]
3639
+ )
3640
+ )
3641
+ end
3642
+ end
3643
+ end
3644
+
3645
+ describe 'with a Hash' do
3646
+ describe 'that is empty' do
3647
+ before :all do
3648
+ @copy = @query.dup
3649
+ @return = @query.update({})
3650
+ end
3651
+
3652
+ it { @return.should be_kind_of(DataMapper::Query) }
3653
+
3654
+ it { @return.should equal(@original) }
3655
+
3656
+ it 'should not change the Query' do
3657
+ @return.should == @copy
3658
+ end
3659
+ end
3660
+
3661
+ describe 'using different options' do
3662
+ before :all do
3663
+ @return = @query.update(@other_options)
3664
+ end
3665
+
3666
+ it { @return.should be_kind_of(DataMapper::Query) }
3667
+
3668
+ it { @return.should equal(@original) }
3669
+
3670
+ it 'should update the fields' do
3671
+ @return.fields.should == @other_options[:fields]
3672
+ end
3673
+
3674
+ it 'should update the links' do
3675
+ @return.links.should == @other_options[:links]
3676
+ end
3677
+
3678
+ it 'should update the conditions' do
3679
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(:and, [ 'name = ?', [ 'Dan Kubb' ] ])
3680
+ end
3681
+
3682
+ it 'should update the offset' do
3683
+ @return.offset.should == @other_options[:offset]
3684
+ end
3685
+
3686
+ it 'should update the limit' do
3687
+ @return.limit.should == @other_options[:limit]
3688
+ end
3689
+
3690
+ it 'should update the order' do
3691
+ @return.order.should == @other_options[:order]
3692
+ end
3693
+
3694
+ it 'should update the unique' do
3695
+ @return.unique?.should == @other_options[:unique]
3696
+ end
3697
+
3698
+ it 'should update the add_reversed' do
3699
+ @return.add_reversed?.should == @other_options[:add_reversed]
3700
+ end
3701
+
3702
+ it 'should update the reload' do
3703
+ @return.reload?.should == @other_options[:reload]
3704
+ end
3705
+ end
3706
+
3707
+ describe 'using extra options' do
3708
+ before :all do
3709
+ @options = { :name => 'Dan Kubb' }
3710
+
3711
+ @return = @query.update(@options)
3712
+ end
3713
+
3714
+ it { @return.should be_kind_of(DataMapper::Query) }
3715
+
3716
+ it { @return.should equal(@original) }
3717
+
3718
+ it 'should update the conditions' do
3719
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(
3720
+ :and,
3721
+ DataMapper::Query::Conditions::Comparison.new(
3722
+ :eql,
3723
+ @model.properties[:name],
3724
+ @options[:name]
3725
+ )
3726
+ )
3727
+ end
3728
+ end
3729
+
3730
+ describe 'using raw conditions' do
3731
+ before :all do
3732
+ @query.update(:conditions => [ 'name IS NOT NULL' ])
3733
+
3734
+ @return = @query.update(:conditions => [ 'name = ?', 'Dan Kubb' ])
3735
+ end
3736
+
3737
+ it { @return.should be_kind_of(DataMapper::Query) }
3738
+
3739
+ it { @return.should equal(@original) }
3740
+
3741
+ it 'should update the conditions' do
3742
+ @return.conditions.should == DataMapper::Query::Conditions::Operation.new(
3743
+ :and,
3744
+ [ 'name IS NOT NULL' ],
3745
+ [ 'name = ?', [ 'Dan Kubb' ] ]
3746
+ )
3747
+ end
3748
+ end
3749
+
3750
+ describe 'with the String key mapping to a Query::Path' do
3751
+ before :all do
3752
+ @query.links.should be_empty
3753
+
3754
+ @options = { 'grandparents.name' => 'Dan Kubb' }
3755
+
3756
+ @return = @query.update(@options)
3757
+ end
3758
+
3759
+ it { @return.should be_kind_of(DataMapper::Query) }
3760
+
3761
+ it 'should not set the conditions' do
3762
+ pending do
3763
+ @return.conditions.should be_nil
3764
+ end
3765
+ end
3766
+
3767
+ it 'should set the links' do
3768
+ @return.links.should == [ @model.relationships[:referrals], @model.relationships[:referrer] ]
3769
+ end
3770
+
3771
+ it 'should be valid' do
3772
+ @return.should be_valid
3773
+ end
3774
+ end
3775
+ end
3776
+ end
3777
+ end