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
data/lib/mongo/client.rb CHANGED
@@ -122,7 +122,7 @@ module Mongo
122
122
  # attempt a connection.
123
123
  # @option options [ Hash ] :read The read preference options. They consist of a
124
124
  # mode specified as a symbol, an array of hashes known as tag_sets,
125
- # and two timing options: local_threshold and server_selection_timeout.
125
+ # and local_threshold.
126
126
  # :mode can be one of :secondary, :secondary_preferred, :primary,
127
127
  # :primary_preferred, :nearest.
128
128
  # @option options [ Array<Hash, String> ] :roles The list of roles for the
@@ -148,6 +148,9 @@ module Mongo
148
148
  # Integer, :fsync => Boolean, :j => Boolean.
149
149
  # @option options [ true, false ] :monitoring Initializes a client without
150
150
  # any default monitoring if false is provided.
151
+ # @option options [ Logger ] :logger A custom logger if desired.
152
+ # @option options [ true, false ] :truncate_logs Whether to truncate the
153
+ # logs at the default 250 characters.
151
154
  #
152
155
  # @since 2.0.0
153
156
  def initialize(addresses_or_uri, options = {})
@@ -182,7 +185,7 @@ module Mongo
182
185
  #
183
186
  # @since 2.0.0
184
187
  def read_preference
185
- @read_preference ||= ServerSelector.get(options[:read] || {}, options)
188
+ @read_preference ||= ServerSelector.get((options[:read] || {}).merge(options))
186
189
  end
187
190
 
188
191
  # Use the database with the provided name. This will switch the current
@@ -295,7 +298,7 @@ module Mongo
295
298
  end
296
299
 
297
300
  def create_from_uri(connection_string, opts = {})
298
- uri = URI.new(connection_string)
301
+ uri = URI.new(connection_string, opts)
299
302
  @options = Database::DEFAULT_OPTIONS.merge(uri.client_options.merge(opts)).freeze
300
303
  @cluster = Cluster.new(uri.servers, @monitoring, options)
301
304
  @database = Database.new(self, options[:database], options)
@@ -303,6 +306,7 @@ module Mongo
303
306
 
304
307
  def initialize_copy(original)
305
308
  @options = original.options.dup
309
+ @monitoring = Monitoring.new(@options)
306
310
  @database = nil
307
311
  @read_preference = nil
308
312
  @write_concern = nil
data/lib/mongo/cluster.rb CHANGED
@@ -65,7 +65,7 @@ module Mongo
65
65
  address = Address.new(host)
66
66
  if !addresses.include?(address)
67
67
  if addition_allowed?(address)
68
- log_debug([ "Adding #{address.to_s} to the cluster." ])
68
+ log_debug("Adding #{address.to_s} to the cluster.")
69
69
  @update_lock.synchronize { @addresses.push(address) }
70
70
  server = Server.new(address, self, @monitoring, event_listeners, options)
71
71
  @update_lock.synchronize { @servers.push(server) }
@@ -125,7 +125,7 @@ module Mongo
125
125
  #
126
126
  # @since 2.0.0
127
127
  def next_primary
128
- ServerSelector.get({ mode: :primary }, options).select_server(self)
128
+ ServerSelector.get({ mode: :primary }.merge(options)).select_server(self)
129
129
  end
130
130
 
131
131
  # Elect a primary server from the description that has just changed to a
@@ -166,7 +166,7 @@ module Mongo
166
166
  #
167
167
  # @since 2.0.0
168
168
  def remove(host)
169
- log_debug([ "#{host} being removed from the cluster." ])
169
+ log_debug("#{host} being removed from the cluster.")
170
170
  address = Address.new(host)
171
171
  removed_servers = @servers.select { |s| s.address == address }
172
172
  @update_lock.synchronize { @servers = @servers - removed_servers }
@@ -61,7 +61,7 @@ module Mongo
61
61
  def elect_primary(description, servers)
62
62
  if description.replica_set_name == replica_set_name
63
63
  unless detect_stale_primary!(description)
64
- log_debug([ "Server #{description.address.to_s} elected as primary in #{replica_set_name}." ])
64
+ log_debug("Server #{description.address.to_s} elected as primary in #{replica_set_name}.")
65
65
  servers.each do |server|
