sbf-dm-core 1.3.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +29 -0
  3. data/.document +5 -0
  4. data/.gitignore +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