jmongo 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +14 -1
- data/jmongo.gemspec +2 -2
- data/lib/jmongo/collection.rb +32 -50
- data/lib/jmongo/connection.rb +24 -9
- data/lib/jmongo/db.rb +42 -32
- data/lib/jmongo/mongo/bson.rb +26 -2
- data/lib/jmongo/mongo/collection.rb +24 -16
- data/lib/jmongo/mongo/connection.rb +3 -2
- data/lib/jmongo/mongo/db.rb +13 -13
- data/lib/jmongo/mongo/jmongo.rb +21 -1
- data/lib/jmongo/mongo/ruby_ext.rb +6 -0
- data/lib/jmongo/mongo/utils.rb +48 -0
- data/lib/jmongo/version.rb +1 -1
- data/test/collection_test.rb +273 -288
- data/test/cursor_test.rb +130 -144
- data/test/db_api_test.rb +267 -284
- data/test/test_helper.rb +43 -14
- metadata +26 -29
@@ -7,14 +7,14 @@ module Mongo
|
|
7
7
|
private
|
8
8
|
|
9
9
|
def name_from opts
|
10
|
-
return unless (opts[:name] || opts['name'])
|
11
10
|
name = opts.delete(:name) || opts.delete('name')
|
12
11
|
name ? name.to_s : nil
|
13
12
|
end
|
14
13
|
|
15
14
|
def _drop_index(spec)
|
16
15
|
name = generate_index_name(spec.is_a?(String) || spec.is_a?(Symbol) ? spec : parse_index_spec(spec))
|
17
|
-
|
16
|
+
info = @db.index_information(@name)
|
17
|
+
idx = info.values.select do |entry|
|
18
18
|
entry['name'] == name || name == generate_index_name(entry['key'])
|
19
19
|
end
|
20
20
|
if idx.nil? || idx.empty?
|
@@ -23,17 +23,24 @@ module Mongo
|
|
23
23
|
@j_collection.dropIndexes(idx.first['name'].to_s)
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
26
|
+
def _ensure_index(obj, opts = {})
|
27
|
+
opts[:ensure] = true
|
28
|
+
_create_index(obj, opts)
|
29
|
+
end
|
30
|
+
|
31
|
+
def _create_index(obj, opts = {})
|
32
|
+
opt_name = name_from(opts)
|
33
|
+
opts[:dropDups] = opts.delete(:drop_dups) if opts.has_key?(:drop_dups)
|
28
34
|
field_spec = parse_index_spec(obj)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
name = generate_index_name(field_spec) unless name
|
34
|
-
opts['name'] = name
|
35
|
+
name = generate_index_name(field_spec)
|
36
|
+
opts['name'] = opt_name || name
|
37
|
+
opts['ns'] = @j_collection.full_name
|
35
38
|
begin
|
36
|
-
|
39
|
+
if opts.delete(:ensure)
|
40
|
+
@j_collection.ensure_index(to_dbobject(field_spec),to_dbobject(opts))
|
41
|
+
else
|
42
|
+
@j_collection.create_index(to_dbobject(field_spec),to_dbobject(opts))
|
43
|
+
end
|
37
44
|
rescue => e
|
38
45
|
if opts[:dropDups] && e.message =~ /E11000/
|
39
46
|
# NOP. If the user is intentionally dropping dups, we can ignore duplicate key errors.
|
@@ -42,7 +49,7 @@ module Mongo
|
|
42
49
|
raise Mongo::OperationFailure, msg
|
43
50
|
end
|
44
51
|
end
|
45
|
-
name
|
52
|
+
opts['name']
|
46
53
|
end
|
47
54
|
|
48
55
|
def generate_index_name(spec)
|
@@ -93,7 +100,7 @@ module Mongo
|
|
93
100
|
out << res if res
|
94
101
|
end
|
95
102
|
if to_do.size != out.size
|
96
|
-
msg = "Failed to insert document #{obj.inspect}, duplicate key"
|
103
|
+
msg = "Failed to insert document #{obj.inspect}, duplicate key, E11000"
|
97
104
|
raise(Mongo::OperationFailure, msg)
|
98
105
|
end
|
99
106
|
else
|
@@ -102,7 +109,7 @@ module Mongo
|
|
102
109
|
rescue => ex
|
103
110
|
if ex.message =~ /E11000/
|
104
111
|
msg = "Failed to insert document #{obj.inspect}, duplicate key, E11000"
|
105
|
-
raise(Mongo::OperationFailure, msg)
|
112
|
+
raise(Mongo::OperationFailure, msg) if concern.w > 0
|
106
113
|
else
|
107
114
|
msg = "Failed to insert document #{obj.inspect} db error: #{ex.message}"
|
108
115
|
raise Mongo::MongoDBError, msg
|
@@ -145,11 +152,12 @@ module Mongo
|
|
145
152
|
|
146
153
|
def update_documents(selector, document, upsert=false, multi=false, safe=nil)
|
147
154
|
begin
|
148
|
-
|
155
|
+
concern = @db.write_concern(safe)
|
156
|
+
@j_collection.update(to_dbobject(selector),to_dbobject(document), upsert, multi, concern)
|
149
157
|
rescue => ex
|
150
158
|
if ex.message =~ /E11001/
|
151
159
|
msg = "Failed to update document #{document.inspect}, duplicate key"
|
152
|
-
raise(Mongo::OperationFailure, msg)
|
160
|
+
raise(Mongo::OperationFailure, msg) if concern.w > 0
|
153
161
|
else
|
154
162
|
msg = "Failed to update document #{document.inspect} db error: #{ex.message}"
|
155
163
|
raise Mongo::MongoDBError, msg
|
@@ -18,8 +18,9 @@ module Mongo
|
|
18
18
|
|
19
19
|
module ClassMethods
|
20
20
|
URI_RE = /^mongodb:\/\/(([-.\w]+):([^@]+)@)?([-.\w]+)(:([\w]+))?(\/([-\w]+))?/
|
21
|
-
OPTS_KEYS = %W[maxpoolsize
|
22
|
-
|
21
|
+
OPTS_KEYS = %W[maxpoolsize connecttimeoutms autoconnectretry
|
22
|
+
waitqueuemultiple waitqueuetimeoutms sockettimeoutms
|
23
|
+
slaveok safe w wtimeout fsync]
|
23
24
|
|
24
25
|
def _from_uri uri, opts={}
|
25
26
|
optarr = []
|
data/lib/jmongo/mongo/db.rb
CHANGED
@@ -13,15 +13,8 @@ module Mongo
|
|
13
13
|
#@collection.save({:doc => 'foo'}, :safe => {:w => 2, :wtimeout => 200, :fsync => true}) ---> new WriteConcern( 2 , 0 , true)
|
14
14
|
#@collection.save({:doc => 'foo'}, :safe => {:fsync => true}) ---> FSYNC_SAFE = new WriteConcern( 1 , 0 , true)
|
15
15
|
|
16
|
-
def write_concern(
|
17
|
-
|
18
|
-
return JMongo::WriteConcern.new(0) if safe.is_a?(FalseClass)
|
19
|
-
return JMongo::WriteConcern.new(1) if safe.is_a?(TrueClass)
|
20
|
-
return JMongo::WriteConcern.new(0) unless safe.is_a?(Hash)
|
21
|
-
w = safe[:w] || 1
|
22
|
-
t = safe[:wtimeout] || 0
|
23
|
-
f = !!(safe[:fsync] || false)
|
24
|
-
JMongo::WriteConcern.new(w, t, f) #dont laugh!
|
16
|
+
def write_concern(safe_)
|
17
|
+
self.class.write_concern(safe_ || self.safe || @connection.write_concern)
|
25
18
|
end
|
26
19
|
|
27
20
|
private
|
@@ -29,20 +22,27 @@ module Mongo
|
|
29
22
|
def exec_command(cmd)
|
30
23
|
cmd_hash = cmd.kind_of?(Hash) ? cmd : {cmd => 1}
|
31
24
|
cmd_res = @j_db.command(to_dbobject(cmd_hash))
|
32
|
-
from_dbobject
|
25
|
+
from_dbobject cmd_res
|
33
26
|
end
|
34
27
|
|
35
28
|
def do_eval(string, *args)
|
36
|
-
|
29
|
+
command(BSON::OrderedHash['$eval', string,'args', args])
|
37
30
|
end
|
38
31
|
|
39
|
-
def
|
40
|
-
@j_db.collection_exists(name)
|
32
|
+
def collection_exists?(name)
|
33
|
+
system_name?(name) || @j_db.collection_exists(name)
|
41
34
|
end
|
42
35
|
|
43
36
|
def get_last_error
|
44
37
|
from_dbobject @j_db.get_last_error
|
45
38
|
end
|
39
|
+
|
40
|
+
def _collections_info(coll_name=nil)
|
41
|
+
selector = {}
|
42
|
+
selector[:name] = full_collection_name(coll_name) if coll_name
|
43
|
+
coll = @j_db.get_collection(SYSTEM_NAMESPACE_COLLECTION)
|
44
|
+
from_dbobject(coll.find(to_dbobject(selector)))
|
45
|
+
end
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
data/lib/jmongo/mongo/jmongo.rb
CHANGED
@@ -3,7 +3,6 @@ module JMongo
|
|
3
3
|
java_import com.mongodb.BasicDBObject
|
4
4
|
java_import com.mongodb.Bytes
|
5
5
|
java_import com.mongodb.DB
|
6
|
-
java_import com.mongodb.DBRef
|
7
6
|
java_import com.mongodb.DBCollection
|
8
7
|
java_import com.mongodb.DBCursor
|
9
8
|
java_import com.mongodb.DBObject
|
@@ -16,6 +15,27 @@ module JMongo
|
|
16
15
|
java_import com.mongodb.MongoURI
|
17
16
|
java_import com.mongodb.MapReduceCommand
|
18
17
|
java_import com.mongodb.MapReduceOutput
|
18
|
+
|
19
|
+
SECS_TO_MILLI_FUNC = lambda { |v| v.to_f * 1_000 }
|
20
|
+
DO_NOTHING_FUNC = lambda { |v| v }
|
21
|
+
|
22
|
+
RUBY_JAVA_OPTIONS_KEYS = {
|
23
|
+
:pool_size => [:connections_per_host, DO_NOTHING_FUNC],
|
24
|
+
:pool_timeout => [:max_wait_time, SECS_TO_MILLI_FUNC],
|
25
|
+
:timeout => [:max_wait_time, SECS_TO_MILLI_FUNC],
|
26
|
+
:op_timeout => [:socket_timeout, SECS_TO_MILLI_FUNC],
|
27
|
+
:connect_timeout => [:connect_timeout, SECS_TO_MILLI_FUNC]
|
28
|
+
}
|
29
|
+
|
30
|
+
RUBY_JAVA_OPTIONS_KEYS.default = [nil, DO_NOTHING_FUNC]
|
31
|
+
|
32
|
+
def self.options_ruby2java_lu(key)
|
33
|
+
RUBY_JAVA_OPTIONS_KEYS[key].first || key
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.options_ruby2java_xf(key,val)
|
37
|
+
RUBY_JAVA_OPTIONS_KEYS[key].last[val] || val
|
38
|
+
end
|
19
39
|
end
|
20
40
|
|
21
41
|
class Java::ComMongodb::BasicDBObject
|
data/lib/jmongo/mongo/utils.rb
CHANGED
@@ -21,6 +21,52 @@ module Mongo
|
|
21
21
|
raise ex_class, msg ? "#{msg} - #{ex.message}" : ex.message
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
def system_name?(name)
|
26
|
+
name =~ /((^\$cmd)|(oplog\.\$main))/
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate_name(new_name)
|
30
|
+
unless [String, Symbol].include?(new_name.class)
|
31
|
+
raise TypeError, "db_name must be a string or symbol"
|
32
|
+
end
|
33
|
+
|
34
|
+
name = new_name.to_s
|
35
|
+
|
36
|
+
if name.empty?
|
37
|
+
raise Mongo::InvalidNSName, "collection names cannot be empty"
|
38
|
+
end
|
39
|
+
if name.include?("..")
|
40
|
+
raise Mongo::InvalidNSName, "collection names cannot contain '..'"
|
41
|
+
end
|
42
|
+
if name.include? "$"
|
43
|
+
raise Mongo::InvalidNSName, "collection names cannot contain '$'" unless name =~ /((^\$cmd)|(oplog\.\$main))/
|
44
|
+
end
|
45
|
+
if name.match(/^\./) || name.match(/\.$/)
|
46
|
+
raise Mongo::InvalidNSName, "collection names cannot start or end with '.'"
|
47
|
+
end
|
48
|
+
name
|
49
|
+
end
|
50
|
+
|
51
|
+
def prep_id(doc)
|
52
|
+
if doc[:_id] && !doc['_id']
|
53
|
+
doc['_id'] = doc.delete(:_id)
|
54
|
+
end
|
55
|
+
doc
|
56
|
+
end
|
57
|
+
|
58
|
+
def prep_hint(hint)
|
59
|
+
case hint
|
60
|
+
when String, Symbol
|
61
|
+
{hint => 1}
|
62
|
+
when Hash
|
63
|
+
hint
|
64
|
+
when nil
|
65
|
+
nil
|
66
|
+
else
|
67
|
+
Hash[hint.to_a.zip( [1]*hint.size )]
|
68
|
+
end
|
69
|
+
end
|
24
70
|
|
25
71
|
def prep_fields(fields)
|
26
72
|
case fields
|
@@ -75,6 +121,8 @@ module Mongo
|
|
75
121
|
Time.at(obj.get_time/1000.0)
|
76
122
|
when Java::OrgBsonTypes::Symbol
|
77
123
|
obj.toString.to_sym
|
124
|
+
when Java::JavaUtilRegex::Pattern
|
125
|
+
Regexp.new(obj.pattern, (obj.flags/2))
|
78
126
|
else
|
79
127
|
obj
|
80
128
|
end
|
data/lib/jmongo/version.rb
CHANGED
data/test/collection_test.rb
CHANGED
@@ -1,43 +1,27 @@
|
|
1
1
|
require './test/test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
VERSION = CONNECTION.server_version
|
7
|
-
apr VERSION
|
8
|
-
|
9
|
-
def clear_collections
|
10
|
-
$db.collection_names.each do |n|
|
11
|
-
$db.drop_collection(n) unless n =~ /system/
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
clear_collections
|
16
|
-
|
17
|
-
$test = $db.collection("test")
|
3
|
+
Cfg.connection :op_timeout => 10
|
4
|
+
Cfg.db
|
18
5
|
|
19
6
|
class TestCollection < MiniTest::Unit::TestCase
|
20
7
|
|
21
8
|
def setup
|
22
|
-
|
9
|
+
Cfg.clear_all
|
23
10
|
end
|
24
11
|
|
25
12
|
def test_capped_method
|
26
|
-
$db.drop_collection('normal')
|
27
13
|
|
28
|
-
|
29
|
-
assert
|
30
|
-
$db.drop_collection('normal')
|
14
|
+
Cfg.db.create_collection('normal').insert('x'=>3)
|
15
|
+
assert !Cfg.db['normal'].capped?
|
31
16
|
|
32
|
-
|
33
|
-
assert
|
34
|
-
$db.drop_collection('c')
|
17
|
+
Cfg.db.create_collection('c', :capped => true, :size => 100_000).insert('g'=>4)
|
18
|
+
assert Cfg.db['c'].capped?
|
35
19
|
end
|
36
20
|
|
37
21
|
def test_optional_pk_factory
|
38
|
-
@coll_default_pk =
|
22
|
+
@coll_default_pk = Cfg.db.collection('stuff')
|
39
23
|
assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
|
40
|
-
@coll_default_pk =
|
24
|
+
@coll_default_pk = Cfg.db.create_collection('more-stuff')
|
41
25
|
assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
|
42
26
|
|
43
27
|
# Create a db with a pk_factory.
|
@@ -56,74 +40,71 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
56
40
|
end
|
57
41
|
|
58
42
|
def test_pk_factory_on_collection
|
59
|
-
@coll2 = Collection.new('foo',
|
43
|
+
@coll2 = Collection.new('foo', Cfg.db, :pk => TestPK)
|
60
44
|
assert_equal TestPK, @coll2.pk_factory
|
61
45
|
end
|
62
46
|
|
63
47
|
def test_valid_names
|
64
48
|
assert_raises Mongo::InvalidNSName do
|
65
|
-
|
49
|
+
Cfg.db["te$t"]
|
66
50
|
end
|
67
51
|
|
68
52
|
assert_raises Mongo::InvalidNSName do
|
69
|
-
|
53
|
+
Cfg.db['$main']
|
70
54
|
end
|
71
55
|
|
72
|
-
assert
|
73
|
-
assert
|
56
|
+
assert Cfg.db['$cmd']
|
57
|
+
assert Cfg.db['oplog.$main']
|
74
58
|
end
|
75
59
|
|
76
60
|
def test_collection
|
77
|
-
assert_kind_of Collection,
|
78
|
-
assert_equal
|
79
|
-
assert_equal
|
61
|
+
assert_kind_of Collection, Cfg.db["test"]
|
62
|
+
assert_equal Cfg.db["test"].name(), Cfg.db.collection("test").name()
|
63
|
+
assert_equal Cfg.db["test"].name(), Cfg.db[:test].name()
|
80
64
|
|
81
|
-
assert_kind_of Collection,
|
82
|
-
assert_equal
|
83
|
-
assert_equal
|
65
|
+
assert_kind_of Collection, Cfg.db["test"]["foo"]
|
66
|
+
assert_equal Cfg.db["test"]["foo"].name(), Cfg.db.collection("test.foo").name()
|
67
|
+
assert_equal Cfg.db["test"]["foo"].name(), Cfg.db["test.foo"].name()
|
84
68
|
|
85
|
-
|
86
|
-
|
87
|
-
assert_equal 5,
|
69
|
+
Cfg.db["test"]["foo"].remove
|
70
|
+
Cfg.db["test"]["foo"].insert("x" => 5)
|
71
|
+
assert_equal 5, Cfg.db.collection("test.foo").find_one()["x"]
|
88
72
|
end
|
89
73
|
|
90
74
|
def test_rename_collection
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
@col = $db.create_collection('foo1')
|
75
|
+
@col = Cfg.db.create_collection('foo1')
|
76
|
+
@col.insert("x" => 5) #must insert something to actually create collection
|
95
77
|
assert_equal 'foo1', @col.name
|
96
|
-
|
97
78
|
@col.rename('bar1')
|
98
79
|
assert_equal 'bar1', @col.name
|
99
80
|
end
|
100
81
|
|
101
82
|
def test_nil_id
|
102
83
|
skip("The Java driver does not allow nil _id")
|
103
|
-
assert_equal 5,
|
104
|
-
assert_equal 5,
|
105
|
-
assert_equal nil,
|
106
|
-
assert_equal "baz",
|
84
|
+
assert_equal 5, Cfg.test.insert({"_id" => 5, "foo" => "bar"}, {:safe => true})
|
85
|
+
assert_equal 5, Cfg.test.save({"_id" => 5, "foo" => "baz"}, {:safe => true})
|
86
|
+
assert_equal nil, Cfg.test.find_one("foo" => "bar")
|
87
|
+
assert_equal "baz", Cfg.test.find_one(:_id => 5)["foo"]
|
107
88
|
assert_raises OperationFailure do
|
108
|
-
|
89
|
+
Cfg.test.insert({"_id" => 5, "foo" => "bar"}, {:safe => true})
|
109
90
|
end
|
110
91
|
|
111
|
-
assert_equal nil,
|
112
|
-
assert_equal nil,
|
113
|
-
assert_equal nil,
|
114
|
-
assert_equal "baz",
|
92
|
+
assert_equal nil, Cfg.test.insert({"_id" => nil, "foo" => "bar"}, {:safe => true})
|
93
|
+
assert_equal nil, Cfg.test.save({"_id" => nil, "foo" => "baz"}, {:safe => true})
|
94
|
+
assert_equal nil, Cfg.test.find_one("foo" => "bar")
|
95
|
+
assert_equal "baz", Cfg.test.find_one(:_id => nil)["foo"]
|
115
96
|
assert_raises OperationFailure do
|
116
|
-
|
97
|
+
Cfg.test.insert({"_id" => nil, "foo" => "bar"}, {:safe => true})
|
117
98
|
end
|
118
99
|
assert_raises OperationFailure do
|
119
|
-
|
100
|
+
Cfg.test.insert({:_id => nil, "foo" => "bar"}, {:safe => true})
|
120
101
|
end
|
121
102
|
end
|
122
103
|
|
123
|
-
if
|
104
|
+
if Cfg.version > "1.1"
|
124
105
|
def setup_for_distinct
|
125
|
-
|
126
|
-
|
106
|
+
Cfg.test.remove
|
107
|
+
Cfg.test.insert([{:a => 0, :b => {:c => "a"}},
|
127
108
|
{:a => 1, :b => {:c => "b"}},
|
128
109
|
{:a => 1, :b => {:c => "c"}},
|
129
110
|
{:a => 2, :b => {:c => "a"}},
|
@@ -133,48 +114,48 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
133
114
|
|
134
115
|
def test_distinct_queries
|
135
116
|
setup_for_distinct
|
136
|
-
assert_equal [0, 1, 2, 3],
|
137
|
-
assert_equal ["a", "b", "c"],
|
117
|
+
assert_equal [0, 1, 2, 3], Cfg.test.distinct(:a).sort
|
118
|
+
assert_equal ["a", "b", "c"], Cfg.test.distinct("b.c").sort
|
138
119
|
end
|
139
120
|
|
140
|
-
if
|
121
|
+
if Cfg.version >= "1.2"
|
141
122
|
def test_filter_collection_with_query
|
142
123
|
setup_for_distinct
|
143
|
-
assert_equal [2, 3],
|
124
|
+
assert_equal [2, 3], Cfg.test.distinct(:a, {:a => {"$gt" => 1}}).sort
|
144
125
|
end
|
145
126
|
|
146
127
|
def test_filter_nested_objects
|
147
128
|
setup_for_distinct
|
148
|
-
assert_equal ["a", "b"],
|
129
|
+
assert_equal ["a", "b"], Cfg.test.distinct("b.c", {"b.c" => {"$ne" => "c"}}).sort
|
149
130
|
end
|
150
131
|
end
|
151
132
|
end
|
152
133
|
|
153
134
|
def test_safe_insert
|
154
|
-
|
135
|
+
Cfg.test.create_index("hello", :unique => true)
|
155
136
|
a = {"hello" => "world"}
|
156
|
-
|
157
|
-
|
158
|
-
assert(
|
137
|
+
Cfg.test.insert(a)
|
138
|
+
Cfg.test.insert(a)
|
139
|
+
assert(Cfg.db.get_last_error['err'].include?("11000"))
|
159
140
|
|
160
141
|
assert_raises OperationFailure do
|
161
|
-
|
142
|
+
Cfg.test.insert(a, :safe => true)
|
162
143
|
end
|
163
144
|
end
|
164
145
|
|
165
146
|
def test_bulk_insert_with_continue_on_error
|
166
|
-
if
|
167
|
-
|
147
|
+
if Cfg.version >= "2.0"
|
148
|
+
Cfg.test.create_index([["foo", 1]], :unique => true)
|
168
149
|
docs = []
|
169
150
|
docs << {:foo => 1}
|
170
151
|
docs << {:foo => 1}
|
171
152
|
docs << {:foo => 2}
|
172
153
|
docs << {:foo => 3}
|
173
154
|
assert_raises OperationFailure do
|
174
|
-
|
155
|
+
Cfg.test.insert(docs, :safe => true)
|
175
156
|
end
|
176
|
-
assert_equal 1,
|
177
|
-
|
157
|
+
assert_equal 1, Cfg.test.count
|
158
|
+
Cfg.test.remove
|
178
159
|
|
179
160
|
docs = []
|
180
161
|
docs << {:foo => 1}
|
@@ -183,12 +164,12 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
183
164
|
docs << {:foo => 3}
|
184
165
|
docs << {:foo => 3}
|
185
166
|
assert_raises OperationFailure do
|
186
|
-
|
167
|
+
Cfg.test.insert(docs, :safe => true, :continue_on_error => true)
|
187
168
|
end
|
188
|
-
assert_equal 3,
|
169
|
+
assert_equal 3, Cfg.test.count
|
189
170
|
|
190
|
-
|
191
|
-
|
171
|
+
Cfg.test.remove
|
172
|
+
Cfg.test.drop_index("foo_1")
|
192
173
|
end
|
193
174
|
end
|
194
175
|
|
@@ -200,70 +181,70 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
200
181
|
end
|
201
182
|
|
202
183
|
assert_raises InvalidOperation do
|
203
|
-
|
184
|
+
Cfg.test.insert(docs)
|
204
185
|
end
|
205
186
|
end
|
206
187
|
|
207
188
|
def test_update
|
208
|
-
id1 =
|
209
|
-
|
210
|
-
assert_equal 1,
|
211
|
-
assert_equal 6,
|
189
|
+
id1 = Cfg.test.save("x" => 5)
|
190
|
+
Cfg.test.update({}, {"$inc" => {"x" => 1}})
|
191
|
+
assert_equal 1, Cfg.test.count()
|
192
|
+
assert_equal 6, Cfg.test.find_one(:_id => id1)["x"]
|
212
193
|
|
213
|
-
id2 =
|
214
|
-
|
215
|
-
assert_equal 7,
|
216
|
-
assert_equal 1,
|
194
|
+
id2 = Cfg.test.save("x" => 1)
|
195
|
+
Cfg.test.update({"x" => 6}, {"$inc" => {"x" => 1}})
|
196
|
+
assert_equal 7, Cfg.test.find_one(:_id => id1)["x"]
|
197
|
+
assert_equal 1, Cfg.test.find_one(:_id => id2)["x"]
|
217
198
|
end
|
218
199
|
|
219
200
|
def test_multi_update
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
assert_equal 3,
|
201
|
+
Cfg.test.save("num" => 10)
|
202
|
+
Cfg.test.save("num" => 10)
|
203
|
+
Cfg.test.save("num" => 10)
|
204
|
+
assert_equal 3, Cfg.test.count
|
224
205
|
|
225
|
-
|
226
|
-
|
206
|
+
Cfg.test.update({"num" => 10}, {"$set" => {"num" => 100}}, :multi => true)
|
207
|
+
Cfg.test.find.each do |doc|
|
227
208
|
assert_equal 100, doc["num"]
|
228
209
|
end
|
229
210
|
end
|
230
211
|
|
231
212
|
def test_upsert
|
232
|
-
|
233
|
-
|
213
|
+
Cfg.test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
|
214
|
+
Cfg.test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
|
234
215
|
|
235
|
-
assert_equal 1,
|
236
|
-
assert_equal 2,
|
216
|
+
assert_equal 1, Cfg.test.count()
|
217
|
+
assert_equal 2, Cfg.test.find_one()["count"]
|
237
218
|
end
|
238
219
|
|
239
220
|
def test_safe_update
|
240
|
-
|
241
|
-
|
242
|
-
|
221
|
+
Cfg.test.create_index("x", :unique => true)
|
222
|
+
Cfg.test.insert("x" => 5)
|
223
|
+
Cfg.test.insert("x" => 10)
|
243
224
|
|
244
225
|
# Can update an indexed collection.
|
245
|
-
|
246
|
-
assert
|
226
|
+
Cfg.test.update({}, {"$inc" => {"x" => 1}})
|
227
|
+
assert !Cfg.db.error?
|
247
228
|
|
248
229
|
# Can't duplicate an index.
|
249
230
|
assert_raises OperationFailure do
|
250
|
-
|
231
|
+
Cfg.test.update({}, {"x" => 10}, :safe => true)
|
251
232
|
end
|
252
233
|
end
|
253
234
|
|
254
235
|
def test_safe_save
|
255
|
-
|
236
|
+
Cfg.test.create_index("hello", :unique => true)
|
256
237
|
|
257
|
-
|
258
|
-
|
238
|
+
Cfg.test.save("hello" => "world")
|
239
|
+
Cfg.test.save("hello" => "world")
|
259
240
|
|
260
241
|
assert_raises OperationFailure do
|
261
|
-
|
242
|
+
Cfg.test.save({"hello" => "world"}, :safe => true)
|
262
243
|
end
|
263
244
|
end
|
264
245
|
|
265
246
|
def test_safe_remove
|
266
|
-
@conn =
|
247
|
+
@conn = Cfg.new_connection
|
267
248
|
@db = @conn[MONGO_TEST_DB]
|
268
249
|
@test = @db['test-safe-remove']
|
269
250
|
@test.save({:a => 50})
|
@@ -272,135 +253,135 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
272
253
|
end
|
273
254
|
|
274
255
|
def test_remove_return_value
|
275
|
-
assert_equal true,
|
256
|
+
assert_equal true, Cfg.test.remove({})
|
276
257
|
end
|
277
258
|
|
278
259
|
def test_count
|
279
260
|
|
280
|
-
assert_equal 0,
|
281
|
-
|
282
|
-
|
283
|
-
assert_equal 2,
|
261
|
+
assert_equal 0, Cfg.test.count
|
262
|
+
Cfg.test.save(:x => 1)
|
263
|
+
Cfg.test.save(:x => 2)
|
264
|
+
assert_equal 2, Cfg.test.count
|
284
265
|
|
285
|
-
assert_equal 1,
|
286
|
-
assert_equal 1,
|
287
|
-
assert_equal 0,
|
266
|
+
assert_equal 1, Cfg.test.count(:query => {:x => 1})
|
267
|
+
assert_equal 1, Cfg.test.count(:limit => 1)
|
268
|
+
assert_equal 0, Cfg.test.count(:skip => 2)
|
288
269
|
end
|
289
270
|
|
290
271
|
# Note: #size is just an alias for #count.
|
291
272
|
def test_size
|
292
|
-
assert_equal 0,
|
293
|
-
assert_equal
|
294
|
-
|
295
|
-
|
296
|
-
assert_equal
|
273
|
+
assert_equal 0, Cfg.test.count
|
274
|
+
assert_equal Cfg.test.size, Cfg.test.count
|
275
|
+
Cfg.test.save("x" => 1)
|
276
|
+
Cfg.test.save("x" => 2)
|
277
|
+
assert_equal Cfg.test.size, Cfg.test.count
|
297
278
|
end
|
298
279
|
|
299
280
|
def test_no_timeout_option
|
300
281
|
|
301
282
|
assert_raises ArgumentError, "Timeout can be set to false only when #find is invoked with a block." do
|
302
|
-
|
283
|
+
Cfg.test.find({}, :timeout => false)
|
303
284
|
end
|
304
285
|
|
305
|
-
|
286
|
+
Cfg.test.find({}, :timeout => false) do |cursor|
|
306
287
|
assert_equal 0, cursor.count
|
307
288
|
end
|
308
289
|
|
309
|
-
|
310
|
-
|
311
|
-
|
290
|
+
Cfg.test.save("x" => 1)
|
291
|
+
Cfg.test.save("x" => 2)
|
292
|
+
Cfg.test.find({}, :timeout => false) do |cursor|
|
312
293
|
assert_equal 2, cursor.count
|
313
294
|
end
|
314
295
|
end
|
315
296
|
|
316
297
|
def test_default_timeout
|
317
|
-
cursor =
|
298
|
+
cursor = Cfg.test.find
|
318
299
|
assert_equal true, cursor.timeout
|
319
300
|
end
|
320
301
|
|
321
302
|
def test_fields_as_hash
|
322
|
-
|
303
|
+
Cfg.test.save(:a => 1, :b => 1, :c => 1)
|
323
304
|
|
324
|
-
doc =
|
305
|
+
doc = Cfg.test.find_one({:a => 1}, :fields => {:b => 0})
|
325
306
|
assert_nil doc['b']
|
326
307
|
assert doc['a']
|
327
308
|
assert doc['c']
|
328
309
|
|
329
|
-
doc =
|
310
|
+
doc = Cfg.test.find_one({:a => 1}, :fields => {:a => 1, :b => 1})
|
330
311
|
assert_nil doc['c']
|
331
312
|
assert doc['a']
|
332
313
|
assert doc['b']
|
333
314
|
|
334
315
|
|
335
316
|
assert_raises Mongo::OperationFailure do
|
336
|
-
|
317
|
+
Cfg.test.find_one({:a => 1}, :fields => {:a => 1, :b => 0})
|
337
318
|
end
|
338
319
|
end
|
339
320
|
|
340
|
-
if
|
321
|
+
if Cfg.version >= "1.5.1"
|
341
322
|
def test_fields_with_slice
|
342
|
-
|
323
|
+
Cfg.test.save({:foo => [1, 2, 3, 4, 5, 6], :test => 'slice'})
|
343
324
|
|
344
|
-
doc =
|
325
|
+
doc = Cfg.test.find_one({:test => 'slice'}, :fields => {'foo' => {'$slice' => [0, 3]}})
|
345
326
|
assert_equal [1, 2, 3], doc['foo']
|
346
|
-
|
327
|
+
Cfg.test.remove
|
347
328
|
end
|
348
329
|
end
|
349
330
|
|
350
331
|
def test_find_one
|
351
|
-
id =
|
332
|
+
id = Cfg.test.save("hello" => "world", "foo" => "bar")
|
352
333
|
|
353
|
-
assert_equal "world",
|
354
|
-
assert_equal
|
355
|
-
assert_equal
|
356
|
-
assert_equal
|
357
|
-
assert_equal
|
358
|
-
assert_equal
|
334
|
+
assert_equal "world", Cfg.test.find_one()["hello"]
|
335
|
+
assert_equal Cfg.test.find_one(id), Cfg.test.find_one()
|
336
|
+
assert_equal Cfg.test.find_one(nil), Cfg.test.find_one()
|
337
|
+
assert_equal Cfg.test.find_one({}), Cfg.test.find_one()
|
338
|
+
assert_equal Cfg.test.find_one("hello" => "world"), Cfg.test.find_one()
|
339
|
+
assert_equal Cfg.test.find_one(BSON::OrderedHash["hello", "world"]), Cfg.test.find_one()
|
359
340
|
|
360
|
-
assert
|
361
|
-
assert
|
362
|
-
assert_equal ["_id"],
|
341
|
+
assert Cfg.test.find_one(nil, :fields => ["hello"]).include?("hello")
|
342
|
+
assert !Cfg.test.find_one(nil, :fields => ["foo"]).include?("hello")
|
343
|
+
assert_equal ["_id"], Cfg.test.find_one(nil, :fields => []).keys()
|
363
344
|
|
364
|
-
assert_equal nil,
|
365
|
-
assert_equal nil,
|
366
|
-
assert_equal nil,
|
345
|
+
assert_equal nil, Cfg.test.find_one("hello" => "foo")
|
346
|
+
assert_equal nil, Cfg.test.find_one(BSON::OrderedHash["hello", "foo"])
|
347
|
+
assert_equal nil, Cfg.test.find_one(ObjectId.new)
|
367
348
|
|
368
349
|
assert_raises TypeError do
|
369
|
-
|
350
|
+
Cfg.test.find_one(6)
|
370
351
|
end
|
371
352
|
end
|
372
353
|
|
373
354
|
def test_insert_adds_id
|
374
355
|
doc = {"hello" => "world"}
|
375
|
-
|
376
|
-
assert(doc.include?(:_id))
|
356
|
+
Cfg.test.insert(doc)
|
357
|
+
assert(doc.include?(:_id) || doc.include?('_id'))
|
377
358
|
|
378
359
|
docs = [{"hello" => "world"}, {"hello" => "world"}]
|
379
|
-
|
360
|
+
Cfg.test.insert(docs)
|
380
361
|
docs.each do |d|
|
381
|
-
assert(d.include?(:_id))
|
362
|
+
assert(d.include?(:_id) || doc.include?('_id'))
|
382
363
|
end
|
383
364
|
end
|
384
365
|
|
385
366
|
def test_save_adds_id
|
386
367
|
doc = {"hello" => "world"}
|
387
|
-
|
388
|
-
assert(doc.include?(:_id))
|
368
|
+
Cfg.test.save(doc)
|
369
|
+
assert(doc.include?(:_id) || doc.include?('_id'))
|
389
370
|
end
|
390
371
|
|
391
372
|
def test_optional_find_block
|
392
373
|
10.times do |i|
|
393
|
-
|
374
|
+
Cfg.test.save("i" => i)
|
394
375
|
end
|
395
376
|
|
396
377
|
x = nil
|
397
|
-
|
378
|
+
Cfg.test.find("i" => 2) { |cursor|
|
398
379
|
x = cursor.count()
|
399
380
|
}
|
400
381
|
assert_equal 1, x
|
401
382
|
|
402
383
|
i = 0
|
403
|
-
|
384
|
+
Cfg.test.find({}, :skip => 5) do |cursor|
|
404
385
|
cursor.each do |doc|
|
405
386
|
i = i + 1
|
406
387
|
end
|
@@ -408,173 +389,173 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
408
389
|
assert_equal 5, i
|
409
390
|
|
410
391
|
c = nil
|
411
|
-
|
392
|
+
Cfg.test.find() do |cursor|
|
412
393
|
c = cursor
|
413
394
|
end
|
414
395
|
assert c.closed?
|
415
396
|
end
|
416
397
|
|
417
398
|
def test_map_reduce
|
418
|
-
|
419
|
-
|
399
|
+
Cfg.test << { "user_id" => 1 }
|
400
|
+
Cfg.test << { "user_id" => 2 }
|
420
401
|
m = "function() { emit(this.user_id, 1); }"
|
421
402
|
r = "function(k,vals) { return 1; }"
|
422
|
-
res =
|
403
|
+
res = Cfg.test.map_reduce(m, r, :out => 'foo');
|
423
404
|
assert res.find_one({"_id" => 1})
|
424
405
|
assert res.find_one({"_id" => 2})
|
425
406
|
end
|
426
407
|
|
427
408
|
def test_map_reduce_with_code_objects
|
428
|
-
|
429
|
-
|
409
|
+
Cfg.test << { "user_id" => 1 }
|
410
|
+
Cfg.test << { "user_id" => 2 }
|
430
411
|
m = Code.new("function() { emit(this.user_id, 1); }")
|
431
412
|
r = Code.new("function(k,vals) { return 1; }")
|
432
|
-
res =
|
413
|
+
res = Cfg.test.map_reduce(m, r, :out => 'foo');
|
433
414
|
assert res.find_one({"_id" => 1})
|
434
415
|
assert res.find_one({"_id" => 2})
|
435
416
|
end
|
436
417
|
|
437
418
|
def test_map_reduce_with_options
|
438
|
-
|
439
|
-
|
440
|
-
|
419
|
+
Cfg.test << { "user_id" => 1 }
|
420
|
+
Cfg.test << { "user_id" => 2 }
|
421
|
+
Cfg.test << { "user_id" => 3 }
|
441
422
|
m = Code.new("function() { emit(this.user_id, 1); }")
|
442
423
|
r = Code.new("function(k,vals) { return 1; }")
|
443
|
-
res =
|
424
|
+
res = Cfg.test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}}, :out => 'foo');
|
444
425
|
assert_equal 2, res.count
|
445
426
|
assert res.find_one({"_id" => 2})
|
446
427
|
assert res.find_one({"_id" => 3})
|
447
428
|
end
|
448
429
|
|
449
430
|
def test_map_reduce_with_raw_response
|
450
|
-
|
451
|
-
|
452
|
-
|
431
|
+
Cfg.test << { "user_id" => 1 }
|
432
|
+
Cfg.test << { "user_id" => 2 }
|
433
|
+
Cfg.test << { "user_id" => 3 }
|
453
434
|
m = Code.new("function() { emit(this.user_id, 1); }")
|
454
435
|
r = Code.new("function(k,vals) { return 1; }")
|
455
|
-
res =
|
436
|
+
res = Cfg.test.map_reduce(m, r, :raw => true, :out => 'foo')
|
456
437
|
assert res["result"]
|
457
438
|
assert res["counts"]
|
458
439
|
assert res["timeMillis"]
|
459
440
|
end
|
460
441
|
|
461
442
|
def test_map_reduce_with_output_collection
|
462
|
-
|
463
|
-
|
464
|
-
|
443
|
+
Cfg.test << { "user_id" => 1 }
|
444
|
+
Cfg.test << { "user_id" => 2 }
|
445
|
+
Cfg.test << { "user_id" => 3 }
|
465
446
|
output_collection = "test-map-coll"
|
466
447
|
m = Code.new("function() { emit(this.user_id, 1); }")
|
467
448
|
r = Code.new("function(k,vals) { return 1; }")
|
468
|
-
res =
|
449
|
+
res = Cfg.test.map_reduce(m, r, :raw => true, :out => output_collection)
|
469
450
|
assert_equal output_collection, res["result"]
|
470
451
|
assert res["counts"]
|
471
452
|
assert res["timeMillis"]
|
472
453
|
end
|
473
454
|
|
474
|
-
if
|
455
|
+
if Cfg.version >= "1.8.0"
|
475
456
|
def test_map_reduce_with_collection_merge
|
476
|
-
|
477
|
-
|
457
|
+
Cfg.test << {:user_id => 1}
|
458
|
+
Cfg.test << {:user_id => 2}
|
478
459
|
output_collection = "test-map-coll"
|
479
460
|
m = Code.new("function() { emit(this.user_id, {count: 1}); }")
|
480
461
|
r = Code.new("function(k,vals) { var sum = 0;" +
|
481
462
|
" vals.forEach(function(v) { sum += v.count;} ); return {count: sum}; }")
|
482
|
-
res =
|
463
|
+
res = Cfg.test.map_reduce(m, r, :out => output_collection)
|
483
464
|
|
484
|
-
|
485
|
-
|
486
|
-
res =
|
465
|
+
Cfg.test.remove
|
466
|
+
Cfg.test << {:user_id => 3}
|
467
|
+
res = Cfg.test.map_reduce(m, r, :out => {:merge => output_collection})
|
487
468
|
assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 1}
|
488
469
|
|
489
|
-
|
490
|
-
|
491
|
-
res =
|
470
|
+
Cfg.test.remove
|
471
|
+
Cfg.test << {:user_id => 3}
|
472
|
+
res = Cfg.test.map_reduce(m, r, :out => {:reduce => output_collection})
|
492
473
|
assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 2}
|
493
474
|
|
494
475
|
assert_raises ArgumentError do
|
495
|
-
|
476
|
+
Cfg.test.map_reduce(m, r, :out => {:inline => 1})
|
496
477
|
end
|
497
478
|
|
498
|
-
|
479
|
+
Cfg.test.map_reduce(m, r, :raw => true, :out => {:inline => 1})
|
499
480
|
assert res["results"]
|
500
481
|
end
|
501
482
|
end
|
502
483
|
|
503
|
-
if
|
484
|
+
if Cfg.version > "1.3.0"
|
504
485
|
def test_find_and_modify
|
505
|
-
|
506
|
-
|
507
|
-
|
486
|
+
Cfg.test << { :a => 1, :processed => false }
|
487
|
+
Cfg.test << { :a => 2, :processed => false }
|
488
|
+
Cfg.test << { :a => 3, :processed => false }
|
508
489
|
|
509
|
-
|
490
|
+
Cfg.test.find_and_modify(:query => {}, :sort => [['a', -1]], :update => {"$set" => {:processed => true}})
|
510
491
|
|
511
|
-
assert
|
492
|
+
assert Cfg.test.find_one({:a => 3})['processed']
|
512
493
|
end
|
513
494
|
|
514
495
|
def test_find_and_modify_with_invalid_options
|
515
|
-
|
516
|
-
|
517
|
-
|
496
|
+
Cfg.test << { :a => 1, :processed => false }
|
497
|
+
Cfg.test << { :a => 2, :processed => false }
|
498
|
+
Cfg.test << { :a => 3, :processed => false }
|
518
499
|
|
519
500
|
assert_raises Mongo::OperationFailure do
|
520
|
-
|
501
|
+
Cfg.test.find_and_modify(:blimey => {})
|
521
502
|
end
|
522
503
|
end
|
523
504
|
end
|
524
505
|
|
525
|
-
if
|
506
|
+
if Cfg.version >= "1.3.5"
|
526
507
|
def test_coll_stats
|
527
|
-
|
528
|
-
|
529
|
-
stats =
|
530
|
-
assert_equal "#{
|
508
|
+
Cfg.test << {:n => 1}
|
509
|
+
Cfg.test.create_index("n")
|
510
|
+
stats = Cfg.test.stats
|
511
|
+
assert_equal "#{MONGO_TEST_DB}.test", stats['ns']
|
531
512
|
end
|
532
513
|
end
|
533
514
|
|
534
515
|
def test_saving_dates_pre_epoch
|
535
516
|
begin
|
536
|
-
|
537
|
-
assert_in_delta Time.utc(1600),
|
517
|
+
Cfg.test.save({'date' => Time.utc(1600)})
|
518
|
+
assert_in_delta Time.utc(1600), Cfg.test.find_one()["date"], 2
|
538
519
|
rescue ArgumentError
|
539
520
|
# See note in test_date_before_epoch (BSONTest)
|
540
521
|
end
|
541
522
|
end
|
542
523
|
|
543
524
|
def test_save_symbol_find_string
|
544
|
-
|
525
|
+
Cfg.test.save(:foo => :mike, :foo1 => 'mike')
|
545
526
|
|
546
|
-
assert_equal :mike,
|
547
|
-
assert_equal :mike,
|
548
|
-
assert_equal 'mike',
|
527
|
+
assert_equal :mike, Cfg.test.find_one(:foo => :mike)["foo"]
|
528
|
+
assert_equal :mike, Cfg.test.find_one("foo" => :mike)["foo"]
|
529
|
+
assert_equal 'mike', Cfg.test.find_one("foo" => :mike)["foo1"]
|
549
530
|
|
550
|
-
assert_equal :mike,
|
551
|
-
assert_equal :mike,
|
531
|
+
assert_equal :mike, Cfg.test.find_one(:foo => "mike")["foo"]
|
532
|
+
assert_equal :mike, Cfg.test.find_one("foo" => "mike")["foo"]
|
552
533
|
end
|
553
534
|
|
554
535
|
def test_limit_and_skip
|
555
536
|
10.times do |i|
|
556
|
-
|
537
|
+
Cfg.test.save(:foo => i)
|
557
538
|
end
|
558
539
|
|
559
|
-
assert_equal 5,
|
560
|
-
assert_equal nil,
|
540
|
+
assert_equal 5, Cfg.test.find({}, :skip => 5).next_document()["foo"]
|
541
|
+
assert_equal nil, Cfg.test.find({}, :skip => 10).next_document()
|
561
542
|
|
562
|
-
assert_equal 5,
|
543
|
+
assert_equal 5, Cfg.test.find({}, :limit => 5).to_a.length
|
563
544
|
|
564
|
-
assert_equal 3,
|
565
|
-
assert_equal 5,
|
545
|
+
assert_equal 3, Cfg.test.find({}, :skip => 3, :limit => 5).next_document()["foo"]
|
546
|
+
assert_equal 5, Cfg.test.find({}, :skip => 3, :limit => 5).to_a.length
|
566
547
|
end
|
567
548
|
|
568
549
|
def test_large_limit
|
569
550
|
2000.times do |i|
|
570
|
-
|
551
|
+
Cfg.test.insert("x" => i, "y" => "mongomongo" * 1000)
|
571
552
|
end
|
572
553
|
|
573
|
-
assert_equal 2000,
|
554
|
+
assert_equal 2000, Cfg.test.count
|
574
555
|
|
575
556
|
i = 0
|
576
557
|
y = 0
|
577
|
-
|
558
|
+
Cfg.test.find({}, :limit => 1900).each do |doc|
|
578
559
|
i += 1
|
579
560
|
y += doc["x"]
|
580
561
|
end
|
@@ -584,13 +565,13 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
584
565
|
end
|
585
566
|
|
586
567
|
def test_small_limit
|
587
|
-
|
588
|
-
|
568
|
+
Cfg.test.insert("x" => "hello world")
|
569
|
+
Cfg.test.insert("x" => "goodbye world")
|
589
570
|
|
590
|
-
assert_equal 2,
|
571
|
+
assert_equal 2, Cfg.test.count
|
591
572
|
|
592
573
|
x = 0
|
593
|
-
|
574
|
+
Cfg.test.find({}, :limit => 1).each do |doc|
|
594
575
|
x += 1
|
595
576
|
assert_equal "hello world", doc["x"]
|
596
577
|
end
|
@@ -601,126 +582,128 @@ class TestCollection < MiniTest::Unit::TestCase
|
|
601
582
|
def test_find_with_transformer
|
602
583
|
klass = Struct.new(:id, :a)
|
603
584
|
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
604
|
-
cursor =
|
585
|
+
cursor = Cfg.test.find({}, :transformer => transformer)
|
605
586
|
assert_equal(transformer, cursor.transformer)
|
606
587
|
end
|
607
588
|
|
608
589
|
def test_find_one_with_transformer
|
609
590
|
klass = Struct.new(:id, :a)
|
610
591
|
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
611
|
-
id =
|
612
|
-
doc =
|
592
|
+
id = Cfg.test.insert('a' => 1)
|
593
|
+
doc = Cfg.test.find_one(id, :transformer => transformer)
|
613
594
|
assert_instance_of(klass, doc)
|
614
595
|
end
|
615
596
|
|
616
597
|
def test_ensure_index
|
617
|
-
|
618
|
-
|
619
|
-
assert_equal 1,
|
598
|
+
Cfg.test.drop_indexes
|
599
|
+
Cfg.test.insert("x" => "hello world")
|
600
|
+
assert_equal 1, Cfg.test.index_information.keys.count #default index
|
620
601
|
|
621
|
-
|
622
|
-
assert_equal 2,
|
623
|
-
assert
|
602
|
+
Cfg.test.ensure_index([["x", Mongo::DESCENDING]], {})
|
603
|
+
assert_equal 2, Cfg.test.index_information.keys.count
|
604
|
+
assert Cfg.test.index_information.keys.include? "x_-1"
|
624
605
|
|
625
|
-
|
626
|
-
assert
|
606
|
+
Cfg.test.ensure_index([["x", Mongo::ASCENDING]])
|
607
|
+
assert Cfg.test.index_information.keys.include? "x_1"
|
627
608
|
|
628
|
-
|
629
|
-
assert
|
609
|
+
Cfg.test.ensure_index([["type", 1], ["date", -1]])
|
610
|
+
assert Cfg.test.index_information.keys.include? "type_1_date_-1"
|
630
611
|
|
631
|
-
|
632
|
-
assert_equal 3,
|
633
|
-
|
634
|
-
assert_equal 2,
|
612
|
+
Cfg.test.drop_index("x_1")
|
613
|
+
assert_equal 3, Cfg.test.index_information.keys.count
|
614
|
+
Cfg.test.drop_index("x_-1")
|
615
|
+
assert_equal 2, Cfg.test.index_information.keys.count
|
635
616
|
|
636
|
-
|
637
|
-
assert_equal 3,
|
638
|
-
assert
|
617
|
+
Cfg.test.ensure_index([["x", Mongo::DESCENDING]], {})
|
618
|
+
assert_equal 3, Cfg.test.index_information.keys.count
|
619
|
+
assert Cfg.test.index_information.keys.include? "x_-1"
|
639
620
|
|
640
621
|
# Make sure that drop_index expires cache properly
|
641
|
-
|
642
|
-
assert
|
643
|
-
|
644
|
-
assert
|
645
|
-
|
646
|
-
assert
|
647
|
-
|
622
|
+
Cfg.test.ensure_index([['a', 1]])
|
623
|
+
assert Cfg.test.index_information.keys.include?("a_1")
|
624
|
+
Cfg.test.drop_index("a_1")
|
625
|
+
assert !Cfg.test.index_information.keys.include?("a_1")
|
626
|
+
Cfg.test.ensure_index([['a', 1]])
|
627
|
+
assert Cfg.test.index_information.keys.include?("a_1")
|
628
|
+
Cfg.test.drop_index("a_1")
|
648
629
|
end
|
649
630
|
|
650
631
|
end
|
651
632
|
|
652
633
|
require 'minitest/spec'
|
653
634
|
|
635
|
+
describe "Collection" do
|
636
|
+
before do
|
637
|
+
Cfg.clear_all
|
638
|
+
end
|
639
|
+
|
654
640
|
describe "Grouping" do
|
655
641
|
before do
|
656
|
-
|
657
|
-
|
658
|
-
$test.save("b" => 1)
|
642
|
+
Cfg.test.save("a" => 1)
|
643
|
+
Cfg.test.save("b" => 1)
|
659
644
|
@initial = {"count" => 0}
|
660
645
|
@reduce_function = "function (obj, prev) { prev.count += inc_value; }"
|
661
646
|
@grp_opts = {:initial => @initial, :reduce => BSON::Code.new(@reduce_function, {"inc_value" => 1})}
|
662
647
|
end
|
663
648
|
|
664
649
|
it "should fail if missing required options" do
|
665
|
-
lambda {
|
666
|
-
lambda {
|
650
|
+
lambda { Cfg.test.group(:initial => {}) }.must_raise Mongo::MongoArgumentError
|
651
|
+
lambda { Cfg.test.group(:reduce => "foo") }.must_raise Mongo::MongoArgumentError
|
667
652
|
end
|
668
653
|
|
669
654
|
it "should group results using eval form" do
|
670
655
|
@grp_opts[:reduce] = BSON::Code.new(@reduce_function, {"inc_value" => 0.5})
|
671
|
-
|
656
|
+
Cfg.test.group( @grp_opts )[0]["count"].must_equal 1
|
672
657
|
|
673
658
|
@grp_opts[:reduce] = BSON::Code.new(@reduce_function, {"inc_value" => 1})
|
674
|
-
|
659
|
+
Cfg.test.group( @grp_opts )[0]["count"].must_equal 2
|
675
660
|
|
676
661
|
@grp_opts[:reduce] = BSON::Code.new(@reduce_function, {"inc_value" => 2})
|
677
|
-
|
662
|
+
Cfg.test.group( @grp_opts )[0]["count"].must_equal 4
|
678
663
|
end
|
679
664
|
|
680
665
|
it "should finalize grouped results" do
|
681
666
|
@grp_opts[:finalize] = "function(doc) {doc.f = doc.count + 200; }"
|
682
|
-
|
667
|
+
Cfg.test.group( @grp_opts )[0]["f"].must_equal 202
|
683
668
|
end
|
684
669
|
end
|
685
670
|
|
686
671
|
describe "Grouping with key" do
|
687
672
|
before do
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
$test.save("a" => 2, "pop" => 100)
|
673
|
+
Cfg.test.save("a" => 1, "pop" => 100)
|
674
|
+
Cfg.test.save("a" => 1, "pop" => 100)
|
675
|
+
Cfg.test.save("a" => 2, "pop" => 100)
|
676
|
+
Cfg.test.save("a" => 2, "pop" => 100)
|
693
677
|
@initial = {"count" => 0, "foo" => 1}
|
694
678
|
@reduce_function = "function (obj, prev) { prev.count += obj.pop; }"
|
695
679
|
end
|
696
680
|
|
697
681
|
it "should group" do
|
698
|
-
result =
|
682
|
+
result = Cfg.test.group(:key => ['a'], :initial => @initial, :reduce => @reduce_function)
|
699
683
|
true.must_equal result.all? { |r| r['count'] == 200 }
|
700
684
|
end
|
701
685
|
end
|
702
686
|
|
703
687
|
describe "Grouping with a key function" do
|
704
688
|
before do
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
$test.save("a" => 5)
|
689
|
+
Cfg.test.save("a" => 1)
|
690
|
+
Cfg.test.save("a" => 2)
|
691
|
+
Cfg.test.save("a" => 3)
|
692
|
+
Cfg.test.save("a" => 4)
|
693
|
+
Cfg.test.save("a" => 5)
|
711
694
|
@initial = {"count" => 0}
|
712
695
|
@keyf = "function (doc) { if(doc.a % 2 == 0) { return {even: true}; } else {return {odd: true}} };"
|
713
696
|
@reduce = "function (obj, prev) { prev.count += 1; }"
|
714
697
|
end
|
715
698
|
|
716
699
|
it "should group results" do
|
717
|
-
results =
|
700
|
+
results = Cfg.test.group(:keyf => @keyf, :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
|
718
701
|
true.must_equal results[0]['even'] && results[0]['count'] == 2.0
|
719
702
|
true.must_equal results[1]['odd'] && results[1]['count'] == 3.0
|
720
703
|
end
|
721
704
|
|
722
705
|
it "should group filtered results" do
|
723
|
-
results =
|
706
|
+
results = Cfg.test.group(:keyf => @keyf, :cond => {:a => {'$ne' => 2}},
|
724
707
|
:initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
|
725
708
|
true.must_equal results[0]['even'] && results[0]['count'] == 1.0
|
726
709
|
true.must_equal results[1]['odd'] && results[1]['count'] == 3.0
|
@@ -729,8 +712,7 @@ require 'minitest/spec'
|
|
729
712
|
|
730
713
|
describe "A collection with two records" do
|
731
714
|
before do
|
732
|
-
@collection =
|
733
|
-
@collection.remove
|
715
|
+
@collection = Cfg.db.collection('test-collection')
|
734
716
|
@collection.insert({:name => "Jones"})
|
735
717
|
@collection.insert({:name => "Smith"})
|
736
718
|
end
|
@@ -757,8 +739,7 @@ require 'minitest/spec'
|
|
757
739
|
|
758
740
|
describe "Drop index " do
|
759
741
|
before do
|
760
|
-
|
761
|
-
@collection = $db.collection('test-collection')
|
742
|
+
@collection = Cfg.db.collection('test-collection')
|
762
743
|
end
|
763
744
|
|
764
745
|
it "should drop an index" do
|
@@ -792,10 +773,10 @@ require 'minitest/spec'
|
|
792
773
|
|
793
774
|
describe "Creating indexes " do
|
794
775
|
before do
|
795
|
-
|
796
|
-
|
797
|
-
@collection
|
798
|
-
@geo =
|
776
|
+
Cfg.db.drop_collection('test-collection')
|
777
|
+
@collection = Cfg.db.collection('test-collection')
|
778
|
+
@collection.insert({:aaa => 1})
|
779
|
+
@geo = Cfg.db.collection('geo')
|
799
780
|
end
|
800
781
|
|
801
782
|
it "should create index using symbols" do
|
@@ -817,15 +798,18 @@ require 'minitest/spec'
|
|
817
798
|
|
818
799
|
it "should create a unique index" do
|
819
800
|
@collection.create_index([['a', Mongo::ASCENDING]], :unique => true)
|
820
|
-
|
801
|
+
info = @collection.index_information['a_1']
|
802
|
+
assert info
|
803
|
+
assert info['unique']
|
821
804
|
end
|
822
805
|
|
823
806
|
it "should drop duplicates" do
|
824
807
|
@collection.insert({:a => 1})
|
825
808
|
@collection.insert({:a => 1})
|
826
|
-
assert_equal 2, @collection.
|
809
|
+
assert_equal 2, @collection.count(:query => {:a => 1})
|
827
810
|
@collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :dropDups => true)
|
828
811
|
assert_equal 1, @collection.find({:a => 1}).count
|
812
|
+
assert_equal 1, @collection.find({:a => 1}).count
|
829
813
|
end
|
830
814
|
|
831
815
|
it "should drop duplicates with ruby-like drop_dups key" do
|
@@ -845,7 +829,7 @@ require 'minitest/spec'
|
|
845
829
|
end
|
846
830
|
|
847
831
|
it "should create an index in the background" do
|
848
|
-
if
|
832
|
+
if Cfg.version > '1.3.1'
|
849
833
|
@collection.create_index([['b', Mongo::ASCENDING]], :background => true)
|
850
834
|
assert @collection.index_information['b_1']['background'] == true
|
851
835
|
else
|
@@ -896,8 +880,8 @@ require 'minitest/spec'
|
|
896
880
|
|
897
881
|
# describe "Capped collections" do
|
898
882
|
# before do
|
899
|
-
#
|
900
|
-
# @capped =
|
883
|
+
# Cfg.db.drop_collection('log')
|
884
|
+
# @capped = Cfg.db.create_collection('log', :capped => true, :size => 1024)
|
901
885
|
|
902
886
|
# 10.times { |n| @capped.insert({:n => n}) }
|
903
887
|
# end
|
@@ -913,7 +897,7 @@ require 'minitest/spec'
|
|
913
897
|
# end
|
914
898
|
|
915
899
|
# it "should fail tailable cursor on a non-capped collection" do
|
916
|
-
# col =
|
900
|
+
# col = Cfg.db['regular-collection']
|
917
901
|
# col.insert({:a => 1000})
|
918
902
|
# tail = Cursor.new(col, :tailable => true, :order => [['$natural', 1]])
|
919
903
|
# assert_raises OperationFailure do
|
@@ -931,3 +915,4 @@ require 'minitest/spec'
|
|
931
915
|
# assert tail.next_document
|
932
916
|
# end
|
933
917
|
# end
|
918
|
+
end
|