66
66
  if server.primary? && server.address != description.address
67
67
  server.description.unknown!
@@ -70,9 +70,10 @@ module Mongo
70
70
  update_max_election_id(description)
71
71
  end
72
72
  else
73
- log_warn([
74
- "Server #{description.address.to_s} in incorrect replica set: #{description.replica_set_name}."
75
- ])
73
+ log_warn(
74
+ "Server #{description.address.to_s} has incorrect replica set name: " +
75
+ "'#{description.replica_set_name}'. The current replica set name is '#{replica_set_name}'."
76
+ )
76
77
  end
77
78
  self
78
79
  end
@@ -157,8 +158,9 @@ module Mongo
157
158
  def remove_hosts?(description)
158
159
  !description.config.empty? &&
159
160
  (description.primary? ||
160
- description.hosts.empty? ||
161
- !member_of_this_set?(description))
161
+ description.me_mismatch? ||
162
+ description.hosts.empty? ||
163
+ !member_of_this_set?(description))
162
164
  end
163
165
 
164
166
  # Whether a specific server in the cluster can be removed, given a description.
@@ -55,7 +55,7 @@ module Mongo
55
55
  # @return [ Sharded, ReplicaSet ] The new topology.
56
56
  def elect_primary(description, servers)
57
57
  if description.mongos?
58
- log_debug([ "Mongos #{description.address.to_s} discovered." ])
58
+ log_debug("Mongos #{description.address.to_s} discovered.")
59
59
  Sharded.new(options)
60
60
  else
61
61
  initialize_replica_set(description, servers)
@@ -204,7 +204,10 @@ module Mongo
204
204
  private
205
205
 
206
206
  def initialize_replica_set(description, servers)
207
- log_debug([ "Server #{description.address.to_s} discovered as primary." ])
207
+ log_debug(
208
+ "Server #{description.address.to_s} discovered as primary in replica set: " +
209
+ "'#{description.replica_set_name}'. Changing topology to replica set."
210
+ )
208
211
  servers.each do |server|
209
212
  if server.standalone? && server.address != description.address
210
213
  server.description.unknown!
@@ -12,6 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require 'mongo/bulk_write'
15
16
  require 'mongo/collection/view'
16
17
 
17
18
  module Mongo
@@ -33,7 +34,7 @@ module Mongo
33
34
  attr_reader :options
34
35
 
35
36
  # Get client, cluster, read preference, and write concern from client.
36
- def_delegators :database, :client, :cluster, :read_preference, :write_concern
37
+ def_delegators :database, :client, :cluster
37
38
 
38
39
  # Delegate to the cluster for the next primary.
39
40
  def_delegators :cluster, :next_primary
@@ -41,6 +42,11 @@ module Mongo
41
42
  # Convenience delegators to find.
42
43
  def_delegators :find, :parallel_scan
43
44
 
45
+ # Options that can be updated on a new Collection instance via the #with method.
46
+ #
47
+ # @since 2.1.0
48
+ CHANGEABLE_OPTIONS = [ :read, :write ]
49
+
44
50
  # Check if a collection is equal to another object. Will check the name and
45
51
  # the database for equality.
46
52
  #
@@ -74,6 +80,53 @@ module Mongo
74
80
  @options = options.freeze
75
81
  end
76
82
 
83
+ # Get the read preference on this collection.
84
+ #
85
+ # @example Get the read preference.
86
+ # collection.read_preference
87
+ #
88
+ # @return [ Mongo::ServerSelector ] The read preference.
89
+ #
90
+ # @since 2.0.0
91
+ def read_preference
92
+ @read_preference ||= options[:read] ? ServerSelector.get(client.options.merge(options[:read])) :
93
+ database.read_preference
94
+ end
95
+
96
+ # Get the write concern on this collection.
97
+ #
98
+ # @example Get the write concern.
99
+ # collection.write_concern
100
+ #
101
+ # @return [ Mongo::WriteConcern ] The write concern.
102
+ #
103
+ # @since 2.0.0
104
+ def write_concern
105
+ @write_concern ||= options[:write] ? WriteConcern.get(options[:write]) :
106
+ database.write_concern
107
+ end
108
+
109
+ # Provides a new collection with either a new read preference or new write concern
110
+ # merged over the existing read preference / write concern.
111
+ #
112
+ # @example Get a collection with changed read preference.
113
+ # collection.with(:read => { :mode => :primary_preferred })
114
+ #
115
+ # @example Get a collection with changed write concern.
116
+ # collection.with(:write => { w: 3 })
117
+
118
+ # @param [ Hash ] new_options The new options to use.
119
+ #
120
+ # @return [ Mongo::Collection ] A new collection instance.
121
+ #
122
+ # @since 2.1.0
123
+ def with(new_options)
124
+ new_options.keys.each do |k|
125
+ raise Error::UnchangeableCollectionOption.new(k) unless CHANGEABLE_OPTIONS.include?(k)
126
+ end
127
+ Collection.new(database, name, options.merge(new_options))
128
+ end
129
+
77
130
  # Is the collection capped?
