jmongo 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +43 -0
  3. data/Rakefile +72 -0
  4. data/jmongo.gemspec +84 -6
  5. data/lib/jmongo.rb +6 -14
  6. data/lib/jmongo/collection.rb +196 -114
  7. data/lib/jmongo/connection.rb +39 -13
  8. data/lib/jmongo/cursor.rb +161 -63
  9. data/lib/jmongo/db.rb +119 -30
  10. data/lib/jmongo/exceptions.rb +39 -0
  11. data/lib/jmongo/mongo-2.6.5.gb1.jar +0 -0
  12. data/lib/jmongo/mongo/bson.rb +130 -0
  13. data/lib/jmongo/mongo/collection.rb +185 -0
  14. data/lib/jmongo/mongo/connection.rb +45 -0
  15. data/lib/jmongo/mongo/db.rb +31 -0
  16. data/lib/jmongo/mongo/jmongo.rb +44 -0
  17. data/lib/jmongo/mongo/mongo.rb +98 -0
  18. data/lib/jmongo/mongo/ruby_ext.rb +38 -0
  19. data/lib/jmongo/mongo/utils.rb +136 -0
  20. data/lib/jmongo/version.rb +1 -1
  21. data/test-results.txt +98 -0
  22. data/test/auxillary/1.4_features.rb +166 -0
  23. data/test/auxillary/authentication_test.rb +68 -0
  24. data/test/auxillary/autoreconnect_test.rb +41 -0
  25. data/test/auxillary/fork_test.rb +30 -0
  26. data/test/auxillary/repl_set_auth_test.rb +58 -0
  27. data/test/auxillary/slave_connection_test.rb +36 -0
  28. data/test/auxillary/threaded_authentication_test.rb +101 -0
  29. data/test/bson/binary_test.rb +15 -0
  30. data/test/bson/bson_test.rb +657 -0
  31. data/test/bson/byte_buffer_test.rb +208 -0
  32. data/test/bson/hash_with_indifferent_access_test.rb +38 -0
  33. data/test/bson/json_test.rb +17 -0
  34. data/test/bson/object_id_test.rb +138 -0
  35. data/test/bson/ordered_hash_test.rb +245 -0
  36. data/test/bson/test_helper.rb +46 -0
  37. data/test/bson/timestamp_test.rb +46 -0
  38. data/test/collection_test.rb +933 -0
  39. data/test/connection_test.rb +325 -0
  40. data/test/conversions_test.rb +121 -0
  41. data/test/cursor_fail_test.rb +75 -0
  42. data/test/cursor_message_test.rb +43 -0
  43. data/test/cursor_test.rb +547 -0
  44. data/test/data/empty_data +0 -0
  45. data/test/data/sample_data +0 -0
  46. data/test/data/sample_file.pdf +0 -0
  47. data/test/data/small_data.txt +1 -0
  48. data/test/db_api_test.rb +739 -0
  49. data/test/db_connection_test.rb +15 -0
  50. data/test/db_test.rb +325 -0
  51. data/test/grid_file_system_test.rb +260 -0
  52. data/test/grid_io_test.rb +210 -0
  53. data/test/grid_test.rb +259 -0
  54. data/test/load/thin/config.ru +6 -0
  55. data/test/load/thin/config.yml.template +6 -0
  56. data/test/load/thin/load.rb +24 -0
  57. data/test/load/unicorn/config.ru +6 -0
  58. data/test/load/unicorn/load.rb +23 -0
  59. data/test/load/unicorn/unicorn.rb.template +29 -0
  60. data/test/replica_sets/connect_test.rb +111 -0
  61. data/test/replica_sets/connection_string_test.rb +29 -0
  62. data/test/replica_sets/count_test.rb +36 -0
  63. data/test/replica_sets/insert_test.rb +54 -0
  64. data/test/replica_sets/pooled_insert_test.rb +58 -0
  65. data/test/replica_sets/query_secondaries.rb +109 -0
  66. data/test/replica_sets/query_test.rb +52 -0
  67. data/test/replica_sets/read_preference_test.rb +43 -0
  68. data/test/replica_sets/refresh_test.rb +123 -0
  69. data/test/replica_sets/replication_ack_test.rb +71 -0
  70. data/test/replica_sets/rs_test_helper.rb +27 -0
  71. data/test/safe_test.rb +68 -0
  72. data/test/support/hash_with_indifferent_access.rb +186 -0
  73. data/test/support/keys.rb +45 -0
  74. data/test/support_test.rb +19 -0
  75. data/test/test_helper.rb +111 -0
  76. data/test/threading/threading_with_large_pool_test.rb +90 -0
  77. data/test/threading_test.rb +88 -0
  78. data/test/tools/auth_repl_set_manager.rb +14 -0
  79. data/test/tools/keyfile.txt +1 -0
  80. data/test/tools/repl_set_manager.rb +377 -0
  81. data/test/unit/collection_test.rb +128 -0
  82. data/test/unit/connection_test.rb +85 -0
  83. data/test/unit/cursor_test.rb +127 -0
  84. data/test/unit/db_test.rb +96 -0
  85. data/test/unit/grid_test.rb +51 -0
  86. data/test/unit/node_test.rb +73 -0
  87. data/test/unit/pool_manager_test.rb +47 -0
  88. data/test/unit/pool_test.rb +9 -0
  89. data/test/unit/read_test.rb +101 -0
  90. data/test/unit/safe_test.rb +125 -0
  91. data/test/uri_test.rb +92 -0
  92. metadata +170 -99
  93. data/lib/jmongo/ajrb.rb +0 -189
  94. data/lib/jmongo/jmongo_jext.rb +0 -302
  95. data/lib/jmongo/mongo-2.6.3.jar +0 -0
  96. data/lib/jmongo/utils.rb +0 -61
