ardm-core 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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