78
131
  #
79
132
  # @example Is the collection capped?
@@ -286,7 +339,7 @@ module Mongo
286
339
  # @example Execute a bulk write.
287
340
  # collection.bulk_write(operations, options)
288
341
  #
289
- # @param [ Array<Hash> ] operations The operations.
342
+ # @param [ Array<Hash> ] requests The bulk write requests.
290
343
  # @param [ Hash ] options The options.
291
344
  #
292
345
  # @option options [ true, false ] :ordered Whether the operations
@@ -297,8 +350,8 @@ module Mongo
297
350
  # @return [ BulkWrite::Result ] The result of the operation.
298
351
  #
299
352
  # @since 2.0.0
300
- def bulk_write(operations, options = {})
301
- BulkWrite.get(self, operations, options).execute
353
+ def bulk_write(requests, options = {})
354
+ BulkWrite.new(self, requests, options).execute
302
355
  end
303
356
 
304
357
  # Remove a document from the collection.
@@ -329,6 +382,24 @@ module Mongo
329
382
  find(filter).delete_many
330
383
  end
331
384
 
385
+ # Execute a parallel scan on the collection view.
386
+ #
387
+ # Returns a list of up to cursor_count cursors that can be iterated concurrently.
388
+ # As long as the collection is not modified during scanning, each document appears once
389
+ # in one of the cursors' result sets.
390
+ #
391
+ # @example Execute a parallel collection scan.
392
+ # collection.parallel_scan(2)
393
+ #
394
+ # @param [ Integer ] cursor_count The max number of cursors to return.
395
+ #
396
+ # @return [ Array<Cursor> ] An array of cursors.
397
+ #
398
+ # @since 2.1
399
+ def parallel_scan(cursor_count)
400
+ find.send(:parallel_scan, cursor_count)
401
+ end
402
+
332
403
  # Replaces a single document in the collection with the new document.
333
404
  #
334
405
  # @example Replace a single document.
@@ -127,8 +127,7 @@ module Mongo
127
127
  def initialize(collection, selector = {}, options = {})
128
128
  validate_doc!(selector)
129
129
  @collection = collection
130
- @selector = selector.dup
131
- @options = options.dup
130
+ setup(selector, options)
132
131
  end
133
132
 
134
133
  # Get a human-readable string representation of +View+.
@@ -25,6 +25,7 @@ module Mongo
25
25
  include Immutable
26
26
  include Iterable
27
27
  include Explainable
28
+ include Loggable
28
29
 
29
30
  # @return [ View ] view The collection view.
30
31
  attr_reader :view
@@ -132,16 +133,20 @@ module Mongo
132
133
  Operation::Aggregate.new(aggregate_spec)
133
134
  end
134
135
 
136
+ def valid_server?(server)
137
+ server.standalone? || server.mongos? || server.primary? || secondary_ok?
138
+ end
139
+
140
+ def secondary_ok?
141
+ pipeline.none? { |op| op.key?('$out') || op.key?(:$out) }
142
+ end
143
+
135
144
  def send_initial_query(server)
136
- begin
137
- initial_query_op.execute(server.context)
138
- rescue Mongo::Error::NeedPrimaryServer
139
- log_warn([
140
- 'Rerouting the Aggregation operation to the primary server.'
141
- ])
142
- server = ServerSelector.get(mode: :primary).select_server(cluster)
143
- initial_query_op.execute(server.context)
145
+ unless valid_server?(server)
146
+ log_warn('Rerouting the Aggregation operation to the primary server.')
147
+ server = cluster.next_primary
144
148
  end
