mongodb-mongo 0.12 → 0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README.rdoc +12 -12
  2. data/Rakefile +1 -1
  3. data/bin/bson_benchmark.rb +1 -1
  4. data/bin/mongo_console +3 -3
  5. data/bin/run_test_script +2 -2
  6. data/bin/standard_benchmark +3 -3
  7. data/examples/admin.rb +3 -3
  8. data/examples/benchmarks.rb +2 -2
  9. data/examples/blog.rb +4 -4
  10. data/examples/capped.rb +3 -3
  11. data/examples/cursor.rb +3 -3
  12. data/examples/gridfs.rb +4 -4
  13. data/examples/index_test.rb +11 -11
  14. data/examples/info.rb +3 -3
  15. data/examples/queries.rb +3 -3
  16. data/examples/simple.rb +3 -3
  17. data/examples/strict.rb +3 -3
  18. data/examples/types.rb +4 -9
  19. data/lib/mongo.rb +35 -3
  20. data/lib/mongo/admin.rb +56 -60
  21. data/lib/mongo/collection.rb +368 -320
  22. data/lib/mongo/connection.rb +166 -0
  23. data/lib/mongo/cursor.rb +206 -209
  24. data/lib/mongo/db.rb +478 -489
  25. data/lib/mongo/errors.rb +8 -9
  26. data/lib/mongo/gridfs/chunk.rb +66 -70
  27. data/lib/mongo/gridfs/grid_store.rb +406 -410
  28. data/lib/mongo/message/get_more_message.rb +8 -13
  29. data/lib/mongo/message/insert_message.rb +7 -11
  30. data/lib/mongo/message/kill_cursors_message.rb +7 -12
  31. data/lib/mongo/message/message.rb +58 -62
  32. data/lib/mongo/message/message_header.rb +19 -24
  33. data/lib/mongo/message/msg_message.rb +5 -9
  34. data/lib/mongo/message/opcodes.rb +10 -15
  35. data/lib/mongo/message/query_message.rb +42 -46
  36. data/lib/mongo/message/remove_message.rb +8 -12
  37. data/lib/mongo/message/update_message.rb +9 -13
  38. data/lib/mongo/query.rb +84 -88
  39. data/lib/mongo/types/binary.rb +13 -17
  40. data/lib/mongo/types/code.rb +9 -13
  41. data/lib/mongo/types/dbref.rb +10 -14
  42. data/lib/mongo/types/objectid.rb +103 -107
  43. data/lib/mongo/types/regexp_of_holding.rb +18 -22
  44. data/lib/mongo/types/undefined.rb +7 -10
  45. data/lib/mongo/util/bson.rb +4 -9
  46. data/lib/mongo/util/xml_to_ruby.rb +1 -3
  47. data/mongo-ruby-driver.gemspec +33 -32
  48. data/{tests → test}/mongo-qa/_common.rb +1 -1
  49. data/{tests → test}/mongo-qa/admin +1 -1
  50. data/{tests → test}/mongo-qa/capped +1 -1
  51. data/{tests → test}/mongo-qa/count1 +4 -4
  52. data/{tests → test}/mongo-qa/dbs +1 -1
  53. data/{tests → test}/mongo-qa/find +1 -1
  54. data/{tests → test}/mongo-qa/find1 +1 -1
  55. data/{tests → test}/mongo-qa/gridfs_in +2 -2
  56. data/{tests → test}/mongo-qa/gridfs_out +2 -2
  57. data/{tests → test}/mongo-qa/indices +2 -2
  58. data/{tests → test}/mongo-qa/remove +1 -1
  59. data/{tests → test}/mongo-qa/stress1 +1 -1
  60. data/{tests → test}/mongo-qa/test1 +1 -1
  61. data/{tests → test}/mongo-qa/update +1 -1
  62. data/{tests → test}/test_admin.rb +3 -3
  63. data/{tests → test}/test_bson.rb +4 -4
  64. data/{tests → test}/test_byte_buffer.rb +0 -0
  65. data/{tests → test}/test_chunk.rb +4 -4
  66. data/{tests → test}/test_collection.rb +42 -4
  67. data/{tests/test_mongo.rb → test/test_connection.rb} +35 -11
  68. data/test/test_cursor.rb +223 -0
  69. data/{tests → test}/test_db.rb +12 -12
  70. data/{tests → test}/test_db_api.rb +28 -33
  71. data/{tests → test}/test_db_connection.rb +3 -3
  72. data/{tests → test}/test_grid_store.rb +4 -4
  73. data/{tests → test}/test_message.rb +1 -1
  74. data/{tests → test}/test_objectid.rb +3 -3
  75. data/{tests → test}/test_ordered_hash.rb +0 -0
  76. data/{tests → test}/test_round_trip.rb +6 -2
  77. data/{tests → test}/test_threading.rb +3 -3
  78. data/test/test_xgen.rb +73 -0
  79. metadata +33 -32
  80. data/lib/mongo/mongo.rb +0 -164
  81. data/tests/test_cursor.rb +0 -121
