jmongo 1.0.3 → 1.1.0
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.
- 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
|