mongo 2.1.0.beta → 2.1.0.rc0

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 (253) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -2
  5. data/lib/mongo.rb +2 -3
  6. data/lib/mongo/address.rb +7 -5
  7. data/lib/mongo/address/unix.rb +2 -2
  8. data/lib/mongo/auth/ldap/conversation.rb +6 -2
  9. data/lib/mongo/auth/scram/conversation.rb +8 -2
  10. data/lib/mongo/auth/user/view.rb +21 -0
  11. data/lib/mongo/bulk_write.rb +155 -23
  12. data/lib/mongo/bulk_write/combineable.rb +51 -0
  13. data/lib/mongo/bulk_write/ordered_combiner.rb +55 -0
  14. data/lib/mongo/bulk_write/result.rb +61 -8
  15. data/lib/mongo/bulk_write/result_combiner.rb +117 -0
  16. data/lib/mongo/bulk_write/transformable.rb +117 -0
  17. data/lib/mongo/bulk_write/unordered_combiner.rb +52 -0
  18. data/lib/mongo/bulk_write/validatable.rb +62 -0
  19. data/lib/mongo/client.rb +7 -3
  20. data/lib/mongo/cluster.rb +3 -3
  21. data/lib/mongo/cluster/topology/replica_set.rb +8 -6
  22. data/lib/mongo/cluster/topology/unknown.rb +5 -2
  23. data/lib/mongo/collection.rb +75 -4
  24. data/lib/mongo/collection/view.rb +1 -2
  25. data/lib/mongo/collection/view/aggregation.rb +13 -8
  26. data/lib/mongo/collection/view/immutable.rb +6 -6
  27. data/lib/mongo/collection/view/iterable.rb +13 -4
  28. data/lib/mongo/collection/view/map_reduce.rb +22 -17
  29. data/lib/mongo/collection/view/readable.rb +121 -70
  30. data/lib/mongo/cursor.rb +5 -1
  31. data/lib/mongo/database.rb +3 -3
  32. data/lib/mongo/database/view.rb +1 -1
  33. data/lib/mongo/error.rb +7 -0
  34. data/lib/mongo/{bulk_write/unordered_bulk_write.rb → error/closed_stream.rb} +12 -21
  35. data/lib/mongo/{bulk_write/ordered_bulk_write.rb → error/extra_file_chunk.rb} +13 -27
  36. data/lib/mongo/error/file_not_found.rb +37 -0
  37. data/lib/mongo/error/invalid_file.rb +2 -2
  38. data/lib/mongo/error/invalid_file_revision.rb +37 -0
  39. data/lib/mongo/error/invalid_uri.rb +5 -4
  40. data/lib/mongo/error/missing_file_chunk.rb +38 -0
  41. data/lib/mongo/error/operation_failure.rb +1 -1
  42. data/lib/mongo/error/unchangeable_collection_option.rb +38 -0
  43. data/lib/mongo/error/unexpected_chunk_length.rb +39 -0
  44. data/lib/mongo/grid.rb +2 -1
  45. data/lib/mongo/grid/file.rb +12 -9
  46. data/lib/mongo/grid/file/chunk.rb +6 -6
  47. data/lib/mongo/grid/file/{metadata.rb → info.rb} +41 -39
  48. data/lib/mongo/grid/fs_bucket.rb +441 -0
  49. data/lib/mongo/grid/stream.rb +64 -0
  50. data/lib/mongo/grid/stream/read.rb +208 -0
  51. data/lib/mongo/grid/stream/write.rb +187 -0
  52. data/lib/mongo/index/view.rb +1 -1
  53. data/lib/mongo/loggable.rb +34 -57
  54. data/lib/mongo/logger.rb +16 -78
  55. data/lib/mongo/monitoring.rb +1 -5
  56. data/lib/mongo/monitoring/command_log_subscriber.rb +35 -17
  57. data/lib/mongo/monitoring/event/command_succeeded.rb +20 -1
  58. data/lib/mongo/monitoring/publishable.rb +22 -12
  59. data/lib/mongo/operation.rb +3 -6
  60. data/lib/mongo/operation/commands.rb +24 -0
  61. data/lib/mongo/operation/{aggregate.rb → commands/aggregate.rb} +3 -41
  62. data/lib/mongo/operation/{aggregate → commands/aggregate}/result.rb +0 -0
  63. data/lib/mongo/operation/commands/collections_info.rb +66 -0
  64. data/lib/mongo/operation/{command.rb → commands/command.rb} +2 -18
  65. data/lib/mongo/operation/commands/indexes.rb +70 -0
  66. data/lib/mongo/operation/commands/list_collections.rb +54 -0
  67. data/lib/mongo/operation/commands/list_collections/result.rb +112 -0
  68. data/lib/mongo/operation/commands/list_indexes.rb +56 -0
  69. data/lib/mongo/operation/commands/list_indexes/result.rb +115 -0
  70. data/lib/mongo/operation/{map_reduce.rb → commands/map_reduce.rb} +3 -41
  71. data/lib/mongo/operation/{map_reduce → commands/map_reduce}/result.rb +0 -0
  72. data/lib/mongo/operation/{parallel_scan.rb → commands/parallel_scan.rb} +3 -23
  73. data/lib/mongo/operation/{parallel_scan → commands/parallel_scan}/result.rb +0 -0
  74. data/lib/mongo/operation/commands/user_query.rb +69 -0
  75. data/lib/mongo/operation/commands/users_info.rb +53 -0
  76. data/lib/mongo/operation/commands/users_info/result.rb +36 -0
  77. data/lib/mongo/operation/executable.rb +4 -68
  78. data/lib/mongo/operation/kill_cursors.rb +3 -3
  79. data/lib/mongo/operation/read.rb +0 -4
  80. data/lib/mongo/operation/read/get_more.rb +2 -22
  81. data/lib/mongo/operation/read/query.rb +2 -21
  82. data/lib/mongo/operation/{read_preferrable.rb → read_preference.rb} +3 -2
  83. data/lib/mongo/operation/specifiable.rb +24 -0
  84. data/lib/mongo/operation/write.rb +2 -0
  85. data/lib/mongo/operation/write/bulk.rb +6 -3
  86. data/lib/mongo/operation/write/bulk/bulkable.rb +82 -0
  87. data/lib/mongo/operation/write/bulk/delete.rb +71 -0
  88. data/lib/mongo/operation/write/bulk/delete/result.rb +74 -0
  89. data/lib/mongo/operation/write/bulk/insert.rb +96 -0
  90. data/lib/mongo/operation/write/bulk/insert/result.rb +129 -0
  91. data/lib/mongo/operation/write/bulk/legacy_mergable.rb +87 -0
  92. data/lib/mongo/operation/write/bulk/mergable.rb +71 -0
  93. data/lib/mongo/operation/write/bulk/update.rb +81 -0
  94. data/lib/mongo/operation/write/bulk/update/result.rb +174 -0
  95. data/lib/mongo/operation/write/command/create_index.rb +0 -1
  96. data/lib/mongo/operation/write/command/create_user.rb +0 -1
  97. data/lib/mongo/operation/write/command/delete.rb +0 -1
  98. data/lib/mongo/operation/write/command/drop_index.rb +0 -1
  99. data/lib/mongo/operation/write/command/insert.rb +0 -1
  100. data/lib/mongo/operation/write/command/remove_user.rb +0 -1
  101. data/lib/mongo/operation/write/command/update.rb +0 -1
  102. data/lib/mongo/operation/write/command/update_user.rb +0 -1
  103. data/lib/mongo/operation/write/command/writable.rb +13 -18
  104. data/lib/mongo/operation/write/create_index.rb +4 -27
  105. data/lib/mongo/operation/write/create_user.rb +4 -30
  106. data/lib/mongo/operation/write/delete.rb +5 -28
  107. data/lib/mongo/operation/write/drop_index.rb +3 -3
  108. data/lib/mongo/operation/write/gle.rb +48 -0
  109. data/lib/mongo/operation/write/idable.rb +5 -0
  110. data/lib/mongo/operation/write/insert.rb +2 -24
  111. data/lib/mongo/operation/write/remove_user.rb +4 -27
  112. data/lib/mongo/operation/write/update.rb +4 -32
  113. data/lib/mongo/operation/write/update_user.rb +4 -30
  114. data/lib/mongo/operation/write/write_command_enabled.rb +53 -0
  115. data/lib/mongo/options/mapper.rb +4 -2
  116. data/lib/mongo/protocol/delete.rb +68 -3
  117. data/lib/mongo/protocol/get_more.rb +54 -2
  118. data/lib/mongo/protocol/insert.rb +59 -1
  119. data/lib/mongo/protocol/kill_cursors.rb +53 -4
  120. data/lib/mongo/protocol/message.rb +12 -12
  121. data/lib/mongo/protocol/query.rb +139 -65
  122. data/lib/mongo/protocol/reply.rb +69 -1
  123. data/lib/mongo/protocol/update.rb +70 -1
  124. data/lib/mongo/server/connection.rb +11 -3
  125. data/lib/mongo/server/description.rb +29 -0
  126. data/lib/mongo/server/description/features.rb +2 -1
  127. data/lib/mongo/server/monitor.rb +2 -2
  128. data/lib/mongo/server_selector.rb +14 -10
  129. data/lib/mongo/server_selector/selectable.rb +24 -22
  130. data/lib/mongo/socket.rb +6 -3
  131. data/lib/mongo/socket/tcp.rb +2 -2
  132. data/lib/mongo/socket/unix.rb +5 -8
  133. data/lib/mongo/uri.rb +243 -139
  134. data/lib/mongo/version.rb +1 -1
  135. data/spec/mongo/address/unix_spec.rb +1 -1
  136. data/spec/mongo/address_spec.rb +25 -0
  137. data/spec/mongo/auth/ldap/conversation_spec.rb +43 -0
  138. data/spec/mongo/auth/user/view_spec.rb +26 -1
  139. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +271 -0
  140. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +239 -0
  141. data/spec/mongo/bulk_write_spec.rb +332 -166
  142. data/spec/mongo/client_spec.rb +25 -0
  143. data/spec/mongo/cluster/topology/replica_set_spec.rb +2 -0
  144. data/spec/mongo/collection/view/aggregation_spec.rb +65 -0
  145. data/spec/mongo/collection/view/immutable_spec.rb +103 -0
  146. data/spec/mongo/collection/view/map_reduce_spec.rb +98 -3
  147. data/spec/mongo/collection/view/readable_spec.rb +17 -30
  148. data/spec/mongo/collection/view_spec.rb +233 -7
  149. data/spec/mongo/collection_spec.rb +360 -18
  150. data/spec/mongo/command_monitoring_spec.rb +51 -0
  151. data/spec/mongo/connection_string_spec.rb +137 -0
  152. data/spec/mongo/database_spec.rb +27 -11
  153. data/spec/mongo/grid/file/chunk_spec.rb +5 -5
  154. data/spec/mongo/grid/file/{metadata_spec.rb → info_spec.rb} +29 -17
  155. data/spec/mongo/grid/file_spec.rb +8 -8
  156. data/spec/mongo/grid/fs_bucket_spec.rb +1020 -0
  157. data/spec/mongo/grid/stream/read_spec.rb +275 -0
  158. data/spec/mongo/grid/stream/write_spec.rb +440 -0
  159. data/spec/mongo/grid/stream_spec.rb +48 -0
  160. data/spec/mongo/gridfs_spec.rb +50 -0
  161. data/spec/mongo/logger_spec.rb +0 -40
  162. data/spec/mongo/monitoring/command_log_subscriber_spec.rb +76 -0
  163. data/spec/mongo/operation/{aggregate_spec.rb → commands/aggregate_spec.rb} +0 -42
  164. data/spec/mongo/operation/{read → commands}/collections_info_spec.rb +1 -1
  165. data/spec/mongo/operation/{command_spec.rb → commands/command_spec.rb} +0 -0
  166. data/spec/mongo/operation/{read → commands}/indexes_spec.rb +1 -1
  167. data/spec/mongo/operation/{map_reduce_spec.rb → commands/map_reduce_spec.rb} +0 -18
  168. data/spec/mongo/operation/kill_cursors_spec.rb +1 -1
  169. data/spec/mongo/operation/{read_preferrable_spec.rb → read_preference_spec.rb} +11 -11
  170. data/spec/mongo/operation/write/bulk/{bulk_delete_spec.rb → delete_spec.rb} +1 -12
  171. data/spec/mongo/operation/write/bulk/{bulk_insert_spec.rb → insert_spec.rb} +1 -12
  172. data/spec/mongo/operation/write/bulk/{bulk_update_spec.rb → update_spec.rb} +1 -12
  173. data/spec/mongo/operation/write/insert_spec.rb +0 -11
  174. data/spec/mongo/protocol/kill_cursors_spec.rb +5 -3
  175. data/spec/mongo/server/description_spec.rb +42 -0
  176. data/spec/mongo/server/monitor_spec.rb +21 -0
  177. data/spec/mongo/server_discovery_and_monitoring_spec.rb +1 -0
  178. data/spec/mongo/server_selection_spec.rb +3 -3
  179. data/spec/mongo/server_selector/nearest_spec.rb +34 -27
  180. data/spec/mongo/server_selector/primary_preferred_spec.rb +31 -30
  181. data/spec/mongo/server_selector/primary_spec.rb +14 -13
  182. data/spec/mongo/server_selector/secondary_preferred_spec.rb +27 -26
  183. data/spec/mongo/server_selector/secondary_spec.rb +23 -22
  184. data/spec/mongo/server_selector_spec.rb +87 -24
  185. data/spec/mongo/socket/unix_spec.rb +52 -0
  186. data/spec/mongo/uri_spec.rb +251 -39
  187. data/spec/spec_helper.rb +11 -4
  188. data/spec/support/authorization.rb +4 -5
  189. data/spec/support/command_monitoring.rb +365 -0
  190. data/spec/support/command_monitoring/bulkWrite.yml +73 -0
  191. data/spec/support/command_monitoring/command.yml +42 -0
  192. data/spec/support/command_monitoring/deleteMany.yml +55 -0
  193. data/spec/support/command_monitoring/deleteOne.yml +55 -0
  194. data/spec/support/command_monitoring/find.yml +219 -0
  195. data/spec/support/command_monitoring/insertMany.yml +81 -0
  196. data/spec/support/command_monitoring/insertOne.yml +51 -0
  197. data/spec/support/command_monitoring/updateMany.yml +67 -0
  198. data/spec/support/command_monitoring/updateOne.yml +95 -0
  199. data/spec/support/connection_string.rb +228 -0
  200. data/spec/support/connection_string_tests/invalid-uris.yml +193 -0
  201. data/spec/support/connection_string_tests/valid-auth.yml +256 -0
  202. data/spec/support/connection_string_tests/valid-host_identifiers.yml +121 -0
  203. data/spec/support/connection_string_tests/valid-options.yml +30 -0
  204. data/spec/support/connection_string_tests/valid-unix_socket-absolute.yml +197 -0
  205. data/spec/support/connection_string_tests/valid-unix_socket-relative.yml +213 -0
  206. data/spec/support/connection_string_tests/valid-warnings.yml +55 -0
  207. data/spec/support/crud.rb +3 -1
  208. data/spec/support/crud/read.rb +14 -10
  209. data/spec/support/crud/write.rb +36 -9
  210. data/spec/support/gridfs.rb +637 -0
  211. data/spec/support/gridfs_tests/delete.yml +157 -0
  212. data/spec/support/gridfs_tests/download.yml +210 -0
  213. data/spec/support/gridfs_tests/download_by_name.yml +113 -0
  214. data/spec/support/gridfs_tests/upload.yml +158 -0
  215. data/spec/support/sdam/rs/equal_electionids.yml +1 -2
  216. data/spec/support/sdam/rs/new_primary_new_electionid.yml +0 -3
  217. data/spec/support/sdam/rs/primary_mismatched_me.yml +37 -0
  218. data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +75 -0
  219. data/spec/support/sdam/rs/secondary_mismatched_me.yml +37 -0
  220. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
  221. data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
  222. data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
  223. data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
  224. data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
  225. data/spec/support/sdam/single/not_ok_response.yml +0 -1
  226. data/spec/support/server_discovery_and_monitoring.rb +3 -1
  227. data/spec/support/server_selection.rb +3 -1
  228. data/spec/support/shared/bulk_write.rb +192 -0
  229. data/spec/support/shared/server_selector.rb +21 -12
  230. metadata +147 -57
  231. metadata.gz.sig +0 -0
  232. data/lib/mongo/bulk_write/bulk_writable.rb +0 -252
  233. data/lib/mongo/bulk_write/deletable.rb +0 -57
  234. data/lib/mongo/bulk_write/insertable.rb +0 -49
  235. data/lib/mongo/bulk_write/replacable.rb +0 -58
  236. data/lib/mongo/bulk_write/updatable.rb +0 -69
  237. data/lib/mongo/grid/fs.rb +0 -146
  238. data/lib/mongo/operation/list_collections/result.rb +0 -114
  239. data/lib/mongo/operation/list_indexes/result.rb +0 -118
  240. data/lib/mongo/operation/read/collections_info.rb +0 -68
  241. data/lib/mongo/operation/read/indexes.rb +0 -69
  242. data/lib/mongo/operation/read/list_collections.rb +0 -76
  243. data/lib/mongo/operation/read/list_indexes.rb +0 -78
  244. data/lib/mongo/operation/write/bulk/bulk_delete.rb +0 -145
  245. data/lib/mongo/operation/write/bulk/bulk_delete/result.rb +0 -75
  246. data/lib/mongo/operation/write/bulk/bulk_insert.rb +0 -132
  247. data/lib/mongo/operation/write/bulk/bulk_insert/result.rb +0 -130
  248. data/lib/mongo/operation/write/bulk/bulk_mergable.rb +0 -67
  249. data/lib/mongo/operation/write/bulk/bulk_update.rb +0 -154
  250. data/lib/mongo/operation/write/bulk/bulk_update/result.rb +0 -174
  251. data/lib/mongo/operation/write/bulk/legacy_bulk_mergable.rb +0 -83
  252. data/spec/mongo/grid/fs_spec.rb +0 -160
  253. data/spec/mongo/loggable_spec.rb +0 -63
