mongo 2.4.3 → 2.5.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 (235) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -2
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo.rb +3 -2
  5. data/lib/mongo/auth/cr.rb +6 -4
  6. data/lib/mongo/auth/cr/conversation.rb +33 -17
  7. data/lib/mongo/auth/ldap.rb +4 -2
  8. data/lib/mongo/auth/ldap/conversation.rb +19 -9
  9. data/lib/mongo/auth/scram.rb +7 -4
  10. data/lib/mongo/auth/scram/conversation.rb +62 -24
  11. data/lib/mongo/auth/user.rb +10 -0
  12. data/lib/mongo/auth/user/view.rb +44 -22
  13. data/lib/mongo/auth/x509.rb +4 -2
  14. data/lib/mongo/auth/x509/conversation.rb +19 -9
  15. data/lib/mongo/bulk_write.rb +33 -27
  16. data/lib/mongo/bulk_write/combineable.rb +5 -0
  17. data/lib/mongo/bulk_write/transformable.rb +2 -0
  18. data/lib/mongo/bulk_write/validatable.rb +4 -0
  19. data/lib/mongo/client.rb +123 -12
  20. data/lib/mongo/cluster.rb +52 -11
  21. data/lib/mongo/cluster/app_metadata.rb +8 -2
  22. data/lib/mongo/cluster/cursor_reaper.rb +0 -1
  23. data/lib/mongo/cluster/topology.rb +1 -1
  24. data/lib/mongo/collection.rb +114 -27
  25. data/lib/mongo/collection/view.rb +8 -2
  26. data/lib/mongo/collection/view/aggregation.rb +11 -7
  27. data/lib/mongo/collection/view/builder/aggregation.rb +5 -1
  28. data/lib/mongo/collection/view/builder/find_command.rb +5 -3
  29. data/lib/mongo/collection/view/builder/map_reduce.rb +11 -3
  30. data/lib/mongo/collection/view/builder/op_query.rb +1 -1
  31. data/lib/mongo/collection/view/change_stream.rb +160 -0
  32. data/lib/mongo/collection/view/change_stream/retryable.rb +57 -0
  33. data/lib/mongo/collection/view/iterable.rb +11 -10
  34. data/lib/mongo/collection/view/map_reduce.rb +22 -18
  35. data/lib/mongo/collection/view/readable.rb +51 -37
  36. data/lib/mongo/collection/view/writable.rb +72 -40
  37. data/lib/mongo/cursor.rb +25 -4
  38. data/lib/mongo/cursor/builder/get_more_command.rb +4 -2
  39. data/lib/mongo/database.rb +22 -11
  40. data/lib/mongo/database/view.rb +16 -12
  41. data/lib/mongo/error.rb +5 -0
  42. data/lib/mongo/error/invalid_session.rb +36 -0
  43. data/lib/mongo/error/missing_resume_token.rb +39 -0
  44. data/lib/mongo/error/operation_failure.rb +17 -0
  45. data/lib/mongo/error/parser.rb +3 -2
  46. data/lib/mongo/error/unknown_payload_type.rb +41 -0
  47. data/lib/mongo/error/unsupported_array_filters.rb +51 -0
  48. data/lib/mongo/error/unsupported_message_type.rb +23 -0
  49. data/lib/mongo/grid/fs_bucket.rb +5 -4
  50. data/lib/mongo/grid/stream/read.rb +3 -2
  51. data/lib/mongo/grid/stream/write.rb +2 -2
  52. data/lib/mongo/index/view.rb +35 -25
  53. data/lib/mongo/monitoring/event/secure.rb +14 -0
  54. data/lib/mongo/operation.rb +16 -0
  55. data/lib/mongo/operation/commands.rb +1 -0
  56. data/lib/mongo/operation/commands/aggregate.rb +9 -5
  57. data/lib/mongo/operation/commands/aggregate/result.rb +1 -1
  58. data/lib/mongo/operation/commands/collections_info.rb +6 -6
  59. data/lib/mongo/operation/commands/command.rb +2 -1
  60. data/lib/mongo/operation/commands/create.rb +6 -2
  61. data/lib/mongo/operation/commands/drop.rb +6 -2
  62. data/lib/mongo/operation/commands/drop_database.rb +6 -2
  63. data/lib/mongo/operation/commands/explain.rb +27 -0
  64. data/lib/mongo/operation/commands/explain/result.rb +52 -0
  65. data/lib/mongo/operation/commands/indexes.rb +1 -1
  66. data/lib/mongo/operation/commands/list_collections.rb +1 -1
  67. data/lib/mongo/operation/commands/list_collections/result.rb +1 -1
  68. data/lib/mongo/operation/commands/list_indexes.rb +1 -1
  69. data/lib/mongo/operation/commands/list_indexes/result.rb +1 -1
  70. data/lib/mongo/operation/commands/map_reduce.rb +8 -4
  71. data/lib/mongo/operation/commands/map_reduce/result.rb +13 -1
  72. data/lib/mongo/operation/commands/user_query.rb +1 -1
  73. data/lib/mongo/operation/commands/users_info.rb +6 -2
  74. data/lib/mongo/operation/executable.rb +4 -1
  75. data/lib/mongo/operation/read_preference.rb +10 -5
  76. data/lib/mongo/operation/result.rb +26 -2
  77. data/lib/mongo/operation/specifiable.rb +13 -1
  78. data/lib/mongo/operation/uses_command_op_msg.rb +47 -0
  79. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -1
  80. data/lib/mongo/operation/write/bulk/insert/result.rb +4 -4
  81. data/lib/mongo/operation/write/command/create_index.rb +6 -1
  82. data/lib/mongo/operation/write/command/delete.rb +28 -4
  83. data/lib/mongo/operation/write/command/drop_index.rb +6 -1
  84. data/lib/mongo/operation/write/command/insert.rb +22 -18
  85. data/lib/mongo/operation/write/command/update.rb +24 -9
  86. data/lib/mongo/operation/write/command/writable.rb +14 -1
  87. data/lib/mongo/operation/write/insert.rb +4 -1
  88. data/lib/mongo/operation/write/insert/result.rb +2 -2
  89. data/lib/mongo/operation/write/update.rb +7 -1
  90. data/lib/mongo/operation/write/write_command_enabled.rb +20 -3
  91. data/lib/mongo/protocol.rb +3 -0
  92. data/lib/mongo/protocol/bit_vector.rb +2 -2
  93. data/lib/mongo/protocol/compressed.rb +135 -0
  94. data/lib/mongo/protocol/delete.rb +8 -6
  95. data/lib/mongo/protocol/get_more.rb +8 -6
  96. data/lib/mongo/protocol/insert.rb +8 -6
  97. data/lib/mongo/protocol/kill_cursors.rb +8 -6
  98. data/lib/mongo/protocol/message.rb +31 -3
  99. data/lib/mongo/protocol/msg.rb +172 -0
  100. data/lib/mongo/protocol/query.rb +26 -6
  101. data/lib/mongo/protocol/registry.rb +76 -0
  102. data/lib/mongo/protocol/reply.rb +10 -5
  103. data/lib/mongo/protocol/serializers.rb +224 -0
  104. data/lib/mongo/protocol/update.rb +8 -6
  105. data/lib/mongo/retryable.rb +4 -2
  106. data/lib/mongo/server.rb +6 -3
  107. data/lib/mongo/server/connectable.rb +1 -1
  108. data/lib/mongo/server/connection.rb +30 -8
  109. data/lib/mongo/server/description.rb +25 -1
  110. data/lib/mongo/server/description/features.rb +4 -1
  111. data/lib/mongo/server/monitor.rb +5 -0
  112. data/lib/mongo/server/monitor/connection.rb +50 -2
  113. data/lib/mongo/server_selector/nearest.rb +10 -4
  114. data/lib/mongo/server_selector/primary.rb +20 -0
  115. data/lib/mongo/server_selector/primary_preferred.rb +10 -4
  116. data/lib/mongo/server_selector/secondary.rb +10 -4
  117. data/lib/mongo/server_selector/secondary_preferred.rb +24 -4
  118. data/lib/mongo/session.rb +180 -0
  119. data/lib/mongo/session/server_session.rb +73 -0
  120. data/lib/mongo/session/session_pool.rb +161 -0
  121. data/lib/mongo/uri.rb +11 -0
  122. data/lib/mongo/version.rb +1 -1
  123. data/mongo.gemspec +2 -1
  124. data/spec/mongo/auth/cr_spec.rb +12 -0
  125. data/spec/mongo/auth/ldap_spec.rb +2 -0
  126. data/spec/mongo/auth/scram/conversation_spec.rb +6 -6
  127. data/spec/mongo/auth/scram_spec.rb +25 -1
  128. data/spec/mongo/auth/user/view_spec.rb +268 -76
  129. data/spec/mongo/auth/x509_spec.rb +2 -0
  130. data/spec/mongo/bulk_write_spec.rb +435 -5
  131. data/spec/mongo/client_spec.rb +356 -39
  132. data/spec/mongo/cluster/app_metadata_spec.rb +2 -2
  133. data/spec/mongo/cluster_spec.rb +176 -0
  134. data/spec/mongo/collection/view/aggregation_spec.rb +33 -12
  135. data/spec/mongo/collection/view/builder/find_command_spec.rb +46 -6
  136. data/spec/mongo/collection/view/change_stream_spec.rb +814 -0
  137. data/spec/mongo/collection/view/map_reduce_spec.rb +94 -17
  138. data/spec/mongo/collection/view/readable_spec.rb +3 -12
  139. data/spec/mongo/collection_spec.rb +1048 -42
  140. data/spec/mongo/cursor/builder/get_more_command_spec.rb +19 -0
  141. data/spec/mongo/cursor_spec.rb +2 -2
  142. data/spec/mongo/database_spec.rb +50 -1
  143. data/spec/mongo/grid/fs_bucket_spec.rb +225 -137
  144. data/spec/mongo/grid/stream/read_spec.rb +2 -2
  145. data/spec/mongo/index/view_spec.rb +146 -8
  146. data/spec/mongo/monitoring/event/secure_spec.rb +42 -0
  147. data/spec/mongo/operation/read/query_spec.rb +2 -1
  148. data/spec/mongo/operation/specifiable_spec.rb +2 -2
  149. data/spec/mongo/operation/write/command/delete_spec.rb +96 -13
  150. data/spec/mongo/operation/write/command/insert_spec.rb +111 -12
  151. data/spec/mongo/operation/write/command/update_spec.rb +93 -10
  152. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  153. data/spec/mongo/operation/write/insert_spec.rb +1 -1
  154. data/spec/mongo/operation/write/update_spec.rb +1 -1
  155. data/spec/mongo/protocol/compressed_spec.rb +66 -0
  156. data/spec/mongo/protocol/delete_spec.rb +14 -0
  157. data/spec/mongo/protocol/get_more_spec.rb +14 -0
  158. data/spec/mongo/protocol/insert_spec.rb +14 -0
  159. data/spec/mongo/protocol/kill_cursors_spec.rb +14 -0
  160. data/spec/mongo/protocol/msg_spec.rb +499 -0
  161. data/spec/mongo/protocol/query_spec.rb +45 -0
  162. data/spec/mongo/protocol/registry_spec.rb +31 -0
  163. data/spec/mongo/protocol/reply_spec.rb +14 -0
  164. data/spec/mongo/protocol/update_spec.rb +14 -0
  165. data/spec/mongo/retryable_spec.rb +6 -2
  166. data/spec/mongo/sdam_spec.rb +4 -0
  167. data/spec/mongo/server/connection_spec.rb +4 -2
  168. data/spec/mongo/server/description_spec.rb +28 -1
  169. data/spec/mongo/session/server_session_spec.rb +16 -0
  170. data/spec/mongo/session/session_pool_spec.rb +194 -0
  171. data/spec/mongo/uri_spec.rb +31 -2
  172. data/spec/spec_helper.rb +104 -0
  173. data/spec/support/authorization.rb +6 -1
  174. data/spec/support/crud.rb +3 -1
  175. data/spec/support/crud/write.rb +6 -1
  176. data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +69 -0
  177. data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +63 -0
  178. data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +109 -0
  179. data/spec/support/sdam/rs/discover_arbiters.yml +1 -1
  180. data/spec/support/sdam/rs/discover_passives.yml +2 -2
  181. data/spec/support/sdam/rs/discover_primary.yml +1 -1
  182. data/spec/support/sdam/rs/discover_secondary.yml +1 -1
  183. data/spec/support/sdam/rs/discovery.yml +4 -4
  184. data/spec/support/sdam/rs/equal_electionids.yml +1 -0
  185. data/spec/support/sdam/rs/ghost_discovered.yml +1 -1
  186. data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +1 -1
  187. data/spec/support/sdam/rs/ls_timeout.yml +88 -0
  188. data/spec/support/sdam/rs/member_reconfig.yml +2 -2
  189. data/spec/support/sdam/rs/member_standalone.yml +2 -2
  190. data/spec/support/sdam/rs/new_primary.yml +2 -2
  191. data/spec/support/sdam/rs/new_primary_new_electionid.yml +3 -0
  192. data/spec/support/sdam/rs/new_primary_new_setversion.yml +3 -0
  193. data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +2 -2
  194. data/spec/support/sdam/rs/non_rs_member.yml +1 -1
  195. data/spec/support/sdam/rs/normalize_case.yml +1 -1
  196. data/spec/support/sdam/rs/null_election_id.yml +4 -0
  197. data/spec/support/sdam/rs/primary_becomes_standalone.yml +2 -2
  198. data/spec/support/sdam/rs/primary_changes_set_name.yml +2 -2
  199. data/spec/support/sdam/rs/primary_disconnect.yml +2 -2
  200. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +5 -0
  201. data/spec/support/sdam/rs/primary_disconnect_setversion.yml +5 -0
  202. data/spec/support/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +58 -0
  203. data/spec/support/sdam/rs/primary_reports_new_member.yml +4 -4
  204. data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +2 -2
  205. data/spec/support/sdam/rs/primary_wrong_set_name.yml +1 -1
  206. data/spec/support/sdam/rs/response_from_removed.yml +2 -2
  207. data/spec/support/sdam/rs/rsother_discovered.yml +1 -1
  208. data/spec/support/sdam/rs/sec_not_auth.yml +1 -1
  209. data/spec/support/sdam/rs/secondary_wrong_set_name.yml +1 -1
  210. data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +2 -2
  211. data/spec/support/sdam/rs/setversion_without_electionid.yml +2 -0
  212. data/spec/support/sdam/rs/stepdown_change_set_name.yml +2 -2
  213. data/spec/support/sdam/rs/unexpected_mongos.yml +1 -1
  214. data/spec/support/sdam/rs/use_setversion_without_electionid.yml +3 -0
  215. data/spec/support/sdam/rs/wrong_set_name.yml +1 -1
  216. data/spec/support/sdam/sharded/ls_timeout_mongos.yml +97 -0
  217. data/spec/support/sdam/sharded/mongos_disconnect.yml +3 -3
  218. data/spec/support/sdam/sharded/multiple_mongoses.yml +1 -1
  219. data/spec/support/sdam/sharded/non_mongos_removed.yml +1 -1
  220. data/spec/support/sdam/sharded/normalize_uri_case.yml +1 -1
  221. data/spec/support/sdam/single/direct_connection_external_ip.yml +1 -1
  222. data/spec/support/sdam/single/direct_connection_mongos.yml +1 -1
  223. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
  224. data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
  225. data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
  226. data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
  227. data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
  228. data/spec/support/sdam/single/ls_timeout_standalone.yml +35 -0
  229. data/spec/support/sdam/single/not_ok_response.yml +1 -1
  230. data/spec/support/sdam/single/standalone_removed.yml +1 -1
  231. data/spec/support/sdam/single/unavailable_seed.yml +1 -1
  232. data/spec/support/server_discovery_and_monitoring.rb +4 -0
  233. data/spec/support/shared/session.rb +236 -0
  234. metadata +53 -15
  235. metadata.gz.sig +0 -0