@@ -0,0 +1,166 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'mongo/db'
18
+
19
+ module Mongo
20
+
21
+ # A connection to MongoDB.
22
+ class Connection
23
+
24
+ DEFAULT_PORT = 27017
25
+
26
+ # Create a Mongo database server instance. You specify either one or a
27
+ # pair of servers. If one, you also say if connecting to a slave is
28
+ # OK. In either case, the host default is "localhost" and port default
29
+ # is DEFAULT_PORT.
30
+ #
31
+ # If you specify a pair, pair_or_host is a hash with two keys :left
32
+ # and :right. Each key maps to either
33
+ # * a server name, in which case port is DEFAULT_PORT
34
+ # * a port number, in which case server is "localhost"
35
+ # * an array containing a server name and a port number in that order
36
+ #
37
+ # +options+ are passed on to each DB instance:
38
+ #
39
+ # :slave_ok :: Only used if one host is specified. If false, when
40
+ # connecting to that host/port a DB object will check to
41
+ # see if the server is the master. If it is not, an error
42
+ # is thrown.
43
+ #
44
+ # :auto_reconnect :: If a DB connection gets closed (for example, we
45
+ # have a server pair and saw the "not master"
46
+ # error, which closes the connection), then
47
+ # automatically try to reconnect to the master or
48
+ # to the single server we have been given. Defaults
49
+ # to +false+.
50
+ #
51
+ # Since that's so confusing, here are a few examples:
52
+ #
53
+ # Connection.new # localhost, DEFAULT_PORT, !slave
54
+ # Connection.new("localhost") # localhost, DEFAULT_PORT, !slave
55
+ # Connection.new("localhost", 3000) # localhost, 3000, slave not ok
56
+ # # localhost, 3000, slave ok
57
+ # Connection.new("localhost", 3000, :slave_ok => true)
58
+ # # localhost, DEFAULT_PORT, auto reconnect
59
+ # Connection.new(nil, nil, :auto_reconnect => true)
60
+ #
61
+ # # A pair of servers. DB will always talk to the master. On socket
62
+ # # error or "not master" error, we will auto-reconnect to the
63
+ # # current master.
64
+ # Connection.new({:left => ["db1.example.com", 3000],
65
+ # :right => "db2.example.com"}, # DEFAULT_PORT
66
+ # nil, :auto_reconnect => true)
67
+ #
68
+ # # Here, :right is localhost/DEFAULT_PORT. No auto-reconnect.
69
+ # Connection.new({:left => ["db1.example.com", 3000]})
70
+ #
71
+ # When a DB object first connects to a pair, it will find the master
72
+ # instance and connect to that one.
73
+ def initialize(pair_or_host=nil, port=nil, options={})
74
+ @pair = case pair_or_host
75
+ when String
76
+ [[pair_or_host, port ? port.to_i : DEFAULT_PORT]]
77
+ when Hash
78
+ connections = []
79
+ connections << pair_val_to_connection(pair_or_host[:left])
80
+ connections << pair_val_to_connection(pair_or_host[:right])
81
+ connections
82
+ when nil
83
+ [['localhost', DEFAULT_PORT]]
84
+ end
85
+ @options = options
86
+ end
87
+
88
+ # Return the Mongo::DB named +db_name+. The slave_ok and
89
+ # auto_reconnect options passed in via #new may be overridden here.
90
+ # See DB#new for other options you can pass in.
91
+ def db(db_name, options={})
92
+ DB.new(db_name, @pair, @options.merge(options))
93
+ end
94
+
95
+ # Returns a hash containing database names as keys and disk space for
96
+ # each as values.
97
+ def database_info
98
+ doc = single_db_command('admin', :listDatabases => 1)
99
+ h = {}
100
+ doc['databases'].each { |db|
101
+ h[db['name']] = db['sizeOnDisk'].to_i
102
+ }
103
+ h
104
+ end
105
+
106
+ # Returns an array of database names.
107
+ def database_names
108
+ database_info.keys
109
+ end
110
+
111
+ # Not implemented.
112
+ def clone_database(from)
113
+ raise "not implemented"
114
+ end
115
+
116
+ # Not implemented.
117
+ def copy_database(from_host, from_db, to_db)
118
+ raise "not implemented"
119
+ end
120
+
121
+ # Drops the database +name+.
122
+ def drop_database(name)
123
+ single_db_command(name, :dropDatabase => 1)
124
+ end
125
+
126
+ protected
127
+
128
+ # Turns an array containing a host name string and a
129
+ # port number integer into a [host, port] pair array.
130
+ def pair_val_to_connection(a)
131
+ case a
132
+ when nil
133
+ ['localhost', DEFAULT_PORT]
134
+ when String
135
+ [a, DEFAULT_PORT]
136
+ when Integer
137
+ ['localhost', a]
138
+ when Array
139
+ a
140
+ end
141
+ end
142
+
143
+ # Send cmd (a hash, possibly ordered) to the admin database and return
144
+ # the answer. Raises an error unless the return is "ok" (DB#ok?
145
+ # returns +true+).
146
+ def single_db_command(db_name, cmd)
147
+ db = nil
148
+ begin
149
+ db = db(db_name)
150
+ doc = db.db_command(cmd)
151
+ raise "error retrieving database info: #{doc.inspect}" unless db.ok?(doc)
152
+ doc
153
+ ensure
154
+ db.close if db
155
+ end
156
+ end
157
+ end
158
+
159
+ class Mongo < Connection
160
+ def initialize(pair_or_host=nil, port=nil, options={})
161
+ super(pair_or_host, port, options)
162
+
163
+ warn "Mongo::Mongo is deprecated and will be removed - please use Mongo::Connection"
164
+ end
165
+ end
166
+ end
data/lib/mongo/cursor.rb CHANGED
@@ -1,4 +1,3 @@
1
- # --
2
1
  # Copyright (C) 2008-2009 10gen Inc.
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,220 +11,218 @@
12
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
12
  # See the License for the specific language governing permissions and
