mongo 2.0.6 → 2.1.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) 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.rb +2 -0
  5. data/lib/mongo/bulk_write.rb +1 -0
  6. data/lib/mongo/bulk_write/bulk_writable.rb +87 -31
  7. data/lib/mongo/bulk_write/deletable.rb +8 -7
  8. data/lib/mongo/bulk_write/insertable.rb +4 -3
  9. data/lib/mongo/bulk_write/ordered_bulk_write.rb +6 -6
  10. data/lib/mongo/bulk_write/replacable.rb +4 -3
  11. data/lib/mongo/bulk_write/result.rb +138 -0
  12. data/lib/mongo/bulk_write/unordered_bulk_write.rb +5 -8
  13. data/lib/mongo/bulk_write/updatable.rb +8 -7
  14. data/lib/mongo/client.rb +36 -4
  15. data/lib/mongo/cluster.rb +39 -4
  16. data/lib/mongo/cluster/topology/replica_set.rb +20 -4
  17. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  18. data/lib/mongo/collection.rb +282 -29
  19. data/lib/mongo/collection/view/aggregation.rb +32 -4
  20. data/lib/mongo/collection/view/iterable.rb +2 -1
  21. data/lib/mongo/collection/view/map_reduce.rb +3 -1
  22. data/lib/mongo/collection/view/readable.rb +89 -14
  23. data/lib/mongo/collection/view/writable.rb +11 -5
  24. data/lib/mongo/cursor.rb +11 -3
  25. data/lib/mongo/dbref.rb +113 -0
  26. data/lib/mongo/error.rb +6 -2
  27. data/lib/mongo/error/parser.rb +1 -1
  28. data/lib/mongo/event/description_changed.rb +1 -1
  29. data/lib/mongo/grid/file.rb +1 -1
  30. data/lib/mongo/grid/fs.rb +2 -5
  31. data/lib/mongo/monitoring.rb +199 -0
  32. data/lib/mongo/monitoring/command_log_subscriber.rb +88 -0
  33. data/lib/mongo/monitoring/event.rb +17 -0
  34. data/lib/mongo/monitoring/event/command_failed.rb +96 -0
  35. data/lib/mongo/monitoring/event/command_started.rb +88 -0
  36. data/lib/mongo/monitoring/event/command_succeeded.rb +96 -0
  37. data/lib/mongo/monitoring/publishable.rb +96 -0
  38. data/lib/mongo/operation.rb +1 -0
  39. data/lib/mongo/operation/executable.rb +1 -1
  40. data/lib/mongo/operation/parallel_scan.rb +76 -0
  41. data/lib/mongo/operation/parallel_scan/result.rb +72 -0
  42. data/lib/mongo/operation/specifiable.rb +18 -0
  43. data/lib/mongo/operation/write/bulk/bulk_delete.rb +1 -1
  44. data/lib/mongo/operation/write/bulk/bulk_insert.rb +1 -1
  45. data/lib/mongo/operation/write/bulk/bulk_mergable.rb +2 -2
  46. data/lib/mongo/operation/write/bulk/bulk_update.rb +1 -1
  47. data/lib/mongo/operation/write/bulk/bulk_update/result.rb +13 -1
  48. data/lib/mongo/protocol/delete.rb +8 -13
  49. data/lib/mongo/protocol/get_more.rb +13 -13
  50. data/lib/mongo/protocol/insert.rb +8 -13
  51. data/lib/mongo/protocol/kill_cursors.rb +7 -11
  52. data/lib/mongo/protocol/query.rb +58 -20
  53. data/lib/mongo/protocol/reply.rb +12 -0
  54. data/lib/mongo/protocol/update.rb +13 -14
  55. data/lib/mongo/server.rb +23 -2
  56. data/lib/mongo/server/connectable.rb +0 -22
  57. data/lib/mongo/server/connection.rb +29 -0
  58. data/lib/mongo/server/description.rb +23 -1
  59. data/lib/mongo/server/monitor.rb +17 -1
  60. data/lib/mongo/server/monitor/connection.rb +24 -0
  61. data/lib/mongo/socket/ssl.rb +28 -16
  62. data/lib/mongo/socket/tcp.rb +1 -1
  63. data/lib/mongo/socket/unix.rb +1 -1
  64. data/lib/mongo/uri.rb +12 -5
  65. data/lib/mongo/version.rb +1 -1
  66. data/spec/mongo/auth/cr_spec.rb +9 -1
  67. data/spec/mongo/auth/ldap_spec.rb +9 -1
  68. data/spec/mongo/auth/scram_spec.rb +9 -1
  69. data/spec/mongo/auth/x509_spec.rb +9 -1
  70. data/spec/mongo/{bulk/bulk_write_spec.rb → bulk_write_spec.rb} +15 -15
  71. data/spec/mongo/client_spec.rb +42 -0
  72. data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -9
  73. data/spec/mongo/cluster/topology/sharded_spec.rb +11 -3
  74. data/spec/mongo/cluster/topology/single_spec.rb +12 -4
  75. data/spec/mongo/cluster_spec.rb +55 -10
  76. data/spec/mongo/collection/view/aggregation_spec.rb +123 -1
  77. data/spec/mongo/collection/view/explainable_spec.rb +1 -1
  78. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  79. data/spec/mongo/collection/view/readable_spec.rb +251 -6
  80. data/spec/mongo/collection/view/writable_spec.rb +4 -4
  81. data/spec/mongo/collection/view_spec.rb +233 -71
  82. data/spec/mongo/collection_spec.rb +905 -9
  83. data/spec/mongo/crud_spec.rb +2 -2
  84. data/spec/mongo/cursor_spec.rb +3 -3
  85. data/spec/mongo/dbref_spec.rb +149 -0
  86. data/spec/mongo/monitoring_spec.rb +168 -0
  87. data/spec/mongo/operation/map_reduce_spec.rb +1 -1
  88. data/spec/mongo/operation/write/bulk/bulk_delete_spec.rb +1 -1
  89. data/spec/mongo/operation/write/bulk/bulk_insert_spec.rb +2 -2
  90. data/spec/mongo/operation/write/bulk/bulk_update_spec.rb +1 -1
  91. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  92. data/spec/mongo/operation/write/insert_spec.rb +2 -2
  93. data/spec/mongo/operation/write/update_spec.rb +1 -1
  94. data/spec/mongo/protocol/query_spec.rb +0 -29
  95. data/spec/mongo/server/connection_pool_spec.rb +18 -6
  96. data/spec/mongo/server/connection_spec.rb +12 -4
  97. data/spec/mongo/server/description_spec.rb +7 -3
  98. data/spec/mongo/server/monitor_spec.rb +30 -0
  99. data/spec/mongo/server_discovery_and_monitoring_spec.rb +11 -4
  100. data/spec/mongo/server_selection_spec.rb +14 -6
  101. data/spec/mongo/server_spec.rb +27 -8
  102. data/spec/mongo/socket/ssl_spec.rb +94 -8
  103. data/spec/mongo/uri_spec.rb +25 -9
  104. data/spec/spec_helper.rb +29 -20
  105. data/spec/support/authorization.rb +19 -4
  106. data/spec/support/certificates/client.pem +4 -4
  107. data/spec/support/crud/read.rb +9 -10
  108. data/spec/support/crud/write.rb +24 -20
  109. data/spec/support/sdam/rs/equal_electionids.yml +45 -0
  110. data/spec/support/sdam/rs/new_primary_new_electionid.yml +98 -0
  111. data/spec/support/sdam/rs/null_election_id.yml +144 -0
  112. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +124 -0
  113. data/spec/support/sdam/sharded/mongos_disconnect.yml +104 -0
  114. data/spec/support/server_discovery_and_monitoring.rb +19 -2
  115. data/spec/support/shared/bulk_write.rb +26 -22
  116. data/spec/support/shared/server_selector.rb +2 -1
  117. metadata +31 -7
  118. metadata.gz.sig +0 -0
  119. data/lib/mongo/error/invalid_uri_option.rb +0 -38