@@ -50,7 +50,7 @@ module Mongo
50
50
  def_delegators :view, :collection, :read, :cluster
51
51
 
52
52
  # Delegate necessary operations to the collection.
53
- def_delegators :collection, :database
53
+ def_delegators :collection, :database, :client
54
54
 
55
55
  # Iterate through documents returned by the map/reduce.
56
56
  #
@@ -66,10 +66,10 @@ module Mongo
66
66
  # @yieldparam [ Hash ] Each matching document.
67
67
  def each
68
68
  @cursor = nil
69
- write_with_retry do
70
- server = read.select_server(cluster, false)
71
- result = send_initial_query(server)
72
- @cursor = Cursor.new(view, result, server)
69
+ session = client.send(:get_session, view.options)
70
+ write_with_retry(session, Proc.new { server_selector.select_server(cluster, false) }) do |server|
71
+ result = send_initial_query(server, session)
72
+ @cursor = Cursor.new(view, result, server, session: session)
73
73
  end
74
74
  @cursor.each do |doc|
75
75
  yield doc
@@ -182,20 +182,24 @@ module Mongo
182
182
 
183
183
  private
184
184
 
185
+ def server_selector
186
+ @view.send(:server_selector)
187
+ end
188
+
185
189
  def inline?
186
190
  out.nil? || out == { inline: 1 } || out == { INLINE => 1 }
