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.

Files changed (50) hide show
  1. data/MIT_LICENSE +19 -0
  2. data/README.md +323 -0
  3. data/lib/moped.rb +19 -0
  4. data/lib/moped/bson.rb +25 -0
  5. data/lib/moped/bson/binary.rb +68 -0
  6. data/lib/moped/bson/code.rb +61 -0
  7. data/lib/moped/bson/document.rb +16 -0
  8. data/lib/moped/bson/extensions.rb +81 -0
  9. data/lib/moped/bson/extensions/array.rb +44 -0
  10. data/lib/moped/bson/extensions/boolean.rb +14 -0
  11. data/lib/moped/bson/extensions/false_class.rb +15 -0
  12. data/lib/moped/bson/extensions/float.rb +23 -0
  13. data/lib/moped/bson/extensions/hash.rb +49 -0
  14. data/lib/moped/bson/extensions/integer.rb +37 -0
  15. data/lib/moped/bson/extensions/nil_class.rb +20 -0
  16. data/lib/moped/bson/extensions/regexp.rb +40 -0
  17. data/lib/moped/bson/extensions/string.rb +35 -0
  18. data/lib/moped/bson/extensions/symbol.rb +25 -0
  19. data/lib/moped/bson/extensions/time.rb +21 -0
  20. data/lib/moped/bson/extensions/true_class.rb +15 -0
  21. data/lib/moped/bson/max_key.rb +21 -0
  22. data/lib/moped/bson/min_key.rb +21 -0
  23. data/lib/moped/bson/object_id.rb +123 -0
  24. data/lib/moped/bson/timestamp.rb +15 -0
  25. data/lib/moped/bson/types.rb +67 -0
  26. data/lib/moped/cluster.rb +193 -0
  27. data/lib/moped/collection.rb +67 -0
  28. data/lib/moped/cursor.rb +60 -0
  29. data/lib/moped/database.rb +76 -0
  30. data/lib/moped/errors.rb +61 -0
  31. data/lib/moped/indexes.rb +93 -0
  32. data/lib/moped/logging.rb +25 -0
  33. data/lib/moped/protocol.rb +20 -0
  34. data/lib/moped/protocol/command.rb +27 -0
  35. data/lib/moped/protocol/commands.rb +11 -0
  36. data/lib/moped/protocol/commands/authenticate.rb +54 -0
  37. data/lib/moped/protocol/delete.rb +92 -0
  38. data/lib/moped/protocol/get_more.rb +79 -0
  39. data/lib/moped/protocol/insert.rb +92 -0
  40. data/lib/moped/protocol/kill_cursors.rb +61 -0
  41. data/lib/moped/protocol/message.rb +320 -0
  42. data/lib/moped/protocol/query.rb +131 -0
  43. data/lib/moped/protocol/reply.rb +90 -0
  44. data/lib/moped/protocol/update.rb +107 -0
  45. data/lib/moped/query.rb +230 -0
  46. data/lib/moped/server.rb +73 -0
  47. data/lib/moped/session.rb +253 -0
  48. data/lib/moped/socket.rb +201 -0
  49. data/lib/moped/version.rb +4 -0
  50. 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