@@ -37,6 +37,15 @@ module Mongo
37
37
  # Delegate necessary operations to the collection.
38
38
  def_delegators :collection, :database
39
39
 
40
+ # Options mapping for an aggregation.
41
+ #
42
+ # @since 2.1.0
43
+ OPTIONS_MAP = {
44
+ :allow_disk_use => :allowDiskUse,
45
+ :max_time_ms => :maxTimeMS,
46
+ :explain => :explain
47
+ }
48
+
40
49
  # Set to true if disk usage is allowed during the aggregation.
41
50
  #
42
51
  # @example Set disk usage flag.
@@ -49,7 +58,7 @@ module Mongo
49
58
  #
50
59
  # @since 2.0.0
51
60
  def allow_disk_use(value = nil)
52
- configure(:allowDiskUse, value)
61
+ configure(__method__, value)
53
62
  end
54
63
 
55
64
  # Initialize the aggregation for the provided collection view, pipeline
@@ -89,11 +98,28 @@ module Mongo
89
98
  :selector => {
90
99
  :aggregate => collection.name,
91
100
  :pipeline => pipeline,
92
- :cursor => view.batch_size ? { :batchSize => view.batch_size } : {}
93
- }.merge!(options)
101
+ :cursor => cursor,
102
+ }.merge!(agg_options)
94
103
  }