187
191
  end
188
192
 
189
- def map_reduce_spec
190
- Builder::MapReduce.new(map, reduce, view, options).specification
193
+ def map_reduce_spec(session)
194
+ Builder::MapReduce.new(map, reduce, view, options.merge(session: session)).specification
191
195
  end
192
196
 
193
197
  def new(options)
194
198
  MapReduce.new(view, map, reduce, options)
195
199
  end
196
200
 
197
- def initial_query_op
198
- Operation::Commands::MapReduce.new(map_reduce_spec)
201
+ def initial_query_op(session)
202
+ Operation::Commands::MapReduce.new(map_reduce_spec(session))
199
203
  end
200
204
 
201
205
  def valid_server?(server)
@@ -206,34 +210,34 @@ module Mongo
206
210
  out.respond_to?(:keys) && out.keys.first.to_s.downcase == INLINE
207
211
  end
208
212
 
209
- def send_initial_query(server)
213
+ def send_initial_query(server, session)
210
214
  unless valid_server?(server)
211
215
  log_warn(REROUTE)
212
216
  server = cluster.next_primary(false)
213
217
  end
214
218
  validate_collation!(server)
215
- result = initial_query_op.execute(server)
216
- inline? ? result : send_fetch_query(server)
219
+ result = initial_query_op(session).execute(server)
220
+ inline? ? result : send_fetch_query(server, session)
217
221
  end