@@ -20,6 +20,10 @@ describe Mongo::Client do
20
20
  )
21
21
  end
22
22
 
23
+ after do
24
+ client.close
25
+ end
26
+
23
27
  context 'when the other is a client' do
24
28
 
25
29
  context 'when the options and cluster are equal' do
@@ -222,6 +226,27 @@ describe Mongo::Client do
222
226
  expect(client[:users].name).to eq('users')
223
227
  end
224
228
  end
229
+
230
+ context 'when providing a custom logger' do
231
+
232
+ let(:logger) do
233
+ Logger.new($stdout).tap do |l|
234
+ l.level = Logger::FATAL
235
+ end
236
+ end
237
+
238
+ let(:client) do
239
+ authorized_client.with(logger: logger)
240
+ end
241
+
242
+ after do
243
+ client.close
244
+ end
245
+
246
+ it 'does not use the global logger' do
247
+ expect(client.cluster.logger).to_not eq(Mongo::Logger.logger)
248
+ end
249
+ end
225
250
  end
226
251
 
227
252
  context 'when providing a connection string' do
@@ -239,6 +239,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
239
239
  double('description').tap do |d|
240
240
  allow(d).to receive(:config).and_return({ 'ismaster' => true })
241
241
  allow(d).to receive(:primary?).and_return(false)
