em-mongo 0.2.10 → 0.2.11

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.
@@ -5,12 +5,14 @@ module EM::Mongo
5
5
  DEFAULT_NS = "ns"
6
6
  DEFAULT_QUERY_DOCS = 101
7
7
 
8
- module EMConnection
9
- class Error < Exception;
8
+ class EMConnection < EM::Connection
9
+ MAX_RETRIES = 5
10
+
11
+ class Error < Exception;
10
12
  class ConnectionNotBound
11
13
  end
12
14
  end
13
-
15
+
14
16
  include EM::Deferrable
15
17
 
16
18
  RESERVED = 0
@@ -20,7 +22,7 @@ module EM::Mongo
20
22
  OP_INSERT = 2002
21
23
  OP_QUERY = 2004
22
24
  OP_DELETE = 2006
23
-
25
+
24
26
  STANDARD_HEADER_SIZE = 16
25
27
  RESPONSE_HEADER_SIZE = 20
26
28
 
@@ -50,7 +52,6 @@ module EM::Mongo
50
52
  end
51
53
 
52
54
  def send_command(buffer, request_id, &blk)
53
-
54
55
  callback do
55
56
  send_data buffer
56
57
  end
@@ -81,7 +82,7 @@ module EM::Mongo
81
82
  message.put_int(flags)
82
83
 
83
84
  message.put_array(BSON::BSON_CODER.serialize(selector, true, true).to_a)
84
- message.put_array(BSON::BSON_CODER.serialize(document, false, true).to_a)
85
+ message.put_array(BSON::BSON_CODER.serialize(document, false, true).to_a)
85
86
 
86
87
  req_id = new_request_id
87
88
  message.prepend!(message_headers(OP_UPDATE, req_id, message))
@@ -114,11 +115,12 @@ module EM::Mongo
114
115
  # EM hooks
115
116
  def initialize(options={})
116
117
  @request_id = 0
118
+ @retries = 0
117
119
  @responses = {}
118
120
  @is_connected = false
119
121
  @host = options[:host] || DEFAULT_IP
120
122
  @port = options[:port] || DEFAULT_PORT
121
- @on_unbind = options[:unbind_cb] || proc {}
123
+ @on_unbind = options[:unbind_cb] || proc {}
122
124
 
