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
data/Rakefile
CHANGED
@@ -36,6 +36,10 @@ def replace_header(head, header_name)
|
|
36
36
|
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
37
37
|
end
|
38
38
|
|
39
|
+
def jruby?
|
40
|
+
RUBY_PLATFORM.to_s == 'java'
|
41
|
+
end
|
42
|
+
|
39
43
|
#############################################################################
|
40
44
|
#
|
41
45
|
# Custom tasks
|
@@ -65,7 +69,16 @@ task :release => :build do
|
|
65
69
|
sh "git tag v#{version}"
|
66
70
|
sh "git push origin master"
|
67
71
|
sh "git push origin v#{version}"
|
68
|
-
|
72
|
+
|
73
|
+
command = "gem push pkg/#{name}-#{version}.gem"
|
74
|
+
|
75
|
+
if jruby?
|
76
|
+
puts "--------------------------------------------------------------------------------------"
|
77
|
+
puts "can't push to rubygems using jruby at the moment, so switch to mri and run: #{command}"
|
78
|
+
puts "--------------------------------------------------------------------------------------"
|
79
|
+
else
|
80
|
+
sh command
|
81
|
+
end
|
69
82
|
end
|
70
83
|
|
71
84
|
desc "Build #{gem_file} into the pkg directory"
|
data/jmongo.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'jmongo'
|
3
|
-
s.version = '1.1.
|
4
|
-
s.date = '2011-10-
|
3
|
+
s.version = '1.1.2'
|
4
|
+
s.date = '2011-10-10'
|
5
5
|
s.platform = Gem::Platform::RUBY
|
6
6
|
s.authors = ["Chuck Remes","Guy Boertje", "Lee Henson"]
|
7
7
|
s.email = ["cremes@mac.com", "guyboertje@gmail.com", "lee.m.henson@gmail.com"]
|
data/lib/jmongo/collection.rb
CHANGED
@@ -19,7 +19,7 @@ module Mongo
|
|
19
19
|
include Mongo::JavaImpl::Collection_
|
20
20
|
|
21
21
|
attr_reader :j_collection, :j_db
|
22
|
-
attr_reader :db, :name, :pk_factory
|
22
|
+
attr_reader :db, :name, :pk_factory
|
23
23
|
|
24
24
|
# Initialize a collection object.
|
25
25
|
#
|
@@ -57,9 +57,13 @@ module Mongo
|
|
57
57
|
@name = validate_name(name)
|
58
58
|
@db, @j_db = db, db.j_db
|
59
59
|
@connection = @db.connection
|
60
|
-
@pk_factory = @opts
|
60
|
+
@pk_factory = @opts.delete(:pk)|| BSON::ObjectId
|
61
61
|
@hint = nil
|
62
|
-
@j_collection = j_collection || @j_db.
|
62
|
+
@j_collection = j_collection || @j_db.create_collection(@name, to_dbobject(@opts))
|
63
|
+
end
|
64
|
+
|
65
|
+
def safe
|
66
|
+
!!@opts.fetch(:safe, false)
|
63
67
|
end
|
64
68
|
|
65
69
|
# Return a sub-collection of this collection by name. If 'users' is a collection, then
|
@@ -75,13 +79,13 @@ module Mongo
|
|
75
79
|
# the specified sub-collection
|
76
80
|
def [](name)
|
77
81
|
new_name = "#{self.name}.#{name}"
|
78
|
-
|
79
|
-
@db.create_collection(new_name, @opts)
|
82
|
+
@db.collection(new_name, @opts)
|
80
83
|
end
|
81
84
|
|
82
85
|
def capped?
|
83
|
-
@j_collection.
|
86
|
+
@j_collection.capped?
|
84
87
|
end
|
88
|
+
|
85
89
|
# Set a hint field for query optimizer. Hint may be a single field
|
86
90
|
# name, array of field names, or a hash (preferably an [OrderedHash]).
|
87
91
|
# If using MongoDB > 1.1, you probably don't ever need to set a hint.
|
@@ -89,8 +93,13 @@ module Mongo
|
|
89
93
|
# @param [String, Array, OrderedHash] hint a single field, an array of
|
90
94
|
# fields, or a hash specifying fields
|
91
95
|
def hint=(hint=nil)
|
96
|
+
@hint = prep_hint(hint)
|
97
|
+
self
|
92
98
|
end
|
93
99
|
|
100
|
+
def hint
|
101
|
+
@hint
|
102
|
+
end
|
94
103
|
# Query the database.
|
95
104
|
#
|
96
105
|
# The +selector+ argument is a prototype document that all results must
|
@@ -152,7 +161,7 @@ module Mongo
|
|
152
161
|
end
|
153
162
|
|
154
163
|
if hint
|
155
|
-
hint =
|
164
|
+
hint = prep_hint(hint)
|
156
165
|
else
|
157
166
|
hint = @hint # assumed to be normalized already
|
158
167
|
end
|
@@ -239,9 +248,13 @@ module Mongo
|
|
239
248
|
# @core insert insert-instance_method
|
240
249
|
def insert(doc_or_docs, options={})
|
241
250
|
doc_or_docs = [doc_or_docs] unless doc_or_docs.kind_of?(Array)
|
242
|
-
doc_or_docs.collect!
|
251
|
+
doc_or_docs.collect! do |doc|
|
252
|
+
@pk_factory.create_pk(doc)
|
253
|
+
prep_id(doc)
|
254
|
+
end
|
255
|
+
safe = options.fetch(:safe, @opts[:safe])
|
243
256
|
continue = (options[:continue_on_error] || false)
|
244
|
-
docs = insert_documents(doc_or_docs,
|
257
|
+
docs = insert_documents(doc_or_docs, safe, continue)
|
245
258
|
docs.size == 1 ? docs.first['_id'] : docs.collect{|doc| doc['_id']}
|
246
259
|
end
|
247
260
|
alias_method :<<, :insert
|
@@ -293,7 +306,8 @@ module Mongo
|
|
293
306
|
# @core update update-instance_method
|
294
307
|
def update(selector, document, options={})
|
295
308
|
upsert, multi = !!(options[:upsert]), !!(options[:multi])
|
296
|
-
|
309
|
+
safe = options.fetch(:safe, @opts[:safe])
|
310
|
+
update_documents(selector, document, upsert, multi, safe)
|
297
311
|
end
|
298
312
|
|
299
313
|
# Create a new index.
|
@@ -339,10 +353,13 @@ module Mongo
|
|
339
353
|
#
|
340
354
|
# @core indexes create_index-instance_method
|
341
355
|
def create_index(spec, opts={})
|
342
|
-
|
356
|
+
_create_index(spec, opts)
|
343
357
|
end
|
344
|
-
alias_method :ensure_index, :create_index
|
345
358
|
|
359
|
+
def ensure_index(spec, opts={})
|
360
|
+
_ensure_index(spec, opts)
|
361
|
+
end
|
362
|
+
|
346
363
|
# Drop a specified index.
|
347
364
|
#
|
348
365
|
# @param [String, Array] spec
|
@@ -583,10 +600,10 @@ module Mongo
|
|
583
600
|
#
|
584
601
|
# @raise [Mongo::InvalidNSName] if +new_name+ is an invalid collection name.
|
585
602
|
def rename(new_name)
|
586
|
-
|
603
|
+
_name = validate_name(new_name)
|
587
604
|
begin
|
588
|
-
jcol = @j_collection.rename(
|
589
|
-
@name =
|
605
|
+
jcol = @j_collection.rename(_name)
|
606
|
+
@name = _name
|
590
607
|
@j_collection = jcol
|
591
608
|
rescue => ex
|
592
609
|
raise MongoDBError, "Error renaming collection: #{name}, more: #{ex.message}"
|
@@ -608,7 +625,6 @@ module Mongo
|
|
608
625
|
# @return [Hash] options that apply to this collection.
|
609
626
|
def options
|
610
627
|
info = @db.collections_info(@name).to_a
|
611
|
-
ap info
|
612
628
|
info.last['options']
|
613
629
|
end
|
614
630
|
|
@@ -632,39 +648,5 @@ module Mongo
|
|
632
648
|
end
|
633
649
|
|
634
650
|
alias :size :count
|
635
|
-
|
636
|
-
protected
|
637
|
-
|
638
|
-
def validate_name(new_name)
|
639
|
-
raise TypeError, "new_name must be a string like" unless new_name.respond_to?(:to_s)
|
640
|
-
|
641
|
-
name = new_name.to_s
|
642
|
-
|
643
|
-
if name.empty? || name.include?("..")
|
644
|
-
raise Mongo::InvalidNSName, "collection names cannot be empty"
|
645
|
-
end
|
646
|
-
if name.include? "$"
|
647
|
-
raise Mongo::InvalidNSName, "collection names must not contain '$'" unless name =~ /((^\$cmd)|(oplog\.\$main))/
|
648
|
-
end
|
649
|
-
if name.match(/^\./) || name.match(/\.$/)
|
650
|
-
raise Mongo::InvalidNSName, "collection names must not start or end with '.'"
|
651
|
-
end
|
652
|
-
name
|
653
|
-
end
|
654
|
-
|
655
|
-
def normalize_hint_fields(hint)
|
656
|
-
case hint
|
657
|
-
when String
|
658
|
-
{hint => 1}
|
659
|
-
when Hash
|
660
|
-
hint
|
661
|
-
when nil
|
662
|
-
nil
|
663
|
-
else
|
664
|
-
h = BSON::OrderedHash.new
|
665
|
-
hint.to_a.each { |k| h[k.to_s] = 1 }
|
666
|
-
h
|
667
|
-
end
|
668
|
-
end
|
669
651
|
end
|
670
652
|
end
|
data/lib/jmongo/connection.rb
CHANGED
@@ -20,28 +20,40 @@ module Mongo
|
|
20
20
|
include Mongo::JavaImpl::Connection_::InstanceMethods
|
21
21
|
extend Mongo::JavaImpl::Connection_::ClassMethods
|
22
22
|
|
23
|
-
attr_reader :connection, :connector, :logger, :auths, :primary
|
23
|
+
attr_reader :connection, :connector, :logger, :auths, :primary, :write_concern
|
24
24
|
|
25
25
|
DEFAULT_PORT = 27017
|
26
26
|
|
27
27
|
def initialize host = nil, port = nil, opts = {}
|
28
|
+
@logger = opts.delete(:logger)
|
29
|
+
@auths = opts.delete(:auths) || []
|
28
30
|
if opts.has_key?(:new_from_uri)
|
29
|
-
@options = opts
|
30
31
|
@mongo_uri = opts[:new_from_uri]
|
32
|
+
@options = @mongo_uri.options
|
33
|
+
@write_concern = @options.write_concern
|
31
34
|
@connection = JMongo::Mongo.new(@mongo_uri)
|
32
35
|
else
|
33
|
-
@logger = opts[:logger]
|
34
36
|
@host = host || 'localhost'
|
35
37
|
@port = port || 27017
|
36
38
|
@server_address = JMongo::ServerAddress.new @host, @port
|
37
39
|
@options = JMongo::MongoOptions.new
|
38
|
-
|
39
|
-
|
40
|
+
opts.each do |k,v|
|
41
|
+
key = k.to_sym
|
42
|
+
jmo_key = JMongo.options_ruby2java_lu(key)
|
43
|
+
case jmo_key
|
44
|
+
when :safe
|
45
|
+
@write_concern = DB.write_concern(v)
|
46
|
+
@options.w = @write_concern.w
|
47
|
+
@options.wtimeout = @write_concern.wtimeout
|
48
|
+
@options.fsync = @write_concern.fsync
|
49
|
+
else
|
50
|
+
jmo_val = JMongo.options_ruby2java_xf(key, v)
|
51
|
+
@options.send("#{jmo_key}=", jmo_val)
|
52
|
+
end
|
53
|
+
end
|
40
54
|
@connection = JMongo::Mongo.new(@server_address, @options)
|
41
55
|
end
|
42
56
|
@connector = @connection.connector
|
43
|
-
@logger = opts[:logger]
|
44
|
-
@auths = opts.fetch(:auths, [])
|
45
57
|
add = @connector.address
|
46
58
|
@primary = [add.host, add.port]
|
47
59
|
end
|
@@ -124,7 +136,10 @@ module Mongo
|
|
124
136
|
#
|
125
137
|
# @return [Hash]
|
126
138
|
def database_info
|
127
|
-
|
139
|
+
doc = self['admin'].command({:listDatabases => 1})
|
140
|
+
doc['databases'].each_with_object({}) do |db, info|
|
141
|
+
info[db['name']] = db['sizeOnDisk'].to_i
|
142
|
+
end
|
128
143
|
end
|
129
144
|
|
130
145
|
# Return an array of database names.
|
@@ -143,7 +158,7 @@ module Mongo
|
|
143
158
|
#
|
144
159
|
# @core databases db-instance_method
|
145
160
|
def db(db_name, options={})
|
146
|
-
DB.new db_name, self, options
|
161
|
+
DB.new db_name, self, options
|
147
162
|
end
|
148
163
|
|
149
164
|
# Shortcut for returning a database. Use DB#db to accept options.
|
data/lib/jmongo/db.rb
CHANGED
@@ -18,19 +18,30 @@ module Mongo
|
|
18
18
|
include Mongo::JavaImpl::Db_
|
19
19
|
include Mongo::JavaImpl::Utils
|
20
20
|
|
21
|
-
attr_reader :j_db
|
22
|
-
attr_reader :name
|
23
|
-
attr_reader :connection
|
21
|
+
attr_reader :j_db, :name, :connection, :safe
|
24
22
|
|
25
|
-
|
23
|
+
attr_accessor :strict
|
26
24
|
|
27
25
|
ProfileLevel = {:off => 0, :slow_only => 1, :all => 2, 0 => 'off', 1 => 'slow_only', 2 => 'all'}
|
28
26
|
|
27
|
+
def self.write_concern(safe_)
|
28
|
+
return safe_ if safe_.is_a?(JMongo::WriteConcern)
|
29
|
+
return JMongo::WriteConcern.new(0) if safe_.is_a?(FalseClass)
|
30
|
+
return JMongo::WriteConcern.new(true) if safe_.is_a?(TrueClass)
|
31
|
+
return JMongo::WriteConcern.new(safe.to_i) if safe_.is_a?(Numeric)
|
32
|
+
return JMongo::WriteConcern.new(-1) unless safe_.is_a?(Hash)
|
33
|
+
w = safe_.fetch(:w, 0)
|
34
|
+
t = safe_.fetch(:wtimeout, 0)
|
35
|
+
f = !!safe_.fetch(:fsync, false)
|
36
|
+
JMongo::WriteConcern.new(w, t, f) #dont laugh!
|
37
|
+
end
|
38
|
+
|
29
39
|
def initialize(db_name, connection, options={})
|
30
40
|
@name = db_name
|
31
41
|
@connection = connection
|
32
42
|
@j_db = @connection.connection.get_db db_name
|
33
43
|
@pk_factory = options[:pk]
|
44
|
+
@safe = options[:safe]
|
34
45
|
@strict = options.fetch(:strict, false)
|
35
46
|
end
|
36
47
|
|
@@ -64,39 +75,45 @@ module Mongo
|
|
64
75
|
|
65
76
|
def collections
|
66
77
|
collection_names.map do |name|
|
67
|
-
|
78
|
+
collection(name)
|
68
79
|
end
|
69
80
|
end
|
70
81
|
|
71
82
|
def collections_info(coll_name=nil)
|
72
|
-
|
73
|
-
selector[:name] = full_collection_name(coll_name) if coll_name
|
74
|
-
coll = self.collection(SYSTEM_NAMESPACE_COLLECTION)
|
75
|
-
coll.find selector
|
83
|
+
_collections_info coll_name
|
76
84
|
end
|
77
85
|
|
78
86
|
def create_collection(name, options={})
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
Collection.new self, name, options, jc
|
86
|
-
rescue NativeException => ex
|
87
|
-
raise MongoDBError, "Collection #{name} creation error: " +
|
88
|
-
ex.message
|
87
|
+
validate_name(name)
|
88
|
+
if collection_exists?(name)
|
89
|
+
if strict?
|
90
|
+
raise MongoDBError, "Collection #{name} already exists. Currently in strict mode."
|
91
|
+
else
|
92
|
+
return Collection.new self, name, options, @j_db.get_collection(name)
|
89
93
|
end
|
90
94
|
end
|
95
|
+
begin
|
96
|
+
Collection.new self, name, options
|
97
|
+
rescue => ex
|
98
|
+
raise MongoDBError, "Collection #{name} creation error: " + ex.message
|
99
|
+
end
|
91
100
|
end
|
92
101
|
|
93
102
|
def collection(name, options = {})
|
94
|
-
|
103
|
+
validate_name(name)
|
104
|
+
if strict? && !collection_exists?(name)
|
105
|
+
raise MongoDBError, "Collection #{name} does not exists. Currently in strict mode."
|
106
|
+
else
|
107
|
+
Collection.new self, name, options, @j_db.get_collection(name)
|
108
|
+
end
|
95
109
|
end
|
96
110
|
alias_method :[], :collection
|
97
111
|
|
98
112
|
def drop_collection(name)
|
99
|
-
|
113
|
+
col_name = name.to_s
|
114
|
+
return true unless collection_exists?(col_name)
|
115
|
+
|
116
|
+
ok?(command(:drop => col_name))
|
100
117
|
end
|
101
118
|
|
102
119
|
def get_last_error
|
@@ -122,15 +139,13 @@ module Mongo
|
|
122
139
|
|
123
140
|
def dereference(dbref)
|
124
141
|
ns = dbref.namespace
|
125
|
-
raise MongoArgumentError, "No
|
142
|
+
raise MongoArgumentError, "No collection for dbref: #{dbref.inspect}" unless collection_exists?(ns)
|
126
143
|
collection(ns).find_one("_id" => dbref.object_id)
|
127
144
|
end
|
128
145
|
|
129
146
|
def eval(code, *args)
|
130
147
|
doc = do_eval(code, *args)
|
131
|
-
|
132
|
-
return doc['retval']['value'] if doc['retval'] && doc['retval']['value']
|
133
|
-
doc['retval']
|
148
|
+
(retval = doc['retval']).is_a?(Hash) && (value = retval['value']) ? value : retval
|
134
149
|
end
|
135
150
|
|
136
151
|
def rename_collection(from, to)
|
@@ -143,12 +158,12 @@ module Mongo
|
|
143
158
|
end
|
144
159
|
|
145
160
|
def drop_index(collection_name, index_name)
|
146
|
-
|
161
|
+
collection(collection_name).drop_index(index_name)
|
147
162
|
end
|
148
163
|
|
149
164
|
def index_information(collection_name)
|
150
165
|
info = {}
|
151
|
-
from_dbobject(@j_db.
|
166
|
+
from_dbobject(@j_db.getCollectionFromString(collection_name).getIndexInfo).each do |index|
|
152
167
|
info[index['name']] = index
|
153
168
|
end
|
154
169
|
info
|
@@ -258,11 +273,6 @@ module Mongo
|
|
258
273
|
end
|
259
274
|
doc
|
260
275
|
end
|
261
|
-
|
262
|
-
# additions to the ruby driver
|
263
|
-
def has_collection?(name)
|
264
|
-
has_coll name
|
265
|
-
end
|
266
276
|
end # class DB
|
267
277
|
|
268
278
|
end # module Mongo
|
data/lib/jmongo/mongo/bson.rb
CHANGED
@@ -2,7 +2,6 @@ module BSON
|
|
2
2
|
# add missing BSON::ObjectId ruby methods
|
3
3
|
java_import Java::OrgBsonTypes::ObjectId
|
4
4
|
|
5
|
-
java_import Java::ComMongodb::DBRef
|
6
5
|
java_import Java::OrgBsonTypes::MaxKey
|
7
6
|
java_import Java::OrgBsonTypes::MinKey
|
8
7
|
java_import Java::OrgBsonTypes::Symbol
|
@@ -18,7 +17,7 @@ module BSON
|
|
18
17
|
end
|
19
18
|
|
20
19
|
def self.create_pk(doc)
|
21
|
-
doc.has_key?(:_id) || doc.has_key?('_id') ? doc : doc.merge!(
|
20
|
+
doc.has_key?(:_id) || doc.has_key?('_id') ? doc : doc.merge!('_id' => self.new)
|
22
21
|
end
|
23
22
|
|
24
23
|
def self.from_time(time, opts={})
|
@@ -105,6 +104,31 @@ module BSON
|
|
105
104
|
alias :to_bson_code :to_bson
|
106
105
|
end
|
107
106
|
|
107
|
+
class DBRef
|
108
|
+
|
109
|
+
attr_reader :namespace, :object_id
|
110
|
+
|
111
|
+
# Create a DBRef. Use this class in conjunction with DB#dereference.
|
112
|
+
#
|
113
|
+
# @param [String] a collection name
|
114
|
+
# @param [ObjectId] an object id
|
115
|
+
#
|
116
|
+
# @core dbrefs constructor_details
|
117
|
+
def initialize(namespace, object_id)
|
118
|
+
@namespace = namespace
|
119
|
+
@object_id = object_id
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_s
|
123
|
+
"ns: #{namespace}, id: #{object_id}"
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_hash
|
127
|
+
{"$ns" => @namespace, "$id" => @object_id }
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
108
132
|
# Generic Mongo Ruby Driver exception class.
|
109
133
|
class MongoRubyError < StandardError; end
|
110
134
|
|