242
+ allow(d).to receive(:me_mismatch?).and_return(false)
242
243
  allow(d).to receive(:hosts).and_return([])
243
244
  end
244
245
  end
@@ -257,6 +258,7 @@ describe Mongo::Cluster::Topology::ReplicaSet do
257
258
  allow(d).to receive(:hosts).and_return([ primary ])
258
259
  allow(d).to receive(:replica_set_name).and_return('test')
259
260
  allow(d).to receive(:replica_set_member?).and_return(true)
261
+ allow(d).to receive(:me_mismatch?).and_return(false)
260
262
  end
261
263
  end
262
264
 
@@ -300,4 +300,69 @@ describe Mongo::Collection::View::Aggregation do
300
300
  end
301
301
  end
302
302
  end
303
+
304
+ context 'when $out is in the pipeline', if: write_command_enabled? do
305
+
306
+ let(:pipeline) do
307
+ [{
308
+ "$group" => {
309
+ "_id" => "$city",
310
+ "totalpop" => { "$sum" => "$pop" }
311
+ }
312
+ },
313
+ {
314
+ '$out' => 'output_collection'
315
+ }
316
+ ]
317
+ end
318
+
319
+ after do
320
+ authorized_client['output_collection'].delete_many
321
+ end
322
+
323
+ context 'when $out is a string' do
324
+
325
+ it 'does not allow the operation on a secondary' do
326
+ expect(aggregation.send(:secondary_ok?)).to be(false)
327
+ end
328
+ end
329
+
330
+ context 'when $out is a symbol' do
331
+
332
+ let(:pipeline) do
333
+ [{
334
+ "$group" => {
335
+ "_id" => "$city",
336
+ "totalpop" => { "$sum" => "$pop" }
337
+ }
338
+ },
339
+ {
340
+ :$out => 'output_collection'
341
+ }
342
+ ]
343
+ end
344
+
345
+ it 'does not allow the operation on a secondary' do
346
+ expect(aggregation.send(:secondary_ok?)).to be(false)
347
+ end
348
+ end
349
+
350
+
351
+ context 'when the context is not a valid server for writing' do
352
+
353
+ it 'reroutes the operation to a primary' do
354
+ allow(aggregation).to receive(:valid_server?).and_return(false)
355
+ expect(Mongo::Logger.logger).to receive(:warn?).and_call_original
356
+ aggregation.to_a
357
+ end
358
+ end
359
+
360
+ context 'when the context is a valid server for writing' do
361
+
362
+ it 'does not reroute the operation to a primary' do
363
+ expect(Mongo::Logger.logger).not_to receive(:warn?)
364
+ aggregation.to_a
365
+ end
366
+ end
367
+ end
303
368
  end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Collection::View::Immutable do
