em-mongo 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/CHANGELOG +117 -0
- data/Gemfile +9 -0
- data/README.rdoc +255 -0
- data/Rakefile +127 -0
- data/VERSION +1 -1
- data/em-mongo.gemspec +30 -0
- data/examples/legacy.rb +38 -0
- data/examples/readme.rb +58 -0
- data/lib/em-mongo/collection.rb +11 -6
- data/lib/em-mongo/connection.rb +2 -0
- data/spec/gem/Gemfile +5 -0
- data/spec/gem/bundler.rb +21 -0
- data/spec/gem/rubygems.rb +19 -0
- data/spec/integration/collection_spec.rb +13 -3
- data/spec/spec_helper.rb +37 -0
- data/spec/unit/bson_spec.rb +21 -0
- metadata +19 -11
data/.gitignore
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
- 0.5.0
|
2
|
+
|
3
|
+
* debian packaging changes
|
4
|
+
(https://github.com/bcg/em-mongo/pull/53)
|
5
|
+
* added new 2d indexes EM::Mongo::FLAT2D, EM::Mongo::SPHERE2D
|
6
|
+
(https://github.com/bcg/em-mongo/pull/49)
|
7
|
+
|
8
|
+
- 0.4.3
|
9
|
+
|
10
|
+
* ensure new buffers aren't created when not needed (FlockOfBirds) #40
|
11
|
+
|
12
|
+
- 0.4.2
|
13
|
+
|
14
|
+
* defer_as_a instead to to_a
|
15
|
+
* bugger optimizations
|
16
|
+
* Jruby fixes
|
17
|
+
|
18
|
+
- 0.4.1
|
19
|
+
|
20
|
+
* fix collection response value on success (pawelpacana)
|
21
|
+
* whitepsace (pawelpacana)
|
22
|
+
|
23
|
+
- 0.4.0
|
24
|
+
|
25
|
+
* added a Cursor implementation
|
26
|
+
* replaced raw callbacks in the API with deferrables
|
27
|
+
* removed CRUD methods from the Connection
|
28
|
+
* added a variety of server side aggregation commands
|
29
|
+
* added support for indexes
|
30
|
+
* added safe update methods
|
31
|
+
|
32
|
+
- 0.3.6
|
33
|
+
|
34
|
+
* dj2: fixes reconnects. (see: https://github.com/bcg/em-mongo/pull/23)
|
35
|
+
|
36
|
+
- 0.3.5
|
37
|
+
|
38
|
+
* gvarela: added orderby functionality based on the mongo-ruby-driver.
|
39
|
+
(https://github.com/bcg/em-mongo/pull/19)
|
40
|
+
|
41
|
+
- 0.3.4
|
42
|
+
|
43
|
+
* Silly regression issue. Added em requires to tests and so I missed it when
|
44
|
+
I yanked it from lib/em-mongo.rb
|
45
|
+
* dynamix found *another* regression in the new database code.
|
46
|
+
(see: https://github.com/bcg/em-mongo/pull/16)
|
47
|
+
|
48
|
+
- 0.3.3
|
49
|
+
|
50
|
+
* Yank Bundler out lib/em-mongo.rb and push it into spec/spec_helper.rb
|
51
|
+
* Numerous Rakefile changes
|
52
|
+
|
53
|
+
- 0.3.2
|
54
|
+
|
55
|
+
* Added spec/gem to help with release testing
|
56
|
+
* Added some Rakefile helpers
|
57
|
+
|
58
|
+
- 0.3.1
|
59
|
+
|
60
|
+
* Added VERSION to the gem. It was breaking the new EM::Mongo::Version module.
|
61
|
+
|
62
|
+
- 0.3
|
63
|
+
|
64
|
+
* Refactored test suite
|
65
|
+
* Followed ruby-mongo-driver's _id convention. This will BREAK your apps.
|
66
|
+
See: http://twitter.com/#!/brendengrace/status/9445253316608000
|
67
|
+
* Split out database.rb and pulled in support.rb and conversons.rb from
|
68
|
+
ruby-mongo-driver
|
69
|
+
* Added initial authentication support to to EM::Mongo::Database
|
70
|
+
|
71
|
+
- 0.2.14
|
72
|
+
|
73
|
+
* .close was reconnecting automatically so now its configureable
|
74
|
+
|
75
|
+
- 0.2.12
|
76
|
+
|
77
|
+
* Use BSON::ObjectID for _id instead of String (gaffneyc).
|
78
|
+
|
79
|
+
= 0.2.11
|
80
|
+
|
81
|
+
* Auto Reconnect on lost connection (dj2)
|
82
|
+
* Options handling on Em.connect (dj2)
|
83
|
+
* Bundler support (pkieltyka)
|
84
|
+
|
85
|
+
= 0.2.10
|
86
|
+
|
87
|
+
* Ruby 1.8 was broken in the last set of patches pulled in.
|
88
|
+
|
89
|
+
= 0.2.9
|
90
|
+
|
91
|
+
* Performance enhacements by merrells
|
92
|
+
* Cleanups by jarib
|
93
|
+
|
94
|
+
= 0.2.7
|
95
|
+
|
96
|
+
* Fixes modifier issues in update. BSON would not allow '$' with key checks. (http://github.com/bcg/em-mongo/issues/3)
|
97
|
+
|
98
|
+
= 0.2.6
|
99
|
+
|
100
|
+
* 'limit' was broken in find because of poor protocol parsing. (http://github.com/bcg/em-mongo/issues/1)
|
101
|
+
|
102
|
+
= 0.2.5
|
103
|
+
|
104
|
+
* collection.update
|
105
|
+
|
106
|
+
= 0.2.4
|
107
|
+
|
108
|
+
* Remove support for symbols, needs to be enforced still
|
109
|
+
* Remove lib/buffer.rb and all custom BSON parsing
|
110
|
+
* Remove UUID dependency (replaced by BSON::ObjectID.new)
|
111
|
+
* Fixes a BufferOverflow because of misunderstood types
|
112
|
+
|
113
|
+
= 0.1.1 - Initial Relase
|
114
|
+
|
115
|
+
* Rspec tests
|
116
|
+
* Fixes a BufferOverflow with large Hashes
|
117
|
+
* Fork of RMongo
|
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,255 @@
|
|
1
|
+
|
2
|
+
Em-mongo is no longer being maintained (hasn't been for some time). If you are interested in the commit bit
|
3
|
+
or want to take over the full project, please let me know!
|
4
|
+
|
5
|
+
= EM-Mongo
|
6
|
+
|
7
|
+
An EventMachine client for MongoDB. Originally based on RMongo, this client aims to be as api compatible
|
8
|
+
with mongo-ruby-driver as possible.
|
9
|
+
|
10
|
+
For methods that do not retrieve data from the database the api of em-mongo should be identical (though a subset) to the mongo-ruby-driver. This includes the various update methods like insert, save and update (without the :safe flag, which is handled separately) as well as find, which returns a cursor.
|
11
|
+
|
12
|
+
For operations that require IO, em-mongo always returns an EventMachine deferrable.
|
13
|
+
|
14
|
+
== Some examples
|
15
|
+
|
16
|
+
#this file can be found in the examples directory.
|
17
|
+
# bundle exec examples/readme.rb
|
18
|
+
|
19
|
+
#insert a few records, then read some back using Collection#find
|
20
|
+
|
21
|
+
require 'em-mongo'
|
22
|
+
require 'eventmachine'
|
23
|
+
|
24
|
+
EM.run do
|
25
|
+
db = EM::Mongo::Connection.new('localhost').db('my_database')
|
26
|
+
collection = db.collection('my_collection')
|
27
|
+
EM.next_tick do
|
28
|
+
(1..10).each do |i|
|
29
|
+
collection.insert( { :revolution => i } )
|
30
|
+
end
|
31
|
+
|
32
|
+
#find returns an EM::Mongo::Cursor
|
33
|
+
|
34
|
+
cursor = collection.find
|
35
|
+
|
36
|
+
#most cursor methods return an EM::Mongo::RequestResponse,
|
37
|
+
#which is an EventMachine::Deferrable
|
38
|
+
|
39
|
+
resp = cursor.defer_as_a
|
40
|
+
|
41
|
+
#when em-mongo IO methods succeed, they
|
42
|
+
#will always call back with the return
|
43
|
+
#value you would have expected from the
|
44
|
+
#synchronous version of the same method from
|
45
|
+
#the mongo-ruby-driver
|
46
|
+
|
47
|
+
resp.callback do |documents|
|
48
|
+
puts "I just got #{documents.length} documents! I'm really cool!"
|
49
|
+
end
|
50
|
+
|
51
|
+
#when em-mongo IO methods fail, they
|
52
|
+
#errback with an array in the form
|
53
|
+
#[ErrorClass, "error message"]
|
54
|
+
|
55
|
+
resp.errback do |err|
|
56
|
+
raise *err
|
57
|
+
end
|
58
|
+
|
59
|
+
#iterate though each result in a query
|
60
|
+
|
61
|
+
collection.find( :revolution => { "$gt" => 5 } ).limit(1).skip(1).each do |doc|
|
62
|
+
#unlike the mongo-ruby-driver, each returns null at the end of the cursor
|
63
|
+
if doc
|
64
|
+
puts "Revolution ##{doc['revolution']}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#add an index
|
69
|
+
|
70
|
+
collection.create_index [[:revolution, -1]]
|
71
|
+
|
72
|
+
#insert a document and ensure it gets written
|
73
|
+
|
74
|
+
save_resp = collection.safe_save( { :hi => "there" }, :last_error_params => {:fsync=>true} )
|
75
|
+
save_resp.callback { puts "Hi is there, let us give thanks" }
|
76
|
+
save_resp.errback { |err| puts "AAAAAAAAAAAAAAAARGH! Oh why! WHY!?!?!" }
|
77
|
+
|
78
|
+
collection.drop
|
79
|
+
|
80
|
+
EM.add_periodic_timer(1) { EM.stop }
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
== Error handling
|
87
|
+
|
88
|
+
em-mongo will present errors in two different ways. First, em-mongo will raise exceptions like any other synchronous library if an error is enountered in a method that does not need to perform IO or if an error is encountered prior to peforming IO.
|
89
|
+
|
90
|
+
Errors returned by the database, or errors communicating with the database, will be delivered via standard EM::Deferrable errbacks. While it is tempting to subscribe just to a callback
|
91
|
+
|
92
|
+
my_collection.find.defer_as_a.callback {|docs| ... }
|
93
|
+
|
94
|
+
in the case of an error you will never receive a response. If you are waiting for a response before your program continues, you will be waiting a very long time. A better approach would be to store the deferrable into a variable and subscribe to its callback and errback
|
95
|
+
|
96
|
+
resp = my_collection.find.defer_as_a
|
97
|
+
resp.callback { |docs| ... }
|
98
|
+
resp.errback { |err| raise *err }
|
99
|
+
|
100
|
+
errback's blocks will always be called with a single argument which is a two element array containing the error class and the error message
|
101
|
+
|
102
|
+
[EM::Mongo::OperationError, "aw snap"]
|
103
|
+
|
104
|
+
== Safe Writes
|
105
|
+
|
106
|
+
As you are probably aware the default behavior for the mongo-ruby-driver, and therefore em-mongo, is to send update messages to MongoDB in a fire-and-forget manner. This means that if a unique index is violated, or some other problem causes MongoDB to raise an exception and refuse to apply your changes, you'll never know about it until you go to look for that record later. For many applications such as logging this might be OK, but for many use cases like analytics you will want to know if your writes don't succeed.
|
107
|
+
|
108
|
+
This is one place where em-mongo diverges substantially from the mongo-ruby-driver because an unsafe write will not receive a response from the server, whereas a safe write will receive a response from the server and requires a deferrable and a callback.
|
109
|
+
|
110
|
+
#default, unsafe write
|
111
|
+
my_collection.insert( {:a => "b" } )
|
112
|
+
|
113
|
+
#a safe write using em-mongo
|
114
|
+
insert_resp = my_collection.safe_insert( {:a => "b" } )
|
115
|
+
insert_resp.callback { #all ok }
|
116
|
+
insert_resp.errback { |err| puts '<sigh>' }
|
117
|
+
|
118
|
+
em-mongo has the following safe methods:
|
119
|
+
safe_insert, safe_update, safe_save
|
120
|
+
|
121
|
+
In addition to calling your errback if the write fails, you can provide the usual 'safety' options that you can to Database#get_last_error, such as :fsync => true or :w => 2, to control the degree of safety you want. Please the 10gen documentation on DB#get_last_error for specifics.
|
122
|
+
|
123
|
+
safe_insert( {:a=>"v"}, :last_error_params => { :fsync => true, :w => 5 } )
|
124
|
+
|
125
|
+
== Documentation
|
126
|
+
|
127
|
+
em-mongo now has some YARD docs. These are mostly ported directly from the mongo-ruby-driver. While they have been updated to reflect em-mongo's async API, there are probably a few errors left over in the translation. Please file an issue or submit a pull request if you notice any inaccuracies.
|
128
|
+
|
129
|
+
http://rubydoc.info/github/bcg/em-mongo/master/frames
|
130
|
+
|
131
|
+
== Upgrading
|
132
|
+
|
133
|
+
**The API for em-mongo has changed since version 0.3.6.**
|
134
|
+
|
135
|
+
em-mongo methods no longer directly accept callbacks and instead return EM::Mongo::RequestResponse objects, which are EM::Deferrable(s). This means you need to convert calls like this
|
136
|
+
|
137
|
+
my_collection.first() { |doc| p doc }
|
138
|
+
|
139
|
+
to this
|
140
|
+
|
141
|
+
my_collection.first().callback { |doc| p doc }
|
142
|
+
|
143
|
+
EM::Mongo::Collection#find now returns a cursor, not an array, to maintain compatibility with the mongo-ruby-driver. This provides a great deal more flexibility, but requires you to select a specific cursor method to actually fetch data from the server, such as #defer_as_a or #next
|
144
|
+
|
145
|
+
my_collection.find() { |docs| ... }
|
146
|
+
|
147
|
+
becomes
|
148
|
+
|
149
|
+
my_collection.find.defer_as_a.callback { |docs| ... }
|
150
|
+
|
151
|
+
If for some reason you aren't ready to upgrade your project but you want to be able to use the newer gem, you can require a compatibility file that will revert the new API to the API found in 0.3.6
|
152
|
+
|
153
|
+
require 'em-mongo'
|
154
|
+
require 'em-mongo/prev.rb'
|
155
|
+
|
156
|
+
This file will not remain in the project forever, though, so it is better to upgrade your projects sooner rather than later.
|
157
|
+
|
158
|
+
== What's in the box?
|
159
|
+
|
160
|
+
=== Collection
|
161
|
+
|
162
|
+
CRUD operations
|
163
|
+
|
164
|
+
#find, #find_one, #save, #safe_save, #insert, #save_insert, #update, #safe_update, #remove, #find_and_modify
|
165
|
+
|
166
|
+
Index management
|
167
|
+
|
168
|
+
#create_index, #drop_index
|
169
|
+
|
170
|
+
Collection management
|
171
|
+
|
172
|
+
#drop, #stats, #count, #name
|
173
|
+
|
174
|
+
Server-side aggregations
|
175
|
+
|
176
|
+
#map_reduce, #group, #distinct
|
177
|
+
|
178
|
+
=== Database
|
179
|
+
|
180
|
+
Collection management
|
181
|
+
|
182
|
+
#collection, #collection_names, #collections, #collections_info, #create_collection, #drop_collection
|
183
|
+
|
184
|
+
Index management
|
185
|
+
|
186
|
+
#drop_index, #index_information
|
187
|
+
|
188
|
+
Authentication
|
189
|
+
|
190
|
+
#authenticate, #add_user
|
191
|
+
|
192
|
+
Misc
|
193
|
+
|
194
|
+
#get_last_error, #error?, #name, #command
|
195
|
+
|
196
|
+
=== Cursor
|
197
|
+
|
198
|
+
Query options
|
199
|
+
:selector, :order, :skip, :limit, :explain, :batch_size, :fields, :tailable, :transformer
|
200
|
+
|
201
|
+
Enumerable-ish
|
202
|
+
**EM::Mongo::Cursor does **not** use the Enumerable mixin for obvious reasons**
|
203
|
+
|
204
|
+
#next_document, #rewind!, #has_next?, #count, #each, #to_a
|
205
|
+
|
206
|
+
Misc
|
207
|
+
|
208
|
+
#batch_size, #explain, #close, #closed?
|
209
|
+
|
210
|
+
Query modifier methods
|
211
|
+
|
212
|
+
#sort, #limit, #skip
|
213
|
+
|
214
|
+
== Compatibility
|
215
|
+
* em-mongo has been tested on Ruby 1.8.7 and 1.9.2
|
216
|
+
* em-mongo will not run under JRuby. We'd love some help figuring out why :)
|
217
|
+
* Compatibility with other runtimes is unknown
|
218
|
+
|
219
|
+
== Still Missing / TODO
|
220
|
+
* Replica Sets
|
221
|
+
* GRIDFS support
|
222
|
+
* Connection pooling
|
223
|
+
* PK factories
|
224
|
+
* JRuby support
|
225
|
+
|
226
|
+
== Contact
|
227
|
+
|
228
|
+
* Twitter: @brendengrace
|
229
|
+
* IRC: bcg
|
230
|
+
* Email: brenden.grace@gmail.com
|
231
|
+
|
232
|
+
== Credit
|
233
|
+
|
234
|
+
Aman Gupta (tmm1) wrote the original RMongo which em-mongo is based on.
|
235
|
+
|
236
|
+
== References
|
237
|
+
|
238
|
+
* Rmongo: http://github.com/tmm1/rmongo
|
239
|
+
* EM-Mongo: http://github.com/bcg/em-mongo
|
240
|
+
* mongo-ruby-driver: http://github.com/mongodb/mongo-ruby-driver
|
241
|
+
* Mongo Wire Protocol: http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol
|
242
|
+
|
243
|
+
== License
|
244
|
+
|
245
|
+
(The MIT License)
|
246
|
+
|
247
|
+
Copyright © 2010 Brenden Grace
|
248
|
+
|
249
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
250
|
+
|
251
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
252
|
+
|
253
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
254
|
+
|
255
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
def em_mongo_version
|
6
|
+
File.read("VERSION").strip
|
7
|
+
end
|
8
|
+
|
9
|
+
def root_dir
|
10
|
+
File.dirname(__FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => 'spec:integration:default'
|
14
|
+
|
15
|
+
class MongoRunner
|
16
|
+
def self.run(options={})
|
17
|
+
auth = "--auth" if options[:auth]
|
18
|
+
dir = Dir.tmpdir + "/em-mongo-tests-#$$"
|
19
|
+
FileUtils.mkdir dir
|
20
|
+
pidf = "#{dir}/mongod.pid"
|
21
|
+
logf = "#{dir}/mongo.log"
|
22
|
+
begin
|
23
|
+
system "mongod run #{auth} --fork -vvvvvvv --dbpath #{dir} --pidfilepath #{pidf} --logpath #{logf} >> /dev/null "
|
24
|
+
yield if block_given?
|
25
|
+
ensure
|
26
|
+
if File.exists?(pidf) and File.read(pidf).to_i != 0
|
27
|
+
Process.kill("KILL", File.read(pidf).to_i)
|
28
|
+
FileUtils.rm_r dir unless options[:noclean]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
spec = eval(File.read('em-mongo.gemspec'))
|
35
|
+
|
36
|
+
namespace :bundle do
|
37
|
+
task :install do
|
38
|
+
if `bundle check` =~ /bundle install/
|
39
|
+
system("bundle install --path vendor/gems")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
namespace :gem do
|
45
|
+
|
46
|
+
desc "build gem"
|
47
|
+
task :build do
|
48
|
+
puts "Building em-mongo #{em_mongo_version}"
|
49
|
+
system "gem build em-mongo.gemspec -q"
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "release gem"
|
53
|
+
task :release do
|
54
|
+
system "gem push em-mongo-#{em_mongo_version}.gem"
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
namespace :spec do
|
60
|
+
|
61
|
+
namespace :gem do
|
62
|
+
|
63
|
+
desc "bundler tests"
|
64
|
+
task :bundler do
|
65
|
+
MongoRunner.run do
|
66
|
+
print "Testing Bundler integration ... "
|
67
|
+
if system "cd spec/gem && bundle install --quiet && ./bundler.rb"
|
68
|
+
puts "SUCCESS."
|
69
|
+
else
|
70
|
+
puts "FAILURE."
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
desc "rubygems tests"
|
76
|
+
task :rubygems do
|
77
|
+
MongoRunner.run do
|
78
|
+
print "Testing Rubygems integration ... "
|
79
|
+
steps =[]
|
80
|
+
steps << "cd spec/gem"
|
81
|
+
|
82
|
+
if `gem list -i em-mongo` == 'true'
|
83
|
+
steps << "gem uninstall --force -a em-mongo >/dev/null"
|
84
|
+
end
|
85
|
+
steps << "gem install #{root_dir}/em-mongo-#{em_mongo_version}.gem >/dev/null "
|
86
|
+
steps << "./rubygems.rb"
|
87
|
+
if system steps.join(" && ")
|
88
|
+
puts "SUCCESS."
|
89
|
+
else
|
90
|
+
puts "FAILURE."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
desc "all gem tests"
|
96
|
+
task :all => [:bundler, :rubygems]
|
97
|
+
end
|
98
|
+
|
99
|
+
namespace :integration do
|
100
|
+
|
101
|
+
desc "default tests"
|
102
|
+
task :default => ['bundle:install'] do
|
103
|
+
MongoRunner.run do
|
104
|
+
system "bundle exec spec #{spec.test_files.join(' ')} -t -b -fs -color"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
desc "exhaustive tests"
|
109
|
+
task :exhaustive => ['bundle:install'] do
|
110
|
+
MongoRunner.run({:noclean => true}) do
|
111
|
+
system "bundle exec spec #{spec.test_files.join(' ')} -t -b -fs -color"
|
112
|
+
end
|
113
|
+
MongoRunner.run({:auth => true}) do
|
114
|
+
system "bundle exec spec #{spec.test_files.join(' ')} -t -b -fs -color"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
desc "default tests, but don't start mongodb for me"
|
119
|
+
task :no_mongo => ['bundle:install'] do
|
120
|
+
system "bundle exec spec #{spec.test_files.join(' ')} -t -b -fs -color"
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
desc "release testing"
|
126
|
+
task :release => ['spec:integration:default','gem:build','spec:gem:bundler','spec:gem:rubygems']
|
127
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/em-mongo.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
version = File.read("VERSION").strip
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'em-mongo'
|
5
|
+
s.version = version
|
6
|
+
|
7
|
+
s.authors = ['bcg', 'PlasticLizard']
|
8
|
+
s.email = 'brenden.grace@gmail.com'
|
9
|
+
s.date = "2010-12-01"
|
10
|
+
|
11
|
+
s.description = 'EventMachine driver for MongoDB.'
|
12
|
+
s.homepage = 'https://github.com/bcg/em-mongo'
|
13
|
+
s.rubyforge_project = 'em-mongo'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
|
19
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
20
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.rubygems_version = '1.3.6'
|
24
|
+
|
25
|
+
s.summary = 'An EventMachine driver for MongoDB.'
|
26
|
+
|
27
|
+
s.add_dependency 'eventmachine', ['>= 0.12.10']
|
28
|
+
s.add_dependency 'bson', ['>= 1.1.3']
|
29
|
+
|
30
|
+
end
|
data/examples/legacy.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#bundle exec ruby examples/legacy.rb
|
2
|
+
require 'em-mongo'
|
3
|
+
require 'em-mongo/prev.rb'
|
4
|
+
|
5
|
+
require 'eventmachine'
|
6
|
+
|
7
|
+
EM.run do
|
8
|
+
conn = EM::Mongo::Connection.new('localhost')
|
9
|
+
db = conn.db('my_database')
|
10
|
+
collection = db.collection('my_collection')
|
11
|
+
EM.next_tick do
|
12
|
+
|
13
|
+
(1..10).each do |i|
|
14
|
+
conn.insert('my_database.my_collection', { :revolution => i } )
|
15
|
+
end
|
16
|
+
|
17
|
+
conn.update('my_database.my_collection', {:revolution => 9}, {:revolution => 8.5})
|
18
|
+
|
19
|
+
conn.delete('my_database.my_collection', {:revolution => 1})
|
20
|
+
|
21
|
+
collection.find do |documents|
|
22
|
+
puts "I just got #{documents.length} documents! I'm really cool!"
|
23
|
+
end
|
24
|
+
|
25
|
+
#iterate though each result in a query
|
26
|
+
collection.find( {:revolution => { "$gt" => 5 }}, :limit =>1, :skip => 1, :order => [:revolution, -1]) do |docs|
|
27
|
+
docs.each do |doc|
|
28
|
+
puts "Revolution ##{doc['revolution']}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
collection.drop
|
33
|
+
|
34
|
+
EM.add_periodic_timer(1) { EM.stop }
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/examples/readme.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#bundle exec ruby examples/readme.rb
|
2
|
+
require 'em-mongo'
|
3
|
+
require 'eventmachine'
|
4
|
+
|
5
|
+
EM.run do
|
6
|
+
db = EM::Mongo::Connection.new('localhost').db('my_database')
|
7
|
+
collection = db.collection('my_collection')
|
8
|
+
EM.next_tick do
|
9
|
+
(1..10).each do |i|
|
10
|
+
collection.insert( { :revolution => i } )
|
11
|
+
end
|
12
|
+
|
13
|
+
#find returns an EM::Mongo::Cursor
|
14
|
+
cursor = collection.find
|
15
|
+
|
16
|
+
#most cursor methods return an EM::Mongo::RequestResponse,
|
17
|
+
#which is an EventMachine::Deferrable
|
18
|
+
resp = cursor.to_a
|
19
|
+
|
20
|
+
#when em-mongo IO methods succeed, they
|
21
|
+
#will always call back with the return
|
22
|
+
#value you would have expected from the
|
23
|
+
#synchronous version of the method from
|
24
|
+
#the mongo-ruby-driver
|
25
|
+
resp.callback do |documents|
|
26
|
+
puts "I just got #{documents.length} documents! I'm really cool!"
|
27
|
+
end
|
28
|
+
|
29
|
+
#when em-mongo IO methods fail, they
|
30
|
+
#errback with an array in the form
|
31
|
+
#[ErrorClass, "error message"]
|
32
|
+
resp.errback do |err|
|
33
|
+
raise *err
|
34
|
+
end
|
35
|
+
|
36
|
+
#iterate though each result in a query
|
37
|
+
collection.find( :revolution => { "$gt" => 5 } ).limit(1).skip(1).each do |doc|
|
38
|
+
#unlike the mongo-ruby-driver, each returns null at the end of the cursor
|
39
|
+
if doc
|
40
|
+
puts "Revolution ##{doc['revolution']}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#add an index
|
45
|
+
collection.create_index [[:revolution, -1]]
|
46
|
+
|
47
|
+
#insert a document and ensure it gets written
|
48
|
+
save_resp = collection.safe_save( { :hi => "there" }, :last_error_params => {:fsync=>true} )
|
49
|
+
save_resp.callback { puts "Hi is there, let us give thanks" }
|
50
|
+
save_resp.errback { |err| puts "AAAAAAAAAAAAAAAARGH! Oh why! WHY!?!?!" }
|
51
|
+
|
52
|
+
collection.drop
|
53
|
+
|
54
|
+
EM.add_periodic_timer(1) { EM.stop }
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/lib/em-mongo/collection.rb
CHANGED
@@ -597,7 +597,10 @@ module EM::Mongo
|
|
597
597
|
# @param [String, Array] spec
|
598
598
|
# should be either a single field name or an array of
|
599
599
|
# [field name, direction] pairs. Directions should be specified
|
600
|
-
# as Mongo::ASCENDING, Mongo::DESCENDING,
|
600
|
+
# as EM::Mongo::ASCENDING, EM::Mongo::DESCENDING, EM::Mongo::FLAT2D, EM::Mongo::SPHERE2D
|
601
|
+
#
|
602
|
+
# Note that MongoDB 2.2 used 2d flat indexes and called them geo, MongoDB 2.4 has 2d and 2dsphere indexes
|
603
|
+
# EM::Mongo::GEO2D is kept for backward compatiblity and is creating a flat 2d index
|
601
604
|
#
|
602
605
|
# Note that geospatial indexing only works with versions of MongoDB >= 1.3.3+. Keep in mind, too,
|
603
606
|
# that in order to geo-index a given field, that field must reference either an array or a sub-object
|
@@ -618,10 +621,10 @@ module EM::Mongo
|
|
618
621
|
# @option opts [Integer] :max (nil) specify the maximum longitude and latitude for a geo index.
|
619
622
|
#
|
620
623
|
# @example Creating a compound index:
|
621
|
-
# @posts.create_index([['subject', Mongo::ASCENDING], ['created_at', Mongo::DESCENDING]])
|
624
|
+
# @posts.create_index([['subject', EM::Mongo::ASCENDING], ['created_at', EM::Mongo::DESCENDING]])
|
622
625
|
#
|
623
626
|
# @example Creating a geospatial index:
|
624
|
-
# @restaurants.create_index([['location', Mongo::
|
627
|
+
# @restaurants.create_index([['location', EM::Mongo::SPHERE2D]])
|
625
628
|
#
|
626
629
|
# # Note that this will work only if 'location' represents x,y coordinates:
|
627
630
|
# {'location': [0, 50]}
|
@@ -629,7 +632,7 @@ module EM::Mongo
|
|
629
632
|
# {'location': {'latitude' => 0, 'longitude' => 50}}
|
630
633
|
#
|
631
634
|
# @example A geospatial index with alternate longitude and latitude:
|
632
|
-
# @restaurants.create_index([['location', Mongo::
|
635
|
+
# @restaurants.create_index([['location', EM::Mongo::SPHERE2D]], :min => 500, :max => 500)
|
633
636
|
#
|
634
637
|
# @return [String] the name of the index created.
|
635
638
|
#
|
@@ -770,11 +773,13 @@ module EM::Mongo
|
|
770
773
|
field_spec[spec.to_s] = 1
|
771
774
|
elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) }
|
772
775
|
spec.each do |f|
|
773
|
-
if [EM::Mongo::ASCENDING, EM::Mongo::DESCENDING,
|
776
|
+
if [EM::Mongo::ASCENDING, EM::Mongo::DESCENDING,
|
777
|
+
EM::Mongo::SPHERE2D, EM::Mongo::FLAT2D, EM::Mongo::GEO2D].include?(f[1])
|
774
778
|
field_spec[f[0].to_s] = f[1]
|
775
779
|
else
|
776
780
|
raise MongoArgumentError, "Invalid index field #{f[1].inspect}; " +
|
777
|
-
"should be one of Mongo::ASCENDING (1), Mongo::DESCENDING (-1)
|
781
|
+
"should be one of EM::Mongo::ASCENDING (1), EM::Mongo::DESCENDING (-1), EM::Mongo::SPHERE2D ('2dsphere')" +
|
782
|
+
" or EM::Mongo::FLAT2D ('2d') (GEO2D is deprecated)"
|
778
783
|
end
|
779
784
|
end
|
780
785
|
else
|
data/lib/em-mongo/connection.rb
CHANGED
data/spec/gem/Gemfile
ADDED
data/spec/gem/bundler.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env bundle exec ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "bundler"
|
5
|
+
Bundler.setup(:default)
|
6
|
+
require "eventmachine"
|
7
|
+
require "em-mongo"
|
8
|
+
|
9
|
+
$return = -1
|
10
|
+
|
11
|
+
EM.run do
|
12
|
+
@conn = EM::Mongo::Connection.new
|
13
|
+
EM.next_tick do
|
14
|
+
id = @conn.db.collection('test').insert({:hello => "world"})
|
15
|
+
@conn.db.collection('test').first(:_id => id) do |document|
|
16
|
+
$return = 0 if document
|
17
|
+
EM.stop
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
exit($return)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "eventmachine"
|
5
|
+
require "em-mongo"
|
6
|
+
|
7
|
+
$return = -1
|
8
|
+
|
9
|
+
EM.run do
|
10
|
+
@conn = EM::Mongo::Connection.new
|
11
|
+
EM.next_tick do
|
12
|
+
id = @conn.db.collection('test').insert({:hello => "world"})
|
13
|
+
@conn.db.collection('test').first(:_id => id) do |document|
|
14
|
+
$return = 0 if document
|
15
|
+
EM.stop
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
exit($return)
|
@@ -642,16 +642,26 @@ describe EMMongo::Collection do
|
|
642
642
|
end
|
643
643
|
end
|
644
644
|
|
645
|
-
it "should create a
|
646
|
-
@conn, @geo = connection_and_collection('
|
645
|
+
it "should create a flat 2d index" do
|
646
|
+
@conn, @geo = connection_and_collection('2d')
|
647
647
|
@geo.save({'loc' => [-100, 100]})
|
648
|
-
@geo.create_index([['loc', EM::Mongo::
|
648
|
+
@geo.create_index([['loc', EM::Mongo::FLAT2D]])
|
649
649
|
@geo.index_information.callback do |info|
|
650
650
|
info['loc_2d'].should_not be_nil
|
651
651
|
done
|
652
652
|
end
|
653
653
|
end
|
654
654
|
|
655
|
+
it "should create a sphere 2d index" do
|
656
|
+
@conn, @geo = connection_and_collection('2dsphere')
|
657
|
+
@geo.save({'loc' => [-100, 100]})
|
658
|
+
@geo.create_index([['loc', EM::Mongo::SPHERE2D]])
|
659
|
+
@geo.index_information.callback do |info|
|
660
|
+
info['loc_2dsphere'].should_not be_nil
|
661
|
+
done
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
655
665
|
it "should create a unique index" do
|
656
666
|
@conn, @collection = connection_and_collection('test-collection')
|
657
667
|
@collection.create_index([['a', EM::Mongo::ASCENDING]], :unique => true)
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
require "eventmachine"
|
5
|
+
begin
|
6
|
+
require "bson_ext"
|
7
|
+
rescue LoadError
|
8
|
+
require "bson"
|
9
|
+
end
|
10
|
+
|
11
|
+
require File.expand_path('../lib/em-mongo', File.dirname(__FILE__))
|
12
|
+
|
13
|
+
require "em-spec/rspec"
|
14
|
+
|
15
|
+
def connection_and_collection(collection_name=EM::Mongo::DEFAULT_NS)
|
16
|
+
conn = EMMongo::Connection.new
|
17
|
+
return conn, collection(conn, collection_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def collection(conn, name)
|
21
|
+
conn.db.collection(name).remove
|
22
|
+
conn.db.collection(name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def number_hash
|
26
|
+
@numbers = {
|
27
|
+
1 => 'one',
|
28
|
+
2 => 'two',
|
29
|
+
3 => 'three',
|
30
|
+
4 => 'four',
|
31
|
+
5 => 'five',
|
32
|
+
6 => 'six',
|
33
|
+
7 => 'seven',
|
34
|
+
8 => 'eight',
|
35
|
+
9 => 'nine'
|
36
|
+
}
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path('spec_helper', File.dirname(__FILE__) + '/../')
|
2
|
+
|
3
|
+
# This is to prove how BSON works so we can code around it where appropriate
|
4
|
+
# BSON documents and Ruby Hashes are not the same thing afterall.
|
5
|
+
#
|
6
|
+
# http://www.mongodb.org/display/DOCS/BSON
|
7
|
+
|
8
|
+
describe BSON do
|
9
|
+
|
10
|
+
it 'should do what it does' do
|
11
|
+
doc = {:_id => 12345, :foo => 'notbar', "foo" => "bar", :hello => :world }
|
12
|
+
doc = BSON::BSON_CODER.deserialize(BSON::BSON_CODER.serialize(doc, false, true).to_s)
|
13
|
+
# 1. An ID passed as Symbol is really a String
|
14
|
+
doc['_id'].should == 12345
|
15
|
+
# 2. More to the point, all keys are Strings.
|
16
|
+
doc['hello'].should == :world
|
17
|
+
# 3. The last String/Symbol wins
|
18
|
+
doc['foo'].should == 'bar'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
MC40LjM=
|
4
|
+
version: 0.5.0
|
6
5
|
prerelease:
|
7
6
|
platform: ruby
|
8
7
|
authors:
|
@@ -49,9 +48,19 @@ description: EventMachine driver for MongoDB.
|
|
49
48
|
email: brenden.grace@gmail.com
|
50
49
|
executables: []
|
51
50
|
extensions: []
|
52
|
-
extra_rdoc_files:
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.rdoc
|
53
53
|
files:
|
54
|
+
- .gitignore
|
55
|
+
- CHANGELOG
|
56
|
+
- Gemfile
|
57
|
+
- README.rdoc
|
58
|
+
- Rakefile
|
54
59
|
- VERSION
|
60
|
+
- em-mongo.gemspec
|
61
|
+
- examples/legacy.rb
|
62
|
+
- examples/readme.rb
|
63
|
+
- lib/em-mongo.rb
|
55
64
|
- lib/em-mongo/collection.rb
|
56
65
|
- lib/em-mongo/connection.rb
|
57
66
|
- lib/em-mongo/conversions.rb
|
@@ -63,13 +72,17 @@ files:
|
|
63
72
|
- lib/em-mongo/request_response.rb
|
64
73
|
- lib/em-mongo/server_response.rb
|
65
74
|
- lib/em-mongo/support.rb
|
66
|
-
-
|
75
|
+
- spec/gem/Gemfile
|
76
|
+
- spec/gem/bundler.rb
|
77
|
+
- spec/gem/rubygems.rb
|
67
78
|
- spec/integration/collection_spec.rb
|
68
79
|
- spec/integration/connection_spec.rb
|
69
80
|
- spec/integration/cursor_spec.rb
|
70
81
|
- spec/integration/database_spec.rb
|
71
82
|
- spec/integration/request_response_spec.rb
|
72
|
-
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
- spec/unit/bson_spec.rb
|
85
|
+
homepage: https://github.com/bcg/em-mongo
|
73
86
|
licenses: []
|
74
87
|
post_install_message:
|
75
88
|
rdoc_options:
|
@@ -94,9 +107,4 @@ rubygems_version: 1.8.23
|
|
94
107
|
signing_key:
|
95
108
|
specification_version: 3
|
96
109
|
summary: An EventMachine driver for MongoDB.
|
97
|
-
test_files:
|
98
|
-
- spec/integration/collection_spec.rb
|
99
|
-
- spec/integration/connection_spec.rb
|
100
|
-
- spec/integration/cursor_spec.rb
|
101
|
-
- spec/integration/database_spec.rb
|
102
|
-
- spec/integration/request_response_spec.rb
|
110
|
+
test_files: []
|