218
222
 
219
223
  def fetch_query_spec
220
224
  Builder::MapReduce.new(map, reduce, view, options).query_specification
221
225
  end
222
226
 
223
- def find_command_spec
224
- Builder::MapReduce.new(map, reduce, view, options).command_specification
227
+ def find_command_spec(session)
228
+ Builder::MapReduce.new(map, reduce, view, options.merge(session: session)).command_specification
225
229
  end
226
230
 
227
- def fetch_query_op(server)
231
+ def fetch_query_op(server, session)
228
232
  if server.features.find_command_enabled?
229
- Operation::Commands::Find.new(find_command_spec)
233
+ Operation::Commands::Find.new(find_command_spec(session))
230
234
  else
231
235
  Operation::Read::Query.new(fetch_query_spec)
232
236
  end
233
237
  end
234
238
 
235
- def send_fetch_query(server)
236
- fetch_query_op(server).execute(server)
239
+ def send_fetch_query(server, session)
240
+ fetch_query_op(server, session).execute(server)
237
241
  end
238
242
 
239
243
  def validate_collation!(server)
@@ -133,20 +133,24 @@ module Mongo
133
133
  cmd[:limit] = opts[:limit] if opts[:limit]
134
134
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
135
135
  cmd[:readConcern] = collection.read_concern if collection.read_concern