@@ -2,4 +2,43 @@ module Mongo
2
2
  MongoDBException = Java::ComMongodb::MongoException
3
3
  NetworkException = Java::ComMongodb::MongoException::Network
4
4
  DuplicateKeyException = Java::ComMongodb::MongoException::DuplicateKey
5
+
6
+ # Generic Mongo Ruby Driver exception class.
7
+ class MongoRubyError < StandardError; end
8
+
9
+ # Raised when MongoDB itself has returned an error.
10
+ class MongoDBError < RuntimeError; end
11
+
12
+ # Raised when invalid arguments are sent to Mongo Ruby methods.
13
+ class MongoArgumentError < MongoRubyError; end
14
+
15
+ # Raised on failures in connection to the database server.
16
+ class ConnectionError < MongoRubyError; end
17
+
18
+ # Raised on failures in connection to the database server.
19
+ class ReplicaSetConnectionError < ConnectionError; end
20
+
21
+ # Raised on failures in connection to the database server.
22
+ class ConnectionTimeoutError < MongoRubyError; end
23
+
24
+ # Raised when a connection operation fails.
25
+ class ConnectionFailure < MongoDBError; end
26
+
27
+ # Raised when authentication fails.
28
+ class AuthenticationError < MongoDBError; end
29
+
30
+ # Raised when a database operation fails.
31
+ class OperationFailure < MongoDBError; end
32
+
33
+ # Raised when a socket read operation times out.
34
+ class OperationTimeout < MongoDBError; end
35
+
36
+ # Raised when a client attempts to perform an invalid operation.
37
+ class InvalidOperation < MongoDBError; end
38
+
39
+ # Raised when an invalid collection or database name is used (invalid namespace name).
40
+ class InvalidNSName < RuntimeError; end
41
+
42
+ # Raised when the client supplies an invalid value to sort by.
43
+ class InvalidSortValueError < MongoRubyError; end
5
44
  end
