mongo 2.0.4 → 2.0.5

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 (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/address.rb +1 -1
  5. data/lib/mongo/address/ipv4.rb +8 -4
  6. data/lib/mongo/address/ipv6.rb +8 -4
  7. data/lib/mongo/address/unix.rb +2 -2
  8. data/lib/mongo/auth/user/view.rb +5 -1
  9. data/lib/mongo/bulk_write/bulk_writable.rb +5 -0
  10. data/lib/mongo/bulk_write/deletable.rb +0 -4
  11. data/lib/mongo/bulk_write/insertable.rb +0 -4
  12. data/lib/mongo/client.rb +30 -2
  13. data/lib/mongo/collection/view/aggregation.rb +17 -4
  14. data/lib/mongo/collection/view/map_reduce.rb +19 -2
  15. data/lib/mongo/database.rb +12 -0
  16. data/lib/mongo/database/view.rb +12 -0
  17. data/lib/mongo/grid/fs.rb +5 -5
  18. data/lib/mongo/loggable.rb +5 -3
  19. data/lib/mongo/logger.rb +21 -5
  20. data/lib/mongo/operation/aggregate.rb +18 -11
  21. data/lib/mongo/operation/aggregate/result.rb +16 -1
  22. data/lib/mongo/operation/map_reduce.rb +7 -9
  23. data/lib/mongo/operation/read/query.rb +1 -1
  24. data/lib/mongo/operation/read_preferrable.rb +11 -5
  25. data/lib/mongo/operation/result.rb +5 -1
  26. data/lib/mongo/operation/write.rb +1 -0
  27. data/lib/mongo/operation/write/command.rb +1 -0
  28. data/lib/mongo/operation/write/command/update_user.rb +43 -0
  29. data/lib/mongo/operation/write/update_user.rb +75 -0
  30. data/lib/mongo/protocol/reply.rb +12 -0
  31. data/lib/mongo/server/connection_pool/queue.rb +3 -3
  32. data/lib/mongo/socket.rb +22 -11
  33. data/lib/mongo/socket/ssl.rb +6 -3
  34. data/lib/mongo/version.rb +1 -1
  35. data/spec/mongo/auth/user/view_spec.rb +42 -0
  36. data/spec/mongo/client_spec.rb +19 -0
  37. data/spec/mongo/cluster_spec.rb +2 -1
  38. data/spec/mongo/collection/view/aggregation_spec.rb +34 -1
  39. data/spec/mongo/collection/view/map_reduce_spec.rb +92 -0
  40. data/spec/mongo/collection/view_spec.rb +14 -11
  41. data/spec/mongo/collection_spec.rb +13 -0
  42. data/spec/mongo/database_spec.rb +29 -0
  43. data/spec/mongo/grid/fs_spec.rb +32 -1
  44. data/spec/mongo/loggable_spec.rb +2 -1
  45. data/spec/mongo/operation/read/query_spec.rb +19 -0
  46. data/spec/mongo/operation/read_preferrable_spec.rb +192 -0
  47. data/spec/mongo/operation/write/update_user_spec.rb +46 -0
  48. data/spec/mongo/server/connection_pool/queue_spec.rb +4 -0
  49. data/spec/mongo/socket/ssl_spec.rb +21 -1
  50. data/spec/spec_helper.rb +4 -0
  51. data/spec/support/authorization.rb +6 -4
  52. data/spec/support/shared/operation.rb +12 -0
  53. metadata +9 -3
  54. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e38363c98850f8cb9f7ef56552faf0b6bbaf88e6
4
- data.tar.gz: 9bb3295506cf0fdd420a7232283982145824cb11
3
+ metadata.gz: 009aca6194505e854c2e8ce72b50826c76b81942
4
+ data.tar.gz: ec9fa507bafe9c3f79ce430bee77bee9fa6452c3
5
5
  SHA512:
6
- metadata.gz: 391cb75664da5c1d1f24a8b61b59703b2767c60c221c601342bf2597096af1a828b1eaec2402e91e5e512e251f64534a31dcc73103062cc111f6247137953edf
7
- data.tar.gz: fe3b98b0be277225dbe52ca0a39a8bc3e31e80eff077041bf87d7327d9adfba697a8ed6b8333637dd5c6b887b7599b893b15ebfbf347af90cfdcae97582682c1
6
+ metadata.gz: ac666b6d3593018bf29f22a212bcf36a1b0dff88e9aee3e439c3f599bff14c90b8e2507355b10cc40e4426a7135313fa161d78fdc853ac4c094acfa9122d2c2c
7
+ data.tar.gz: 0ff89ae3bc0661a5a39e067a0c96d7a044b291333f314dd6dbd89e8bb7c6d2f4f95ba894785d784acc8126f66896b0505900d56b39c77c5e1a4ac66f8f43f0ca
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -148,7 +148,7 @@ module Mongo
148
148
  error = nil
149
149
  ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).detect do |info|