149
+ initial_query_op.execute(server.context)
145
150
  end
146
151
  end
147
152
  end
@@ -22,14 +22,14 @@ module Mongo
22
22
 
23
23
  private
24
24
 
25
- # @api private
26
- #
27
- # @note In the including class, the method #immutable needs to be
28
- # implemented in order to define how a new class of that type needs to
29
- # be instantiated.
30
25
  def configure(field, value)
31
26
  return options[field] if value.nil?
32
- new(options.merge(field => value))
27
+ new(options.merge(field => value, :modifiers => @modifiers))
28
+ end
29
+
30
+ def configure_modifier(field, value)
31
+ return @modifiers[Readable::SPECIAL_FIELDS[field]] if value.nil?
32
+ new(options.merge(:modifiers => @modifiers.merge(Readable::SPECIAL_FIELDS[field] => value)))
33
33
  end
34
34
 
35
35
  def configure_flag(flag)
@@ -36,12 +36,21 @@ module Mongo
36
36
  # @yieldparam [ Hash ] Each matching document.
37
37
  def each
38
38
  server = read.select_server(cluster)
39
- initial_query = send_initial_query(server)
40
- cursor = Cursor.new(view, initial_query, server).to_enum
41
- cursor.each do |doc|
39
+ @cursor = Cursor.new(view, send_initial_query(server), server)
40
+ @cursor.each do |doc|
42
41
  yield doc
43
42
  end if block_given?
44
- cursor
43
+ @cursor.to_enum
44
+ end
45
+
46
+ # Stop the iteration by sending a KillCursors command to the server.
47
+ #
48
+ # @example Stop the iteration.
49
+ # view.close_query
50
+ #
51
+ # @since 2.1.0
52
+ def close_query
53
+ @cursor.send(:kill_cursors) if @cursor
45
54
  end
46
55
  end
47
56
  end
@@ -25,6 +25,7 @@ module Mongo
25
25
  include Enumerable
26
26
  include Immutable
27
27
  include Iterable
28
+ include Loggable
28
29
 
29
30
  # @return [ View ] view The collection view.
30
31
  attr_reader :view
@@ -158,12 +159,16 @@ module Mongo
158
159
  :mapreduce => collection.name,
159
160
  :map => map,
160
161
  :reduce => reduce,
161
- :query => view.selector[:$query] || view.selector,
162
+ :query => view.modifiers[:$query] || view.selector,
162
163
  :out => { inline: 1 }
163
- }.merge(options).merge(view.options)
164
+ }.merge(options).merge(view_options)
164
165
  }
165
166
  end
166
167
 
168
+ def view_options
169
+ view.sort ? view.options.merge(:sort => view.sort) : view.options
170
+ end
171
+
167
172
  def new(options)
168
173
  MapReduce.new(view, map, reduce, options)
169
174
  end
@@ -172,29 +177,29 @@ module Mongo
172
177
  Operation::MapReduce.new(map_reduce_spec)
173
178
  end
174
179
 
180
+ def valid_server?(server)
181
+ server.standalone? || server.mongos? || server.primary? || secondary_ok?
182
+ end
183
+
184
+ def secondary_ok?
185
+ out.respond_to?(:keys) &&
186
+ out.keys.first.to_s.downcase == 'inline'
187
+ end
188
+
175
189
  def send_initial_query(server)
176
- result =
177
- begin
178
- initial_query_op.execute(server.context)
179
- rescue Mongo::Error::NeedPrimaryServer
180
- log_warn([
181
- 'Rerouting the MapReduce operation to the primary server.'
182
- ])
183
- server = ServerSelector.get(mode: :primary).select_server(cluster)
184
- initial_query_op.execute(server.context)
185
- end
186
- if inline?
187
- result
188
- else
189
- send_fetch_query(server)
190
+ unless valid_server?(server)
191
+ log_warn('Rerouting the MapReduce operation to the primary server.')
192
+ server = cluster.next_primary
190
193
  end
194
+ result = initial_query_op.execute(server.context)
195
+ inline? ? result : send_fetch_query(server)
191
196
  end