@@ -0,0 +1,130 @@
1
+ module BSON
2
+ # add missing BSON::ObjectId ruby methods
3
+ java_import Java::OrgBsonTypes::ObjectId
4
+
5
+ java_import Java::ComMongodb::DBRef
6
+ java_import Java::OrgBsonTypes::MaxKey
7
+ java_import Java::OrgBsonTypes::MinKey
8
+ java_import Java::OrgBsonTypes::Symbol
9
+
10
+ OrderedHash = Java::ComMongodb::BasicDBObject
11
+ BsonCode = Java::OrgBsonTypes::CodeWScope
12
+
13
+ class ObjectId
14
+ def self.from_string(str)
15
+ v = is_valid?(str.to_s)
16
+ raise BSON::InvalidObjectId, "illegal ObjectID format" unless v
17
+ new(str.to_s)
18
+ end
19
+
20
+ def self.create_pk(doc)
21
+ doc.has_key?(:_id) || doc.has_key?('_id') ? doc : doc.merge!(:_id => self.new)
22
+ end
23
+
24
+ def self.from_time(time, opts={})
25
+ unique = opts.fetch(:unique, false)
26
+ if unique
27
+ self.new(time)
28
+ else
29
+ self.new([time.to_i,0,0].pack("NNN").to_java_bytes)
30
+ end
31
+ end
32
+
33
+ #"data=", "decode64", "encode64", "decode_b", "b64encode" - shout out if these methods are needed
34
+
35
+ def data
36
+ self.to_byte_array.to_a.map{|x| x & 0xFF}
37
+ end
38
+
39
+ def clone
40
+ self.class.new(self.to_byte_array)
41
+ end
42
+
43
+ def inspect
44
+ "BSON::ObjectID('#{self.to_s}')"
45
+ end
46
+
47
+ def generation_time
48
+ Time.at(self.get_time/1000).utc
49
+ end
50
+ end
51
+
52
+ class MaxKey
53
+ def ==(obj)
54
+ obj.class == self.class
55
+ end
56
+ end
57
+
58
+ class MinKey
59
+ def ==(obj)
60
+ obj.class == self.class
61
+ end
62
+ end
63
+
64
+ class Code
65
+ # Wrap code to be evaluated by MongoDB.
66
+ #
67
+ # @param [String] code the JavaScript code.
68
+ # @param [Hash] a document mapping identifiers to values, which
69
+ # represent the scope in which the code is to be executed.
70
+ def initialize(code, scope={})
71
+ unless code.is_a?(String)
72
+ raise ArgumentError, "BSON::Code must be in the form of a String; #{code.class} is not accepted."
73
+ end
74
+ @bson_code = BsonCode.new(code, scope.to_bson)
75
+ end
76
+
77
+ def code
78
+ @bson_code.code
79
+ end
80
+
81
+ def scope
82
+ @bson_code.scope
83
+ end
84
+
85
+ def length
86
+ code.length
87
+ end
88
+
89
+ def ==(other)
90
+ self.class == other.class &&
91
+ code == other.code && scope == other.scope
92
+ end
93
+
94
+ def inspect
95
+ "<BSON::Code:#{object_id} @code=\"#{code}\" @scope=\"#{scope.inspect}\">"
96
+ end
97
+
98
+ def to_s
99
+ code.to_s
100
+ end
101
+
102
+ def to_bson
103
+ @bson_code
104
+ end
105
+ alias :to_bson_code :to_bson
106
+ end
107
+
108
+ # Generic Mongo Ruby Driver exception class.
109
+ class MongoRubyError < StandardError; end
110
+
111
+ # Raised when MongoDB itself has returned an error.
112
+ class MongoDBError < RuntimeError; end
113
+
114
+ # This will replace MongoDBError.
115
+ class BSONError < MongoDBError; end
116
+
117
+ # Raised when given a string is not valid utf-8 (Ruby 1.8 only).
118
+ class InvalidStringEncoding < BSONError; end
119
+
120
+ # Raised when attempting to initialize an invalid ObjectId.
121
+ class InvalidObjectId < BSONError; end
122
+ class InvalidObjectID < BSONError; end
123
+
124
+ # Raised when trying to insert a document that exceeds the 4MB limit or
125
+ # when the document contains objects that can't be serialized as BSON.
126
+ class InvalidDocument < BSONError; end
127
+
128
+ # Raised when an invalid name is used.
129
+ class InvalidKeyName < BSONError; end
130
+ end
@@ -0,0 +1,185 @@
1
+ # Copyright (C) 2010 Guy Boertje
2
+
3
+ module Mongo
4
+ module JavaImpl
5
+ module Collection_
6
+
7
+ private
8
+
9
+ def name_from opts
10
+ return unless (opts[:name] || opts['name'])
11
+ name = opts.delete(:name) || opts.delete('name')
12
+ name ? name.to_s : nil
13
+ end
14
+
15
+ def _drop_index(spec)
16
+ name = generate_index_name(spec.is_a?(String) || spec.is_a?(Symbol) ? spec : parse_index_spec(spec))
17
+ idx = @db.index_information(@name).values.select do |entry|
18
+ entry['name'] == name || name == generate_index_name(entry['key'])
19
+ end
20
+ if idx.nil? || idx.empty?
21
+ raise MongoDBError, "Error with drop_index command for: #{name}"
22
+ end
23
+ @j_collection.dropIndexes(idx.first['name'].to_s)
24
+ end
25
+
26
+ def _create_indexes(obj,opts = {})
27
+ name = name_from(opts)
28
+ field_spec = parse_index_spec(obj)
29
+ opts[:dropDups] = opts[:drop_dups] if opts[:drop_dups]
30
+ if obj.is_a?(String) || obj.is_a?(Symbol)
31
+ name = obj.to_s unless name
32
+ end
33
+ name = generate_index_name(field_spec) unless name
34
+ opts['name'] = name
35
+ begin
36
+ @j_collection.ensureIndex(to_dbobject(field_spec),to_dbobject(opts))
37
+ rescue => e
38
+ if opts[:dropDups] && e.message =~ /E11000/
39
+ # NOP. If the user is intentionally dropping dups, we can ignore duplicate key errors.
40
+ else
41
+ msg = "Failed to create index #{field_spec.inspect} with the following error: #{e.message}"
42
+ raise Mongo::OperationFailure, msg
43
+ end
44
+ end
45
+ name
46
+ end
47
+
48
+ def generate_index_name(spec)
49
+ return spec.to_s if spec.is_a?(String) || spec.is_a?(Symbol)
50
+ indexes = []
51
+ spec.each_pair do |field, direction|
52
+ dir = sort_value(field,direction)
53
+ indexes.push("#{field}_#{dir}")
54
+ end
55
+ indexes.join("_")
56
+ end
57
+
58
+ def parse_index_spec(spec)
59
+ field_spec = Hash.new
60
+ if spec.is_a?(String) || spec.is_a?(Symbol)
61
+ field_spec[spec.to_s] = 1
62
+ elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) }
63
+ spec.each do |f|
64
+ if [Mongo::ASCENDING, Mongo::DESCENDING, Mongo::GEO2D].include?(f[1])
65
+ field_spec[f[0].to_s] = f[1]
66
+ else
67
+ raise MongoArgumentError, "Invalid index field #{f[1].inspect}; " +
68
+ "should be one of Mongo::ASCENDING (1), Mongo::DESCENDING (-1) or Mongo::GEO2D ('2d')."
69
+ end
70
+ end
71
+ else
72
+ raise MongoArgumentError, "Invalid index specification #{spec.inspect}; " +
73
+ "should be either a string, symbol, or an array of arrays."
74
+ end
75
+ field_spec
76
+ end
77
+
78
+ def remove_documents(obj, safe=nil)
79
+ concern = write_concern(safe)
80
+ wr = @j_collection.remove(to_dbobject(obj), concern)
81
+ return from_dbobject(wr.last_error(concern)) if concern.call_get_last_error
82
+ true
83
+ end
84
+
85
+ ## Note: refactor when java driver fully supports continue_on_error
86
+ def insert_documents(obj, safe=nil, continue_on_error=false)
87
+ to_do = [obj].flatten
88
+ concern = write_concern(safe)
89
+ if continue_on_error
90
+ out = []
91
+ to_do.each do |doc|
92
+ res = _insert_one(doc, concern)
93
+ out << res if res
94
+ end
95
+ if to_do.size != out.size
96
+ msg = "Failed to insert document #{obj.inspect}, duplicate key"
97
+ raise(Mongo::OperationFailure, msg)
98
+ end
99
+ else
100
+ begin
101
+ @j_collection.insert( to_dbobject(to_do), concern )
102
+ rescue => ex
103
+ if ex.message =~ /E11000/
104
+ msg = "Failed to insert document #{obj.inspect}, duplicate key, E11000"
105
+ raise(Mongo::OperationFailure, msg)
106
+ else
107
+ msg = "Failed to insert document #{obj.inspect} db error: #{ex.message}"
108
+ raise Mongo::MongoDBError, msg
109
+ end
110
+ end
111
+ end
112
+ to_do
113
+ end
114
+
115
+ def _insert_one(obj, concern)
116
+ one_obj = [obj].flatten.first
117
+ dbo = to_dbobject(one_obj)
118
+ begin
119
+ jres = @j_collection.insert( dbo, concern )
120
+ result = from_dbobject(jres.get_last_error(concern))
121
+ rescue => ex
122
+ if ex.message =~ /E11000/ #noop duplicate key
123
+ result = {'err'=>ex.message}
124
+ else
125
+ msg = "Failed to insert document #{obj.inspect} db error: #{ex.message}"
126
+ raise Mongo::MongoDBError, msg
127
+ end
128
+ end
129
+ doc = from_dbobject(dbo)
130
+ result["err"] =~ /E11000/ ? nil : doc
131
+ end
132
+
133
+ def find_and_modify_document(query,fields,sort,remove,update,new_,upsert)
134
+ from_dbobject @j_collection.find_and_modify(to_dbobject(query),to_dbobject(fields),to_dbobject(sort),remove,to_dbobject(update),new_,upsert)
135
+ end
136
+
137
+ def find_one_document(spec, opts = {})
138
+ opts[:skip] = 0
139
+ opts[:batch_size] = -1
140
+ opts[:limit] = 0
141
+ doc = nil
142
+ self.find(spec, opts) { |c| doc = c.next }
143
+ doc
144
+ end
145
+
146
+ def update_documents(selector, document, upsert=false, multi=false, safe=nil)
147
+ begin
148
+ @j_collection.update(to_dbobject(selector),to_dbobject(document), upsert, multi, write_concern(safe))
149
+ rescue => ex
150
+ if ex.message =~ /E11001/
151
+ msg = "Failed to update document #{document.inspect}, duplicate key"
152
+ raise(Mongo::OperationFailure, msg)
153
+ else
154
+ msg = "Failed to update document #{document.inspect} db error: #{ex.message}"
155
+ raise Mongo::MongoDBError, msg
156
+ end
157
+ end
158
+ end
159
+
160
+ def save_document(obj, safe=nil)
161
+ @pk_factory.create_pk(obj)
162
+ db_obj = to_dbobject(obj)
163
+ concern = write_concern(safe)
164
+ begin
165
+ @j_collection.save( db_obj, concern )
166
+ rescue => ex
167
+ if ex.message =~ /E11000/
168
+ msg = "Failed to insert document #{obj.inspect}, duplicate key"
169
+ raise(Mongo::OperationFailure, msg)
170
+ else
171
+ msg = "Failed to insert document #{obj.inspect} db error: #{ex.message}"
172
+ raise Mongo::MongoDBError, msg
173
+ end
174
+ end
175
+ db_obj['_id']
176
+ end
177
+
178
+ # def id_nil?(obj)
179
+ # return true if obj.has_key?(:_id) && obj[:_id].nil?
180
+ # return true if obj.has_key?('_id') && obj['_id'].nil?
181
+ # false
182
+ # end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright (C) 2010 Guy Boertje
2
+
3
+ module Mongo
4
+ module JavaImpl
5
+ module Connection_
6
+ module InstanceMethods
7
+
8
+ private
9
+
10
+ def get_db_names
11
+ @connection.get_database_names
12
+ end
13
+
14
+ def drop_a_db name
15
+ @connection.drop_database(name)
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ URI_RE = /^mongodb:\/\/(([-.\w]+):([^@]+)@)?([-.\w]+)(:([\w]+))?(\/([-\w]+))?/
21
+ OPTS_KEYS = %W[maxpoolsize waitqueuemultiple waitqueuetimeoutms connecttimeoutms sockettimeoutms
22
+ autoconnectretry slaveok safe w wtimeout fsync]
23
+
24
+ def _from_uri uri, opts={}
25
+ optarr = []
26
+ unless uri =~ URI_RE
27
+ raise MongoArgumentError, "MongoDB URI incorrect"
28
+ end
29
+ pieces = uri.split("//")
30
+ extra = pieces.last.count('/') == 0 ? "/" : ""
31
+ opts.each do|k,v|
32
+ if OPTS_KEYS.include?(k.to_s) && !v.nil?
33
+ (optarr << "#{k}=#{v}")
34
+ end
35
+ end
36
+ unless optarr.empty?
37
+ uri << "#{extra}?" << optarr.join("&")
38
+ end
39
+ opts[:new_from_uri] = Java::ComMongodb::MongoURI.new(uri)
40
+ new("",0,opts)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (C) 2010 Guy Boertje
2
+
3
+ module Mongo
4
+ module JavaImpl
5
+ module Db_
6
+ SYSTEM_NAMESPACE_COLLECTION = "system.namespaces"
7
+ SYSTEM_PROFILE_COLLECTION = "system.profile"
8
+
9
+ private
10
+
11
+ def exec_command(cmd)
12
+ cmd_hash = cmd.kind_of?(Hash) ? cmd : {cmd => 1}
13
+ cmd_res = @j_db.command(to_dbobject(cmd_hash))
14
+ from_dbobject(cmd_res)
15
+ end
16
+
17
+ def do_eval(string, *args)
18
+ @j_db.do_eval(string, *args)
19
+ end
20
+
21
+ def has_coll(name)
22
+ @j_db.collection_exists(name)
23
+ end
24
+
25
+ def get_last_error
26
+ from_dbobject @j_db.get_last_error
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ module JMongo
2
+ java_import com.mongodb.BasicDBList
3
+ java_import com.mongodb.BasicDBObject
4
+ java_import com.mongodb.Bytes
5
+ java_import com.mongodb.DB
6
+ java_import com.mongodb.DBRef
7
+ java_import com.mongodb.DBCollection
8
+ java_import com.mongodb.DBCursor
9
+ java_import com.mongodb.DBObject
10
+ java_import com.mongodb.Mongo
11
+ java_import com.mongodb.MongoOptions
12
+ java_import com.mongodb.ServerAddress
13
+ java_import com.mongodb.WriteConcern
14
+ java_import com.mongodb.WriteResult
15
+ java_import com.mongodb.MongoException
16
+ java_import com.mongodb.MongoURI
17
+ java_import com.mongodb.MapReduceCommand
18
+ java_import com.mongodb.MapReduceOutput
19
+ end
20
+
21
+ class Java::ComMongodb::BasicDBObject
22
+ def self.[](*args)
23
+ Hash[*args]
24
+ end
25
+
26
+ if RUBY_PLATFORM == 'java' && JRUBY_VERSION =~ /(1\.[6-9]|[2-9]\.[0-9])..*/
27
+ def hashify
28
+ self.to_map.to_hash
29
+ end
30
+ else
31
+ def hashify
32
+ Hash[self.key_set.to_a.zip(self.values.to_a)]
33
+ end
34
+ end
35
+ def get(key)
36
+ self.java_send(:get,key.to_s)
37
+ end
38
+ end
39
+
40
+ class Java::ComMongodb::BasicDBList
41
+ def arrayify
42
+ self.to_array
43
+ end
44
+ end