150
150
  begin
151
- return FAMILY_MAP[info[4]].new(info[3], port).tap do |res|
151
+ return FAMILY_MAP[info[4]].new(info[3], port, host).tap do |res|
152
152
  res.socket(timeout, ssl_options).connect!
153
153
  end
154
154
  rescue IOError, SystemCallError => e
@@ -21,9 +21,12 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  class IPv4
23
23
 
24
- # @return [ String ] host The original host name.
24
+ # @return [ String ] host The host.
25
25
  attr_reader :host
26
26
 
27
+ # @return [ String ] host_name The original host name.
28
+ attr_reader :host_name
29
+
27
30
  # @return [ Integer ] port The port.
28
31
  attr_reader :port
29
32
 
@@ -52,15 +55,16 @@ module Mongo
52
55
  # Initialize the IPv4 resolver.
53
56
  #
54
57
  # @example Initialize the resolver.
55
- # IPv4.new("127.0.0.1", 27017, "127.0.0.1:28011")
58
+ # IPv4.new("127.0.0.1", 27017, 'localhost')
56
59
  #
57
60
  # @param [ String ] host The host.
58
61
  # @param [ Integer ] port The port.
59
62
  #
60
63
  # @since 2.0.0
61
- def initialize(host, port)
64
+ def initialize(host, port, host_name=nil)
62
65
  @host = host
63
66
  @port = port
67
+ @host_name = host_name
64
68
  end
65
69
 
66
70
  # Get a socket for the provided address type, given the options.
@@ -76,7 +80,7 @@ module Mongo
76
80
  # @since 2.0.0
77
81
  def socket(timeout, ssl_options = {})
78
82
  unless ssl_options.empty?
79
- Socket::SSL.new(host, port, timeout, Socket::PF_INET, ssl_options)
83
+ Socket::SSL.new(host, port, host_name, timeout, Socket::PF_INET, ssl_options)
80
84
  else
81
85
  Socket::TCP.new(host, port, timeout, Socket::PF_INET)
82
86
  end
@@ -21,9 +21,12 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  class IPv6
23
23
 
24
- # @return [ String ] host The original host name.
24
+ # @return [ String ] host The host.
25
25
  attr_reader :host
26
26
 
27
+ # @return [ String ] host_name The original host name.
28
+ attr_reader :host_name
29
+
27
30
  # @return [ Integer ] port The port.
28
31
  attr_reader :port
29
32
 
@@ -52,15 +55,16 @@ module Mongo
52
55
  # Initialize the IPv6 resolver.
53
56
  #
54
57
  # @example Initialize the resolver.
55
- # IPv6.new("::1", 28011, "[::1]:28011")
58
+ # IPv6.new("::1", 28011, 'localhost')
56
59
  #
57
60
  # @param [ String ] host The host.
58
61
  # @param [ Integer ] port The port.
59
62
  #
60
63
  # @since 2.0.0
61
- def initialize(host, port)
64
+ def initialize(host, port, host_name=nil)
62
65
  @host = host
63
66
  @port = port
67
+ @host_name = host_name
64
68
  end
65
69
 
66
70
  # Get a socket for the provided address type, given the options.
@@ -76,7 +80,7 @@ module Mongo
76
80
  # @since 2.0.0
77
81
  def socket(timeout, ssl_options = {})
78
82
  unless ssl_options.empty?
79
- Socket::SSL.new(host, port, timeout, Socket::PF_INET6, ssl_options)
83
+ Socket::SSL.new(host, port, host_name, timeout, Socket::PF_INET6, ssl_options)
80
84
  else
81
85
  Socket::TCP.new(host, port, timeout, Socket::PF_INET6)
82
86
  end
@@ -20,7 +20,7 @@ module Mongo
20
20
  # @since 2.0.0
21
21
  class Unix
22
22
 
23
- # @return [ String ] host The original host name.
23
+ # @return [ String ] host The host.
24
24
  attr_reader :host
25
25
 
26
26
  # @return [ nil ] port Will always be nil.