95
104
  end
96
105
 
106
+ def agg_options
107
+ @agg_options ||= options.each.reduce({}) do |opts, (key, value)|
108
+ OPTIONS_MAP[key] ? opts.merge!(OPTIONS_MAP[key] => value) : opts
109
+ end
110
+ end
111
+
112
+ def cursor
113
+ if options[:use_cursor] == true || options[:use_cursor].nil?
114
+ batch_size_doc
115
+ end
116
+ end
117
+
118
+ def batch_size_doc
119
+ (value = options[:batch_size] || view.batch_size) ?
120
+ { :batchSize => value } : {}
121
+ end
122
+
97
123
  def explain_options
98
124
  { :explain => true }
99
125
  end
@@ -110,7 +136,9 @@ module Mongo
110
136
  begin
111
137
  initial_query_op.execute(server.context)
112
138
  rescue Mongo::Error::NeedPrimaryServer
113
- warn 'Rerouting the Aggregation operation to the primary server.'
139
+ log_warn([
140
+ 'Rerouting the Aggregation operation to the primary server.'
141
+ ])
114
142
  server = ServerSelector.get(mode: :primary).select_server(cluster)
115
143
  initial_query_op.execute(server.context)
116
144
  end
@@ -36,7 +36,8 @@ module Mongo
36
36
  # @yieldparam [ Hash ] Each matching document.
37
37
  def each
38
38
  server = read.select_server(cluster)
39
- cursor = Cursor.new(view, send_initial_query(server), server).to_enum
39
+ initial_query = send_initial_query(server)
40
+ cursor = Cursor.new(view, initial_query, server).to_enum
40
41
  cursor.each do |doc|
41
42
  yield doc
42
43
  end if block_given?
@@ -177,7 +177,9 @@ module Mongo
177
177
  begin
178
178
  initial_query_op.execute(server.context)
179
179
  rescue Mongo::Error::NeedPrimaryServer
180
- warn 'Rerouting the MapReduce operation to the primary server.'
180
+ log_warn([
181
+ 'Rerouting the MapReduce operation to the primary server.'
182
+ ])
181
183
  server = ServerSelector.get(mode: :primary).select_server(cluster)
182
184
  initial_query_op.execute(server.context)
183
185
  end
@@ -32,10 +32,22 @@ module Mongo
32
32
  :$comment => :comment,
33
33
  :$snapshot => :snapshot,
34
34
  :$maxScan => :max_scan,
35
+ :$maxTimeMS => :max_time_ms,
35
36
  :$showDiskLoc => :show_disk_loc,
36
37
  :$explain => :explained?
37
38
  }.freeze
38
39
 
40
+ # Options to cursor flags mapping.
41
+ #
42
+ # @since 2.1.0
43
+ CURSOR_FLAGS_MAP = {
44
+ :allow_partial_results => [ :partial ],
45
+ :oplog_replay => [ :oplog_replay ],
46
+ :no_cursor_timeout => [ :no_cursor_timeout ],
47
+ :tailable => [ :tailable_cursor ],
48
+ :tailable_await => [ :await_data, :tailable_cursor]
49
+ }.freeze
50
+
39
51
  # Execute an aggregation on the collection view.
40
52
  #
41
53
  # @example Aggregate documents.
@@ -53,6 +65,35 @@ module Mongo
53
65
  Aggregation.new(self, pipeline, options)