4
+
5
+ let(:selector) do
6
+ {}
7
+ end
8
+
9
+ let(:options) do
10
+ {}
11
+ end
12
+
13
+ let(:view) do
14
+ Mongo::Collection::View.new(authorized_collection, selector, options)
15
+ end
16
+
17
+ after do
18
+ authorized_collection.delete_many
19
+ end
20
+
21
+ describe '#configure' do
22
+
23
+ context 'when the options has a modifiers document' do
24
+
25
+ let(:options) do
26
+ { modifiers: { :$maxTimeMS => 500 } }
27
+ end
28
+
29
+ let(:new_view) do
30
+ view.projection(_id: 1)
31
+ end
32
+
33
+ it 'returns a new view' do
34
+ expect(view).not_to be(new_view)
35
+ end
36
+
37
+ it 'creates a new options hash' do
38
+ expect(view.options).not_to be(new_view.options)
39
+ end
40
+
41
+ it 'keeps the modifier fields already in the options hash' do
42
+ expect(new_view.modifiers[:$maxTimeMS]).to eq(500)
43
+ end
44
+
45
+ it 'sets the option' do
46
+ expect(new_view.projection).to eq(_id: 1)
47
+ end
48
+
49
+ it 'creates a new modifiers document' do
50
+ expect(view.modifiers).not_to be(new_view.modifiers)
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#configure_modifier' do
56
+
57
+ let(:new_view) do
58
+ view.sort('x' => Mongo::Index::ASCENDING)
59
+ end
60
+
61
+ context 'when the options does not have a modifiers document' do
62
+
63
+ it 'returns a new view' do
64
+ expect(view).not_to be(new_view)
65
+ end
66
+
67
+ it 'returns a new view with the modifiers document containing the option' do
68
+ expect(new_view.modifiers[:$orderby]).to eq({ 'x' => Mongo::Index::ASCENDING })
69
+ end
70
+ end
71
+
72
+ context 'when the options has a modifiers document' do
73
+
74
+ let(:options) do
75
+ { modifiers: { :$maxTimeMS => 500 } }
76
+ end
77
+
78
+ it 'returns a new view' do
79
+ expect(view).not_to be(new_view)
80
+ end
81
+
82
+ it 'creates a new options hash' do
83
+ expect(view.options).not_to be(new_view.options)
84
+ end
85
+
86
+ it 'keeps the fields already in the options hash and merges in the new one' do
87
+ expect(new_view.modifiers[:$maxTimeMS]).to eq(500)
88
+ end
89
+
90
+ it 'sets the new value in the new view modifier document' do
91
+ expect(new_view.modifiers[:$orderby]).to eq('x' => Mongo::Index::ASCENDING)
92
+ end
93
+
94
+ it 'returns that value when the corresponding option method is called' do
95
+ expect(new_view.sort).to eq({ 'x' => Mongo::Index::ASCENDING })
96
+ end
97
+
98
+ it 'creates a new modifiers document' do
99
+ expect(view.modifiers).not_to be(new_view.modifiers)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -66,6 +66,39 @@ describe Mongo::Collection::View::MapReduce do
66
66
  end