@@ -53,7 +53,7 @@ module Mongo
53
53
  # @param [ String ] host The host.
54
54
  #
55
55
  # @since 2.0.0
56
- def initialize(host)
56
+ def initialize(host, port=nil, host_name=nil)
57
57
  @host = host
58
58
  end
59
59
 
@@ -88,7 +88,11 @@ module Mongo
88
88
  #
89
89
  # @since 2.0.0
90
90
  def update(user_or_name, options = {})
91
-
91
+ user = generate(user_or_name, options)
92
+ Operation::Write::UpdateUser.new(
93
+ user: user,
94
+ db_name: database.name
95
+ ).execute(next_primary.context)
92
96
  end
93
97
 
94
98
  private
@@ -85,6 +85,11 @@ module Mongo
85
85
 
86
86
  private
87
87
 
88
+ def valid_doc?(doc)
89
+ doc.respond_to?(:keys) ||
90
+ doc.respond_to?(:document)
91
+ end
92
+
88
93
  def write_concern
89
94
  @write_concern ||= WriteConcern.get(@options[:write_concern]) ||
90
95
  @collection.write_concern
@@ -22,10 +22,6 @@ module Mongo
22
22
 
23
23
  private
24
24
 
25
- def valid_doc?(doc)
26
- doc.respond_to?(:keys)
27
- end
28
-
29
25
  def validate_delete_op!(type, d)
30
26
  raise Error::InvalidBulkOperation.new(type, d) unless valid_doc?(d)
31
27
  end
@@ -22,10 +22,6 @@ module Mongo
22
22
 
23
23
  private
24
24
 
25
- def valid_doc?(doc)
26
- doc.respond_to?(:keys)
27
- end
28
-
29
25
  def validate_insert_ops!(type, inserts)
30
26
  if inserts.empty?
31
27
  raise Error::InvalidBulkOperation.new(type, inserts)
@@ -111,8 +111,10 @@ module Mongo
111
111
  # seconds, in the connection pool for a connection to be checked in.
112
112
  # @option options [ Float ] :connect_timeout The timeout, in seconds, to
113
113
  # attempt a connection.
114
- # @option options [ Symbol ] :read The read preference options. :mode can
115
- # be one of :secondary, :secondary_preferred, :primary,
114
+ # @option options [ Hash ] :read The read preference options. They consist of a
115
+ # mode specified as a symbol, an array of hashes known as tag_sets,
116
+ # and two timing options: local_threshold and server_selection_timeout.
117
+ # :mode can be one of :secondary, :secondary_preferred, :primary,
116
118
  # :primary_preferred, :nearest.
117
119
  # @option options [ Array<Hash, String> ] :roles The list of roles for the
118
120
  # user.
@@ -221,6 +223,32 @@ module Mongo
221
223
  @write_concern ||= WriteConcern.get(options[:write])
222
224
  end
223
225
 
226
+ # Get the names of all databases.
227
+ #
228
+ # @example Get the database names.
229
+ # client.database_names
230
+ #
231
+ # @return [ Array<String> ] The names of the databases.
232
+ #
233
+ # @since 2.0.5
234
+ def database_names
235
+ list_databases.collect{ |info| info['name'] }
236
+ end
237
+
238
+ # Get info for each database.
239
+ #
240
+ # @example Get the info for each database.
241
+ # client.list_databases
242
+ #
243
+ # @return [ Array<Hash> ] The info for each database.
244
+ #
245
+ # @since 2.0.5
246
+ def list_databases
247
+ use(Database::ADMIN).command(
248
+ listDatabases: 1
249
+ ).first['databases']
250
+ end
251
+
224
252
  private
225
253
 
226
254
  def create_from_addresses(addresses, opts = {})
@@ -69,16 +69,29 @@ module Mongo
69
69
  @options = options.dup
70
70
  end
71
71
 
72
+ # Get the explain plan for the aggregation.
73
+ #
74
+ # @example Get the explain plan for the aggregation.
75
+ # aggregation.explain
76
+ #
77
+ # @return [ Hash ] The explain plan.
78
+ #
79
+ # @since 2.0.0
80
+ def explain
81
+ self.class.new(view, pipeline, options.merge(explain_options)).first
82
+ end
83
+
72
84
  private
73
85
 
74
86
  def aggregate_spec
