sbf-dm-core 1.3.0.beta

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