192
197
 
193
198
  def fetch_query_spec
194
199
  { :selector => {},
195
200
  :options => {},
196
201
  :db_name => database.name,
197
- :coll_name => out.values.first }
202
+ :coll_name => out.respond_to?(:keys) ? out.values.first : out }
198
203
  end
199
204
 
200
205
  def fetch_query_op
@@ -21,20 +21,21 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  module Readable
23
23
 
24
- # Special fields and their getters for the query selector.
24
+ # Special fields and their option names for the query selector.
25
25
  #
26
26
  # @since 2.0.0
27
27
  SPECIAL_FIELDS = {
28
- :$query => :selector,
29
- :$readPreference => :read_pref_formatted,
30
- :$orderby => :sort,
31
- :$hint => :hint,
32
- :$comment => :comment,
33
- :$snapshot => :snapshot,
34
- :$maxScan => :max_scan,
35
- :$maxTimeMS => :max_time_ms,
36
- :$showDiskLoc => :show_disk_loc,
37
- :$explain => :explained?
28
+ :sort => :$orderby,
29
+ :hint => :$hint,
30
+ :comment => :$comment,
31
+ :snapshot => :$snapshot,
32
+ :max_scan => :$maxScan,
33
+ :max_value => :$max,
34
+ :min_value => :$min,
35
+ :max_time_ms => :$maxTimeMS,
36
+ :return_key => :$returnKey,
37
+ :show_disk_loc => :$showDiskLoc,
38
+ :explain => :$explain
38
39
  }.freeze
39
40
 
40
41
  # Options to cursor flags mapping.
@@ -65,35 +66,6 @@ module Mongo
65
66
  Aggregation.new(self, pipeline, options)
66
67
  end
67
68
 
68
- # Execute a parallel scan on the collection view.
69
- # Returns a list of up to cursor_count cursors that can be iterated concurrently.
70
- # As long as the collection is not modified during scanning, each document appears once
71
- # in one of the cursors' result sets.
72
- #
73
- # @example Execute a parallel collection scan.
74
- # view.parallel_scan(2)
75
- #
76
- # @param [ Integer ] cursor_count The max number of cursors to return.
77
- #
78
- # @return [ Array<Cursor> ] An array of cursors.
79
- #
80
- # @since 2.1
81
- def parallel_scan(cursor_count)
82
- server = read.select_server(cluster)
83
- Operation::ParallelScan.new(
84
- :coll_name => collection.name,
85
- :db_name => database.name,
86
- :cursor_count => cursor_count
87
- ).execute(server.context).cursor_ids.map do |cursor_id|
88
- result = Operation::Read::GetMore.new({ :to_return => 0,
89
- :cursor_id => cursor_id,
90
- :db_name => database.name,
91
- :coll_name => collection.name
92
- }).execute(server.context)
93
- Cursor.new(self, result, server)
94
- end
95
- end
96
-
97
69
  # Allows the query to get partial results if some shards are down.
98
70
  #
99
71
  # @example Allow partial results.
@@ -120,7 +92,7 @@ module Mongo
120
92
  #
121
93
  # @since 2.0.0
122
94
  def batch_size(batch_size = nil)
123
- configure(:batch_size, batch_size)
95
+ configure(__method__, batch_size)
124
96
  end
125
97
 
126
98
  # Associate a comment with the query.
@@ -138,7 +110,7 @@ module Mongo
138
110
  #
139
111
  # @since 2.0.0
140
112
  def comment(comment = nil)
141
- configure(:comment, comment)
113
+ configure_modifier(__method__, comment)
142
114
  end
143
115
 
144
116
  # Get a count of matching documents in the collection.
@@ -202,7 +174,7 @@ module Mongo
202
174
  #
203
175
  # @since 2.0.0
204
176
  def hint(hint = nil)
205
- configure(:hint, hint)
177
+ configure_modifier(__method__, hint)
206
178
  end
207
179
 
208
180
  # The max number of docs to return from the query.
@@ -216,7 +188,7 @@ module Mongo
216
188
  #
217
189
  # @since 2.0.0
218
190
  def limit(limit = nil)
219
- configure(:limit, limit)
191
+ configure(__method__, limit)
220
192
  end