67
67
  end
68
68
 
69
+ context 'when out is in the options' do
70
+
71
+ after do
72
+ authorized_client['output_collection'].delete_many
73
+ end
74
+
75
+ context 'when out is a string' do
76
+
77
+ let(:options) do
78
+ { :out => 'output_collection' }
79
+ end
80
+
81
+ it 'iterates over the documents in the result' do
82
+ map_reduce.each do |document|
83
+ expect(document[:value]).to_not be_nil
84
+ end
85
+ end
86
+ end
87
+
88
+ context 'when out is a document' do
89
+
90
+ let(:options) do
91
+ { :out => { replace: 'output_collection' } }
92
+ end
93
+
94
+ it 'iterates over the documents in the result' do
95
+ map_reduce.each do |document|
96
+ expect(document[:value]).to_not be_nil
97
+ end
98
+ end
99
+ end
100
+ end
101
+
69
102
  context 'when out is inline' do
70
103
 
71
104
  let(:new_map_reduce) do
@@ -82,7 +115,7 @@ describe Mongo::Collection::View::MapReduce do
82
115
  context 'when out is a collection' do
83
116
 
84
117
  after do
85
- authorized_client['output_collection'].find.delete_many
118
+ authorized_client['output_collection'].delete_many
86
119
  end
87
120
 
