moped 1.0.0.rc → 1.0.0

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 (45) hide show
  1. data/CHANGELOG.md +11 -0
  2. data/README.md +32 -467
  3. data/lib/moped.rb +0 -1
  4. data/lib/moped/bson.rb +3 -0
  5. data/lib/moped/bson/binary.rb +4 -4
  6. data/lib/moped/bson/code.rb +12 -10
  7. data/lib/moped/bson/extensions.rb +64 -54
  8. data/lib/moped/bson/extensions/array.rb +9 -6
  9. data/lib/moped/bson/extensions/boolean.rb +1 -1
  10. data/lib/moped/bson/extensions/false_class.rb +5 -2
  11. data/lib/moped/bson/extensions/float.rb +1 -2
  12. data/lib/moped/bson/extensions/hash.rb +4 -5
  13. data/lib/moped/bson/extensions/integer.rb +2 -4
  14. data/lib/moped/bson/extensions/nil_class.rb +1 -2
  15. data/lib/moped/bson/extensions/object.rb +13 -0
  16. data/lib/moped/bson/extensions/regexp.rb +5 -6
  17. data/lib/moped/bson/extensions/string.rb +24 -13
  18. data/lib/moped/bson/extensions/symbol.rb +12 -14
  19. data/lib/moped/bson/extensions/time.rb +4 -4
  20. data/lib/moped/bson/extensions/true_class.rb +5 -2
  21. data/lib/moped/bson/max_key.rb +1 -2
  22. data/lib/moped/bson/min_key.rb +1 -2
  23. data/lib/moped/bson/object_id.rb +44 -4
  24. data/lib/moped/bson/types.rb +1 -1
  25. data/lib/moped/cluster.rb +13 -5
  26. data/lib/moped/collection.rb +5 -1
  27. data/lib/moped/connection.rb +4 -4
  28. data/lib/moped/database.rb +58 -29
  29. data/lib/moped/logging.rb +3 -3
  30. data/lib/moped/node.rb +35 -6
  31. data/lib/moped/protocol/command.rb +1 -4
  32. data/lib/moped/protocol/delete.rb +2 -0
  33. data/lib/moped/protocol/get_more.rb +16 -1
  34. data/lib/moped/protocol/insert.rb +2 -0
  35. data/lib/moped/protocol/kill_cursors.rb +2 -0
  36. data/lib/moped/protocol/message.rb +31 -12
  37. data/lib/moped/protocol/query.rb +15 -3
  38. data/lib/moped/protocol/reply.rb +6 -4
  39. data/lib/moped/protocol/update.rb +2 -0
  40. data/lib/moped/query.rb +60 -5
  41. data/lib/moped/session.rb +53 -17
  42. data/lib/moped/session/context.rb +17 -7
  43. data/lib/moped/threaded.rb +2 -1
  44. data/lib/moped/version.rb +1 -1
  45. metadata +11 -6
@@ -13,16 +13,13 @@ module Moped
13
13
  # @param [Hash] command the command to run
14
14
  # @param [Hash] additional query options
15
15
  def initialize(database, command, options = {})
16
- super database, :$cmd, command, options.merge(limit: -1)
16
+ super database, '$cmd', command, options.merge(limit: -1)
17
17
  end
18
18
 
19
19
  def log_inspect
20
20
  type = "COMMAND"
21
-
22
21
  "%-12s database=%s command=%s" % [type, database, selector.inspect]
23
22
  end
24
-
25
23
  end
26
-
27
24
  end
28
25
  end
@@ -45,6 +45,8 @@ module Moped
45
45
  # @return [Hash] the query to use when deleting documents
46
46
  document :selector
47
47
 
48
+ finalize
49
+
48
50
  # @return [String, Symbol] the database to delete from
49
51
  attr_reader :database
50
52
 
@@ -43,6 +43,8 @@ module Moped
43
43
  # @return [Number] the id of the cursor to get more documents from
44
44
  int64 :cursor_id
45
45
 
46
+ finalize
47
+
46
48
  undef op_code
47
49
  # @return [Number] OP_GETMORE operation code (2005)
48
50
  def op_code
@@ -72,9 +74,22 @@ module Moped
72
74
 
73
75
  def log_inspect
74
76
  type = "GET_MORE"
75
-
76
77
  "%-12s database=%s collection=%s limit=%s cursor_id=%s" % [type, database, collection, limit, cursor_id]