54
66
  end
55
67
 
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
+
56
97
  # Allows the query to get partial results if some shards are down.
57
98
  #
58
99
  # @example Allow partial results.
@@ -111,6 +152,8 @@ module Mongo
111
152
  # @option options :hint [ Hash ] Override default index selection and force
112
153
  # MongoDB to use a specific index for the query.
113
154
  # @option options :limit [ Integer ] Max number of docs to return.
155
+ # @option options :max_time_ms [ Integer ] The maximum amount of time to allow the
156
+ # command to run.
114
157
  # @option options :read [ Hash ] The read preference for this command.
115
158
  #
116
159
  # @return [ Integer ] The document count.
@@ -121,6 +164,7 @@ module Mongo
121
164
  cmd[:skip] = options[:skip] if options[:skip]
122
165
  cmd[:hint] = options[:hint] if options[:hint]
123
166
  cmd[:limit] = options[:limit] if options[:limit]
167
+ cmd[:maxTimeMS] = options[:max_time_ms] if options[:max_time_ms]
124
168
  database.command(cmd, options).n
125
169
  end
126
170
 
@@ -132,18 +176,19 @@ module Mongo
132
176
  # @param [ String, Symbol ] field_name The name of the field.
133
177
  # @param [ Hash ] options Options for the distinct command.
134
178
  #
179
+ # @option options :max_time_ms [ Integer ] The maximum amount of time to allow the
180
+ # command to run.
135
181
  # @option options :read [ Hash ] The read preference for this command.
136
182
  #
137
183
  # @return [ Array<Object> ] The list of distinct values.
138
184
  #
139
185
  # @since 2.0.0
140
186
  def distinct(field_name, options={})
141
- database.command({
142
- :distinct => collection.name,
143
- :key => field_name.to_s,
144
- :query => selector },
145
- options
146
- ).documents.first['values']
187
+ cmd = { :distinct => collection.name,
188
+ :key => field_name.to_s,
189
+ :query => selector }
190
+ cmd[:maxTimeMS] = options[:max_time_ms] if options[:max_time_ms]
191
+ database.command(cmd, options).first['values']
147
192
  end
148
193
 
149
194
  # The index that MongoDB will be forced to use for the query.
@@ -249,7 +294,7 @@ module Mongo
249
294
  # @since 2.0.0
250
295
  def read(value = nil)
251
296
  return default_read if value.nil?
252
- configure(:read, value)
297
+ configure(:read, value.is_a?(Hash) ? ServerSelector.get(value) : value)
253
298
  end
254
299
 
255
300
  # Set whether the disk location should be shown for each document.
@@ -312,6 +357,34 @@ module Mongo
312
357
  configure(:sort, spec)
313
358
  end
314
359
 
360
+ # “meta” operators that let you modify the output or behavior of a query.
361
+ #
362
+ # @example Set the modifiers document.
363
+ # view.modifiers(:$orderby => Mongo::Index::ASCENDING)
364
+ #
365
+ # @param [ Hash ] doc The modifiers document.
366
+ #
367
+ # @return [ Hash, View ] Either the modifiers document or a new +View+.
368
+ #
369
+ # @since 2.1.0
370
+ def modifiers(doc = nil)
371
+ configure(:modifiers, doc)
372
+ end
373
+
374
+ # A cumulative time limit in milliseconds for processing operations on a cursor.
375
+ #
376
+ # @example Set the max time ms value.
377
+ # view.max_time_ms(500)
378
+ #
379
+ # @param [ Integer ] max The max time in milliseconds.
380
+ #
381
+ # @return [ Integer, View ] Either the max time ms value or a new +View+.
382
+ #
383
+ # @since 2.1.0
384
+ def max_time_ms(max = nil)
385
+ configure(:max_time_ms, max)
386
+ end
387
+
315
388
  private
316
389
 
317
390
  def default_read(read = nil)
@@ -319,15 +392,17 @@ module Mongo
319
392
  end
320
393
 
321
394
  def flags
322
- @flags ||= (!primary? ? [ :slave_ok ] : [])
395
+ @flags ||= CURSOR_FLAGS_MAP.each.reduce([]) do |flags, (key, value)|
396
+ if options[key] || (options[:cursor_type] && options[:cursor_type] == key)
397
+ flags.push(*value)
398
+ end
399
+ flags
400
+ end
323
401
  end