136
- preference = ServerSelector.get(opts[:read] || read)
136
+ read_pref = opts[:read] || read_preference
137
+ selector = ServerSelector.get(read_pref || server_selector)
137
138
  read_with_retry do
138
- server = preference.select_server(cluster, false)
139
+ server = selector.select_server(cluster, false)
139
140
  apply_collation!(cmd, server, opts)
140
- Operation::Commands::Command.new({
141
- :selector => cmd,
142
- :db_name => database.name,
143
- :options => { :limit => -1 },
144
- :read => preference,
145
- }).execute(server).n.to_i
146
-
141
+ with_session do |session|
142
+ Operation::Commands::Command.new({
143
+ :selector => cmd,
144
+ :db_name => database.name,
145
+ :options => {:limit => -1},
146
+ :read => read_pref,
147
+ :session => session
148
+ }).execute(server)
149
+ end.n.to_i
147
150
  end
148
151
  end
149
152
 
153
+
150
154
  # Get a list of distinct values for a specific field.
151
155
  #
152
156
  # @example Get the distinct values.
@@ -169,17 +173,20 @@ module Mongo
169
173
  :query => filter }
170
174
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
171
175
  cmd[:readConcern] = collection.read_concern if collection.read_concern
172
- preference = ServerSelector.get(opts[:read] || read)
176
+ read_pref = opts[:read] || read_preference
177
+ selector = ServerSelector.get(read_pref || server_selector)
173
178
  read_with_retry do