75
- { :selector => {
87
+ { :db_name => database.name,
88
+ :read => read,
89
+ :selector => {
76
90
  :aggregate => collection.name,
77
91
  :pipeline => pipeline,
78
92
  :cursor => view.batch_size ? { :batchSize => view.batch_size } : {}
79
- }.merge!(options),
80
- :db_name => database.name,
81
- :options => view.options }
93
+ }.merge!(options)
94
+ }
82
95
  end
83
96
 
84
97
  def explain_options
@@ -120,7 +120,7 @@ module Mongo
120
120
  #
121
121
  # @param [ Hash ] object The scope object.
122
122
  #
123
- # @return [ MapReduce, Hash ] The new MapReduce operation or thevalue
123
+ # @return [ MapReduce, Hash ] The new MapReduce operation or the value
124
124
  # of the scope.
125
125
  #
126
126
  # @since 2.0.0
@@ -128,15 +128,32 @@ module Mongo
128
128
  configure(:scope, object)
129
129
  end
130
130
 
131
+ # Whether to include the timing information in the result.
132
+ #
133
+ # @example Set the verbose value.
134
+ # map_reduce.verbose(false)
135
+ #
136
+ # @param [ true, false ] value Whether to include timing information
137
+ # in the result.
138
+ #
139
+ # @return [ MapReduce, Hash ] The new MapReduce operation or the value
140
+ # of the verbose option.
141
+ #
142
+ # @since 2.0.5
143
+ def verbose(value = nil)
144
+ configure(:verbose, value)
145
+ end
146
+
131
147
  private
132
148
 
133
149
  def inline?
134
- out.nil? || out == { inline: 1 }
150
+ out.nil? || out == { inline: 1 } || out == { 'inline' => 1 }
135
151
  end
136
152
 
137
153
  def map_reduce_spec