324
402
 
325
403
  def has_special_fields?
326
- sort || hint || comment || max_scan || show_disk_loc || snapshot || explained? || cluster.sharded?
327
- end
328
-
329
- def primary?
330
- read.name == :primary
404
+ modifiers || sort || hint || comment || max_time_ms || max_scan ||
405
+ show_disk_loc || snapshot || explained? || cluster.sharded?
331
406
  end
332
407
 
333
408
  def query_options
@@ -349,7 +424,7 @@ module Mongo
349
424
 
350
425
  def special_selector
351
426
  SPECIAL_FIELDS.reduce({}) do |hash, (key, method)|
352
- value = send(method)
427
+ value = send(method) || (options[:modifiers] && options[:modifiers][key])
353
428
  hash[key] = value if value
354
429
  hash
355
430
  end
@@ -34,10 +34,11 @@ module Mongo
34
34
  cmd = { :findandmodify => collection.name, :query => selector, :remove => true }
35
35
  cmd[:fields] = projection if projection
36
36
  cmd[:sort] = sort if sort
37
+ cmd[:maxTimeMS] = max_time_ms if max_time_ms
37
38
  database.command(cmd).first['value']
38
39
  end
39
40
 
40
- # Finds a single document and replace it.
41
+ # Finds a single document and replaces it.
41
42
  #
42
43
  # @example Find a document and replace it, returning the original.
43
44
  # view.find_one_and_replace({ name: 'test' }, :return_document => :before)
@@ -45,7 +46,7 @@ module Mongo
45
46
  # @example Find a document and replace it, returning the new document.
46
47
  # view.find_one_and_replace({ name: 'test' }, :return_document => :after)
47
48
  #
48
- # @param [ BSON::Document ] replacement The updates.
49
+ # @param [ BSON::Document ] replacement The replacement.
49
50
  # @param [ Hash ] opts The options.
50
51
  #
51
52
  # @option opts [ Symbol ] :return_document Either :before or :after.
@@ -79,6 +80,7 @@ module Mongo
79
80
  cmd[:sort] = sort if sort
80
81
  cmd[:new] = !!(opts[:return_document] && opts[:return_document] == :after)
81
82
  cmd[:upsert] = opts[:upsert] if opts[:upsert]
83
+ cmd[:maxTimeMS] = max_time_ms if max_time_ms
82
84
  value = database.command(cmd).first['value']
83
85
  value unless value.nil? || value.empty?
84
86
  end
@@ -112,7 +114,7 @@ module Mongo
112
114
  # @example Replace a single document.
113
115
  # collection_view.replace_one({ name: 'test' })
114
116
  #
115
- # @param [ Hash ] document The document to replace.
117
+ # @param [ Hash ] replacement The replacement document.
116
118
  # @param [ Hash ] opts The options.
117
119
  #
118
120
  # @option opts [ true, false ] :upsert Whether to upsert if the
@@ -121,14 +123,16 @@ module Mongo
121
123
  # @return [ Result ] The response from the database.
122
124
  #
123
125
  # @since 2.0.0
124
- def replace_one(document, opts = {})
125
- update(document, false, opts)
126
+ def replace_one(replacement, opts = {})
127
+ update(replacement, false, opts)
126
128
  end
127
129
 
128
130
  # Update documents in the collection.
129
131
  #
130
132
  # @example Update multiple documents in the collection.
131
133
  # collection_view.update_many('$set' => { name: 'test' })
134
+ #
135
+ # @param [ Hash ] spec The update statement.
132
136
  # @param [ Hash ] opts The options.
133
137
  #
134
138
  # @option opts [ true, false ] :upsert Whether to upsert if the
@@ -145,6 +149,8 @@ module Mongo
145
149
  #
146
150
  # @example Update a single document in the collection.
147
151
  # collection_view.update_one('$set' => { name: 'test' })
152
+ #
153
+ # @param [ Hash ] spec The update statement.
148
154
  # @param [ Hash ] opts The options.
149
155
  #
150
156
  # @option opts [ true, false ] :upsert Whether to upsert if the
@@ -97,12 +97,16 @@ module Mongo
97
97
  end
98
98
 
99
99
  def get_more_operation