14
13
  # limitations under the License.
15
- # ++
16
14
 
17
15
  require 'mongo/message'
18
16
  require 'mongo/util/byte_buffer'
19
17
  require 'mongo/util/bson'
20
18
 
21
- module XGen
22
- module Mongo
23
- module Driver
24
-
25
- # A cursor over query results. Returned objects are hashes.
26
- class Cursor
27
-
28
- include Enumerable
29
-
30
- RESPONSE_HEADER_SIZE = 20
31
-
32
- attr_reader :db, :collection, :query
33
-
34
- def initialize(db, collection, query, admin=false)
35
- @db, @collection, @query, @admin = db, collection, query, admin
36
- @num_to_return = @query.number_to_return || 0
37
- @cache = []
38
- @closed = false
39
- @can_call_to_a = true
40
- @query_run = false
41
- @rows = nil
42
- end
43
-
44
- def closed?; @closed; end
45
-
46
- # Internal method, not for general use. Return +true+ if there are
47
- # more records to retrieve. We do not check @num_to_return; #each is
48
- # responsible for doing that.
49
- def more?
50
- num_remaining > 0
51
- end
52
-
53
- # Return the next object or nil if there are no more. Raises an error
54
- # if necessary.
55
- def next_object
56
- refill_via_get_more if num_remaining == 0
57
- o = @cache.shift
58
-
59
- if o && o['$err']
60
- err = o['$err']
61
-
62
- # If the server has stopped being the master (e.g., it's one of a
63
- # pair but it has died or something like that) then we close that
64
- # connection. If the db has auto connect option and a pair of
65
- # servers, next request will re-open on master server.
66
- @db.close if err == "not master"
67
-
68
- raise err
69
- end
70
-
71
- o
72
- end
73
-
74
- # Iterate over each object, yielding it to the given block. At most
75
- # @num_to_return records are returned (or all of them, if
76
- # @num_to_return is 0).
77
- #
78
- # If #to_a has already been called then this method uses the array
79
- # that we store internally. In that case, #each can be called multiple
80
- # times because it re-uses that array.
81
- #
82
- # You can call #each after calling #to_a (multiple times even, because
83
- # it will use the internally-stored array), but you can't call #to_a
84
- # after calling #each unless you also called it before calling #each.
85
- # If you try to do that, an error will be raised.
86
- def each
87
- if @rows # Already turned into an array
88
- @rows.each { |row| yield row }
89
- else
90
- num_returned = 0
91
- while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
92
- yield next_object()
93
- num_returned += 1
94
- end
95
- @can_call_to_a = false
96
- end
97
- end
98
-
99
- # Return all of the rows (up to the +num_to_return+ value specified in
100
- # #new) as an array. Calling this multiple times will work fine; it
101
- # always returns the same array.
102
- #
103
- # Don't use this if you're expecting large amounts of data, of course.
104
- # All of the returned rows are kept in an array stored in this object
105
- # so it can be reused.
106
- #
107
- # You can call #each after calling #to_a (multiple times even, because
108
- # it will use the internally-stored array), but you can't call #to_a
109
- # after calling #each unless you also called it before calling #each.
110
- # If you try to do that, an error will be raised.
111
- def to_a
112
- return @rows if @rows
113
- raise "can't call Cursor#to_a after calling Cursor#each" unless @can_call_to_a
114
- @rows = []
115
- num_returned = 0
116
- while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
117
- @rows << next_object()
118
- num_returned += 1
119
- end
120
- @rows
121
- end
122
-
123
- # Returns an explain plan record.
124
- def explain
125
- old_val = @query.explain
126
- @query.explain = true
127
-
128
- c = Cursor.new(@db, @collection, @query)
129
- explanation = c.next_object
130
- c.close
131
-
132
- @query.explain = old_val
133
- explanation
134
- end
135
-
136
- # Close the cursor.
137
- #
138
- # Note: if a cursor is read until exhausted (read until OP_QUERY or
139
- # OP_GETMORE returns zero for the cursor id), there is no need to
140
- # close it by calling this method.
141
- def close
142
- @db.send_to_db(KillCursorsMessage.new(@cursor_id)) if @cursor_id
143
- @cache = []
144
- @cursor_id = 0
145
- @closed = true
146
- end
147
-
148
- protected
149
-
150
- def read_all
151
- read_message_header
152
- read_response_header
153
- read_objects_off_wire
154
- end
155
-
156
- def read_objects_off_wire
157
- while doc = next_object_on_wire
158
- @cache << doc
159
- end
160
- end
161
-
162
- def read_message_header
163
- MessageHeader.new.read_header(@db)
164
- end
165
-
166
- def read_response_header
167
- header_buf = ByteBuffer.new
168
- header_buf.put_array(@db.receive_full(RESPONSE_HEADER_SIZE).unpack("C*"))
169
- raise "Short read for DB response header; expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}" unless header_buf.length == RESPONSE_HEADER_SIZE
170
- header_buf.rewind
171
- @result_flags = header_buf.get_int
172
- @cursor_id = header_buf.get_long
173
- @starting_from = header_buf.get_int
174
- @n_returned = header_buf.get_int
175
- @n_remaining = @n_returned
176
- end
177
-
178
- def num_remaining
179
- refill_via_get_more if @cache.length == 0
180
- @cache.length
181
- end
182
-
183
- private
184
-
185
- def next_object_on_wire
186
- send_query_if_needed
187
- # if @n_remaining is 0 but we have a non-zero cursor, there are more
188
- # to fetch, so do a GetMore operation, but don't do it here - do it
189
- # when someone pulls an object out of the cache and it's empty
190
- return nil if @n_remaining == 0
191
- object_from_stream
192
- end
193
-
194
- def refill_via_get_more
195
- send_query_if_needed
196
- return if @cursor_id == 0
197
- @db._synchronize {
198
- @db.send_to_db(GetMoreMessage.new(@admin ? 'admin' : @db.name, @collection.name, @cursor_id))
199
- read_all
200
- }
201
- end
202
-
203
- def object_from_stream
204
- buf = ByteBuffer.new
205
- buf.put_array(@db.receive_full(4).unpack("C*"))
206
- buf.rewind
207
- size = buf.get_int
208
- buf.put_array(@db.receive_full(size - 4).unpack("C*"), 4)
209
- @n_remaining -= 1
210
- buf.rewind
211
- BSON.new.deserialize(buf)
212
- end
213
-
214
- def send_query_if_needed
215
- # Run query first time we request an object from the wire
216
- unless @query_run
217
- @db._synchronize {
218
- @db.send_query_message(QueryMessage.new(@admin ? 'admin' : @db.name, @collection.name, @query))
219
- @query_run = true
220
- read_all
221
- }
222
- end
223
- end
224
-
225
- def to_s
226
- "DBResponse(flags=#@result_flags, cursor_id=#@cursor_id, start=#@starting_from, n_returned=#@n_returned)"
227
- end
19
+ module Mongo
20
+
21
+ # A cursor over query results. Returned objects are hashes.
22
+ class Cursor
23
+
24
+ include Enumerable
25
+
26
+ RESPONSE_HEADER_SIZE = 20
27
+
28
+ attr_reader :db, :collection, :query
29
+
30
+ # Create a new cursor.
31
+ #
32
+ # Should not be called directly by application developers.
33
+ def initialize(db, collection, query, admin=false)
34
+ @db, @collection, @query, @admin = db, collection, query, admin
35
+ @num_to_return = @query.number_to_return || 0
36
+ @cache = []
37
+ @closed = false
38
+ @query_run = false
39
+ end
40
+
41
+ # Return the next object or nil if there are no more. Raises an error
42
+ # if necessary.
43
+ def next_object
44
+ refill_via_get_more if num_remaining == 0
45
+ o = @cache.shift
46
+
47
+ if o && o['$err']
48
+ err = o['$err']
49
+
50
+ # If the server has stopped being the master (e.g., it's one of a
51
+ # pair but it has died or something like that) then we close that
52
+ # connection. If the db has auto connect option and a pair of
53
+ # servers, next request will re-open on master server.
54
+ @db.close if err == "not master"
55
+
56
+ raise err
57
+ end
58
+
59
+ o
60
+ end
61
+
62
+ # Get the size of the results set for this query.
63
+ #
64
+ # Returns the number of objects in the results set for this query. Does
65
+ # not take limit and skip into account. Raises OperationFailure on a
66
+ # database error.
67
+ def count
68
+ command = OrderedHash["count", @collection.name,
69
+ "query", @query.selector]
70
+ response = @db.db_command(command)
71
+ return response['n'].to_i if response['ok'] == 1
72
+ return 0 if response['errmsg'] == "ns missing"
73
+ raise OperationFailure, "Count failed: #{response['errmsg']}"
74
+ end
75
+
76
+ # Iterate over each document in this cursor, yielding it to the given
77
+ # block.
78
+ #
79
+ # Iterating over an entire cursor will close it.
80
+ def each
81
+ num_returned = 0
82
+ while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
83
+ yield next_object()
84
+ num_returned += 1
85
+ end
86
+ end
87
+
88
+ # Return all of the documents in this cursor as an array of hashes.
89
+ #
90
+ # Raises InvalidOperation if this cursor has already been used (including
91
+ # any previous calls to this method).
92
+ #
93
+ # Use of this method is discouraged - iterating over a cursor is much
94
+ # more efficient in most cases.
95
+ def to_a
96
+ raise InvalidOperation, "can't call Cursor#to_a on a used cursor" if @query_run
97
+ rows = []
98
+ num_returned = 0
99
+ while more? && (@num_to_return <= 0 || num_returned < @num_to_return)
100
+ rows << next_object()
101
+ num_returned += 1
102
+ end
103
+ rows
104
+ end
105
+
106
+ # Returns an explain plan record for this cursor.
107
+ def explain
108
+ old_val = @query.explain
109
+ @query.explain = true
110
+
111
+ c = Cursor.new(@db, @collection, @query)
112
+ explanation = c.next_object
113
+ c.close
114
+
115
+ @query.explain = old_val
116
+ explanation
117
+ end
118
+
119
+ # Close the cursor.
120
+ #
121
+ # Note: if a cursor is read until exhausted (read until OP_QUERY or
122
+ # OP_GETMORE returns zero for the cursor id), there is no need to
123
+ # close it by calling this method.
124
+ #
125
+ # Collection#find takes an optional block argument which can be used to
126
+ # ensure that your cursors get closed. See the documentation for
127
+ # Collection#find for details.
128
+ def close
129
+ @db.send_to_db(KillCursorsMessage.new(@cursor_id)) if @cursor_id
130
+ @cache = []
131
+ @cursor_id = 0
132
+ @closed = true
133
+ end
134
+
135
+ # Returns true if this cursor is closed, false otherwise.
136
+ def closed?; @closed; end
137
+
138
+ private
139
+
140
+ def read_all
141
+ read_message_header
142
+ read_response_header
143
+ read_objects_off_wire
144
+ end
145
+
146
+ def read_objects_off_wire
147
+ while doc = next_object_on_wire
148
+ @cache << doc
149
+ end
150
+ end
151
+
152
+ def read_message_header
153
+ MessageHeader.new.read_header(@db)
154
+ end
155
+
156
+ def read_response_header
157
+ header_buf = ByteBuffer.new
158
+ header_buf.put_array(@db.receive_full(RESPONSE_HEADER_SIZE).unpack("C*"))
159
+ raise "Short read for DB response header; expected #{RESPONSE_HEADER_SIZE} bytes, saw #{header_buf.length}" unless header_buf.length == RESPONSE_HEADER_SIZE
160
+ header_buf.rewind
161
+ @result_flags = header_buf.get_int
162
+ @cursor_id = header_buf.get_long
163
+ @starting_from = header_buf.get_int
164
+ @n_returned = header_buf.get_int
165
+ @n_remaining = @n_returned
166
+ end
167
+
168
+ def num_remaining
169
+ refill_via_get_more if @cache.length == 0
170
+ @cache.length
171
+ end
172
+
173
+ # Internal method, not for general use. Return +true+ if there are
174
+ # more records to retrieve. We do not check @num_to_return; #each is
175
+ # responsible for doing that.
176
+ def more?
177
+ num_remaining > 0
178
+ end
179
+
180
+ def next_object_on_wire
181
+ send_query_if_needed
182
+ # if @n_remaining is 0 but we have a non-zero cursor, there are more
183
+ # to fetch, so do a GetMore operation, but don't do it here - do it
184
+ # when someone pulls an object out of the cache and it's empty
185
+ return nil if @n_remaining == 0
186
+ object_from_stream
187
+ end
188
+
189
+ def refill_via_get_more
190
+ if send_query_if_needed or @cursor_id == 0
191
+ return
228
192
  end