77
78
  end
79
+
80
+ # Receive replies to the message.
81
+ #
82
+ # @example Receive replies.
83
+ # message.receive_replies(connection)
84
+ #
85
+ # @param [ Connection ] connection The connection.
86
+ #
87
+ # @return [ Protocol::Reply ] The reply.
88
+ #
89
+ # @since 1.0.0
90
+ def receive_replies(connection)
91
+ connection.read
92
+ end
78
93
  end
79
94
  end
80
95
  end
@@ -46,6 +46,8 @@ module Moped
46
46
  # @return [Array<Hash>] the documents to insert
47
47
  document :documents, type: :array
48
48
 
49
+ finalize
50
+
49
51
  undef op_code
50
52
  # @return [Number] OP_INSERT operation code (2002)
51
53
  def op_code
@@ -35,6 +35,8 @@ module Moped
35
35
  # @return [Array] the cursor ids to kill
36
36
  int64 :cursor_ids, type: :array
37
37
 
38
+ finalize
39
+
38
40
  undef op_code
39
41
  # @return [Number] OP_KILL_CURSORS operation code (2007)
40
42
  def op_code
@@ -271,6 +271,23 @@ module Moped
271
271
  fields << name
272
272
  end
273
273
 
274
+ # Declares the message class as complete, and defines its serialization
275
+ # method from the declared fields.
276
+ def finalize
277
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
278
+ def serialize(buffer = "")
279
+ start = buffer.bytesize
280
+
281
+ #{fields.map { |f| "serialize_#{f}(buffer)" }.join("\n")}
282
+
283
+ self.length = buffer.bytesize - start
284
+ buffer[start, 4] = serialize_length ""
285
+ buffer
286
+ end
287
+ alias to_s serialize
288
+ EOS
289
+ end
290
+
274
291
  private
275
292
 
276
293
  # This ensures that subclasses of the primary wire message classes have
@@ -283,25 +300,27 @@ module Moped
283
300
 
284
301
  end
285
302
 
303
+ # Default implementation for a message is to do nothing when receiving
304
+ # replies.
305
+ #
306
+ # @example Receive replies.
307
+ # message.receive_replies(connection)
308
+ #
309
+ # @param [ Connection ] connection The connection.
310
+ #
311
+ # @since 1.0.0
312
+ #
313
+ # @return [ nil ] nil.
314
+ def receive_replies(connection); end
315
+
286
316
  # Serializes the message and all of its fields to a new buffer or to the
287
317
  # provided buffer.
288
318
  #
289
319
  # @param [String] buffer a buffer to serialize to
290
320
  # @return [String] the result of serliazing this message
291
321
  def serialize(buffer = "")
292
- buffer.tap do
293
- start = buffer.length
294
-
295
- self.class.fields.each do |field|
296
- __send__ :"serialize_#{field}", buffer
297
- end
298
-
299
- self.length = buffer.length - start
300
-
301
- buffer[start, 4] = serialize_length("")
302
- end
322
+ raise NotImplementedError, "This method is generated after calling #finalize on a message class"
303
323
  end
304
-
305
324
  alias to_s serialize
306
325
 
307
326
  # @return [String] the nicely formatted version of the message
@@ -64,6 +64,8 @@ module Moped
64
64
  # @return [Hash, nil] the fields to include in the reply
65
65
  document :fields, :optional => true
66
66
 
67
+ finalize
68
+
67
69
  undef op_code
68
70
  # @return [Number] OP_QUERY operation code (2004)
69
71
  def op_code
@@ -111,7 +113,6 @@ module Moped
111
113
 
112
114
  def log_inspect
113
115
  type = "QUERY"
114
-
115
116
  fields = []
116
117
  fields << ["%-12s", type]
117
118
  fields << ["database=%s", database]
@@ -121,12 +122,23 @@ module Moped
121
122
  fields << ["limit=%s", limit.inspect]
122
123
  fields << ["skip=%s", skip.inspect]
123
124
  fields << ["fields=%s", self.fields.inspect]
124
-
125
125
  f, v = fields.transpose
126
-
127
126
  f.join(" ") % v
128
127
  end
129
128
 
129
+ # Receive replies to the message.
130
+ #
131
+ # @example Receive replies.
132
+ # message.receive_replies(connection)
133
+ #
134
+ # @param [ Connection ] connection The connection.
135
+ #
136
+ # @return [ Protocol::Reply ] The reply.
137
+ #
138
+ # @since 1.0.0
139
+ def receive_replies(connection)
140
+ connection.read
141
+ end
130
142
  end