123
125
  @on_close = proc {
124
126
  raise Error, "failure with mongodb server #{@host}:#{@port}"
@@ -127,14 +129,15 @@ module EM::Mongo
127
129
  errback { @on_close.call }
128
130
  end
129
131
 
130
- def self.connect(host = DEFAULT_IP, port = DEFAULT_PORT, timeout = nil)
131
- opt = {:host => host, :port => port, :timeout => timeout}
132
+ def self.connect(host = DEFAULT_IP, port = DEFAULT_PORT, timeout = nil, opts = nil)
133
+ opt = {:host => host, :port => port, :timeout => timeout}.merge(opts)
132
134
  EM.connect(host, port, self, opt)
133
135
  end
134
136
 
135
137
  def connection_completed
136
138
  @buffer = BSON::ByteBuffer.new
137
139
  @is_connected = true
140
+ @retries = 0
138
141
  succeed
139
142
  end
140
143
 
@@ -146,7 +149,7 @@ module EM::Mongo
146
149
  def remaining_bytes(buffer)
147
150
  buffer.size-buffer.position
148
151
  end
149
-
152
+
150
153
  def peek_size(buffer)
151
154
  position= buffer.position
152
155
  size= buffer.get_int
@@ -157,7 +160,7 @@ module EM::Mongo
157
160
  def receive_data(data)
158
161
 
159
162
  @buffer.append!(BSON::ByteBuffer.new(data.unpack('C*')))
160
-
163
+
161
164
  @buffer.rewind
162
165
  while message_received?(@buffer)
163
166
  response_to, docs= next_response
@@ -173,12 +176,12 @@ module EM::Mongo
173
176
  @buffer.clear
174
177
  end
175
178
 
176
- close_connection if @close_pending && @responses.empty?
177
-
179
+ close_connection if @close_pending && @responses.empty?
180
+
178
181
  end
179
-
182
+
180
183
  def next_response()
181
-
184
+
182
185
  # Header
183
186
  size = @buffer.get_int
184
187
  request_id = @buffer.get_int
@@ -204,7 +207,20 @@ module EM::Mongo
204
207
 
205
208
  def unbind
206
209
  @is_connected = false
207
- @on_unbind.call
210
+
211
+ # XXX do we need to fail the responses here?
212
+ @request_id = 0
213
+ @responses = {}
214
+
215
+ set_deferred_status(nil)
216
+
217
+ if @retries >= MAX_RETRIES
218
+ @on_unbind.call
219
+ return
220
+ end
221
+
222
+ @retries += 1
223
+ EM.add_timer(5) { reconnect(@host, @port) }
208
224
  end
209
225
 
210
226
  def close
@@ -238,11 +254,11 @@ module EM::Mongo
238
254
  end
239
255
  end
240
256
  class Connection
241
- def initialize(host = DEFAULT_IP, port = DEFAULT_PORT, timeout = nil)
242
- @em_connection = EMConnection.connect(host, port, timeout)
257
+ def initialize(host = DEFAULT_IP, port = DEFAULT_PORT, timeout = nil, opts = {})
258
+ @em_connection = EMConnection.connect(host, port, timeout, opts)
243
259
  @db = {}
244
260
  end
245
-
261
+
246
262
  def db(name = DEFAULT_DB)
247
263
  @db[name] ||= EM::Mongo::Database.new(name, @em_connection)
248
264
  end
@@ -0,0 +1,219 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe EMMongo::Collection do
4
+ include EM::SpecHelper
5
+
6
+ before(:all) do
7
+ @numbers = {
8
+ 1 => 'one',
9
+ 2 => 'two',
10
+ 3 => 'three',
11
+ 4 => 'four',
12
+ 5 => 'five',
13
+ 6 => 'six',
14
+ 7 => 'seven',
15
+ 8 => 'eight',
16
+ 9 => 'nine'
17
+ }
18
+ end
19
+
20
+ after(:all) do
21
+ end
22
+
23
+ it 'should insert an object' do
24
+ EM::Spec::Mongo.collection do |collection|
25
+ obj = collection.insert('hello' => 'world')
26
+ obj.keys.should include '_id'
27
+ obj['_id'].should be_a_kind_of String
28
+ obj['_id'].length.should == 24
29
+ EM::Spec::Mongo.close
30
+ end
31
+ end
32
+
33
+ it 'should find an object by attribute' do
34
+ EM::Spec::Mongo.collection do |collection|
35
+ collection.insert("hello" => 'world')
36
+ r = collection.find({"hello" => "world"},{}) do |res|
37
+ res.size.should >= 1
38
+ res[0]["hello"].should == "world"
39
+ EM::Spec::Mongo.close
40
+ end
41
+ end
42
+ end
43
+
44
+ it 'should find an object by id' do
45
+ EM::Spec::Mongo.collection do |collection|
46
+ obj = collection.insert('hello' => 'world')
47
+ collection.find({'_id' => obj['_id']},{}) do |res|
48
+ res.size.should >= 1
49
+ res[0]['hello'].should == "world"
50
+ EM::Spec::Mongo.close
51
+ end
52
+ end
53
+ end
54
+
55
+ it 'should find all objects' do
56
+ EM::Spec::Mongo.collection do |collection|
57
+ collection.insert('one' => 'one')
58
+ collection.insert('two' => 'two')
59
+ collection.find do |res|
60
+ res.size.should >= 2
61
+ EM::Spec::Mongo.close
62
+ end
63
+ end
64
+ end
65
+
66
+ it 'should find large sets of objects' do
67
+ EM::Spec::Mongo.collection do |collection|
68
+ (0..1500).each { |n| collection.insert({n.to_s => n.to_s}) }
69
+ collection.find do |res|
70
+ res.size.should == EM::Mongo::DEFAULT_QUERY_DOCS
71
+ collection.find({}, {:limit => 1500}) do |res|
72
+ res.size.should == 1500
73
+ EM::Spec::Mongo.close
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ it 'should update an object' do
80
+ EM::Spec::Mongo.collection do |collection|
81
+ obj = collection.insert('hello' => 'world')
82
+ collection.update({'hello' => 'world'}, {'hello' => 'newworld'})
83
+ collection.find({'_id' => obj['_id']},{}) do |res|
84
+ res[0]['hello'].should == 'newworld'
85
+ EM::Spec::Mongo.close
86
+ end
87
+ end
88
+ end
89
+
90
+ it 'should update an object with $inc' do
91
+ EM::Spec::Mongo.collection do |collection|
92
+ obj = collection.insert('hello' => 'world')
93
+ collection.update({'hello' => 'world'}, {'$inc' => {'count' => 1}})
94
+ collection.find({'_id' => obj['_id']},{}) do |res|
95
+ res.first['hello'].should == 'world'
96
+ res.first['count'].should == 1
97
+ EM::Spec::Mongo.close
98
+ end
99
+ end
100
+ end
101
+
102
+ it 'should remove an object' do
103
+ EM::Spec::Mongo.collection do |collection|
104
+ obj = collection.insert('hello' => 'world')
105
+ collection.remove('_id' => obj['_id'])
106
+ collection.find({'hello' => "world"}) do |res|
107
+ res.size.should == 0
108
+ EM::Spec::Mongo.close
109
+ end
110
+ end
111
+ end
112
+
113
+ it 'should remove all objects' do
114
+ EM::Spec::Mongo.collection do |collection|
115
+ collection.insert('one' => 'one')
116
+ collection.insert('two' => 'two')
117
+ collection.remove
118
+ collection.find do |res|
119
+ res.size.should == 0
120
+ EM::Spec::Mongo.close
121
+ end
122
+ end
123
+ end
124
+
125
+ it 'should insert a Time' do
126
+ EM::Spec::Mongo.collection do |collection|
127
+ t = Time.now.utc.freeze
128
+ collection.insert('date' => t)
129
+ collection.find do |res|
130
+ res[0]['date'].to_s.should == t.to_s
131
+ EM::Spec::Mongo.close
132
+ end
133
+ end
134
+ end
135
+
136
+ it 'should insert a complex object' do
137
+ EM::Spec::Mongo.collection do |collection|
138
+ obj = {
139
+ 'array' => [1,2,3],
140
+ 'float' => 123.456,
141
+ 'hash' => {'boolean' => true},
142
+ 'nil' => nil,
143
+ 'symbol' => :name,
144
+ 'string' => 'hello world',
145
+ 'time' => Time.now.to_f,
146
+ 'regex' => /abc$/ix
147
+ }
148
+ retobj = collection.insert(obj)
149
+ collection.find({'_id' => obj['_id']}) do |ret|
150
+ ret.size.should == 1
151
+ ret[0].each_key do |key|
152
+ ret[0][key].should == obj[key]
153
+ end
154
+ EM::Spec::Mongo.close
155
+ end
156
+
157
+ end
158
+ end
159
+
160
+ it 'should find an object using nested properties' do
161
+ EM::Spec::Mongo.collection do |collection|
162
+ collection.insert({
163
+ 'name' => 'Google',
164
+ 'address' => {
165
+ 'city' => 'Mountain View',
166
+ 'state' => 'California'}
167
+ })
168
+
169
+ collection.first('address.city' => 'Mountain View') do |res|
170
+ res['name'].should == 'Google'
171
+ EM::Spec::Mongo.close
172
+ end
173
+ end
174
+ end
175
+
176
+ it 'should find objects with specific values' do
177
+ EM::Spec::Mongo.collection do |collection|
178
+ @numbers.each do |num, word|
179
+ collection.insert({'num' => num, 'word' => word})
180
+ end
181
+
182
+ collection.find({'num' => {'$in' => [1,3,5]}}) do |res|
183
+ res.size.should == 3
184
+ res.map{|r| r['num'] }.sort.should == [1,3,5]
185
+ EM::Spec::Mongo.close
186
+ end
187
+ end
188
+ end
189
+
190
+ it 'should find objects greater than something' do
191
+ EM::Spec::Mongo.collection do |collection|
192
+ @numbers.each do |num, word|
193
+ collection.insert('num' => num, 'word' => word)
194
+ end
195
+
196
+ collection.find({'num' => {'$gt' => 3}}) do |res|
197
+ res.size.should == 6
198
+ res.map{|r| r['num'] }.sort.should == [4,5,6,7,8,9]
199
+ EM::Spec::Mongo.close
200
+ end
201
+ end
202
+ end
203
+
204
+ it 'should handle multiple pending queries' do
205
+ EM::Spec::Mongo.collection do |collection|
206
+ id = collection.insert("foo" => "bar")['_id']
207
+ received = 0
208
+
209
+ 10.times do |n|
210
+ collection.first("_id" => id) do |res|
211
+ received += 1
212
+ EM::Spec::Mongo.close if received == 10
213
+ end
214
+ end
215
+
216
+ end
217
+ end
218
+
219
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+
3
+ describe EMMongo::Connection do
4
+ include EM::SpecHelper
5
+
6
+ it 'should connect' do
7
+ em do
8
+ connection = EMMongo::Connection.new
9
+ EM.next_tick do
10
+ connection.should be_connected
11
+ done
12
+ end
13
+ end
14
+ end
15
+
16
+ it 'should close' do
17
+ em do
18
+ connection = EMMongo::Connection.new
19
+
20
+ EM.add_timer(1) do
21
+ connection.should be_connected
22
+ connection.close
23
+ end
24
+
25
+ EM.add_timer(2) do
26
+ EM.next_tick do
27
+ connection.should_not be_connected
28
+ done
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ it 'should instantiate a Database' do
35
+ EM::Spec::Mongo.connection do |connection|
36
+ db1 = connection.db
37
+ db1.should be_kind_of(EM::Mongo::Database)
38
+
39
+ db2 = connection.db('db2')
40
+ db2.should be_kind_of(EM::Mongo::Database)
41
+ db2.should_not == db1
42
+
43
+ EM::Spec::Mongo.close
44
+ end
45
+ end
46
+
47
+
48
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 10
9
- version: 0.2.10
8
+ - 11
9
+ version: 0.2.11
10
10
  platform: ruby
11
11
  authors:
12
12
  - bcg
@@ -21,6 +21,7 @@ dependencies:
21
21
  name: eventmachine
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
24
25
  requirements:
25
26
  - - ">="
26
27
  - !ruby/object:Gem::Version
@@ -35,6 +36,7 @@ dependencies:
35
36
  name: bson
36
37
  prerelease: false
37
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
38
40
  requirements:
39
41
  - - ">="
40
42
  - !ruby/object:Gem::Version
@@ -57,6 +59,11 @@ files:
57
59
  - lib/em-mongo/collection.rb
58
60
  - lib/em-mongo/connection.rb
59
61
  - lib/em-mongo.rb
62
+ - spec/collection_spec.rb
63
+ - spec/connection_spec.rb
64
+ - spec/integration/collection_spec.rb
65
+ - spec/integration/connection_spec.rb
66
+ - spec/spec_helper.rb
60
67
  has_rdoc: true
61
68
  homepage:
62
69
  licenses: []
@@ -67,6 +74,7 @@ rdoc_options:
67
74
  require_paths:
68
75
  - lib
69
76
  required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
70
78
  requirements:
71
79
  - - ">="
72
80
  - !ruby/object:Gem::Version
@@ -74,6 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
82
  - 0
75
83
  version: "0"
76
84
  required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
77
86
  requirements:
78
87
  - - ">="
79
88
  - !ruby/object:Gem::Version
@@ -83,11 +92,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
92
  requirements: []
84
93
 
85
94
  rubyforge_project:
86
- rubygems_version: 1.3.6
95
+ rubygems_version: 1.3.7
87
96
  signing_key:
88
97
  specification_version: 3
89
98
  summary: EventMachine driver for MongoDB.
90
99
  test_files:
91
100
  - spec/collection_spec.rb
92
101
  - spec/connection_spec.rb
102
+ - spec/integration/collection_spec.rb
103
+ - spec/integration/connection_spec.rb
93
104
  - spec/spec_helper.rb