88
121
  context 'when the option is to replace' do
@@ -135,6 +168,17 @@ describe Mongo::Collection::View::MapReduce do
135
168
  expect(new_map_reduce.count).to eq(2)
136
169
  end
137
170
  end
171
+
172
+ context 'when the option is a collection name' do
173
+
174
+ let(:new_map_reduce) do
175
+ map_reduce.out('output_collection')
176
+ end
177
+
178
+ it 'fetches the results from the collection' do
179
+ expect(new_map_reduce.count).to eq(2)
180
+ end
181
+ end
138
182
  end
139
183
 
140
184
  context 'when the view has a selector' do
@@ -169,7 +213,7 @@ describe Mongo::Collection::View::MapReduce do
169
213
  end
170
214
 
171
215
  it 'includes the selector in the operation spec' do
172
- expect(map_reduce.send(:map_reduce_spec)[:selector][:query]).to eq(selector[:$query])
216
+ expect(map_reduce.send(:map_reduce_spec)[:selector][:query]).to eq(BSON::Document.new(selector[:$query]))
173
217
  end
174
218
  end
175
219
  end
@@ -250,6 +294,57 @@ describe Mongo::Collection::View::MapReduce do
250
294
  expect(map_reduce.send(:map_reduce_spec)[:selector][:out]).to eq(inline: 1)
251
295
  end
252
296
  end
297
+
298
+ context 'when out is specified in the options' do
299
+
300
+ let(:location) do
301
+ { replace: 'testing' }
302
+ end
303
+
304
+ let(:options) do
305
+ { :out => location }
306
+ end
307
+
308
+ it 'sets the out value' do
309
+ expect(map_reduce.out).to eq(location)
310
+ end
311
+
312
+ it 'includes the out value in the operation spec' do
313
+ expect(map_reduce.send(:map_reduce_spec)[:selector][:out]).to be(location)
314
+ end
315
+ end
316
+
317
+ context 'when out is not inline' do
318
+
319
+ let(:location) do
320
+ { replace: 'testing' }
321
+ end
322
+
323
+ let(:options) do
324
+ { :out => location }
325
+ end
326
+
327
+ it 'does not allow the operation on a secondary' do
328
+ expect(map_reduce.send(:secondary_ok?)).to be(false)
329
+ end
330
+
331
+ context 'when the context is not a valid server for writing' do
332
+
333
+ it 'reroutes the operation to a primary' do
334
+ allow(map_reduce).to receive(:valid_server?).and_return(false)
335
+ expect(Mongo::Logger.logger).to receive(:warn?).and_call_original
336
+ map_reduce.to_a
337
+ end
338
+ end
339
+
340
+ context 'when the context is a valid server for writing' do
341
+
342
+ it 'does not reroute the operation to a primary' do
343
+ expect(Mongo::Logger.logger).not_to receive(:warn?)
344
+ map_reduce.to_a
345
+ end
346
+ end
347
+ end
253
348
  end
254
349
 
255
350
  describe '#scope' do
@@ -316,7 +411,7 @@ describe Mongo::Collection::View::MapReduce do
316
411
  end
317
412
 
318
413
  it 'includes the sort object in the operation spec' do
319
- expect(map_reduce.send(:map_reduce_spec)[:selector][:sort]).to be(sort)
414
+ expect(map_reduce.send(:map_reduce_spec)[:selector][:sort][:name]).to eq(sort[:name])
320
415
  end
321
416
  end
322
417
 
@@ -465,53 +465,40 @@ describe Mongo::Collection::View::Readable do
465
465
  end
466
466
  end
467
467
 
468
- describe '#no_cursor_timeout' do
468
+ describe '#max_value' do
469
469
 
470
470
  let(:new_view) do
471
- view.no_cursor_timeout
471
+ view.max_value(_id: 1)
472
472
  end
473
473
 
474
- it 'sets the flag' do
475
- expect(new_view.send(:flags)).to include(:no_cursor_timeout)
476
- end
477
-
478
- it 'returns a new View' do
479
- expect(new_view).not_to be(view)
474
+ it 'sets the value in the options' do
475
+ expect(new_view.max_value).to eq('_id' => 1)
480
476
  end
481
477
  end
482
478
 
483
- describe '#parallel_scan', unless: sharded? do
479
+ describe '#min_value' do
484
480
 
485
- let(:documents) do
486
- (1..200).map do |i|
487
- { name: "testing-scan-#{i}" }
488
- end
481
+ let(:new_view) do
482
+ view.min_value(_id: 1)
489
483
  end
490
484
 
491
- before do
492
- authorized_collection.insert_many(documents)
485
+ it 'sets the value in the options' do
486
+ expect(new_view.min_value).to eq('_id' => 1)
493
487
  end
488
+ end
494
489
 
495
- let(:cursors) do
496
- view.parallel_scan(2)
497
- end
490
+ describe '#no_cursor_timeout' do
498
491
 