131
143
  end
132
144
  end
@@ -51,6 +51,8 @@ module Moped
51
51
  # @return [Array] the returned documents
52
52
  document :documents, type: :array
53
53
 
54
+ finalize
55
+
54
56
  class << self
55
57
 
56
58
  # Consumes a buffer, returning the deserialized Reply message.
@@ -65,11 +67,11 @@ module Moped
65
67
  # reply from.
66
68
  # @return [Reply] the deserialized reply
67
69
  def deserialize(buffer)
68
- allocate.tap do |reply|
69
- fields.each do |field|
70
- reply.__send__ :"deserialize_#{field}", buffer
71
- end
70
+ reply = allocate
71
+ fields.each do |field|
72
+ reply.__send__ :"deserialize_#{field}", buffer
72
73
  end
74
+ reply
73
75
  end
74
76
  end
75
77
 
@@ -56,6 +56,8 @@ module Moped
56
56
  # @return [Hash] the updates to apply
57
57
  document :update
58
58
 
59
+ finalize
60
+
59
61
  undef op_code
60
62
  # @return [Number] OP_UPDATE operation code (2001)
61
63
  def op_code
@@ -73,11 +73,11 @@ module Moped
73
73
  # @yieldparam [ Hash ] document each matching document
74
74
  def each
75
75
  cursor = Cursor.new(session, operation)
76
- cursor.to_enum.tap do |enum|
77
- enum.each do |document|
78
- yield document
79
- end if block_given?
80
- end
76
+ enum = cursor.to_enum
77
+ enum.each do |document|
78
+ yield document
79
+ end if block_given?
80
+ enum
81
81
  end
82
82
 
83
83
  # Explain the current query.
@@ -118,6 +118,22 @@ module Moped
118
118
  end
119
119
  alias :one :first
120
120
 
121
+ # Apply an index hint to the query.
122
+ #
123
+ # @example Apply an index hint.
124
+ # db[:people].find.hint("$natural" => 1)
125
+ #
126
+ # @param [ Hash ] hint The index hint.
127
+ #
128
+ # @return [ Query ] self
129
+ #
130
+ # @since 1.0.0
131
+ def hint(hint)
132
+ operation.selector = { "$query" => selector } unless operation.selector["$query"]
133
+ operation.selector["$hint"] = hint
134
+ self
135
+ end
136
+
121
137
  # Initialize the query.
122
138
  #
123
139
  # @example Initialize the query.
@@ -151,6 +167,45 @@ module Moped
151
167
  self
152
168
  end
153
169
 
170
+ # Execute a $findAndModify on the query.
171
+ #
172
+ # @example Find and modify a document, returning the original.
173
+ # db[:bands].find.modify({ "$inc" => { likes: 1 }})
174
+ #
175
+ # @example Find and modify a document, returning the updated document.
176
+ # db[:bands].find.modify({ "$inc" => { likes: 1 }}, new: true)
177
+ #
178
+ # @example Find and return a document, removing it from the database.
179
+ # db[:bands].find.modify({}, remove: true)
180
+ #
181
+ # @example Find and return a document, upserting if no match found.
182
+ # db[:bands].find.modify({}, upsert: true, new: true)
183
+ #
184
+ # @param [ Hash ] change The changes to make to the document.
185
+ # @param [ Hash ] options The options.
186
+ #
187
+ # @option options :new Set to true if you want to return the updated document.
188
+ # @option options :remove Set to true if the document should be deleted.
189
+ # @option options :upsert Set to true if you want to upsert
190
+ #
191
+ # @return [ Hash ] The document.
192
+ #
193
+ # @since 1.0.0
194
+ def modify(change, options = {})
195
+ command = {
196
+ findAndModify: collection.name,
197
+ query: selector
198
+ }.merge(options)
199
+
200
+ command[:sort] = operation.selector["$orderby"] if operation.selector["$orderby"]
201
+ command[:fields] = operation.fields if operation.fields
202
+ command[:update] = change unless options[:remove]
203
+
204
+ session.with(consistency: :strong) do |sess|
205
+ sess.command(command)["value"]
206
+ end
207
+ end
208
+
154
209
  # Remove a single document matching the query's selector.
155
210
  #
156
211
  # @example Remove a single document.