174
- server = preference.select_server(cluster, false)
179
+ server = selector.select_server(cluster, false)
175
180
  apply_collation!(cmd, server, opts)
176
- Operation::Commands::Command.new({
177
- :selector => cmd,
178
- :db_name => database.name,
179
- :options => { :limit => -1 },
180
- :read => preference
181
- }).execute(server).first['values']
182
-
181
+ with_session do |session|
182
+ Operation::Commands::Command.new({
183
+ :selector => cmd,
184
+ :db_name => database.name,
185
+ :options => {:limit => -1},
186
+ :read => read_pref,
187
+ :session => session
188
+ }).execute(server)
189
+ end.first['values']
183
190
  end
184
191
  end
185
192
 
@@ -313,9 +320,8 @@ module Mongo
313
320
  #
314
321
  # @since 2.0.0
315
322
  def read(value = nil)
316
- return default_read if value.nil?
317
- selector = ServerSelector.get(value)
318
- configure(:read, selector)
323
+ return read_preference if value.nil?
324
+ configure(:read, value)
319
325
  end
320
326
 
321
327
  # Set whether to return only the indexed field or fields.
@@ -457,33 +463,41 @@ module Mongo
457
463
  configure(:collation, doc)
458
464
  end
459
465
 
460
- def default_read
461
- options[:read] || collection.read_preference
466
+ def read_preference
467
+ @read_preference ||= (options[:read] || collection.read_preference)
468
+ end
469
+
470
+ def server_selector
471
+ @server_selector ||= ServerSelector.get(read_preference || collection.server_selector)
462
472
  end
463
473
 
464
474
  def parallel_scan(cursor_count, options = {})
465
- server = read.select_server(cluster, false)
475
+ session = client.send(:get_session, @options)
476
+ server = server_selector.select_server(cluster, false)
466
477
  cmd = Operation::Commands::ParallelScan.new({
467
478
  :coll_name => collection.name,
468
479
  :db_name => database.name,
469
480
  :cursor_count => cursor_count,
470
- :read_concern => collection.read_concern
481
+ :read_concern => collection.read_concern,
482
+ :session => session
471
483
  }.merge!(options))
472
484
  cmd.execute(server).cursor_ids.map do |cursor_id|
473
485
  result = if server.features.find_command_enabled?
474
- Operation::Commands::GetMore.new({
475
- :selector => { :getMore => cursor_id, :collection => collection.name },
476
- :db_name => database.name
477
- }).execute(server)
478
- else
479
- Operation::Read::GetMore.new({
480
- :to_return => 0,
481
- :cursor_id => cursor_id,
482
- :db_name => database.name,
483
- :coll_name => collection.name
484
- }).execute(server)
486
+ Operation::Commands::GetMore.new({
487
+ :selector => {:getMore => cursor_id,
488
+ :collection => collection.name},
489
+ :db_name => database.name,
490
+ :session => session
491
+ }).execute(server)
492
+ else
493
+ Operation::Read::GetMore.new({
494
+ :to_return => 0,
495
+ :cursor_id => cursor_id,
496
+ :db_name => database.name,
497
+ :coll_name => collection.name
498
+ }).execute(server)
485
499
  end
486
- Cursor.new(self, result, server)
500
+ Cursor.new(self, result, server, session: session)
487
501
  end
488
502
  end
489
503
 
@@ -21,6 +21,11 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  module Writable
23
23
 
24
+ # The array filters field constant.
25
+ #
26
+ # @since 2.5.0
27
+ ARRAY_FILTERS = 'array_filters'.freeze
28
+
24
29
  # Finds a single document in the database via findAndModify and deletes
25
30
  # it, returning the original document.
26
31
  #
@@ -41,15 +46,16 @@ module Mongo
41
46
  cmd[:maxTimeMS] = max_time_ms if max_time_ms
42
47
  cmd[:writeConcern] = write_concern.options if write_concern
43
48
 
44
- write_with_retry do
45
- server = next_primary
46
- apply_collation!(cmd, server, opts)
47
-
48
- Operation::Commands::Command.new({
49
- :selector => cmd,
50
- :db_name => database.name
51
- }).execute(server).first['value']
52
- end
49
+ with_session do |session|
50
+ write_with_retry(session, Proc.new { next_primary }) do |server|
51
+ apply_collation!(cmd, server, opts)
52
+ Operation::Commands::Command.new({
53
+ :selector => cmd,
54
+ :db_name => database.name,
55
+ :session => session
56
+ }).execute(server)
57
+ end
58
+ end.first['value']
53
59
  end