193
+ @db._synchronize {
194
+ @db.send_to_db(GetMoreMessage.new(@admin ? 'admin' : @db.name, @collection.name, @cursor_id))
195
+ read_all
196
+ }
197
+ end
198
+
199
+ def object_from_stream
200
+ buf = ByteBuffer.new
201
+ buf.put_array(@db.receive_full(4).unpack("C*"))
202
+ buf.rewind
203
+ size = buf.get_int
204
+ buf.put_array(@db.receive_full(size - 4).unpack("C*"), 4)
205
+ @n_remaining -= 1
206
+ buf.rewind
207
+ BSON.new.deserialize(buf)
208
+ end
209
+
210
+ def send_query_if_needed
211
+ # Run query first time we request an object from the wire
212
+ if @query_run
213
+ false
214
+ else
215
+ @db._synchronize {
216
+ @db.send_query_message(QueryMessage.new(@admin ? 'admin' : @db.name, @collection.name, @query))
217
+ @query_run = true
218
+ read_all
219
+ }
220
+ true
221
+ end
222
+ end
223
+
224
+ def to_s
225
+ "DBResponse(flags=#@result_flags, cursor_id=#@cursor_id, start=#@starting_from, n_returned=#@n_returned)"
229
226
  end
230
227
  end
231
228
  end