jmongo 1.1.1 → 1.1.2
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 +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
|
|