mongodb-mongo 0.11.1 → 0.12

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/Rakefile CHANGED
@@ -12,7 +12,7 @@ require 'rbconfig'
12
12
  include Config
13
13
 
14
14
  gem_command = "gem"
15
- gem_command = "gem1.9" if CONFIG["MAJOR"] == "1" && CONFIG["MINOR"] == "9"
15
+ gem_command = "gem1.9" if $0.match(/1\.9$/) # use gem1.9 if we used rake1.9
16
16
 
17
17
  # NOTE: some of the tests assume Mongo is running
18
18
  Rake::TestTask.new do |t|
@@ -80,7 +80,7 @@ benchmark('batch insert (medium, no index)', insert_batch, PER_TRIAL/BATCH_SIZE,
80
80
  benchmark('batch insert (large, no index)', insert_batch, PER_TRIAL/BATCH_SIZE, db, 'large_bulk', LARGE)
81
81
 
82
82
  find_one = Proc.new { |coll, x, i|
83
- coll.find_first('x' => x)
83
+ coll.find_one('x' => x)
84
84
  }
85
85
  benchmark('find_one (small, no index)', find_one, PER_TRIAL, db, 'small_none', PER_TRIAL / 2)
86
86
  benchmark('find_one (medium, no index)', find_one, PER_TRIAL, db, 'medium_none', PER_TRIAL / 2)
@@ -1,5 +1,5 @@
1
1
  require "benchmark"
2
-
2
+
3
3
  $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
4
4
  require 'mongo'
5
5
 
@@ -20,21 +20,21 @@ arr = (0..OBJS_COUNT).collect {|x| { :number => x, :rndm => (rand(5)+1), :msg =>
20
20
 
21
21
  puts "Running benchmark"
22
22
  Benchmark.bmbm do |results|
23
- results.report("single object inserts: ") {
23
+ results.report("single object inserts: ") {
24
24
  TEST_COUNT.times {
25
25
  coll.clear
26
- arr.each {|x| coll.insert(x)}
26
+ arr.each {|x| coll.insert(x)}
27
27
  }
28
28
  }
29
- results.report("multiple object insert: ") {
29
+ results.report("multiple object insert: ") {
30
30
  TEST_COUNT.times {
31
31
  coll.clear
32
32
  coll.insert(arr)
33
33
  }
34
34
  }
35
- results.report("find_first: ") {
35
+ results.report("find_one: ") {
36
36
  TEST_COUNT.times {
37
- coll.find_first(:number => 0)
37
+ coll.find_one(:number => 0)
38
38
  }
39
39
  }
40
40
  end
data/lib/mongo.rb CHANGED
@@ -4,6 +4,7 @@ require 'mongo/types/objectid'
4
4
  require 'mongo/types/regexp_of_holding'
5
5
  require 'mongo/types/undefined'
6
6
 
7
+ require 'mongo/errors'
7
8
  require 'mongo/mongo'
8
9
  require 'mongo/message'
9
10
  require 'mongo/db'
@@ -29,25 +29,36 @@ module XGen
29
29
  case name
30
30
  when Symbol, String
31
31
  else
32
- raise RuntimeError, "new_name must be a string or symbol"
32
+ raise TypeError, "new_name must be a string or symbol"
33
33
  end
34
34
 
35
35
  name = name.to_s
36
36
 
37
37
  if name.empty? or name.include? ".."
38
- raise RuntimeError, "collection names cannot be empty"
38
+ raise InvalidName, "collection names cannot be empty"
39
39
  end
40
40
  if name.include? "$" and not name.match(/^\$cmd/)
41
- raise RuntimeError, "collection names must not contain '$'"
41
+ raise InvalidName, "collection names must not contain '$'"
42
42
  end
43
43
  if name.match(/^\./) or name.match(/\.$/)
44
- raise RuntimeError, "collection names must not start or end with '.'"
44
+ raise InvalidName, "collection names must not start or end with '.'"
45
45
  end
46
46
 
47
47
  @db, @name = db, name
48
48
  @hint = nil
49
49
  end
50
50
 
51
+ # Get a sub-collection of this collection by name.
52
+ #
53
+ # Raises InvalidName if an invalid collection name is used.
54
+ #
55
+ # :name :: the name of the collection to get
56
+ def [](name)
57
+ name = "#{self.name}.#{name}"
58
+ return Collection.new(self, name) if !db.strict? || db.collection_names.include?(name)
59
+ raise "Collection #{name} doesn't exist. Currently in strict mode."
60
+ end
61
+
51
62
  # Set hint fields to use and return +self+. hint may be a single field
52
63
  # name, array of field names, or a hash (preferably an OrderedHash).
53
64
  # May be +nil+.
@@ -89,31 +100,82 @@ module XGen
89
100
  @db.query(self, Query.new(selector, fields, offset, limit, sort, hint, snapshot))
90
101
  end
91
102
 
103
+ # Get a single object from the database.
104
+ #
105
+ # Raises TypeError if the argument is of an improper type. Returns a
106
+ # single document (hash), or nil if no result is found.
107
+ #
108
+ # :spec_or_object_id :: a hash specifying elements which must be
109
+ # present for a document to be included in the result set OR an
110
+ # instance of ObjectID to be used as the value for an _id query.
111
+ # if nil an empty spec, {}, will be used.
112
+ # :options :: options, as passed to Collection#find
113
+ def find_one(spec_or_object_id=nil, options={})
114
+ spec = case spec_or_object_id
115
+ when nil
116
+ {}
117
+ when ObjectID
118
+ {:_id => spec_or_object_id}
119
+ when Hash
120
+ spec_or_object_id
121
+ else
122
+ raise TypeError, "spec_or_object_id must be an instance of ObjectID or Hash, or nil"
123
+ end
124
+ find(spec, options.merge(:limit => -1)).next_object
125
+ end
126
+
127
+ # DEPRECATED - use find_one instead
128
+ #
92
129
  # Find the first record that matches +selector+. See #find.
93
130
  def find_first(selector={}, options={})
94
- h = options.dup
95
- h[:limit] = 1
96
- cursor = find(selector, h)
97
- cursor.next_object # don't need to explicitly close b/c of limit
131
+ warn "Collection#find_first is deprecated and will be removed. Please use Collection#find_one instead."
132
+ find_one(selector, options)
98
133
  end
99
134
 
100
- # Save an updated +object+ to the collection, or insert it if it doesn't exist already.
101
- def save(object)
102
- if id = object[:_id] || object['_id']
103
- repsert({:_id => id}, object)
135
+ # Save a document in this collection.
136
+ #
137
+ # If +to_save+ already has an '_id' then an update (upsert) operation
138
+ # is performed and any existing document with that _id is overwritten.
139
+ # Otherwise an insert operation is performed. Returns the _id of the
140
+ # saved document.
141
+ #
142
+ # :to_save :: the document (a hash) to be saved
143
+ #
144
+ # Options:
145
+ # :safe :: if true, check that the save succeeded. OperationFailure
146
+ # will be raised on an error. Checking for safety requires an extra
147
+ # round-trip to the database
148
+ def save(to_save, options={})
149
+ if id = to_save[:_id] || to_save['_id']
150
+ update({:_id => id}, to_save, :upsert => true, :safe => options.delete(:safe))
104
151
  id
105
152
  else
106
- insert(object)
153
+ insert(to_save, :safe => options.delete(:safe))
107
154
  end
108
155
  end
109
156
 
110
- # Insert +objects+, which are hashes. "<<" is aliased to this method.
111
- # Returns either the single inserted object or a new array containing
112
- # +objects+. The object(s) may have been modified by the database's PK
113
- # factory, if it has one.
114
- def insert(*objects)
115
- objects = objects.first if objects.size == 1 && objects.first.is_a?(Array)
116
- res = @db.insert_into_db(@name, objects)
157
+ # Insert a document(s) into this collection.
158
+ #
159
+ # "<<" is aliased to this method. Returns the _id of the inserted
160
+ # document or a list of _ids of the inserted documents. The object(s)
161
+ # may have been modified by the database's PK factory, if it has one.
162
+ #
163
+ # :doc_or_docs :: a document (as a hash) or Array of documents to be
164
+ # inserted
165
+ #
166
+ # Options:
167
+ # :safe :: if true, check that the insert succeeded. OperationFailure
168
+ # will be raised on an error. Checking for safety requires an extra
169
+ # round-trip to the database
170
+ def insert(doc_or_docs, options={})
171
+ doc_or_docs = [doc_or_docs] if !doc_or_docs.is_a?(Array)
172
+ res = @db.insert_into_db(@name, doc_or_docs)
173
+ if options.delete(:safe)
174
+ error = @db.error
175
+ if error
176
+ raise OperationFailure, error
177
+ end
178
+ end
117
179
  res.size > 1 ? res : res.first
118
180
  end
119
181
  alias_method :<<, :insert
@@ -128,23 +190,60 @@ module XGen
128
190
  remove({})
129
191
  end
130
192
 
193
+ # DEPRECATED - use update(... :upsert => true) instead
194
+ #
131
195
  # Update records that match +selector+ by applying +obj+ as an update.
132
196
  # If no match, inserts (???).
133
197
  def repsert(selector, obj)
134
- @db.repsert_in_db(@name, selector, obj)
198
+ warn "Collection#repsert is deprecated and will be removed. Please use Collection#update instead."
199
+ update(selector, obj, :upsert => true)
135
200
  end
136
201
 
202
+ # DEPRECATED - use update(... :upsert => false) instead
203
+ #
137
204
  # Update records that match +selector+ by applying +obj+ as an update.
138
205
  def replace(selector, obj)
139
- @db.replace_in_db(@name, selector, obj)
206
+ warn "Collection#replace is deprecated and will be removed. Please use Collection#update instead."
207
+ update(selector, obj)
140
208
  end
141
209
 
210
+ # DEPRECATED - use update(... :upsert => false) instead
211
+ #
142
212
  # Update records that match +selector+ by applying +obj+ as an update.
143
213
  # Both +selector+ and +modifier_obj+ are required.
144
214
  def modify(selector, modifier_obj)
145
- raise "no object" unless modifier_obj
146
- raise "no selector" unless selector
147
- @db.modify_in_db(@name, selector, modifier_obj)
215
+ warn "Collection#modify is deprecated and will be removed. Please use Collection#update instead."
216
+ update(selector, modifier_obj)
217
+ end
218
+
219
+ # Update a document(s) in this collection.
220
+ #
221
+ # :spec :: a hash specifying elements which must be present for
222
+ # a document to be updated
223
+ # :document :: a hash specifying the fields to be changed in the
224
+ # selected document(s), or (in the case of an upsert) the document to
225
+ # be inserted
226
+ #
227
+ # Options:
228
+ # :upsert :: if true, perform an upsert operation
229
+ # :safe :: if true, check that the update succeeded. OperationFailure
230
+ # will be raised on an error. Checking for safety requires an extra
231
+ # round-trip to the database
232
+ def update(spec, document, options={})
233
+ upsert = options.delete(:upsert)
234
+ safe = options.delete(:safe)
235
+
236
+ if upsert
237
+ @db.repsert_in_db(@name, spec, document)
238
+ else
239
+ @db.replace_in_db(@name, spec, document)
240
+ end
241
+ if safe
242
+ error = @db.error
243
+ if error
244
+ raise OperationFailure, error
245
+ end
246
+ end
148
247
  end
149
248
 
150
249
  # Create a new index. +field_or_spec+
@@ -219,7 +318,7 @@ EOS
219
318
  # Rename this collection.
220
319
  #
221
320
  # If operating in auth mode, client must be authorized as an admin to
222
- # perform this operation. Raises an error if +new_name+ is an invalid
321
+ # perform this operation. Raises +InvalidName+ if +new_name+ is an invalid
223
322
  # collection name.
224
323
  #
225
324
  # :new_name :: new name for this collection
@@ -227,19 +326,19 @@ EOS
227
326
  case new_name
228
327
  when Symbol, String
229
328
  else
230
- raise RuntimeError, "new_name must be a string or symbol"
329
+ raise TypeError, "new_name must be a string or symbol"
231
330
  end
232
331
 
233
332
  new_name = new_name.to_s
234
333
 
235
334
  if new_name.empty? or new_name.include? ".."
236
- raise RuntimeError, "collection names cannot be empty"
335
+ raise InvalidName, "collection names cannot be empty"
237
336
  end
238
337
  if new_name.include? "$"
239
- raise RuntimeError, "collection names must not contain '$'"
338
+ raise InvalidName, "collection names must not contain '$'"
240
339
  end
241
340
  if new_name.match(/^\./) or new_name.match(/\.$/)
242
- raise RuntimeError, "collection names must not start or end with '.'"
341
+ raise InvalidName, "collection names must not start or end with '.'"
243
342
  end
244
343
 
245
344
  @db.rename_collection(@name, new_name)
data/lib/mongo/db.rb CHANGED
@@ -114,7 +114,21 @@ module XGen
114
114
  # instance and connect to that one. On socket error or if we recieve a
115
115
  # "not master" error, we again find the master of the pair.
116
116
  def initialize(db_name, nodes, options={})
117
- raise "Invalid DB name \"#{db_name}\" (must be non-nil, non-zero-length, and can not contain \".\")" if !db_name || (db_name && db_name.length > 0 && db_name.include?("."))
117
+ case db_name
118
+ when Symbol, String
119
+ else
120
+ raise TypeError, "db_name must be a string or symbol"
121
+ end
122
+
123
+ [" ", ".", "$", "/", "\\"].each do |invalid_char|
124
+ if db_name.include? invalid_char
125
+ raise InvalidName, "database names cannot contain the character '#{invalid_char}'"
126
+ end
127
+ end
128
+ if db_name.empty?
129
+ raise InvalidName, "database name cannot be the empty string"
130
+ end
131
+
118
132
  @name, @nodes = db_name, nodes
119
133
  @strict = options[:strict]
120
134
  @pk_factory = options[:pk]
@@ -232,6 +246,7 @@ module XGen
232
246
  return Collection.new(self, name) if !strict? || collection_names.include?(name)
233
247
  raise "Collection #{name} doesn't exist. Currently in strict mode."
234
248
  end
249
+ alias_method :[], :collection
235
250
 
236
251
  # Drop collection +name+. Returns +true+ on success or if the
237
252
  # collection does not exist, +false+ otherwise.
@@ -364,8 +379,11 @@ module XGen
364
379
  }
365
380
  end
366
381
 
367
- # Alias for #replace_in_db. Normally called by Collection.modify.
368
- alias_method :modify_in_db, :replace_in_db
382
+ # DEPRECATED - use Collection#update instead
383
+ def modify_in_db(collection_name, selector, obj)
384
+ warn "DB#modify_in_db is deprecated and will be removed. Please use Collection#update instead."
385
+ replace_in_db(collection_name, selector, obj)
386
+ end
369
387
 
370
388
  # Update records in +collection_name+ that match +selector+ by
371
389
  # applying +obj+ as an update. If no match, inserts (???). Normally
@@ -393,7 +411,7 @@ module XGen
393
411
 
394
412
  # Dereference a DBRef, getting the document it points to.
395
413
  def dereference(dbref)
396
- collection(dbref.namespace).find_first("_id" => dbref.object_id)
414
+ collection(dbref.namespace).find_one("_id" => dbref.object_id)
397
415
  end
398
416
 
399
417
  # Evaluate a JavaScript expression on MongoDB.
@@ -474,8 +492,8 @@ module XGen
474
492
  end
475
493
 
476
494
  # Insert +objects+ into +collection_name+. Normally called by
477
- # Collection#insert. Returns a new array containing +objects+,
478
- # possibly modified by @pk_factory.
495
+ # Collection#insert. Returns a new array containing the _ids
496
+ # of the inserted documents.
479
497
  def insert_into_db(collection_name, objects)
480
498
  _synchronize {
481
499
  if @pk_factory
@@ -484,7 +502,7 @@ module XGen
484
502
  }
485
503
  else
486
504
  objects = objects.collect do |o|
487
- o[:_id] || o['_id'] ? o : o.merge(:_id => ObjectID.new)
505
+ o[:_id] || o['_id'] ? o : o.merge!(:_id => ObjectID.new)
488
506
  end
489
507
  end
490
508
  send_to_db(InsertMessage.new(@name, collection_name, true, *objects))
@@ -0,0 +1,27 @@
1
+ # Copyright 2009 10gen, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Exceptions raised by the MongoDB driver.
16
+
17
+ module XGen
18
+ module Mongo
19
+ module Driver
20
+ # Raised when a database operation fails.
21
+ class OperationFailure < RuntimeError; end
22
+
23
+ # Raised when an invalid name is used.
24
+ class InvalidName < RuntimeError; end
25
+ end
26
+ end
27
+ end
@@ -104,10 +104,10 @@ class BSON
104
104
  k = k.to_s
105
105
  if check_keys
106
106
  if k[0] == ?$
107
- raise RuntimeError.new("key #{k} must not start with '$'")
107
+ raise InvalidName.new("key #{k} must not start with '$'")
108
108
  end
109
109
  if k.include? ?.
110
- raise RuntimeError.new("key #{k} must not contain '.'")
110
+ raise InvalidName.new("key #{k} must not contain '.'")
111
111
  end
112
112
  end
113
113
  type = bson_type(v)
@@ -32,65 +32,82 @@ class OrderedHash < Hash
32
32
 
33
33
  # We only need the body of this class if the RUBY_VERSION is before 1.9
34
34
  if RUBY_VERSION < '1.9'
35
+ attr_accessor :ordered_keys
36
+
37
+ def self.[] *args
38
+ oh = OrderedHash.new
39
+ if Hash === args[0]
40
+ oh.merge! args[0]
41
+ elsif (args.size % 2) != 0
42
+ raise ArgumentError, "odd number of elements for Hash"
43
+ else
44
+ 0.step(args.size - 1, 2) do |key|
45
+ value = key + 1
46
+ oh[args[key]] = args[value]
47
+ end
48
+ end
49
+ oh
50
+ end
35
51
 
36
- attr_accessor :ordered_keys
52
+ def initialize(*a, &b)
53
+ super
54
+ @ordered_keys = []
55
+ end
37
56
 
38
- def keys
39
- @ordered_keys || []
40
- end
57
+ def keys
58
+ @ordered_keys || []
59
+ end
41
60
 
42
- def []=(key, value)
43
- @ordered_keys ||= []
44
- @ordered_keys << key unless @ordered_keys.include?(key)
45
- super(key, value)
46
- end
61
+ def []=(key, value)
62
+ @ordered_keys ||= []
63
+ @ordered_keys << key unless @ordered_keys.include?(key)
64
+ super(key, value)
65
+ end
47
66
 
48
- def each
49
- @ordered_keys ||= []
50
- @ordered_keys.each { |k| yield k, self[k] }
51
- end
67
+ def each
68
+ @ordered_keys ||= []
69
+ @ordered_keys.each { |k| yield k, self[k] }
70
+ end
52
71
 
53
- def values
54
- collect { |k, v| v }
55
- end
72
+ def values
73
+ collect { |k, v| v }
74
+ end
56
75
 
57
- def merge(other)
58
- oh = self.dup
59
- oh.merge!(other)
60
- oh
61
- end
76
+ def merge(other)
77
+ oh = self.dup
78
+ oh.merge!(other)
79
+ oh
80
+ end
62
81
 
63
- def merge!(other)
64
- @ordered_keys ||= []
65
- @ordered_keys += other.keys # unordered if not an OrderedHash
66
- @ordered_keys.uniq!
67
- super(other)
68
- end
82
+ def merge!(other)
83
+ @ordered_keys ||= []
84
+ @ordered_keys += other.keys # unordered if not an OrderedHash
85
+ @ordered_keys.uniq!
86
+ super(other)
87
+ end
69
88
 
70
- def inspect
71
- str = '{'
72
- str << (@ordered_keys || []).collect { |k| "\"#{k}\"=>#{self.[](k).inspect}" }.join(", ")
73
- str << '}'
74
- end
89
+ def inspect
90
+ str = '{'
91
+ str << (@ordered_keys || []).collect { |k| "\"#{k}\"=>#{self.[](k).inspect}" }.join(", ")
92
+ str << '}'
93
+ end
75
94
 
76
- def delete(key, &block)
77
- @ordered_keys.delete(key) if @ordered_keys
78
- super
79
- end
95
+ def delete(key, &block)
96
+ @ordered_keys.delete(key) if @ordered_keys
97
+ super
98
+ end
80
99
 
81
- def delete_if(&block)
82
- self.each { |k,v|
83
- if yield k, v
84
- delete(k)
85
- end
86
- }
87
- end
100
+ def delete_if(&block)
101
+ self.each { |k,v|
102
+ if yield k, v
103
+ delete(k)
104
+ end
105
+ }
106
+ end
88
107
 
89
- def clear
90
- super
91
- @ordered_keys = []
108
+ def clear
109
+ super
110
+ @ordered_keys = []
111
+ end
92
112
  end
93
-
94
- end # Ruby before 1.9
95
-
96
113
  end
@@ -24,6 +24,7 @@ PACKAGE_FILES = ['README.rdoc', 'Rakefile', 'mongo-ruby-driver.gemspec',
24
24
  'lib/mongo/gridfs/chunk.rb',
25
25
  'lib/mongo/gridfs/grid_store.rb',
26
26
  'lib/mongo/gridfs.rb',
27
+ 'lib/mongo/errors.rb',
27
28
  'lib/mongo/message/get_more_message.rb',
28
29
  'lib/mongo/message/insert_message.rb',
29
30
  'lib/mongo/message/kill_cursors_message.rb',
@@ -66,6 +67,7 @@ TEST_FILES = ['tests/mongo-qa/_common.rb',
66
67
  'tests/test_bson.rb',
67
68
  'tests/test_byte_buffer.rb',
68
69
  'tests/test_chunk.rb',
70
+ 'tests/test_collection.rb',
69
71
  'tests/test_cursor.rb',
70
72
  'tests/test_db.rb',
71
73
  'tests/test_db_api.rb',
@@ -80,7 +82,7 @@ TEST_FILES = ['tests/mongo-qa/_common.rb',
80
82
 
81
83
  Gem::Specification.new do |s|
82
84
  s.name = 'mongo'
83
- s.version = '0.11.1'
85
+ s.version = '0.12'
84
86
  s.platform = Gem::Platform::RUBY
85
87
  s.summary = 'Ruby driver for the 10gen Mongo DB'
86
88
  s.description = 'A Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org.'
@@ -22,7 +22,7 @@ n1.times { |i|
22
22
  puts
23
23
 
24
24
  n2.times { |i|
25
- x = c.find_first({:id => i})
25
+ x = c.find_one({:id => i})
26
26
  x['subarray'] = "foo#{i}"
27
27
  p x
28
28
  c.modify({:id => i}, x)
@@ -0,0 +1,143 @@
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
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
18
+ require 'mongo'
19
+ require 'test/unit'
20
+
21
+ # NOTE: assumes Mongo is running
22
+ class TestCollection < Test::Unit::TestCase
23
+ include XGen::Mongo
24
+ include XGen::Mongo::Driver
25
+
26
+ @@db = Mongo.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
27
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT).db('ruby-mongo-test')
28
+ @@test = @@db.collection("test")
29
+
30
+ def setup
31
+ @@test.drop()
32
+ end
33
+
34
+ def test_collection
35
+ assert_raise InvalidName do
36
+ @@db["te$t"]
37
+ end
38
+
39
+ assert_kind_of Collection, @@db["test"]
40
+ assert_equal @@db["test"].name(), @@db.collection("test").name()
41
+ assert_equal @@db["test"].name(), @@db[:test].name()
42
+
43
+ assert_kind_of Collection, @@db["test"]["foo"]
44
+ assert_equal @@db["test"]["foo"].name(), @@db.collection("test.foo").name()
45
+ assert_equal @@db["test"]["foo"].name(), @@db["test.foo"].name()
46
+ end
47
+
48
+ def test_safe_insert
49
+ a = {"hello" => "world"}
50
+ @@test.insert(a)
51
+ @@test.insert(a)
52
+ assert @@db.error.include? "E11000"
53
+
54
+ assert_raise OperationFailure do
55
+ @@test.insert(a, :safe => true)
56
+ end
57
+ end
58
+
59
+ def test_update
60
+ id1 = @@test.save("x" => 5)
61
+ @@test.update({}, {"$inc" => {"x" => 1}})
62
+ assert_equal 1, @@test.count()
63
+ assert_equal 6, @@test.find_one(:_id => id1)["x"]
64
+
65
+ id2 = @@test.save("x" => 1)
66
+ @@test.update({"x" => 6}, {"$inc" => {"x" => 1}})
67
+ assert_equal 7, @@test.find_one(:_id => id1)["x"]
68
+ assert_equal 1, @@test.find_one(:_id => id2)["x"]
69
+ end
70
+
71
+ def test_upsert
72
+ @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
73
+ @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
74
+
75
+ assert_equal 1, @@test.count()
76
+ assert_equal 2, @@test.find_one()["count"]
77
+ end
78
+
79
+ def test_safe_update
80
+ @@test.create_index("x")
81
+ @@test.insert("x" => 5)
82
+
83
+ @@test.update({}, {"$inc" => {"x" => 1}})
84
+ assert @@db.error?
85
+
86
+ assert_raise OperationFailure do
87
+ @@test.update({}, {"$inc" => {"x" => 1}}, :safe => true)
88
+ end
89
+ end
90
+
91
+ def test_safe_save
92
+ @@test.create_index("hello", true)
93
+
94
+ @@test.save("hello" => "world")
95
+ @@test.save("hello" => "world")
96
+ assert @@db.error.include? "E11000"
97
+
98
+ assert_raise OperationFailure do
99
+ @@test.save({"hello" => "world"}, :safe => true)
100
+ end
101
+ end
102
+
103
+ def test_find_one
104
+ id = @@test.save("hello" => "world", "foo" => "bar")
105
+
106
+ assert_equal "world", @@test.find_one()["hello"]
107
+ assert_equal @@test.find_one(id), @@test.find_one()
108
+ assert_equal @@test.find_one(nil), @@test.find_one()
109
+ assert_equal @@test.find_one({}), @@test.find_one()
110
+ assert_equal @@test.find_one("hello" => "world"), @@test.find_one()
111
+ assert_equal @@test.find_one(OrderedHash["hello", "world"]), @@test.find_one()
112
+
113
+ assert @@test.find_one(nil, :fields => ["hello"]).include?("hello")
114
+ assert !@@test.find_one(nil, :fields => ["foo"]).include?("hello")
115
+
116
+ assert_equal nil, @@test.find_one("hello" => "foo")
117
+ assert_equal nil, @@test.find_one(OrderedHash["hello", "foo"])
118
+ assert_equal nil, @@test.find_one(ObjectID.new)
119
+
120
+ assert_raise TypeError do
121
+ @@test.find_one(6)
122
+ end
123
+ end
124
+
125
+ def test_insert_adds_id
126
+ doc = {"hello" => "world"}
127
+ @@test.insert(doc)
128
+ assert doc.include? :_id
129
+
130
+ docs = [{"hello" => "world"}, {"hello" => "world"}]
131
+ @@test.insert(docs)
132
+ docs.each do |doc|
133
+ assert doc.include? :_id
134
+ end
135
+ end
136
+
137
+ def test_save_adds_id
138
+ doc = {"hello" => "world"}
139
+ @@test.save(doc)
140
+ assert doc.include? :_id
141
+ end
142
+ end
143
+
data/tests/test_db.rb CHANGED
@@ -80,7 +80,7 @@ class DBTest < Test::Unit::TestCase
80
80
 
81
81
  insert_id = coll.insert('name' => 'Fred', 'age' => 42)
82
82
  # new id gets added to returned object
83
- row = coll.find_first({'name' => 'Fred'}, :limit => 1)
83
+ row = coll.find_one({'name' => 'Fred'})
84
84
  oid = row['_id']
85
85
  assert_not_nil oid
86
86
  assert_equal insert_id, oid
@@ -88,7 +88,7 @@ class DBTest < Test::Unit::TestCase
88
88
  oid = XGen::Mongo::Driver::ObjectID.new
89
89
  data = {'_id' => oid, 'name' => 'Barney', 'age' => 41}
90
90
  coll.insert(data)
91
- row = coll.find_first({'name' => data['name']}, :limit => 1)
91
+ row = coll.find_one({'name' => data['name']})
92
92
  db_oid = row['_id']
93
93
  assert_equal oid, db_oid
94
94
  assert_equal data, row
@@ -152,7 +152,7 @@ class DBTest < Test::Unit::TestCase
152
152
  assert_equal 1, prev_error['nPrev']
153
153
  assert_equal prev_error["err"], @@db.error
154
154
 
155
- @@db.collection('test').find_first
155
+ @@db.collection('test').find_one
156
156
  assert_nil @@db.error
157
157
  assert !@@db.error?
158
158
  assert @@db.previous_error
data/tests/test_db_api.rb CHANGED
@@ -52,11 +52,15 @@ class DBAPITest < Test::Unit::TestCase
52
52
  oh['b'] = 'foo'
53
53
 
54
54
  oid = @@coll.save(oh)
55
- assert_equal 'foo', @@coll.find_first(:_id => oid)['b']
55
+ assert_equal 'foo', @@coll.find_one(oid)['b']
56
+
57
+ oh = OrderedHash['a' => 1, 'b' => 'foo']
58
+ oid = @@coll.save(oh)
59
+ assert_equal 'foo', @@coll.find_one(oid)['b']
56
60
  end
57
61
 
58
62
  def test_insert_multiple
59
- ids = @@coll.insert({'a' => 2}, {'b' => 3})
63
+ ids = @@coll.insert([{'a' => 2}, {'b' => 3}])
60
64
 
61
65
  ids.each do |i|
62
66
  assert_kind_of ObjectID, i
@@ -242,9 +246,9 @@ class DBAPITest < Test::Unit::TestCase
242
246
  assert_equal 1, x['a']
243
247
  end
244
248
 
245
- def test_find_first_no_records
249
+ def test_find_one_no_records
246
250
  @@coll.clear
247
- x = @@coll.find_first('a' => 1)
251
+ x = @@coll.find_one('a' => 1)
248
252
  assert_nil x
249
253
  end
250
254
 
@@ -469,28 +473,28 @@ class DBAPITest < Test::Unit::TestCase
469
473
 
470
474
  def test_replace
471
475
  assert_equal @@coll.count, 1
472
- assert_equal @@coll.find_first["a"], 1
476
+ assert_equal @@coll.find_one["a"], 1
473
477
 
474
478
  @@coll.replace({"a" => 1}, {"a" => 2})
475
479
  assert_equal @@coll.count, 1
476
- assert_equal @@coll.find_first["a"], 2
480
+ assert_equal @@coll.find_one["a"], 2
477
481
 
478
482
  @@coll.replace({"b" => 1}, {"a" => 3})
479
483
  assert_equal @@coll.count, 1
480
- assert_equal @@coll.find_first["a"], 2
484
+ assert_equal @@coll.find_one["a"], 2
481
485
  end
482
486
 
483
487
  def test_repsert
484
488
  assert_equal @@coll.count, 1
485
- assert_equal @@coll.find_first["a"], 1
489
+ assert_equal @@coll.find_one["a"], 1
486
490
 
487
491
  @@coll.repsert({"a" => 1}, {"a" => 2})
488
492
  assert_equal @@coll.count, 1
489
- assert_equal @@coll.find_first["a"], 2
493
+ assert_equal @@coll.find_one["a"], 2
490
494
 
491
495
  @@coll.repsert({"b" => 1}, {"a" => 3})
492
496
  assert_equal @@coll.count, 2
493
- assert @@coll.find_first({"a" => 3})
497
+ assert @@coll.find_one({"a" => 3})
494
498
  end
495
499
 
496
500
  def test_to_a
@@ -540,7 +544,7 @@ class DBAPITest < Test::Unit::TestCase
540
544
  assert_equal 3, @@db.eval('function (x) {return x;}', 3)
541
545
 
542
546
  assert_equal nil, @@db.eval("function (x) {db.test_eval.save({y:x});}", 5)
543
- assert_equal 5, @@db.collection('test_eval').find_first['y']
547
+ assert_equal 5, @@db.collection('test_eval').find_one['y']
544
548
 
545
549
  assert_equal 5, @@db.eval("function (x, y) {return x + y;}", 2, 3)
546
550
  assert_equal 5, @@db.eval("function () {return 5;}")
@@ -587,7 +591,7 @@ class DBAPITest < Test::Unit::TestCase
587
591
  val = Hash.new(0)
588
592
  val["x"] = 5
589
593
  @@coll.insert val
590
- id = @@coll.find_first("x" => 5)["_id"]
594
+ id = @@coll.find_one("x" => 5)["_id"]
591
595
  assert id != 0
592
596
  end
593
597
 
@@ -610,7 +614,7 @@ class DBAPITest < Test::Unit::TestCase
610
614
 
611
615
  assert_equal nil, @@db.dereference(DBRef.new("test", ObjectID.new))
612
616
  @@coll.insert({"x" => "hello"})
613
- key = @@coll.find_first()["_id"]
617
+ key = @@coll.find_one()["_id"]
614
618
  assert_equal "hello", @@db.dereference(DBRef.new("test", key))["x"]
615
619
 
616
620
  assert_equal nil, @@db.dereference(DBRef.new("test", 4))
@@ -632,26 +636,25 @@ class DBAPITest < Test::Unit::TestCase
632
636
  assert_kind_of ObjectID, id
633
637
  assert_equal 1, @@coll.count
634
638
 
635
- assert_equal id, @@coll.save(@@coll.find_first)
639
+ assert_equal id, @@coll.save(a)
636
640
  assert_equal 1, @@coll.count
637
641
 
638
- assert_equal "world", @@coll.find_first()["hello"]
642
+ assert_equal "world", @@coll.find_one()["hello"]
639
643
 
640
- doc = @@coll.find_first
641
- doc["hello"] = "mike"
642
- @@coll.save(doc)
644
+ a["hello"] = "mike"
645
+ @@coll.save(a)
643
646
  assert_equal 1, @@coll.count
644
647
 
645
- assert_equal "mike", @@coll.find_first()["hello"]
648
+ assert_equal "mike", @@coll.find_one()["hello"]
646
649
 
647
- @@coll.save(a)
650
+ @@coll.save({"hello" => "world"})
648
651
  assert_equal 2, @@coll.count
649
652
  end
650
653
 
651
654
  def test_save_long
652
655
  @@coll.clear
653
656
  @@coll.insert("x" => 9223372036854775807)
654
- assert_equal 9223372036854775807, @@coll.find_first()["x"]
657
+ assert_equal 9223372036854775807, @@coll.find_one()["x"]
655
658
  end
656
659
 
657
660
  def test_find_by_oid
@@ -661,13 +664,13 @@ class DBAPITest < Test::Unit::TestCase
661
664
  id = @@coll.save("hello" => "world")
662
665
  assert_kind_of ObjectID, id
663
666
 
664
- assert_equal "world", @@coll.find_first(:_id => id)["hello"]
667
+ assert_equal "world", @@coll.find_one(:_id => id)["hello"]
665
668
  @@coll.find(:_id => id).to_a.each do |doc|
666
669
  assert_equal "world", doc["hello"]
667
670
  end
668
671
 
669
672
  id = ObjectID.from_string(id.to_s)
670
- assert_equal "world", @@coll.find_first(:_id => id)["hello"]
673
+ assert_equal "world", @@coll.find_one(:_id => id)["hello"]
671
674
  end
672
675
 
673
676
  def test_save_with_object_that_has_id_but_does_not_actually_exist_in_collection
@@ -676,12 +679,12 @@ class DBAPITest < Test::Unit::TestCase
676
679
  a = {'_id' => '1', 'hello' => 'world'}
677
680
  @@coll.save(a)
678
681
  assert_equal(1, @@coll.count)
679
- assert_equal("world", @@coll.find_first()["hello"])
682
+ assert_equal("world", @@coll.find_one()["hello"])
680
683
 
681
684
  a["hello"] = "mike"
682
685
  @@coll.save(a)
683
686
  assert_equal(1, @@coll.count)
684
- assert_equal("mike", @@coll.find_first()["hello"])
687
+ assert_equal("mike", @@coll.find_one()["hello"])
685
688
  end
686
689
 
687
690
  def test_invalid_key_names
@@ -690,32 +693,32 @@ class DBAPITest < Test::Unit::TestCase
690
693
  @@coll.insert({"hello" => "world"})
691
694
  @@coll.insert({"hello" => {"hello" => "world"}})
692
695
 
693
- assert_raise RuntimeError do
696
+ assert_raise InvalidName do
694
697
  @@coll.insert({"$hello" => "world"})
695
698
  end
696
- assert_raise RuntimeError do
699
+ assert_raise InvalidName do
697
700
  @@coll.insert({"hello" => {"$hello" => "world"}})
698
701
  end
699
702
 
700
703
  @@coll.insert({"he$llo" => "world"})
701
704
  @@coll.insert({"hello" => {"hell$o" => "world"}})
702
705
 
703
- assert_raise RuntimeError do
706
+ assert_raise InvalidName do
704
707
  @@coll.insert({".hello" => "world"})
705
708
  end
706
- assert_raise RuntimeError do
709
+ assert_raise InvalidName do
707
710
  @@coll.insert({"hello" => {".hello" => "world"}})
708
711
  end
709
- assert_raise RuntimeError do
712
+ assert_raise InvalidName do
710
713
  @@coll.insert({"hello." => "world"})
711
714
  end
712
- assert_raise RuntimeError do
715
+ assert_raise InvalidName do
713
716
  @@coll.insert({"hello" => {"hello." => "world"}})
714
717
  end
715
- assert_raise RuntimeError do
718
+ assert_raise InvalidName do
716
719
  @@coll.insert({"hel.lo" => "world"})
717
720
  end
718
- assert_raise RuntimeError do
721
+ assert_raise InvalidName do
719
722
  @@coll.insert({"hello" => {"hel.lo" => "world"}})
720
723
  end
721
724
 
@@ -723,22 +726,22 @@ class DBAPITest < Test::Unit::TestCase
723
726
  end
724
727
 
725
728
  def test_collection_names
726
- assert_raise RuntimeError do
729
+ assert_raise TypeError do
727
730
  @@db.collection(5)
728
731
  end
729
- assert_raise RuntimeError do
732
+ assert_raise InvalidName do
730
733
  @@db.collection("")
731
734
  end
732
- assert_raise RuntimeError do
735
+ assert_raise InvalidName do
733
736
  @@db.collection("te$t")
734
737
  end
735
- assert_raise RuntimeError do
738
+ assert_raise InvalidName do
736
739
  @@db.collection(".test")
737
740
  end
738
- assert_raise RuntimeError do
741
+ assert_raise InvalidName do
739
742
  @@db.collection("test.")
740
743
  end
741
- assert_raise RuntimeError do
744
+ assert_raise InvalidName do
742
745
  @@db.collection("tes..t")
743
746
  end
744
747
  end
@@ -749,22 +752,22 @@ class DBAPITest < Test::Unit::TestCase
749
752
  a = @@db.collection("foo")
750
753
  b = @@db.collection("bar")
751
754
 
752
- assert_raise RuntimeError do
755
+ assert_raise TypeError do
753
756
  a.rename(5)
754
757
  end
755
- assert_raise RuntimeError do
758
+ assert_raise InvalidName do
756
759
  a.rename("")
757
760
  end
758
- assert_raise RuntimeError do
761
+ assert_raise InvalidName do
759
762
  a.rename("te$t")
760
763
  end
761
- assert_raise RuntimeError do
764
+ assert_raise InvalidName do
762
765
  a.rename(".test")
763
766
  end
764
- assert_raise RuntimeError do
767
+ assert_raise InvalidName do
765
768
  a.rename("test.")
766
769
  end
767
- assert_raise RuntimeError do
770
+ assert_raise InvalidName do
768
771
  a.rename("tes..t")
769
772
  end
770
773
 
data/tests/test_mongo.rb CHANGED
@@ -17,6 +17,17 @@ class MongoTest < Test::Unit::TestCase
17
17
  @mongo.db('ruby-mongo-test').error
18
18
  end
19
19
 
20
+ def test_invalid_database_names
21
+ assert_raise TypeError do @mongo.db(4) end
22
+
23
+ assert_raise InvalidName do @mongo.db('') end
24
+ assert_raise InvalidName do @mongo.db('te$t') end
25
+ assert_raise InvalidName do @mongo.db('te.t') end
26
+ assert_raise InvalidName do @mongo.db('te\\t') end
27
+ assert_raise InvalidName do @mongo.db('te/t') end
28
+ assert_raise InvalidName do @mongo.db('te st') end
29
+ end
30
+
20
31
  def test_database_info
21
32
  @mongo.drop_database('ruby-mongo-info-test')
22
33
  @mongo.db('ruby-mongo-info-test').collection('info-test').insert('a' => 1)
@@ -12,6 +12,15 @@ class OrderedHashTest < Test::Unit::TestCase
12
12
  @ordered_keys = %w(c a z)
13
13
  end
14
14
 
15
+ def test_initialize
16
+ a = OrderedHash.new
17
+ a['x'] = 1
18
+ a['y'] = 2
19
+
20
+ b = OrderedHash['x' => 1, 'y' => 2]
21
+ assert_equal a, b
22
+ end
23
+
15
24
  def test_empty
16
25
  assert_equal [], OrderedHash.new.keys
17
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongodb-mongo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: "0.12"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Menard
@@ -49,6 +49,7 @@ files:
49
49
  - lib/mongo/gridfs/chunk.rb
50
50
  - lib/mongo/gridfs/grid_store.rb
51
51
  - lib/mongo/gridfs.rb
52
+ - lib/mongo/errors.rb
52
53
  - lib/mongo/message/get_more_message.rb
53
54
  - lib/mongo/message/insert_message.rb
54
55
  - lib/mongo/message/kill_cursors_message.rb
@@ -121,6 +122,7 @@ test_files:
121
122
  - tests/test_bson.rb
122
123
  - tests/test_byte_buffer.rb
123
124
  - tests/test_chunk.rb
125
+ - tests/test_collection.rb
124
126
  - tests/test_cursor.rb
125
127
  - tests/test_db.rb
126
128
  - tests/test_db_api.rb