499
- it 'returns an array of cursors', if: write_command_enabled? do
500
- cursors.each do |cursor|
501
- expect(cursor.class).to be(Mongo::Cursor)
502
- end
492
+ let(:new_view) do
493
+ view.no_cursor_timeout
503
494
  end
504
495
 
505
- it 'returns the correct number of documents', if: write_command_enabled? do
506
- expect(
507
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
508
- ).to eq(200)
496
+ it 'sets the flag' do
497
+ expect(new_view.send(:flags)).to include(:no_cursor_timeout)
509
498
  end
510
499
 
511
- it 'raises an error', unless: write_command_enabled? do
512
- expect {
513
- cursors
514
- }.to raise_error(Mongo::Error::OperationFailure)
500
+ it 'returns a new View' do
501
+ expect(new_view).not_to be(view)
515
502
  end
516
503
  end
517
504
 
@@ -18,6 +18,180 @@ describe Mongo::Collection::View do
18
18
  authorized_collection.delete_many
19
19
  end
20
20
 
21
+ context 'when query modifiers are provided' do
22
+
23
+ context 'when a selector has a query modifier' do
24
+
25
+ let(:options) do
26
+ {}
27
+ end
28
+
29
+ let(:expected_modifiers) do
30
+ BSON::Document.new(selector)
31
+ end
32
+
33
+ let(:parsed_selector) do
34
+ {}
35
+ end
36
+
37
+ let(:query_selector) do
38
+ BSON::Document.new(selector)
39
+ end
40
+
41
+ context 'when the $query key is a string' do
42
+
43
+ let(:selector) do
44
+ { "$query" => { a: 1 }, :$someMod => 100 }
45
+ end
46
+
47
+ let(:expected_modifiers) do
48
+ BSON::Document.new(selector)
49
+ end
50
+
51
+ it 'sets the modifiers' do
52
+ expect(view.instance_variable_get(:@modifiers)).to eq(expected_modifiers)
53
+ end
54
+
55
+ it 'removes the modifiers from the selector' do
56
+ expect(view.selector).to eq(parsed_selector)
57
+ end
58
+
59
+ it 'creates the correct query selector' do
60
+ expect(view.send(:query_spec)[:selector]).to eq(query_selector)
61
+ end
62
+
63
+ end
64
+
65
+ context 'when the $query key is a symbol' do
66
+
67
+ let(:selector) do
68
+ { :$query => { a: 1 }, :$someMod => 100 }
69
+ end
70
+
71
+ let(:expected_modifiers) do
72
+ BSON::Document.new(selector)
73
+ end
74
+
75
+ it 'sets the modifiers' do
76
+ expect(view.instance_variable_get(:@modifiers)).to eq(expected_modifiers)
77
+ end
78
+
79
+ it 'removes the modifiers from the selector' do
80
+ expect(view.selector).to eq(parsed_selector)
81
+ end
82
+
83
+ it 'creates the correct query selector' do
84
+ expect(view.send(:query_spec)[:selector]).to eq(query_selector)
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'when a modifiers document is provided in the options' do
90
+
91
+ let(:selector) do
92
+ { a: 1 }
93
+ end
94
+
95
+ let(:options) do
96
+ { :modifiers => { :$someMod => 100 } }
97
+ end
98
+
99
+ let(:expected_modifiers) do
100
+ options[:modifiers]
101
+ end
102
+
103
+ let(:parsed_selector) do
104
+ { a: 1 }
105
+ end
106
+
107
+ let(:query_selector) do
108
+ BSON::Document.new(:$query => { a: 1 }, :$someMod => 100)
109
+ end
110
+
111
+ it 'sets the modifiers' do
112
+ expect(view.instance_variable_get(:@modifiers)).to eq(expected_modifiers)
113
+ end
114
+
115
+ it 'removes the modifiers from the selector' do
116
+ expect(view.selector).to eq(parsed_selector)
117
+ end
118
+
119
+ it 'creates the correct query selector' do
120
+ expect(view.send(:query_spec)[:selector]).to eq(query_selector)
121
+ end
122
+
123
+ context 'when modifiers and options are both provided' do
124
+
125
+ let(:selector) do
126
+ { a: 1 }
127
+ end
128
+
129
+ let(:options) do
130
+ { :sort => { a: Mongo::Index::ASCENDING }, :modifiers => { :$orderby => { a: Mongo::Index::DESCENDING } } }
131
+ end
132
+
133
+ let(:expected_modifiers) do
134
+ { :$orderby => options[:sort] }
135
+ end
136
+
137
+ let(:parsed_selector) do
138
+ { a: 1 }
139
+ end
140
+
141
+ let(:query_selector) do
142
+ BSON::Document.new(:$query => selector, :$orderby => { a: Mongo::Index::ASCENDING })
143
+ end
144
+
145
+ it 'sets the modifiers' do
146
+ expect(view.instance_variable_get(:@modifiers)).to eq(expected_modifiers)
147
+ end
148
+
149
+ it 'removes the modifiers from the selector' do
150
+ expect(view.selector).to eq(parsed_selector)
151
+ end
152
+
153
+ it 'creates the correct query selector' do
154
+ expect(view.send(:query_spec)[:selector]).to eq(query_selector)
155
+ end
156
+ end
157
+
158
+ context 'when modifiers, options and a query modifier are provided' do
159
+
160
+ let(:selector) do
161
+ { b: 2, :$query => { a: 1 }, :$someMod => 100 }
162
+ end
163
+
164
+ let(:options) do
165
+ { :sort => { a: Mongo::Index::ASCENDING }, :modifiers => { :$someMod => true, :$orderby => { a: Mongo::Index::DESCENDING } } }
166
+ end
167
+
168
+ let(:expected_modifiers) do
169
+ { :$query => { a: 1 }, :$orderby => { a: Mongo::Index::ASCENDING }, :$someMod => 100 }
170
+ end
171
+
172
+ let(:parsed_selector) do
173
+ { b: 2 }
174
+ end
175
+
176
+ let(:query_selector) do
177
+ BSON::Document.new(:$query => { a: 1 }, :$someMod => 100, :$orderby => { a: Mongo::Index::ASCENDING })
178
+ end
179
+
180
+ it 'sets the modifiers' do
181
+ expect(view.instance_variable_get(:@modifiers)).to eq(expected_modifiers)
182
+ end
183
+
184
+ it 'removes the modifiers from the selector' do
185
+ expect(view.selector).to eq(parsed_selector)
186
+ end
187
+
188
+ it 'creates the correct query selector' do
189
+ expect(view.send(:query_spec)[:selector]).to eq(query_selector)
190
+ end
191
+ end
192
+ end
193
+ end
194
+
21
195
  describe '#==' do