54
60
 
55
61
  # Finds a single document and replaces it.
@@ -67,7 +73,7 @@ module Mongo
67
73
  # @option opts [ true, false ] :upsert Whether to upsert if the document doesn't exist.
68
74
  # @option opts [ true, false ] :bypass_document_validation Whether or
69
75
  # not to skip document level validation.
70
- # @option options [ Hash ] :write_concern The write concern options.
76
+ # @option opts [ Hash ] :write_concern The write concern options.
71
77
  # Defaults to the collection's write concern.
72
78
  # @option opts [ Hash ] :collation The collation to use.
73
79
  #
@@ -93,6 +99,8 @@ module Mongo
93
99
  # @option opts [ Hash ] :write_concern The write concern options.
94
100
  # Defaults to the collection's write concern.
95
101
  # @option opts [ Hash ] :collation The collation to use.
102
+ # @options opts [ Array ] :array_filters A set of filters specifying to which array elements
103
+ # an update should apply.
96
104
  #
97
105
  # @return [ BSON::Document ] The document.
98
106
  #
@@ -108,15 +116,17 @@ module Mongo
108
116
  cmd[:bypassDocumentValidation] = !!opts[:bypass_document_validation]
109
117
  cmd[:writeConcern] = write_concern.options if write_concern
110
118
 
111
- value = write_with_retry do
112
- server = next_primary
113
- apply_collation!(cmd, server, opts)
114
-
115
- Operation::Commands::Command.new({
116
- :selector => cmd,
117
- :db_name => database.name
118
- }).execute(server).first['value']
119
- end
119
+ value = with_session do |session|
120
+ write_with_retry(session, Proc.new { next_primary }) do |server|
121
+ apply_collation!(cmd, server, opts)
122
+ apply_array_filters!(cmd, server, opts)
123
+ Operation::Commands::Command.new(
124
+ :selector => cmd,
125
+ :db_name => database.name,
126
+ :session => session
127
+ ).execute(server)
128
+ end
129
+ end.first['value']
120
130
  value unless value.nil? || value.empty?
121
131
  end
122
132
 
@@ -182,6 +192,8 @@ module Mongo
182
192
  # @option opts [ true, false ] :upsert Whether to upsert if the
183
193
  # document doesn't exist.
184
194
  # @option opts [ Hash ] :collation The collation to use.
195
+ # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
196
+ # an update should apply.
185
197
  #
186
198
  # @return [ Result ] The response from the database.
187
199
  #
@@ -201,6 +213,8 @@ module Mongo
201
213
  # @option opts [ true, false ] :upsert Whether to upsert if the
202
214
  # document doesn't exist.
203
215
  # @option opts [ Hash ] :collation The collation to use.
216
+ # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
217
+ # an update should apply.
204
218
  #
205
219
  # @return [ Result ] The response from the database.
206
220
  #
@@ -213,16 +227,18 @@ module Mongo
213
227
 
214
228
  def remove(value, opts = {})
215
229
  delete_doc = { Operation::Q => filter, Operation::LIMIT => value }
216
- write_with_retry do
217
- server = next_primary
218
- apply_collation!(delete_doc, server, opts)
219
-
220
- Operation::Write::Delete.new(
221
- :delete => delete_doc,
222
- :db_name => collection.database.name,
223
- :coll_name => collection.name,
224
- :write_concern => collection.write_concern
225
- ).execute(server)
230
+
231
+ with_session do |session|
232
+ write_with_retry(session, Proc.new { next_primary }) do |server|
233
+ apply_collation!(delete_doc, server, opts)
234
+ Operation::Write::Delete.new(
235
+ :delete => delete_doc,
236
+ :db_name => collection.database.name,
237
+ :coll_name => collection.name,
238
+ :write_concern => collection.write_concern,
239
+ :session => session
240
+ ).execute(server)
241
+ end
226
242
  end
227
243
  end
228
244
 
@@ -231,17 +247,33 @@ module Mongo
231
247
  Operation::U => spec,
232
248
  Operation::MULTI => multi,
233
249
  Operation::UPSERT => !!opts[:upsert] }
