jmongo 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +8 -0
- data/Gemfile.lock +43 -0
- data/Rakefile +72 -0
- data/jmongo.gemspec +84 -6
- data/lib/jmongo.rb +6 -14
- data/lib/jmongo/collection.rb +196 -114
- data/lib/jmongo/connection.rb +39 -13
- data/lib/jmongo/cursor.rb +161 -63
- data/lib/jmongo/db.rb +119 -30
- data/lib/jmongo/exceptions.rb +39 -0
- data/lib/jmongo/mongo-2.6.5.gb1.jar +0 -0
- data/lib/jmongo/mongo/bson.rb +130 -0
- data/lib/jmongo/mongo/collection.rb +185 -0
- data/lib/jmongo/mongo/connection.rb +45 -0
- data/lib/jmongo/mongo/db.rb +31 -0
- data/lib/jmongo/mongo/jmongo.rb +44 -0
- data/lib/jmongo/mongo/mongo.rb +98 -0
- data/lib/jmongo/mongo/ruby_ext.rb +38 -0
- data/lib/jmongo/mongo/utils.rb +136 -0
- data/lib/jmongo/version.rb +1 -1
- data/test-results.txt +98 -0
- data/test/auxillary/1.4_features.rb +166 -0
- data/test/auxillary/authentication_test.rb +68 -0
- data/test/auxillary/autoreconnect_test.rb +41 -0
- data/test/auxillary/fork_test.rb +30 -0
- data/test/auxillary/repl_set_auth_test.rb +58 -0
- data/test/auxillary/slave_connection_test.rb +36 -0
- data/test/auxillary/threaded_authentication_test.rb +101 -0
- data/test/bson/binary_test.rb +15 -0
- data/test/bson/bson_test.rb +657 -0
- data/test/bson/byte_buffer_test.rb +208 -0
- data/test/bson/hash_with_indifferent_access_test.rb +38 -0
- data/test/bson/json_test.rb +17 -0
- data/test/bson/object_id_test.rb +138 -0
- data/test/bson/ordered_hash_test.rb +245 -0
- data/test/bson/test_helper.rb +46 -0
- data/test/bson/timestamp_test.rb +46 -0
- data/test/collection_test.rb +933 -0
- data/test/connection_test.rb +325 -0
- data/test/conversions_test.rb +121 -0
- data/test/cursor_fail_test.rb +75 -0
- data/test/cursor_message_test.rb +43 -0
- data/test/cursor_test.rb +547 -0
- data/test/data/empty_data +0 -0
- data/test/data/sample_data +0 -0
- data/test/data/sample_file.pdf +0 -0
- data/test/data/small_data.txt +1 -0
- data/test/db_api_test.rb +739 -0
- data/test/db_connection_test.rb +15 -0
- data/test/db_test.rb +325 -0
- data/test/grid_file_system_test.rb +260 -0
- data/test/grid_io_test.rb +210 -0
- data/test/grid_test.rb +259 -0
- data/test/load/thin/config.ru +6 -0
- data/test/load/thin/config.yml.template +6 -0
- data/test/load/thin/load.rb +24 -0
- data/test/load/unicorn/config.ru +6 -0
- data/test/load/unicorn/load.rb +23 -0
- data/test/load/unicorn/unicorn.rb.template +29 -0
- data/test/replica_sets/connect_test.rb +111 -0
- data/test/replica_sets/connection_string_test.rb +29 -0
- data/test/replica_sets/count_test.rb +36 -0
- data/test/replica_sets/insert_test.rb +54 -0
- data/test/replica_sets/pooled_insert_test.rb +58 -0
- data/test/replica_sets/query_secondaries.rb +109 -0
- data/test/replica_sets/query_test.rb +52 -0
- data/test/replica_sets/read_preference_test.rb +43 -0
- data/test/replica_sets/refresh_test.rb +123 -0
- data/test/replica_sets/replication_ack_test.rb +71 -0
- data/test/replica_sets/rs_test_helper.rb +27 -0
- data/test/safe_test.rb +68 -0
- data/test/support/hash_with_indifferent_access.rb +186 -0
- data/test/support/keys.rb +45 -0
- data/test/support_test.rb +19 -0
- data/test/test_helper.rb +111 -0
- data/test/threading/threading_with_large_pool_test.rb +90 -0
- data/test/threading_test.rb +88 -0
- data/test/tools/auth_repl_set_manager.rb +14 -0
- data/test/tools/keyfile.txt +1 -0
- data/test/tools/repl_set_manager.rb +377 -0
- data/test/unit/collection_test.rb +128 -0
- data/test/unit/connection_test.rb +85 -0
- data/test/unit/cursor_test.rb +127 -0
- data/test/unit/db_test.rb +96 -0
- data/test/unit/grid_test.rb +51 -0
- data/test/unit/node_test.rb +73 -0
- data/test/unit/pool_manager_test.rb +47 -0
- data/test/unit/pool_test.rb +9 -0
- data/test/unit/read_test.rb +101 -0
- data/test/unit/safe_test.rb +125 -0
- data/test/uri_test.rb +92 -0
- metadata +170 -99
- data/lib/jmongo/ajrb.rb +0 -189
- data/lib/jmongo/jmongo_jext.rb +0 -302
- data/lib/jmongo/mongo-2.6.3.jar +0 -0
- data/lib/jmongo/utils.rb +0 -61
data/lib/jmongo/connection.rb
CHANGED
@@ -20,23 +20,30 @@ module Mongo
|
|
20
20
|
include Mongo::JavaImpl::Connection_::InstanceMethods
|
21
21
|
extend Mongo::JavaImpl::Connection_::ClassMethods
|
22
22
|
|
23
|
-
attr_reader :connection, :logger, :auths
|
23
|
+
attr_reader :connection, :connector, :logger, :auths, :primary
|
24
|
+
|
25
|
+
DEFAULT_PORT = 27017
|
24
26
|
|
25
27
|
def initialize host = nil, port = nil, opts = {}
|
26
28
|
if opts.has_key?(:new_from_uri)
|
27
|
-
@
|
29
|
+
@options = opts
|
30
|
+
@mongo_uri = opts[:new_from_uri]
|
31
|
+
@connection = JMongo::Mongo.new(@mongo_uri)
|
28
32
|
else
|
29
33
|
@logger = opts[:logger]
|
30
34
|
@host = host || 'localhost'
|
31
35
|
@port = port || 27017
|
32
|
-
server_address = JMongo::ServerAddress.new @host, @port
|
33
|
-
options = JMongo::MongoOptions.new
|
34
|
-
options.connectionsPerHost = opts[:pool_size] || 1
|
35
|
-
options.socketTimeout = opts[:timeout].to_i * 1000 || 5000
|
36
|
-
@connection = JMongo::Mongo.new(server_address, options)
|
36
|
+
@server_address = JMongo::ServerAddress.new @host, @port
|
37
|
+
@options = JMongo::MongoOptions.new
|
38
|
+
@options.connectionsPerHost = opts[:pool_size] || 1
|
39
|
+
@options.socketTimeout = opts[:timeout].to_i * 1000 || 5000
|
40
|
+
@connection = JMongo::Mongo.new(@server_address, @options)
|
37
41
|
end
|
42
|
+
@connector = @connection.connector
|
38
43
|
@logger = opts[:logger]
|
39
44
|
@auths = opts.fetch(:auths, [])
|
45
|
+
add = @connector.address
|
46
|
+
@primary = [add.host, add.port]
|
40
47
|
end
|
41
48
|
|
42
49
|
def self.paired(nodes, opts={})
|
@@ -147,7 +154,7 @@ module Mongo
|
|
147
154
|
#
|
148
155
|
# @core databases []-instance_method
|
149
156
|
def [](db_name)
|
150
|
-
|
157
|
+
db db_name
|
151
158
|
end
|
152
159
|
|
153
160
|
# Drop a database.
|
@@ -176,11 +183,18 @@ module Mongo
|
|
176
183
|
raise_not_implemented
|
177
184
|
end
|
178
185
|
|
186
|
+
# Checks if a server is alive. This command will return immediately
|
187
|
+
# even if the server is in a lock.
|
188
|
+
#
|
189
|
+
# @return [Hash]
|
190
|
+
def ping
|
191
|
+
db("admin").command('ping')
|
192
|
+
end
|
179
193
|
# Get the build information for the current connection.
|
180
194
|
#
|
181
195
|
# @return [Hash]
|
182
196
|
def server_info
|
183
|
-
|
197
|
+
db("admin").command('buildinfo')
|
184
198
|
end
|
185
199
|
|
186
200
|
# Get the build version of the current server.
|
@@ -188,7 +202,7 @@ module Mongo
|
|
188
202
|
# @return [Mongo::ServerVersion]
|
189
203
|
# object allowing easy comparability of version.
|
190
204
|
def server_version
|
191
|
-
|
205
|
+
ServerVersion.new(server_info["version"])
|
192
206
|
end
|
193
207
|
|
194
208
|
# Is it okay to connect to a slave?
|
@@ -230,15 +244,27 @@ module Mongo
|
|
230
244
|
end
|
231
245
|
|
232
246
|
def connect_to_master
|
233
|
-
|
247
|
+
connect
|
234
248
|
end
|
235
249
|
|
236
250
|
def connected?
|
237
|
-
|
251
|
+
@connection && @connector && @connector.is_open
|
252
|
+
end
|
253
|
+
|
254
|
+
def connect
|
255
|
+
close
|
256
|
+
if @mongo_uri
|
257
|
+
@connection = JMongo::Mongo.new(@mongo_uri)
|
258
|
+
else
|
259
|
+
@connection = JMongo::Mongo.new(@server_address, @options)
|
260
|
+
end
|
261
|
+
@connector = @connection.connector
|
238
262
|
end
|
263
|
+
alias :reconnect :connect
|
239
264
|
|
240
265
|
def close
|
241
|
-
|
266
|
+
@connection.close if @connection
|
267
|
+
@connection = @connector = nil
|
242
268
|
end
|
243
269
|
|
244
270
|
end # class Connection
|
data/lib/jmongo/cursor.rb
CHANGED
@@ -17,90 +17,173 @@ module Mongo
|
|
17
17
|
class Cursor
|
18
18
|
include Mongo::JavaImpl::Utils
|
19
19
|
|
20
|
-
attr_reader :j_cursor
|
20
|
+
attr_reader :j_cursor, :collection, :selector, :fields,
|
21
|
+
:order, :hint, :snapshot, :timeout,
|
22
|
+
:full_collection_name, :transformer,
|
23
|
+
:options
|
21
24
|
|
22
25
|
def initialize(collection, options={})
|
26
|
+
@collection = collection
|
23
27
|
@j_collection = collection.j_collection
|
24
|
-
|
28
|
+
@query_run = false
|
25
29
|
@selector = convert_selector_for_query(options[:selector])
|
26
30
|
@fields = convert_fields_for_query(options[:fields])
|
27
|
-
@admin = options
|
28
|
-
@
|
29
|
-
@
|
30
|
-
@
|
31
|
+
@admin = options.fetch(:admin, false)
|
32
|
+
@order = nil
|
33
|
+
@batch_size = Mongo::DEFAULT_BATCH_SIZE
|
34
|
+
@skip = 0
|
35
|
+
@limit = 0
|
36
|
+
_skip options[:skip]
|
37
|
+
_limit options[:limit]
|
38
|
+
_sort options[:order]
|
39
|
+
_batch_size options[:batch_size]
|
31
40
|
@hint = options[:hint]
|
32
41
|
@snapshot = options[:snapshot]
|
33
42
|
@explain = options[:explain]
|
34
43
|
@socket = options[:socket]
|
35
|
-
@
|
36
|
-
@
|
37
|
-
@
|
44
|
+
@timeout = options.fetch(:timeout, true)
|
45
|
+
@tailable = options.fetch(:tailable, false)
|
46
|
+
@transformer = options[:transformer]
|
38
47
|
|
39
|
-
|
40
|
-
|
48
|
+
@full_collection_name = "#{@collection.db.name}.#{@collection.name}"
|
49
|
+
|
50
|
+
spawn_cursor
|
51
|
+
end
|
41
52
|
|
53
|
+
def rewind!
|
54
|
+
close
|
55
|
+
@query_run = false
|
42
56
|
spawn_cursor
|
43
57
|
end
|
58
|
+
|
59
|
+
def close
|
60
|
+
@query_run = true
|
61
|
+
@j_cursor.close
|
62
|
+
end
|
63
|
+
|
64
|
+
def cursor_id
|
65
|
+
@j_cursor.get_cursor_id
|
66
|
+
end
|
67
|
+
|
68
|
+
def closed?
|
69
|
+
cursor_id == 0
|
70
|
+
end
|
71
|
+
|
72
|
+
def alive?
|
73
|
+
cursor_id != 0
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_option(opt)
|
77
|
+
check_modifiable
|
78
|
+
@j_cursor.addOption(opt)
|
79
|
+
options
|
80
|
+
end
|
81
|
+
|
82
|
+
def options
|
83
|
+
@j_cursor.getOptions
|
84
|
+
end
|
85
|
+
|
86
|
+
def query_opts
|
87
|
+
warn "The method Cursor#query_opts has been deprecated " +
|
88
|
+
"and will removed in v2.0. Use Cursor#options instead."
|
89
|
+
options
|
90
|
+
end
|
91
|
+
|
92
|
+
def remove_option(opt)
|
93
|
+
check_modifiable
|
94
|
+
@j_cursor.setOptions(options & ~opt)
|
95
|
+
options
|
96
|
+
end
|
97
|
+
|
44
98
|
def current_document
|
45
|
-
|
46
|
-
next_document
|
47
|
-
else
|
48
|
-
from_dbobject(@j_cursor.curr)
|
49
|
-
end
|
99
|
+
_xform(from_dbobject(@j_cursor.curr))
|
50
100
|
end
|
51
101
|
|
52
102
|
def next_document
|
53
|
-
|
54
|
-
@j_cursor.has_next? ? from_dbobject(@j_cursor.next) : BSON::OrderedHash.new
|
103
|
+
_xform(has_next? ? __next : nil)
|
55
104
|
end
|
105
|
+
alias :next :next_document
|
106
|
+
|
107
|
+
def _xform(doc)
|
108
|
+
if @transformer && @transformer.respond_to?('call')
|
109
|
+
@transformer.call(doc)
|
110
|
+
else
|
111
|
+
doc
|
112
|
+
end
|
113
|
+
end
|
114
|
+
private :_xform
|
56
115
|
|
57
116
|
def has_next?
|
58
117
|
@j_cursor.has_next?
|
59
118
|
end
|
119
|
+
|
60
120
|
# iterate directly from the mongo db
|
61
121
|
def each
|
62
122
|
check_modifiable
|
63
|
-
|
64
|
-
while @j_cursor.has_next?
|
123
|
+
while has_next?
|
65
124
|
yield next_document
|
66
125
|
end
|
67
126
|
end
|
68
127
|
|
69
|
-
def
|
70
|
-
return
|
128
|
+
def _batch_size(size=nil)
|
129
|
+
return if size.nil?
|
71
130
|
check_modifiable
|
72
|
-
raise ArgumentError, "
|
131
|
+
raise ArgumentError, "batch_size requires an integer" unless size.is_a? Integer
|
132
|
+
@batch_size = size
|
133
|
+
end
|
134
|
+
private :_batch_size
|
73
135
|
|
74
|
-
|
75
|
-
|
136
|
+
def batch_size(size=nil)
|
137
|
+
_batch_size(size)
|
138
|
+
@j_cursor = @j_cursor.batchSize(@batch_size) if @batch_size
|
76
139
|
self
|
77
140
|
end
|
78
141
|
|
79
|
-
def
|
80
|
-
return
|
142
|
+
def _limit(number_to_return=nil)
|
143
|
+
return if number_to_return.nil?
|
81
144
|
check_modifiable
|
82
|
-
raise ArgumentError, "
|
145
|
+
raise ArgumentError, "limit requires an integer" unless number_to_return.is_a? Integer
|
146
|
+
@limit = number_to_return
|
147
|
+
end
|
148
|
+
private :_limit
|
83
149
|
|
84
|
-
|
85
|
-
|
150
|
+
def limit(number_to_return=nil)
|
151
|
+
_limit(number_to_return)
|
152
|
+
wrap_invalid_op do
|
153
|
+
@j_cursor = @j_cursor.limit(@limit) if @limit
|
154
|
+
end
|
86
155
|
self
|
87
156
|
end
|
88
157
|
|
89
|
-
def
|
158
|
+
def _skip(number_to_skip=nil)
|
159
|
+
return if number_to_skip.nil?
|
90
160
|
check_modifiable
|
91
|
-
|
92
|
-
@
|
161
|
+
raise ArgumentError, "skip requires an integer" unless number_to_skip.is_a? Integer
|
162
|
+
@skip = number_to_skip
|
163
|
+
end
|
164
|
+
private :_skip
|
165
|
+
|
166
|
+
def skip(number_to_skip=nil)
|
167
|
+
_skip(number_to_skip)
|
168
|
+
wrap_invalid_op do
|
169
|
+
@j_cursor = @j_cursor.skip(@skip) if @skip
|
170
|
+
end
|
93
171
|
self
|
94
172
|
end
|
95
173
|
|
96
|
-
def _sort(key_or_list, direction=nil)
|
174
|
+
def _sort(key_or_list=nil, direction=nil)
|
97
175
|
return if key_or_list.nil?
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
176
|
+
check_modifiable
|
177
|
+
@order = prep_sort(key_or_list, direction)
|
178
|
+
end
|
179
|
+
private :_sort
|
180
|
+
|
181
|
+
def sort(key_or_list, direction=nil)
|
182
|
+
_sort(key_or_list, direction)
|
183
|
+
wrap_invalid_op do
|
184
|
+
@j_cursor = @j_cursor.sort(@order) if @order
|
102
185
|
end
|
103
|
-
|
186
|
+
self
|
104
187
|
end
|
105
188
|
|
106
189
|
def size
|
@@ -110,9 +193,9 @@ module Mongo
|
|
110
193
|
def count(skip_and_limit = false)
|
111
194
|
if skip_and_limit && @skip && @limit
|
112
195
|
check_modifiable
|
113
|
-
@j_cursor.skip(@skip).limit(@limit).size
|
114
|
-
else
|
115
196
|
@j_cursor.size
|
197
|
+
else
|
198
|
+
@j_cursor.count
|
116
199
|
end
|
117
200
|
end
|
118
201
|
|
@@ -122,38 +205,38 @@ module Mongo
|
|
122
205
|
|
123
206
|
def map(&block)
|
124
207
|
ret = []
|
125
|
-
|
126
|
-
while
|
127
|
-
ret << block.call(
|
208
|
+
rewind! unless has_next?
|
209
|
+
while has_next?
|
210
|
+
ret << block.call(__next)
|
128
211
|
end
|
129
212
|
ret
|
130
213
|
end
|
131
214
|
|
132
215
|
def to_a
|
133
216
|
ret = []
|
134
|
-
|
135
|
-
while
|
136
|
-
ret <<
|
217
|
+
rewind! unless has_next?
|
218
|
+
while has_next?
|
219
|
+
ret << __next
|
137
220
|
end
|
138
221
|
ret
|
139
222
|
end
|
223
|
+
|
224
|
+
def to_set
|
225
|
+
Set.new self.to_a
|
226
|
+
end
|
227
|
+
|
140
228
|
private
|
141
229
|
|
230
|
+
def __next
|
231
|
+
@query_run = true
|
232
|
+
from_dbobject(@j_cursor.next)
|
233
|
+
end
|
234
|
+
|
142
235
|
# Convert the +:fields+ parameter from a single field name or an array
|
143
236
|
# of fields names to a hash, with the field names for keys and '1' for each
|
144
237
|
# value.
|
145
238
|
def convert_fields_for_query(fields)
|
146
|
-
|
147
|
-
when String, Symbol
|
148
|
-
to_dbobject({fields => 1})
|
149
|
-
when Array
|
150
|
-
return nil if fields.length.zero?
|
151
|
-
hash = {}
|
152
|
-
fields.each { |field| hash[field] = 1 }
|
153
|
-
to_dbobject hash
|
154
|
-
when Hash
|
155
|
-
to_dbobject fields
|
156
|
-
end
|
239
|
+
to_dbobject prep_fields(fields)
|
157
240
|
end
|
158
241
|
|
159
242
|
# Set the query selector hash.
|
@@ -166,14 +249,18 @@ module Mongo
|
|
166
249
|
end
|
167
250
|
end
|
168
251
|
|
252
|
+
def no_fields?
|
253
|
+
@fields.nil? || @fields.empty?
|
254
|
+
end
|
255
|
+
|
169
256
|
def spawn_cursor
|
170
|
-
@j_cursor =
|
257
|
+
@j_cursor = no_fields? ? @j_collection.find(@selector) : @j_collection.find(@selector, @fields)
|
171
258
|
|
172
259
|
if @j_cursor
|
173
260
|
@j_cursor = @j_cursor.sort(@order) if @order
|
174
|
-
@j_cursor = @j_cursor.skip(@skip) if @skip > 0
|
175
|
-
@j_cursor = @j_cursor.limit(@limit) if @limit > 0
|
176
|
-
@j_cursor = @j_cursor.batchSize(@batch_size)
|
261
|
+
@j_cursor = @j_cursor.skip(@skip) if @skip && @skip > 0
|
262
|
+
@j_cursor = @j_cursor.limit(@limit) if @limit && @limit > 0
|
263
|
+
@j_cursor = @j_cursor.batchSize(@batch_size) if @batch_size && @batch_size > 0
|
177
264
|
|
178
265
|
@j_cursor = @j_cursor.addOption JMongo::Bytes::QUERYOPTION_NOTIMEOUT unless @timeout
|
179
266
|
@j_cursor = @j_cursor.addOption JMongo::Bytes::QUERYOPTION_TAILABLE if @tailable
|
@@ -184,10 +271,21 @@ module Mongo
|
|
184
271
|
|
185
272
|
def check_modifiable
|
186
273
|
if @query_run
|
187
|
-
|
274
|
+
raise_invalid_op
|
188
275
|
end
|
189
276
|
end
|
190
277
|
|
278
|
+
def wrap_invalid_op
|
279
|
+
begin
|
280
|
+
yield
|
281
|
+
rescue => ex
|
282
|
+
raise_invalid_op
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def raise_invalid_op
|
287
|
+
raise InvalidOperation, "Cannot modify the query once it has been run or closed."
|
288
|
+
end
|
191
289
|
end # class Cursor
|
192
290
|
|
193
291
|
end # module Mongo
|
data/lib/jmongo/db.rb
CHANGED
@@ -22,10 +22,16 @@ module Mongo
|
|
22
22
|
attr_reader :name
|
23
23
|
attr_reader :connection
|
24
24
|
|
25
|
+
attr_writer :strict
|
26
|
+
|
27
|
+
ProfileLevel = {:off => 0, :slow_only => 1, :all => 2, 0 => 'off', 1 => 'slow_only', 2 => 'all'}
|
28
|
+
|
25
29
|
def initialize(db_name, connection, options={})
|
26
30
|
@name = db_name
|
27
31
|
@connection = connection
|
28
32
|
@j_db = @connection.connection.get_db db_name
|
33
|
+
@pk_factory = options[:pk]
|
34
|
+
@strict = options.fetch(:strict, false)
|
29
35
|
end
|
30
36
|
|
31
37
|
def authenticate(username, password, save_auth=true)
|
@@ -53,9 +59,7 @@ module Mongo
|
|
53
59
|
end
|
54
60
|
|
55
61
|
def collection_names
|
56
|
-
|
57
|
-
names = names.delete_if {|name| name.index(@name).nil? || name.index('$')}
|
58
|
-
names.map {|name| name.sub(@name + '.', '')}
|
62
|
+
@j_db.get_collection_names
|
59
63
|
end
|
60
64
|
|
61
65
|
def collections
|
@@ -67,15 +71,27 @@ module Mongo
|
|
67
71
|
def collections_info(coll_name=nil)
|
68
72
|
selector = {}
|
69
73
|
selector[:name] = full_collection_name(coll_name) if coll_name
|
70
|
-
|
74
|
+
coll = self.collection(SYSTEM_NAMESPACE_COLLECTION)
|
75
|
+
coll.find selector
|
71
76
|
end
|
72
77
|
|
73
78
|
def create_collection(name, options={})
|
74
|
-
|
79
|
+
if collection_names.include?(name)
|
80
|
+
raise MongoDBError, "Collection #{name} already exists. Currently in strict mode." if @strict
|
81
|
+
collection(name, options)
|
82
|
+
else
|
83
|
+
begin
|
84
|
+
jc = @j_db.create_collection(name, to_dbobject(options))
|
85
|
+
Collection.new self, name, options, jc
|
86
|
+
rescue NativeException => ex
|
87
|
+
raise MongoDBError, "Collection #{name} creation error: " +
|
88
|
+
ex.message
|
89
|
+
end
|
90
|
+
end
|
75
91
|
end
|
76
92
|
|
77
|
-
def collection(name)
|
78
|
-
Collection.new self, name
|
93
|
+
def collection(name, options = {})
|
94
|
+
Collection.new self, name, options
|
79
95
|
end
|
80
96
|
alias_method :[], :collection
|
81
97
|
|
@@ -83,24 +99,21 @@ module Mongo
|
|
83
99
|
coll = collection(name).j_collection.drop
|
84
100
|
end
|
85
101
|
|
86
|
-
def
|
87
|
-
raise_not_implemented
|
88
|
-
end
|
89
|
-
|
90
|
-
def last_status
|
102
|
+
def get_last_error
|
91
103
|
from_dbobject(@j_db.getLastError)
|
92
104
|
end
|
105
|
+
alias :last_status :get_last_error
|
93
106
|
|
94
107
|
def error?
|
95
|
-
|
108
|
+
!get_last_error['err'].nil?
|
96
109
|
end
|
97
110
|
|
98
111
|
def previous_error
|
99
|
-
|
112
|
+
exec_command :getpreverror
|
100
113
|
end
|
101
114
|
|
102
115
|
def reset_error_history
|
103
|
-
|
116
|
+
exec_command :reseterror
|
104
117
|
end
|
105
118
|
|
106
119
|
def query(collection, query, admin=false)
|
@@ -108,68 +121,144 @@ module Mongo
|
|
108
121
|
end
|
109
122
|
|
110
123
|
def dereference(dbref)
|
111
|
-
|
124
|
+
ns = dbref.namespace
|
125
|
+
raise MongoArgumentError, "No namespace for dbref: #{dbref.inspect}"
|
126
|
+
collection(ns).find_one("_id" => dbref.object_id)
|
112
127
|
end
|
113
128
|
|
114
129
|
def eval(code, *args)
|
115
|
-
|
130
|
+
doc = do_eval(code, *args)
|
131
|
+
return unless doc
|
132
|
+
return doc['retval']['value'] if doc['retval'] && doc['retval']['value']
|
133
|
+
doc['retval']
|
116
134
|
end
|
117
135
|
|
118
136
|
def rename_collection(from, to)
|
119
|
-
|
137
|
+
begin
|
138
|
+
@j_db.get_collection(from).rename(to)
|
139
|
+
rescue => ex
|
140
|
+
raise(MongoDBError, "Error renaming collection from: #{from}, to: #{to}")
|
141
|
+
end
|
142
|
+
true
|
120
143
|
end
|
121
144
|
|
122
145
|
def drop_index(collection_name, index_name)
|
123
|
-
|
146
|
+
self[collection_name].drop_index(index_name)
|
124
147
|
end
|
125
148
|
|
126
149
|
def index_information(collection_name)
|
127
|
-
|
150
|
+
info = {}
|
151
|
+
from_dbobject(@j_db.get_collection(collection_name).get_index_info).each do |index|
|
152
|
+
info[index['name']] = index
|
153
|
+
end
|
154
|
+
info
|
128
155
|
end
|
129
156
|
|
130
157
|
def stats
|
131
|
-
exec_command(:dbstats)
|
158
|
+
from_dbobject exec_command(:dbstats)
|
132
159
|
end
|
133
160
|
|
134
161
|
def create_index(collection_name, field_or_spec, unique=false)
|
135
162
|
collection(collection_name).create_indexes(field_or_spec,{:unique=>unique})
|
136
163
|
end
|
164
|
+
# Return +true+ if an error was caused by the most recently executed
|
165
|
+
# database operation.
|
166
|
+
#
|
167
|
+
# @return [Boolean]
|
168
|
+
def error?
|
169
|
+
get_last_error['err'] != nil
|
170
|
+
end
|
137
171
|
|
138
172
|
def ok?(doc)
|
139
|
-
doc['ok'] == 1.0
|
173
|
+
doc['ok'] == 1.0 || doc['ok'] == true
|
140
174
|
end
|
141
175
|
|
142
|
-
def command(
|
143
|
-
|
176
|
+
def command(cmd, opts={})
|
177
|
+
selector = cmd.respond_to?('merge') ? cmd : {cmd.to_s => 1}
|
178
|
+
check_response = opts.fetch(:check_response, true)
|
179
|
+
raise MongoArgumentError, "command must be given a selector" if selector.empty?
|
180
|
+
if selector.keys.length > 1 && RUBY_VERSION < '1.9' && selector.class != BSON::OrderedHash
|
181
|
+
raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
|
182
|
+
end
|
183
|
+
|
184
|
+
begin
|
185
|
+
result = exec_command(selector)
|
186
|
+
rescue => ex
|
187
|
+
raise OperationFailure, "Database command '#{selector.keys.first}' failed: #{ex.message}"
|
188
|
+
end
|
189
|
+
|
190
|
+
raise OperationFailure, "Database command '#{selector.keys.first}' failed: returned null." if result.nil?
|
191
|
+
|
192
|
+
if (check_response && !ok?(result))
|
193
|
+
message = "Database command '#{selector.keys.first}' failed: (" + result.map{|k, v| "#{k}: '#{v}'"}.join('; ') + ")."
|
194
|
+
raise OperationFailure.new message
|
195
|
+
else
|
196
|
+
result
|
197
|
+
end
|
144
198
|
end
|
145
199
|
|
146
200
|
def full_collection_name(collection_name)
|
147
201
|
"#{@name}.#{collection_name}"
|
148
202
|
end
|
149
203
|
|
204
|
+
# Returns the value of the +strict+ flag.
|
205
|
+
def strict?; @strict; end
|
206
|
+
|
207
|
+
# The primary key factory object (or +nil+).
|
208
|
+
#
|
209
|
+
# @return [Object, Nil]
|
150
210
|
def pk_factory
|
151
|
-
|
211
|
+
@pk_factory
|
152
212
|
end
|
153
213
|
|
214
|
+
# Specify a primary key factory if not already set.
|
215
|
+
#
|
216
|
+
# @raise [MongoArgumentError] if the primary key factory has already been set.
|
154
217
|
def pk_factory=(pk_factory)
|
155
|
-
|
218
|
+
if @pk_factory
|
219
|
+
raise MongoArgumentError, "Cannot change primary key factory once it's been set"
|
220
|
+
end
|
221
|
+
|
222
|
+
@pk_factory = pk_factory
|
156
223
|
end
|
157
224
|
|
158
225
|
def profiling_level
|
159
|
-
|
226
|
+
oh = BSON::OrderedHash.new
|
227
|
+
oh['profile'] = -1
|
228
|
+
doc = command(oh, :check_response => false)
|
229
|
+
raise "Error with profile command: #{doc.inspect}" unless ok?(doc) && doc['was'].kind_of?(Numeric)
|
230
|
+
was = ProfileLevel[doc['was'].to_i]
|
231
|
+
raise "Error: illegal profiling level value #{doc['was']}" if was.nil?
|
232
|
+
was.to_sym
|
160
233
|
end
|
161
234
|
|
162
235
|
def profiling_level=(level)
|
163
|
-
|
236
|
+
oh = BSON::OrderedHash.new
|
237
|
+
int_lvl = ProfileLevel[level]
|
238
|
+
raise "Error: illegal profiling level value #{level}" if int_lvl.nil?
|
239
|
+
oh['profile'] = int_lvl
|
240
|
+
doc = command(oh, :check_response => false)
|
241
|
+
ok?(doc) || raise(MongoDBError, "Error with profile command: #{doc.inspect}")
|
164
242
|
end
|
165
243
|
|
166
244
|
def profiling_info
|
167
|
-
|
245
|
+
Cursor.new(Collection.new(SYSTEM_PROFILE_COLLECTION, self), :selector => {}).to_a
|
168
246
|
end
|
169
247
|
|
170
248
|
def validate_collection(name)
|
171
|
-
|
249
|
+
cmd = BSON::OrderedHash.new
|
250
|
+
cmd['validate'] = name
|
251
|
+
cmd['full'] = true
|
252
|
+
doc = command(cmd, :check_response => false)
|
253
|
+
if !ok?(doc)
|
254
|
+
raise MongoDBError, "Error with validate command: #{doc.inspect}"
|
255
|
+
end
|
256
|
+
if (doc.has_key?('valid') && !doc['valid']) || (doc['result'] =~ /\b(exception|corrupt)\b/i)
|
257
|
+
raise MongoDBError, "Error: invalid collection #{name}: #{doc.inspect}"
|
258
|
+
end
|
259
|
+
doc
|
172
260
|
end
|
261
|
+
|
173
262
|
# additions to the ruby driver
|
174
263
|
def has_collection?(name)
|
175
264
|
has_coll name
|