100
- Operation::Read::GetMore.new({
100
+ Operation::Read::GetMore.new(get_more_spec)
101
+ end
102
+
103
+ def get_more_spec
104
+ {
101
105
  :to_return => to_return,
102
106
  :cursor_id => @cursor_id,
103
107
  :db_name => database.name,
104
108
  :coll_name => @coll_name || collection.name
105
- })
109
+ }
106
110
  end
107
111
 
108
112
  def kill_cursors
@@ -110,7 +114,11 @@ module Mongo
110
114
  end
111
115
 
112
116
  def kill_cursors_operation
113
- Operation::KillCursors.new({ :cursor_ids => [ @cursor_id ]})
117
+ Operation::KillCursors.new(kill_cursors_spec)
118
+ end
119
+
120
+ def kill_cursors_spec
121
+ { :cursor_ids => [ @cursor_id ]}
114
122
  end
115
123
 
116
124
  def limited?
@@ -0,0 +1,113 @@
1
+ # Copyright (C) 2015 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the 'License');
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an 'AS IS' BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+
17
+ # Represents a DBRef document in the database.
18
+ #
19
+ # @since 2.1.0
20
+ class DBRef
21
+ include BSON::JSON
22
+
23
+ # The constant for the collection reference field.
24
+ #
25
+ # @since 2.1.0
26
+ COLLECTION = '$ref'.freeze
27
+
28
+ # The constant for the id field.
29
+ #
30
+ # @since 2.1.0
31
+ ID = '$id'.freeze
32
+
33
+ # The constant for the database field.
34
+ #
35
+ # @since 2.1.0
36
+ DATABASE = '$db'.freeze
37
+
38
+ # @return [ String ] collection The collection name.
39
+ attr_reader :collection
40
+
41
+ # @return [ BSON::ObjectId ] id The referenced document id.
42
+ attr_reader :id
43
+
44
+ # @return [ String ] database The database name.
45
+ attr_reader :database
46
+
47
+ # Get the DBRef as a JSON document
48
+ #
49
+ # @example Get the DBRef as a JSON hash.
50
+ # dbref.as_json
51
+ #
52
+ # @return [ Hash ] The max key as a JSON hash.
53
+ #
54
+ # @since 2.1.0
55
+ def as_json(*args)
56
+ document = { '$ref' => collection, '$id' => id }
57
+ document.merge!('$db' => database) if database
58
+ document
59
+ end
60
+
61
+ # Instantiate a new DBRef.
62
+ #
63
+ # @example Create the DBRef.
64
+ # Mongo::DBRef.new('users', id, 'database')
65
+ #
66
+ # @param [ String ] collection The collection name.
67
+ # @param [ BSON::ObjectId ] id The object id.
68
+ # @param [ String ] database The database name.
69
+ #
70
+ # @since 2.1.0
71
+ def initialize(collection, id, database = nil)
72
+ @collection = collection
73
+ @id = id
74
+ @database = database
75
+ end
76
+
77
+ # Converts the DBRef to raw BSON.
78
+ #
79
+ # @example Convert the DBRef to raw BSON.
80
+ # dbref.to_bson
81
+ #
82
+ # @param [ String ] encoded The encoded BSON to append to.
83
+ #
84
+ # @return [ String ] The raw BSON.
85
+ #
86
+ # @since 2.1.0
87
+ def to_bson(encoded = ''.force_encoding(BSON::BINARY))
88
+ as_json.to_bson(encoded)
89
+ end
90
+
91
+ module ClassMethods
92
+
93
+ # Deserialize the hash from BSON, converting to a DBRef if appropriate.
94
+ #
95
+ # @param [ IO ] bson The bson representing a hash.
96
+ #
97
+ # @return [ Hash, DBRef ] The decoded hash or DBRef.
98
+ #
99
+ # @see http://bsonspec.org/#/specification
100
+ #
101
+ # @since 2.0.0
102
+ def from_bson(bson)
103
+ decoded = super
104
+ if ref = decoded['$ref']
105
+ decoded = DBRef.new(ref, decoded['$id'], decoded['$db'])
106
+ end
107
+ decoded
108
+ end
109
+ end
110
+ end
111
+
112
+ ::Hash.send(:extend, DBRef::ClassMethods)
113
+ end