234
- write_with_retry do
235
- server = next_primary
236
- apply_collation!(update_doc, server, opts)
237
-
238
- Operation::Write::Update.new(
239
- :update => update_doc,
240
- :db_name => collection.database.name,
241
- :coll_name => collection.name,
242
- :write_concern => collection.write_concern,
243
- :bypass_document_validation => !!opts[:bypass_document_validation]
244
- ).execute(server)
250
+
251
+ with_session do |session|
252
+ write_with_retry(session, Proc.new { next_primary }) do |server|
253
+ apply_collation!(update_doc, server, opts)
254
+ apply_array_filters!(update_doc, server, opts)
255
+ Operation::Write::Update.new(
256
+ :update => update_doc,
257
+ :db_name => collection.database.name,
258
+ :coll_name => collection.name,
259
+ :write_concern => collection.write_concern,
260
+ :bypass_document_validation => !!opts[:bypass_document_validation],
261
+ :session => session
262
+ ).execute(server)
263
+ end
264
+ end
265
+ end
266
+
267
+ def apply_array_filters!(doc, server, opts = {})
268
+ if filters = opts[:array_filters] || opts[ARRAY_FILTERS]
269
+ validate_array_filters!(server, filters)
270
+ doc[:arrayFilters] = filters
271
+ end
272
+ end
273
+
274
+ def validate_array_filters!(server, filters)
275
+ if filters && !server.features.array_filters_enabled?
276
+ raise Error::UnsupportedArrayFilters.new
245
277
  end
246
278
  end
247
279
  end
data/lib/mongo/cursor.rb CHANGED
@@ -35,7 +35,7 @@ module Mongo
35
35
  include Enumerable
36
36
  include Retryable
37
37
 
38
- def_delegators :@view, :collection, :limit
38
+ def_delegators :@view, :collection
39
39
  def_delegators :collection, :client, :database
40
40
  def_delegators :@server, :cluster
41
41
 
@@ -50,15 +50,21 @@ module Mongo
50
50
  # @param [ CollectionView ] view The +CollectionView+ defining the query.
51
51
  # @param [ Operation::Result ] result The result of the first execution.
52
52
  # @param [ Server ] server The server this cursor is locked to.
53
+ # @param [ Hash ] options The cursor options.
54
+ #
55
+ # @option options [ true, false ] :disable_retry Whether to disable retrying on
56
+ # error when sending getmores.
53
57
  #
54
58
  # @since 2.0.0
55
- def initialize(view, result, server)
59
+ def initialize(view, result, server, options = {})
56
60
  @view = view
57
61
  @server = server
58
62
  @initial_result = result
59
63
  @remaining = limit if limited?
60
64
  @cursor_id = result.cursor_id
61
65
  @coll_name = nil
66
+ @options = options
67
+ @session = @options[:session]
62
68
  register
63
69
  ObjectSpace.define_finalizer(self, self.class.finalize(result.cursor_id,
64
70
  cluster,
@@ -185,14 +191,18 @@ module Mongo
185
191
  end
186
192
 
187
193
  def get_more
188
- read_with_retry do
194
+ if @options[:disable_retry]
189
195
  process(get_more_operation.execute(@server))
196
+ else
197
+ read_with_retry do
198
+ process(get_more_operation.execute(@server))
199
+ end
190
200
  end
191
201
  end
192
202
 
193
203
  def get_more_operation
194
204
  if @server.features.find_command_enabled?
195
- Operation::Commands::GetMore.new(Builder::GetMoreCommand.new(self).specification)
205
+ Operation::Commands::GetMore.new(Builder::GetMoreCommand.new(self, @session).specification)
196
206
  else
197
207
  Operation::Read::GetMore.new(Builder::OpGetMore.new(self).specification)
198
208
  end
@@ -203,6 +213,13 @@ module Mongo
203
213
  read_with_one_retry do
204
214
  kill_cursors_operation.execute(@server)
205
215
  end
216
+ ensure
217
+ end_session
218
+ @cursor_id = 0
219
+ end
220
+
221
+ def end_session
222
+ @session.end_implicit_session if @session
206
223
  end
207
224
 
208
225
  def kill_cursors_operation
@@ -241,6 +258,10 @@ module Mongo
241
258
  limited? && batch_size >= @remaining
242
259
  end
243
260
 
261
+ def limit
262
+ @view.send(:limit)
263
+ end
264
+
244
265
  def register
245
266
  cluster.register_cursor(@cursor_id)
246
267
  end