221
193
 
222
194
  # Execute a map/reduce operation on the collection view.
@@ -246,7 +218,35 @@ module Mongo
246
218
  #
247
219
  # @since 2.0.0
248
220
  def max_scan(value = nil)
249
- configure(:max_scan, value)
221
+ configure_modifier(__method__, value)
222
+ end
223
+
224
+ # Set the maximum value to search.
225
+ #
226
+ # @example Set the max value.
227
+ # view.max_value(_id: 1)
228
+ #
229
+ # @param [ Hash ] value The max field and value.
230
+ #
231
+ # @return [ Hash, View ] The value or a new +View+.
232
+ #
233
+ # @since 2.1.0
234
+ def max_value(value = nil)
235
+ configure_modifier(__method__, value)
236
+ end
237
+
238
+ # Set the minimum value to search.
239
+ #
240
+ # @example Set the min value.
241
+ # view.min_value(_id: 1)
242
+ #
243
+ # @param [ Hash ] value The min field and value.
244
+ #
245
+ # @return [ Hash, View ] The value or a new +View+.
246
+ #
247
+ # @since 2.1.0
248
+ def min_value(value = nil)
249
+ configure_modifier(__method__, value)
250
250
  end
251
251
 
252
252
  # The server normally times out idle cursors after an inactivity period
@@ -259,7 +259,7 @@ module Mongo
259
259
  #
260
260
  # @since 2.0.0
261
261
  def no_cursor_timeout
262
- configure_flag(:no_cursor_timeout)
262
+ configure_flag(__method__)
263
263
  end
264
264
 
265
265
  # The fields to include or exclude from each doc in the result set.
@@ -278,7 +278,7 @@ module Mongo
278
278
  # @since 2.0.0
279
279
  def projection(document = nil)
280
280
  validate_doc!(document) if document
281
- configure(:projection, document)
281
+ configure(__method__, document)
282
282
  end
283
283
 
284
284
  # The read preference to use for the query.
@@ -294,7 +294,21 @@ module Mongo
294
294
  # @since 2.0.0
295
295
  def read(value = nil)
296
296
  return default_read if value.nil?
297
- configure(:read, value.is_a?(Hash) ? ServerSelector.get(value) : value)
297
+ configure(__method__, value.is_a?(Hash) ? ServerSelector.get(value) : value)
298
+ end
299
+
300
+ # Set whether to return only the indexed field or fields.
301
+ #
302
+ # @example Set the return key value.
303
+ # view.return_key(true)
304
+ #
305
+ # @param [ true, false ] value The return key value.
306
+ #
307
+ # @return [ true, false, View ] The value or a new +View+.
308
+ #
309
+ # @since 2.1.0
310
+ def return_key(value = nil)
311
+ configure_modifier(__method__, value)
298
312
  end
299
313
 
300
314
  # Set whether the disk location should be shown for each document.
@@ -309,7 +323,7 @@ module Mongo
309
323
  #
310
324
  # @since 2.0.0
311
325
  def show_disk_loc(value = nil)
312
- configure(:show_disk_loc, value)
326
+ configure_modifier(__method__, value)
313
327
  end
314
328
 
315
329
  # The number of docs to skip before returning results.
@@ -324,7 +338,7 @@ module Mongo
324
338
  #
325
339
  # @since 2.0.0
326
340
  def skip(number = nil)
327
- configure(:skip, number)
341
+ configure(__method__, number)
328
342
  end
329
343
 
330
344
  # Set the snapshot value for the view.
@@ -339,7 +353,7 @@ module Mongo
339
353
  #
340
354
  # @since 2.0.0
341
355
  def snapshot(value = nil)
342
- configure(:snapshot, value)
356
+ configure_modifier(__method__, value)
343
357
  end
344
358
 
345
359
  # The key and direction pairs by which the result set will be sorted.
@@ -354,7 +368,7 @@ module Mongo
354
368
  #
355
369
  # @since 2.0.0
356
370
  def sort(spec = nil)
357
- configure(:sort, spec)
371
+ configure_modifier(__method__, spec)
358
372
  end
359
373
 
360
374
  # “meta” operators that let you modify the output or behavior of a query.
@@ -368,7 +382,8 @@ module Mongo
368
382
  #
