moped 0.0.0.beta → 1.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of moped might be problematic. Click here for more details.
- data/MIT_LICENSE +19 -0
- data/README.md +323 -0
- data/lib/moped.rb +19 -0
- data/lib/moped/bson.rb +25 -0
- data/lib/moped/bson/binary.rb +68 -0
- data/lib/moped/bson/code.rb +61 -0
- data/lib/moped/bson/document.rb +16 -0
- data/lib/moped/bson/extensions.rb +81 -0
- data/lib/moped/bson/extensions/array.rb +44 -0
- data/lib/moped/bson/extensions/boolean.rb +14 -0
- data/lib/moped/bson/extensions/false_class.rb +15 -0
- data/lib/moped/bson/extensions/float.rb +23 -0
- data/lib/moped/bson/extensions/hash.rb +49 -0
- data/lib/moped/bson/extensions/integer.rb +37 -0
- data/lib/moped/bson/extensions/nil_class.rb +20 -0
- data/lib/moped/bson/extensions/regexp.rb +40 -0
- data/lib/moped/bson/extensions/string.rb +35 -0
- data/lib/moped/bson/extensions/symbol.rb +25 -0
- data/lib/moped/bson/extensions/time.rb +21 -0
- data/lib/moped/bson/extensions/true_class.rb +15 -0
- data/lib/moped/bson/max_key.rb +21 -0
- data/lib/moped/bson/min_key.rb +21 -0
- data/lib/moped/bson/object_id.rb +123 -0
- data/lib/moped/bson/timestamp.rb +15 -0
- data/lib/moped/bson/types.rb +67 -0
- data/lib/moped/cluster.rb +193 -0
- data/lib/moped/collection.rb +67 -0
- data/lib/moped/cursor.rb +60 -0
- data/lib/moped/database.rb +76 -0
- data/lib/moped/errors.rb +61 -0
- data/lib/moped/indexes.rb +93 -0
- data/lib/moped/logging.rb +25 -0
- data/lib/moped/protocol.rb +20 -0
- data/lib/moped/protocol/command.rb +27 -0
- data/lib/moped/protocol/commands.rb +11 -0
- data/lib/moped/protocol/commands/authenticate.rb +54 -0
- data/lib/moped/protocol/delete.rb +92 -0
- data/lib/moped/protocol/get_more.rb +79 -0
- data/lib/moped/protocol/insert.rb +92 -0
- data/lib/moped/protocol/kill_cursors.rb +61 -0
- data/lib/moped/protocol/message.rb +320 -0
- data/lib/moped/protocol/query.rb +131 -0
- data/lib/moped/protocol/reply.rb +90 -0
- data/lib/moped/protocol/update.rb +107 -0
- data/lib/moped/query.rb +230 -0
- data/lib/moped/server.rb +73 -0
- data/lib/moped/session.rb +253 -0
- data/lib/moped/socket.rb +201 -0
- data/lib/moped/version.rb +4 -0
- metadata +108 -46
data/MIT_LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2011 Bernerd Schaefer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -0,0 +1,323 @@
|
|
1
|
+
Moped is a MongoDB driver for Ruby, which exposes a simple, elegant, and fast
|
2
|
+
API.
|
3
|
+
|
4
|
+
```ruby
|
5
|
+
session = Moped::Session.new %w[127.0.0.1:27017]
|
6
|
+
session.use "echo_test"
|
7
|
+
|
8
|
+
session.with(safe: true) do |safe|
|
9
|
+
safe[:artists].insert(name: "Syd Vicious"
|
10
|
+
end
|
11
|
+
|
12
|
+
session[:artists].find(name: "Syd Vicious").
|
13
|
+
update(
|
14
|
+
:$push => { instruments: { name: "Bass" } }
|
15
|
+
)
|
16
|
+
```
|
17
|
+
|
18
|
+
# Project Breakdown
|
19
|
+
|
20
|
+
Moped is composed of three parts: an implementation of the [BSON
|
21
|
+
specification](http://bsonspec.org/), an implementation of the [Mongo Wire
|
22
|
+
Protocol](http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol), and the
|
23
|
+
driver itself. An overview of the first two follows now, and after that more
|
24
|
+
information about the driver.
|
25
|
+
|
26
|
+
## Moped::BSON
|
27
|
+
|
28
|
+
`Moped::BSON` is the namespace for Moped's BSON implementation. It's
|
29
|
+
implemented in pure (but fast) ruby. The public entry point into the BSON
|
30
|
+
module is `BSON::Document`, which is just subclass of `Hash`, but exposes two
|
31
|
+
class methods: `serialize` and `deserialize`. `serialize` accepts a
|
32
|
+
BSON::Document (or Hash) and returns the serialized BSON representation.
|
33
|
+
`deserialize` does the opposite: it reads data from an IO-like input and
|
34
|
+
returns a deserialized BSON::Document.
|
35
|
+
|
36
|
+
### Moped::BSON::ObjectId
|
37
|
+
|
38
|
+
The `ObjectId` class is used for generating and interacting with Mongo's ids.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
id = Moped::BSON::ObjectId.new # => 4f8583b5e5a4e46a64000002
|
42
|
+
id.generation_time # => 2012-04-11 13:14:29 UTC
|
43
|
+
id == Moped::BSON::ObjectId.from_string(id.to_s) # => true
|
44
|
+
```
|
45
|
+
|
46
|
+
### Moped::BSON::Code
|
47
|
+
|
48
|
+
The `Code` class is used for working with javascript on the server.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Moped::BSON::Code.new("function () { return this.name }")
|
52
|
+
Moped::BSON::Code.new("function (s) { return s.prefix + this.name }",
|
53
|
+
prefix: "_"
|
54
|
+
)
|
55
|
+
```
|
56
|
+
|
57
|
+
### Moped::BSON::Binary
|
58
|
+
|
59
|
+
The `Binary` class allows you to persist binary data to the server, and
|
60
|
+
supports the following types: `:generic`, `:function`, `:old`, `:uuid`, `:md5`,
|
61
|
+
and `:user`. Note that `:old` is deprecated, but still present to support
|
62
|
+
legacy data.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
Moped::BSON::Binary.new(:md5, Digest::MD5.digest(__FILE__))
|
66
|
+
```
|
67
|
+
|
68
|
+
## Moped::Protocol
|
69
|
+
|
70
|
+
`Moped::Protocol` is the namespace for Moped's implementation of the Mongo Wire
|
71
|
+
Protocol. Its public API consists of classes representing each type of message
|
72
|
+
in the protocol: `Delete`, `GetMore`, `Insert`, `KillCursors`, `Query`,
|
73
|
+
`Reply`, `Update`, and a convenience class `Command`.
|
74
|
+
|
75
|
+
You should never have to worry about protocol objects, but more details can be
|
76
|
+
found in the API documentation if you're interested.
|
77
|
+
|
78
|
+
# Driver API
|
79
|
+
|
80
|
+
This is the core, public API for Moped. It lives almost entirely in four classes:
|
81
|
+
|
82
|
+
* `Session`: the root object for all interactions with mongo (c.f., `db` in the
|
83
|
+
mongo shell).
|
84
|
+
* `Collection`: for working with collections in the context of a session
|
85
|
+
* `Indexes`: for manipulating and inspecting a collection's indexes
|
86
|
+
* `Query`: for querying, as well as modifying existing data.
|
87
|
+
|
88
|
+
What follows is a "whirlwind" overview of the Moped driver API. For details on
|
89
|
+
additional options, and more examples, use the [generated API
|
90
|
+
docs](http://rubydoc.info/github/mongoid/moped/master/frames).
|
91
|
+
|
92
|
+
## Session
|
93
|
+
|
94
|
+
### Example
|
95
|
+
```ruby
|
96
|
+
session = Moped::Session.new %w[127.0.0.1:27017 127.0.0.1:27018 127.0.0.1:27019]
|
97
|
+
session.use :moped_test
|
98
|
+
session.command ping: 1 # => {"ok"=>1.0}
|
99
|
+
|
100
|
+
session.with(safe: { w: 2, wtimeout: 5 }) do |safe_session|
|
101
|
+
safe_session[:users].find.remove_all
|
102
|
+
end
|
103
|
+
|
104
|
+
session.with(database: "important_db", consistency: :strong) do |session|
|
105
|
+
session[:users].find.one
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
### API
|
110
|
+
<table><tbody>
|
111
|
+
|
112
|
+
<tr><th>use</th>
|
113
|
+
<td>Set the current database<br>
|
114
|
+
<code>session.use :my_app_test</code></td></tr>
|
115
|
+
|
116
|
+
<tr><th>with</th>
|
117
|
+
<td>Return or yield a copy of session with different options.<br>
|
118
|
+
<code>session.with(safe: true) { |s| ... }</code><br>
|
119
|
+
<code>session.with(database: "admin").command(...)</code></td></tr>
|
120
|
+
|
121
|
+
<tr><th>[]</th>
|
122
|
+
<td>Choose a collection in the current database.<br>
|
123
|
+
<code>session[:people]</code></td></tr>
|
124
|
+
|
125
|
+
<tr><th>drop</th>
|
126
|
+
<td>Drop the current database<br>
|
127
|
+
<code>session.drop</code></td></tr>
|
128
|
+
|
129
|
+
<tr><th>command</th>
|
130
|
+
<td>Run a command on the current database.<br>
|
131
|
+
<code>session.command(ping: 1)</code></td></tr>
|
132
|
+
|
133
|
+
<tr><th>login</th>
|
134
|
+
<td>Log in to the current database.<br>
|
135
|
+
<code>session.login(username, password)</code></td></tr>
|
136
|
+
|
137
|
+
<tr><th>logout</th>
|
138
|
+
<td>Log out from the current database.<br>
|
139
|
+
<code>session.logout</code></td></tr>
|
140
|
+
|
141
|
+
</tbody></table>
|
142
|
+
|
143
|
+
## Collection
|
144
|
+
|
145
|
+
### Example
|
146
|
+
```ruby
|
147
|
+
users = session[:users]
|
148
|
+
users.drop
|
149
|
+
users.find.count # => 0.0
|
150
|
+
|
151
|
+
users.indexes.create({name: 1}, {unique: true})
|
152
|
+
|
153
|
+
users.insert(name: "John")
|
154
|
+
users.find.count # => 1.0
|
155
|
+
|
156
|
+
users.insert(name: "John")
|
157
|
+
users.find.count # => 1.0
|
158
|
+
|
159
|
+
session.with(safe: true) do |session|
|
160
|
+
session[:users].insert(name: "John")
|
161
|
+
end # raises Moped::Errors::OperationFailure
|
162
|
+
```
|
163
|
+
|
164
|
+
### API
|
165
|
+
<table><tbody>
|
166
|
+
|
167
|
+
<tr><th>drop</th>
|
168
|
+
<td>Drop the collection<br>
|
169
|
+
<code>users.drop</code></td></tr>
|
170
|
+
|
171
|
+
<tr><th>indexes</th>
|
172
|
+
<td>Access information about this collection's indexes<br>
|
173
|
+
<code>users.indexes</code></td></tr>
|
174
|
+
|
175
|
+
<tr><th>find</th>
|
176
|
+
<td>Build a query on the collection<br>
|
177
|
+
<code>users.find(name: "John")</code></td></tr>
|
178
|
+
|
179
|
+
<tr><th>insert</th>
|
180
|
+
<td>Insert one or multiple documents.<br>
|
181
|
+
<code>users.insert(name: "John")</code><br>
|
182
|
+
<code>users.insert([{name: "John"}, {name: "Mary"}])</code></td></tr>
|
183
|
+
|
184
|
+
</tbody></table>
|
185
|
+
|
186
|
+
## Index
|
187
|
+
|
188
|
+
### Example
|
189
|
+
```ruby
|
190
|
+
session[:users].indexes.create(name: 1)
|
191
|
+
session[:users].indexes.create(
|
192
|
+
{ name: 1, location: "2d" },
|
193
|
+
{ unique: true }
|
194
|
+
)
|
195
|
+
session[:users].indexes[name: 1]
|
196
|
+
# => {"v"=>1, "key"=>{"name"=>1}, "ns"=>"moped_test.users", "name"=>"name_1" }
|
197
|
+
|
198
|
+
session[:users].indexes.drop(name: 1)
|
199
|
+
session[:users].indexes[name: 1] # => nil
|
200
|
+
```
|
201
|
+
|
202
|
+
### API
|
203
|
+
<table><tbody>
|
204
|
+
|
205
|
+
<tr><th>[]</th>
|
206
|
+
<td>Get an index by its spec.<br>
|
207
|
+
<code>indexes[id: 1]</code></td></tr>
|
208
|
+
|
209
|
+
<tr><th>create</th>
|
210
|
+
<td>Create an index<br>
|
211
|
+
<code>indexes.create({name: 1}, {unique: true})</code></td></tr>
|
212
|
+
|
213
|
+
<tr><th>drop</th>
|
214
|
+
<td>Drop one or all indexes<br>
|
215
|
+
<code>indexes.drop</code><br>
|
216
|
+
<code>indexes.drop(name: 1)</code></td></tr>
|
217
|
+
|
218
|
+
<tr><th>each</th>
|
219
|
+
<td>Yield each index<br>
|
220
|
+
<code>indexes.each { |idx| }</code></td></tr>
|
221
|
+
|
222
|
+
</tbody></table>
|
223
|
+
|
224
|
+
## Query
|
225
|
+
|
226
|
+
### Example
|
227
|
+
```ruby
|
228
|
+
users = session[:users]
|
229
|
+
|
230
|
+
users.insert(name: "John")
|
231
|
+
users.find.count # => 1
|
232
|
+
|
233
|
+
users.find(name: "Mary").upsert(name: "Mary")
|
234
|
+
users.find.count # => 2
|
235
|
+
|
236
|
+
users.find.skip(1).limit(1).sort(name: -1).one
|
237
|
+
# => {"_id" => <...>, "name" => "John" }
|
238
|
+
|
239
|
+
scope = users.find(name: "Mary").select(_id: 0, name: 1)
|
240
|
+
scope.one # => {"name" => "Mary" }
|
241
|
+
scope.remove
|
242
|
+
scope.one # nil
|
243
|
+
```
|
244
|
+
|
245
|
+
### API
|
246
|
+
<table><tbody>
|
247
|
+
|
248
|
+
<tr><th>limit</th>
|
249
|
+
<td>Set the limit for this query.<br>
|
250
|
+
<code>query.limit(5)</code></td></tr>
|
251
|
+
|
252
|
+
<tr><th>skip</th>
|
253
|
+
<td>Set the offset for this query.<br>
|
254
|
+
<code>query.skip(5)</code></td></tr>
|
255
|
+
|
256
|
+
<tr><th>sort</th>
|
257
|
+
<td>Sort the results of the query<br>
|
258
|
+
<code>query.sort(name: -1)</code></td></tr>
|
259
|
+
|
260
|
+
<tr><th>distinct</th>
|
261
|
+
<td>Get the distinct values for a field.<br>
|
262
|
+
<code>query.distinct(:name)</code></td></tr>
|
263
|
+
|
264
|
+
<tr><th>select</th>
|
265
|
+
<td>Select a set of fields to return.<br>
|
266
|
+
<code>query.select(_id: 0, name: 1)</code></td></tr>
|
267
|
+
|
268
|
+
<tr><th>one/first</th>
|
269
|
+
<td>Return the first result from the query.<br>
|
270
|
+
<code>query.one</code></td></tr>
|
271
|
+
|
272
|
+
<tr><th>each</th>
|
273
|
+
<td>Iterate through the results of the query.<br>
|
274
|
+
<code>query.each { |doc| }</code></td></tr>
|
275
|
+
|
276
|
+
<tr><th>count</th>
|
277
|
+
<td>Return the number of documents matching the query.<br>
|
278
|
+
<code>query.count</code></td></tr>
|
279
|
+
|
280
|
+
<tr><th>update</th>
|
281
|
+
<td>Update the first document matching the query's selector.<br>
|
282
|
+
<code>query.update(name: "John")</code></td></tr>
|
283
|
+
|
284
|
+
<tr><th>update_all</th>
|
285
|
+
<td>Update all documents matching the query's selector.<br>
|
286
|
+
<code>query.update_all(name: "John")</code></td></tr>
|
287
|
+
|
288
|
+
<tr><th>upsert</th>
|
289
|
+
<td>Create or update a document using query's selector.<br>
|
290
|
+
<code>query.upsert(name: "John")</code></td></tr>
|
291
|
+
|
292
|
+
<tr><th>remove</th>
|
293
|
+
<td>Remove a single document matching the query's selector.<br>
|
294
|
+
<code>query.remove</code></td></tr>
|
295
|
+
|
296
|
+
<tr><th>remove_all</th>
|
297
|
+
<td>Remove all documents matching the query's selector.<br>
|
298
|
+
<code>query.remove_all</code></td></tr>
|
299
|
+
|
300
|
+
</tbody></table>
|
301
|
+
|
302
|
+
# Thread-Safety
|
303
|
+
|
304
|
+
Moped is thread-safe -- depending on your definition of thread-safe. For Moped,
|
305
|
+
it means that there's no shared, global state between multiple sessions. What
|
306
|
+
it doesn't mean is that a single `Session` instance can be interacted with
|
307
|
+
across threads.
|
308
|
+
|
309
|
+
Why not? Because threading is hard. Well, it's more than that -- though the
|
310
|
+
public API for Moped is quite simple, MongoDB requires a good deal of
|
311
|
+
complexity out of the internal API, specifically around replica sets and
|
312
|
+
failover. We've decided that, for now, it's not worth making the replica set
|
313
|
+
code thread-safe.
|
314
|
+
|
315
|
+
**TL;DR**: use one `Moped::Session` instance per thread.
|
316
|
+
|
317
|
+
# Compatibility
|
318
|
+
|
319
|
+
Moped is tested against MRI 1.9.2, 1.9.3, 2.0.0, and JRuby (1.9).
|
320
|
+
|
321
|
+
<img src="https://secure.travis-ci.org/mongoid/moped.png?branch=master&.png"/>
|
322
|
+
|
323
|
+
[Build History](http://travis-ci.org/mongoid/moped)
|
data/lib/moped.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "stringio"
|
3
|
+
require "monitor"
|
4
|
+
require "forwardable"
|
5
|
+
|
6
|
+
require "moped/bson"
|
7
|
+
require "moped/cluster"
|
8
|
+
require "moped/collection"
|
9
|
+
require "moped/cursor"
|
10
|
+
require "moped/database"
|
11
|
+
require "moped/errors"
|
12
|
+
require "moped/indexes"
|
13
|
+
require "moped/logging"
|
14
|
+
require "moped/protocol"
|
15
|
+
require "moped/query"
|
16
|
+
require "moped/server"
|
17
|
+
require "moped/session"
|
18
|
+
require "moped/socket"
|
19
|
+
require "moped/version"
|
data/lib/moped/bson.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "moped/bson/extensions"
|
2
|
+
|
3
|
+
require "moped/bson/binary"
|
4
|
+
require "moped/bson/code"
|
5
|
+
require "moped/bson/object_id"
|
6
|
+
require "moped/bson/max_key"
|
7
|
+
require "moped/bson/min_key"
|
8
|
+
require "moped/bson/timestamp"
|
9
|
+
|
10
|
+
require "moped/bson/document"
|
11
|
+
require "moped/bson/types"
|
12
|
+
|
13
|
+
module Moped
|
14
|
+
|
15
|
+
# The module for Moped's BSON implementation.
|
16
|
+
module BSON
|
17
|
+
EOD = NULL_BYTE = "\u0000".freeze
|
18
|
+
|
19
|
+
INT32_PACK = 'l'.freeze
|
20
|
+
INT64_PACK = 'q'.freeze
|
21
|
+
FLOAT_PACK = 'E'.freeze
|
22
|
+
|
23
|
+
START_LENGTH = [0].pack(INT32_PACK).freeze
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Moped
|
2
|
+
module BSON
|
3
|
+
class Binary
|
4
|
+
|
5
|
+
SUBTYPE_MAP = {
|
6
|
+
generic: "\x00",
|
7
|
+
function: "\x01",
|
8
|
+
old: "\x02",
|
9
|
+
uuid: "\x03",
|
10
|
+
md5: "\x05",
|
11
|
+
user: "\x80"
|
12
|
+
}
|
13
|
+
|
14
|
+
attr_reader :data, :type
|
15
|
+
|
16
|
+
def initialize(type, data)
|
17
|
+
@type = type
|
18
|
+
@data = data
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def __bson_load__(io)
|
23
|
+
length, = io.read(4).unpack(INT32_PACK)
|
24
|
+
type = SUBTYPE_MAP.invert[io.read(1)]
|
25
|
+
|
26
|
+
if type == :old
|
27
|
+
length -= 4
|
28
|
+
io.read(4)
|
29
|
+
end
|
30
|
+
|
31
|
+
data = io.read length
|
32
|
+
new(type, data)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other)
|
37
|
+
BSON::Binary === other && data == other.data && type == other.type
|
38
|
+
end
|
39
|
+
alias eql? ==
|
40
|
+
|
41
|
+
def hash
|
42
|
+
[data, type].hash
|
43
|
+
end
|
44
|
+
|
45
|
+
def __bson_dump__(io, key)
|
46
|
+
io << Types::BINARY
|
47
|
+
io << key
|
48
|
+
io << NULL_BYTE
|
49
|
+
|
50
|
+
if type == :old
|
51
|
+
io << [data.length + 4].pack(INT32_PACK)
|
52
|
+
io << SUBTYPE_MAP[type]
|
53
|
+
io << [data.length].pack(INT32_PACK)
|
54
|
+
io << data
|
55
|
+
else
|
56
|
+
io << [data.length].pack(INT32_PACK)
|
57
|
+
io << SUBTYPE_MAP[type]
|
58
|
+
io << data
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def inspect
|
63
|
+
"#<#{self.class.name} type=#{type.inspect} length=#{data.length}>"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|