138
154
  {
139
155
  :db_name => database.name,
156
+ :read => read,
140
157
  :selector => {
141
158
  :mapreduce => collection.name,
142
159
  :map => map,
@@ -102,6 +102,18 @@ module Mongo
102
102
  View.new(self).collection_names(options)
103
103
  end
104
104
 
105
+ # Get info on all the collections in the database.
106
+ #
107
+ # @example Get info on each collection.
108
+ # database.list_collections
109
+ #
110
+ # @return [ Array<Hash> ] Info for each collection in the database.
111
+ #
112
+ # @since 2.0.5
113
+ def list_collections
114
+ View.new(self).list_collections
115
+ end
116
+
105
117
  # Get all the collections that belong to this database.
106
118
  #
107
119
  # @example Get all the collections.
@@ -57,6 +57,18 @@ module Mongo
57
57
  end
58
58
  end
59
59
 
60
+ # Get info on all the collections in the database.
61
+ #
62
+ # @example Get info on each collection.
63
+ # database.list_collections
64
+ #
65
+ # @return [ Array<Hash> ] Info for each collection in the database.
66
+ #
67
+ # @since 2.0.5
68
+ def list_collections
69
+ collections_info(next_primary)
70
+ end
71
+
60
72
  # Create the new database view.
61
73
  #
62
74
  # @example Create the new database view.
@@ -75,12 +75,12 @@ module Mongo
75
75
  # @since 2.0.0
76
76
  def insert_one(file)
77
77
  files_collection.insert_one(file.metadata)
78
- result = chunks_collection.insert_many(file.chunks)
79
- if write_concern.get_last_error
80
- validate_md5!(file)
81
- else
82
- result
78
+ inserts = file.chunks.reduce([]) do |ops, chunk|
79
+ ops << { :insert_one => chunk }
83
80
  end
81
+ result = chunks_collection.bulk_write(inserts, ordered: true)
82
+ validate_md5!(file) if write_concern.get_last_error
83
+ file.id
84
84
  end
85
85
 
86
86
  # Create the GridFS.
@@ -45,9 +45,11 @@ module Mongo
45
45
  rescue Exception => e
46
46
  raise e
47
47
  ensure
48
- runtime = ("%.4fms" % (1000 * (Time.now.to_f - started.to_f)))
49
- operations.each do |operation|
50
- Logger.send(level, prefix, log_inspect(operation), runtime)
48
+ if Logger.allow?(level)
49
+ runtime = format("%.4fms", (Time.now.to_f - started.to_f) * 1000.0)
50
+ operations.each do |operation|
51
+ Logger.log(level, prefix, log_inspect(operation), runtime)
52
+ end
51
53
  end
52
54
  end
53
55
  end
@@ -34,7 +34,7 @@ module Mongo
34
34
  #
35
35
  # @since 2.0.0
36
36
  def debug(prefix, message, runtime)
37
- logger.debug("#{prefix} | #{message} | runtime: #{runtime}")
37
+ self.log(:debug, prefix, message, runtime)
38
38
  end
39
39
 
40
40
  # Log a error level message.
@@ -48,7 +48,7 @@ module Mongo
48
48
  #
49
49
  # @since 2.0.0
50
50
  def error(prefix, message, runtime)
51
- logger.error("#{prefix} | #{message} | runtime: #{runtime}")
51
+ self.log(:error, prefix, message, runtime)
52
52
  end
53
53
 
54
54
  # Log a fatal level message.
@@ -62,7 +62,7 @@ module Mongo
62
62
  #
63
63
  # @since 2.0.0
64
64
  def fatal(prefix, message, runtime)
65
- logger.fatal("#{prefix} | #{message} | runtime: #{runtime}")
65
+ self.log(:fatal, prefix, message, runtime)
66
66
  end
67
67
 
68
68
  # Log a info level message.
@@ -76,7 +76,7 @@ module Mongo
76
76
  #
77
77
  # @since 2.0.0
78
78
  def info(prefix, message, runtime)
79
- logger.info("#{prefix} | #{message} | runtime: #{runtime}")
79
+ self.log(:info, prefix, message, runtime)
80
80
  end
81
81
 
82
82
  # Log a warn level message.
@@ -90,7 +90,7 @@ module Mongo
90
90
  #
91
91
  # @since 2.0.0
92
92
  def warn(prefix, message, runtime)
93
- logger.warn("#{prefix} | #{message} | runtime: #{runtime}")
93
+ self.log(:warn, prefix, message, runtime)
94
94
  end
95
95
 
96
96
  # Get the wrapped logger. If none was set will return a default debug
@@ -120,6 +120,22 @@ module Mongo
120
120
  @logger = other
121
121
  end
122
122
 
123
+ def log(level, prefix, message, runtime)
124
+ logger.send(level, format("%s | %s | runtime: %s".freeze, prefix, message, runtime))
125
+ end
126
+
127
+ def allow?(level)
128
+ logger.send(:"#{level}?")
129
+ end
130
+
131
+ def level
132
+ logger.level
133
+ end
134
+
135
+ def level=(level)
136
+ logger.level = level
137
+ end
138
+
123
139
  private
124
140
 
125
141
  def default_logger
@@ -43,6 +43,7 @@ module Mongo
43
43
  include Executable
44
44
  include Specifiable
45
45
  include Limited
46
+ include ReadPreferrable
46
47
 
47
48
  # The need primary error message.
48
49
  #
@@ -62,7 +63,7 @@ module Mongo
62
63
  #
63
64
  # @since 2.0.0
64
65
  def execute(context)
65
- unless context.standalone? || context.mongos? || context.primary? || secondary_ok?
66
+ unless valid_context?(context)
66
67
  raise Error::NeedPrimaryServer.new(ERROR_MESSAGE)
67
68
  end
68
69
  execute_message(context)
@@ -76,24 +77,30 @@ module Mongo
76
77
  end
77
78
  end
78
79
 
79
- # Whether this operation can be executed on a replica set secondary server.
80
- # The aggregate operation may not be executed on a secondary if the user has specified
81
- # an output collection to which the results will be written.
82
- #
83
- # @return [ true, false ] Whether the operation can be executed on a secondary.
84
- #
85
- # @since 2.0.0
80
+ def valid_context?(context)
81
+ context.standalone? || context.mongos? || context.primary? || secondary_ok?
82
+ end
83
+
86
84
  def secondary_ok?
87
85
  selector[:pipeline].none? { |op| op.key?('$out') || op.key?(:$out) }
88
86
  end
89
87
 
90
- def filter(context)
88
+ def query_coll
89
+ Database::COMMAND
90
+ end
91
+
92
+ def filter_selector(context)
91
93
  return selector if context.features.write_command_enabled?
92
94
  selector.reject{ |option, value| option.to_s == 'cursor' }
93
95
  end
94
96
 
95
- def message(context)
96
- Protocol::Query.new(db_name, Database::COMMAND, filter(context), options)
97
+ def update_selector(context)
98
+ if context.mongos? && read_pref = read.to_mongos
99
+ sel = selector[:$query] ? filter_selector(context) : { :$query => filter_selector(context) }
100
+ sel.merge(:$readPreference => read_pref)
101
+ else
102
+ filter_selector(context)
103
+ end
97
104
  end
98
105
  end
99
106
  end