@@ -28,47 +28,88 @@ module Moped
28
28
  # session.with(database: "admin").login("admin", "s3cr3t")
29
29
  #
30
30
  class Session
31
- extend Forwardable
32
31
 
33
32
  # @attribute [r] cluster The session cluster.
34
33
  # @attribute [r] context The session context.
35
34
  # @attribute [r] options The session options.
36
35
  attr_reader :cluster, :context, :options
37
36
 
38
- # @method [](collection)
39
37
  # Return +collection+ from the current database.
40
38
  #
41
39
  # @param (see Moped::Database#[])
40
+ #
42
41
  # @return (see Moped::Database#[])
43
- delegate :"[]" => :current_database
42
+ #
43
+ # @since 1.0.0
44
+ def [](name)
45
+ current_database[name]
46
+ end
47
+
48
+ # Return non system collection name from the current database.
49
+ #
50
+ # @param (see Moped::Database#collection_names)
51
+ #
52
+ # @return (see Moped::Database#collection_names)
53
+ #
54
+ # @since 1.0.0
55
+ def collection_names
56
+ current_database.collection_names
57
+ end
58
+
59
+ # Return non system collection name from the current database.
60
+ #
61
+ # @param (see Moped::Database#collections)
62
+ #
63
+ # @return (see Moped::Database#collections)
64
+ #
65
+ # @since 1.0.0
66
+ def collections
67
+ current_database.collections
68
+ end
44
69
 
45
- # @method command(command)
46
70
  # Run +command+ on the current database.
47
71
  #
48
72
  # @param (see Moped::Database#command)
73
+ #
49
74
  # @return (see Moped::Database#command)
50
- delegate :command => :current_database
75
+ #
76
+ # @since 1.0.0
77
+ def command(op)
78
+ current_database.command(op)
79
+ end
51
80
 
52
- # @method drop
53
81
  # Drop the current database.
54
82
  #
55
83
  # @param (see Moped::Database#drop)
84
+ #
56
85
  # @return (see Moped::Database#drop)
57
- delegate :drop => :current_database
86
+ #
87
+ # @since 1.0.0
88
+ def drop
89
+ current_database.drop
90
+ end
58
91
 
59
- # @method login(username, password)
60
92
  # Log in with +username+ and +password+ on the current database.
61
93
  #
62
94
  # @param (see Moped::Database#login)
95
+ #
63
96
  # @raise (see Moped::Database#login)
64
- delegate :login => :current_database
97
+ #
98
+ # @since 1.0.0
99
+ def login(username, password)
100
+ current_database.login(username, password)
101
+ end
65
102
 
66
- # @method logout
67
103
  # Log out from the current database.
68
104
  #
69
105
  # @param (see Moped::Database#logout)
106
+ #
70
107
  # @raise (see Moped::Database#login)
71
- delegate :logout => :current_database
108
+ #
109
+ # @since 1.0.0
110
+ def logout
111
+ current_database.logout
112
+ end
72
113
 
73
114
  # Get the session's consistency.
74
115
  #
@@ -168,12 +209,7 @@ module Moped
168
209
  #
169
210
  # @since 1.0.0
170
211
  def safety
171
- safe = options[:safe]
172
- case safe
173
- when false then false
174
- when true then { safe: true }
175
- else safe
176
- end
212
+ options[:safe].__safe_options__
177
213
  end
178
214
 
179
215
  # Switch the session's current database.
@@ -3,16 +3,28 @@ module Moped
3
3
 
4
4
  # @api private
5
5
  class Context
6
- extend Forwardable
6
+
7
+ attr_reader :session
7
8
 
8
9
  def initialize(session)
9
10
  @session = session
10
11
  end
11
12
 
12
- delegate :safety => :@session
13
- delegate :safe? => :@session
14
- delegate :consistency => :@session
15
- delegate :cluster => :@session
13
+ def safety
14
+ session.safety
15
+ end
16
+
17
+ def safe?
18
+ session.safe?
19
+ end
20
+
21
+ def consistency
22
+ session.consistency
23
+ end
24
+
25
+ def cluster
26
+ session.cluster
27
+ end
16
28
 
17
29
  def login(database, username, password)
18
30
  cluster.auth[database.to_s] = [username, password]
@@ -98,8 +110,6 @@ module Moped
98
110
  end
99
111
  end
100
112
  end
101
-
102
113
  end
103
-
104
114
  end
105
115
  end