369
383
  # @since 2.1.0
370
384
  def modifiers(doc = nil)
371
- configure(:modifiers, doc)
385
+ return @modifiers if doc.nil?
386
+ new(options.merge(__method__ => doc))
372
387
  end
373
388
 
374
389
  # A cumulative time limit in milliseconds for processing operations on a cursor.
@@ -382,12 +397,12 @@ module Mongo
382
397
  #
383
398
  # @since 2.1.0
384
399
  def max_time_ms(max = nil)
385
- configure(:max_time_ms, max)
400
+ configure_modifier(__method__, max)
386
401
  end
387
402
 
388
403
  private
389
404
 
390
- def default_read(read = nil)
405
+ def default_read
391
406
  options[:read] || read_preference
392
407
  end
393
408
 
@@ -400,17 +415,59 @@ module Mongo
400
415
  end
401
416
  end
402
417
 
403
- def has_special_fields?
404
- modifiers || sort || hint || comment || max_time_ms || max_scan ||
405
- show_disk_loc || snapshot || explained? || cluster.sharded?
418
+ def parallel_scan(cursor_count)
419
+ server = read.select_server(cluster)
420
+ Operation::ParallelScan.new(
421
+ :coll_name => collection.name,
422
+ :db_name => database.name,
423
+ :cursor_count => cursor_count
424
+ ).execute(server.context).cursor_ids.map do |cursor_id|
425
+ result = Operation::Read::GetMore.new({ :to_return => 0,
426
+ :cursor_id => cursor_id,
427
+ :db_name => database.name,
428
+ :coll_name => collection.name
429
+ }).execute(server.context)
430
+ Cursor.new(self, result, server)
431
+ end
432
+ end
433
+
434
+ def setup(sel, opts)
435
+ setup_options(opts)
436
+ setup_selector(sel)
437
+ end
438
+
439
+ def setup_options(opts)
440
+ @options = opts ? opts.dup : {}
441
+ @modifiers = @options[:modifiers] ? @options.delete(:modifiers).dup : BSON::Document.new
442
+ @options.keys.each { |k| @modifiers.merge!(SPECIAL_FIELDS[k] => @options.delete(k)) if SPECIAL_FIELDS[k] }
443
+ @options.freeze
444
+ end
445
+
446
+ def setup_selector(sel)
447
+ @selector = sel ? sel.dup : {}
448
+ if @selector[:$query] || @selector['$query']
449
+ @selector.keys.each { |k| @modifiers.merge!(k => @selector.delete(k)) if k[0] == '$' }
450
+ end
451
+ @modifiers.freeze
452
+ @selector.freeze
406
453
  end
407
454
 
408
455
  def query_options
409
- { :project => projection, :skip => skip, :limit => to_return, :flags => flags }
456
+ {
457
+ :project => projection,
458
+ :skip => skip,
459
+ :limit => limit,
460
+ :flags => flags,
461
+ :batch_size => batch_size
462
+ }
463
+ end
464
+
465
+ def requires_special_selector?
466
+ !modifiers.empty? || cluster.sharded?
410
467
  end
411
468
 
412
469
  def query_spec
413
- sel = has_special_fields? ? special_selector : selector
470
+ sel = requires_special_selector? ? special_selector : selector
414
471
  { :selector => sel,
415
472
  :read => read,
416
473
  :options => query_options,
@@ -419,19 +476,13 @@ module Mongo
419
476
  end
420
477
 
421
478
  def read_pref_formatted
422
- read.to_mongos
479
+ @read_formatted ||= read.to_mongos
423
480
  end
424
481
 
425
482
  def special_selector
426
- SPECIAL_FIELDS.reduce({}) do |hash, (key, method)|
427
- value = send(method) || (options[:modifiers] && options[:modifiers][key])
428
- hash[key] = value if value
429
- hash
430
- end
431
- end
432
-
433
- def to_return
434
- [ limit || batch_size, batch_size || limit ].min
483
+ sel = BSON::Document.new(:$query => selector).merge!(modifiers)
484
+ sel[:$readPreference] = read_pref_formatted unless read_pref_formatted.nil?
485
+ sel
435
486
  end
436
487
 
437
488
  def validate_doc!(doc)