mongodb-mongo 0.12 → 0.13

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 (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