22
196
 
23
197
  context 'when the other object is not a collection view' do
@@ -165,7 +339,7 @@ describe Mongo::Collection::View do
165
339
  end
166
340
 
167
341
  it 'sets the batch size on the initial query' do
168
- expect(query_spec[:options][:limit]).to eq(options[:batch_size])
342
+ expect(query_spec[:options][:batch_size]).to eq(options[:batch_size])
169
343
  end
170
344
 
171
345
  it 'returns all the documents' do
@@ -232,7 +406,11 @@ describe Mongo::Collection::View do
232
406
  end
233
407
 
234
408
  it 'sets the batch size on the initial query' do
235
- expect(query_spec[:options][:limit]).to eq(options[:batch_size])
409
+ expect(query_spec[:options][:batch_size]).to eq(options[:batch_size])
410
+ end
411
+
412
+ it 'sets the limit on the initial query' do
413
+ expect(query_spec[:options][:limit]).to eq(options[:limit])
236
414
  end
237
415
 
238
416
  it 'returns the limit of documents' do
@@ -396,7 +574,6 @@ describe Mongo::Collection::View do
396
574
  context 'when the cluster is sharded', if: sharded? do
397
575
 
398
576
  before do
399
- allow(authorized_collection.cluster).to receive(:sharded?).and_return(true)
400
577
  expect(view).to receive(:special_selector).and_call_original
401
578
  end
402
579
 
@@ -405,6 +582,40 @@ describe Mongo::Collection::View do
405
582
  expect(doc).to have_key('field')
406
583
  end
407
584
  end
585
+
586
+ context 'when there is a read preference' do
587
+
588
+ let(:collection) do
589
+ authorized_collection.with(read: { mode: :secondary})
590
+ end
591
+
592
+ let(:view) do
593
+ described_class.new(collection, selector, options)
594
+ end
595
+
596
+ let(:formatted_read_pref) do
597
+ BSON::Document.new(Mongo::ServerSelector.get(mode: :secondary).to_mongos)
598
+ end
599
+
600
+ it 'adds the formatted read preference to the selector' do
601
+ expect(view.send(:query_spec)[:selector][:$readPreference]).to eq(formatted_read_pref)
602
+ end
603
+ end
604
+
605
+ context 'when the read preference is primary' do
606
+
607
+ let(:collection) do
608
+ authorized_collection.with(read: { mode: :primary})
609
+ end
610
+
611
+ let(:view) do
612
+ described_class.new(collection, selector, options)
613
+ end
614
+
615
+ it 'does not add the formatted read preference to the selector' do
616
+ expect(view.send(:query_spec)[:selector][:$readPreference]).to be(nil)
617
+ end
618
+ end
408
619
  end
409
620
 
410
621
  context 'when a modifier document is provided' do
@@ -541,14 +752,11 @@ describe Mongo::Collection::View do
541
752
  end
542
753
 
543
754
  it 'overrides the modifier value with the option value' do
544
- expect(query_spec[:selector][:$query]).to eq(selector)
755
+ expect(query_spec[:selector][:$query]).to eq(options[:modifiers][:$query])
545
756
  end
546
757
  end
547
-
548
-
549
758
  end
550
759
  end
551
-
552
760
  end
553
761
 
554
762
  context 'when there are no special fields' do
@@ -578,6 +786,24 @@ describe Mongo::Collection::View do
578
786
  end
579
787
  end
580
788
  end
789
+
790
+ describe '#close_query' do
791
+
792
+ let(:options) do
793
+ { :batch_size => 1 }
794
+ end
795
+
796
+ before do
797
+ e = view.to_enum
798
+ e.next
799
+ cursor = view.instance_variable_get(:@cursor)
800
+ expect(cursor).to receive(:kill_cursors).and_call_original
801
+ end
802
+
803
+ it 'sends a kill cursors command for the cursor' do
804
+ view.close_query
805
+ end
806
+ end
581
807
  end
582
808
 
583
809
  describe '#hash' do