moped 1.0.0.beta → 1.0.0.rc

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.

@@ -76,6 +76,7 @@ module Moped
76
76
  @flags = options[:flags]
77
77
  end
78
78
 
79
+ undef op_code
79
80
  # @return [Number] OP_DELETE operation code (2006)
80
81
  def op_code
81
82
  2006
@@ -43,6 +43,7 @@ module Moped
43
43
  # @return [Number] the id of the cursor to get more documents from
44
44
  int64 :cursor_id
45
45
 
46
+ undef op_code
46
47
  # @return [Number] OP_GETMORE operation code (2005)
47
48
  def op_code
48
49
  2005
@@ -46,6 +46,7 @@ module Moped
46
46
  # @return [Array<Hash>] the documents to insert
47
47
  document :documents, type: :array
48
48
 
49
+ undef op_code
49
50
  # @return [Number] OP_INSERT operation code (2002)
50
51
  def op_code
51
52
  2002
@@ -35,6 +35,7 @@ module Moped
35
35
  # @return [Array] the cursor ids to kill
36
36
  int64 :cursor_ids, type: :array
37
37
 
38
+ undef op_code
38
39
  # @return [Number] OP_KILL_CURSORS operation code (2007)
39
40
  def op_code
40
41
  2007
@@ -152,8 +152,6 @@ module Moped
152
152
  # @param [String] name the name of this field
153
153
  # @param [Hash{Symbol => Number}] flags the flags for this flag field
154
154
  def flags(name, flag_map = {})
155
- attr_writer name
156
-
157
155
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
158
156
  def #{name}
159
157
  @#{name} ||= []
@@ -64,6 +64,7 @@ module Moped
64
64
  # @return [Hash, nil] the fields to include in the reply
65
65
  document :fields, :optional => true
66
66
 
67
+ undef op_code
67
68
  # @return [Number] OP_QUERY operation code (2004)
68
69
  def op_code
69
70
  2004
@@ -56,6 +56,7 @@ module Moped
56
56
  # @return [Hash] the updates to apply
57
57
  document :update
58
58
 
59
+ undef op_code
59
60
  # @return [Number] OP_UPDATE operation code (2001)
60
61
  def op_code
61
62
  2001
data/lib/moped/query.rb CHANGED
@@ -19,56 +19,65 @@ module Moped
19
19
  class Query
20
20
  include Enumerable
21
21
 
22
- # @return [Collection] the query's collection
23
- attr_reader :collection
22
+ # @attribute [r] collection The collection to execute the query on.
23
+ # @attribute [r] operation The query operation.
24
+ # @attribute [r] selector The query selector.
25
+ attr_reader :collection, :operation, :selector
24
26
 
25
- # @return [Hash] the query's selector
26
- attr_reader :selector
27
-
28
- # @api private
29
- attr_reader :operation
30
-
31
- # @param [Collection] collection the query's collection
32
- # @param [Hash] selector the query's selector
33
- def initialize(collection, selector)
34
- @collection = collection
35
- @selector = selector
36
-
37
- @operation = Protocol::Query.new(
38
- collection.database.name,
39
- collection.name,
40
- selector
27
+ # Get the count of matching documents in the query.
28
+ #
29
+ # @example Get the count.
30
+ # db[:people].find.count
31
+ #
32
+ # @return [ Integer ] The number of documents that match the selector.
33
+ #
34
+ # @since 1.0.0
35
+ def count
36
+ result = collection.database.command(
37
+ count: collection.name,
38
+ query: selector
41
39
  )
40
+ result["n"].to_i
42
41
  end
43
42
 
44
- # Set the query's limit.
43
+ # Get the distinct values in the collection for the provided key.
45
44
  #
46
- # @param [Numeric] limit
47
- # @return [Query] self
48
- def limit(limit)
49
- operation.limit = limit
50
- self
51
- end
52
-
53
- # Set the number of documents to skip.
45
+ # @example Get the distinct values.
46
+ # db[:people].find.distinct(:name)
54
47
  #
55
- # @param [Numeric] skip
56
- # @return [Query] self
57
- def skip(skip)
58
- operation.skip = skip
59
- self
48
+ # @param [ Symbol, String ] key The name of the field.
49
+ #
50
+ # @return [ Array<Object ] The distinct values.
51
+ #
52
+ # @since 1.0.0
53
+ def distinct(key)
54
+ result = collection.database.command(
55
+ distinct: collection.name,
56
+ key: key.to_s,
57
+ query: selector
58
+ )
59
+ result["values"]
60
60
  end
61
61
 
62
- # Set the sort order for the query.
62
+ # Iterate through documents matching the query's selector.
63
63
  #
64
- # @example
65
- # db[:people].find.sort(name: 1, age: -1).one
64
+ # @example Iterate over the matching documents.
65
+ # db[:people].find.each do |doc|
66
+ # #...
67
+ # end
66
68
  #
67
- # @param [Hash] sort
68
- # @return [Query] self
69
- def sort(sort)
70
- operation.selector = { "$query" => selector, "$orderby" => sort }
71
- self
69
+ # @return [ Enumerator ] The enumerator.
70
+ #
71
+ # @since 1.0.0
72
+ #
73
+ # @yieldparam [ Hash ] document each matching document
74
+ def each
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
72
81
  end
73
82
 
74
83
  # Explain the current query.
@@ -77,6 +86,8 @@ module Moped
77
86
  # db[:people].find.explain
78
87
  #
79
88
  # @return [ Hash ] The explain document.
89
+ #
90
+ # @since 1.0.0
80
91
  def explain
81
92
  operation.selector = {
82
93
  "$query" => selector,
@@ -85,19 +96,14 @@ module Moped
85
96
  } and first
86
97
  end
87
98
 
88
- # Set the fields to return from the query.
99
+ # Get the first matching document.
89
100
  #
90
- # @example
91
- # db[:people].find.select(name: 1).one # => { name: "John" }
101
+ # @example Get the first matching document.
102
+ # db[:people].find.first
92
103
  #
93
- # @param [Hash] select
94
- # @return [Query] self
95
- def select(select)
96
- operation.fields = select
97
- self
98
- end
99
-
100
- # @return [Hash] the first document that matches the selector.
104
+ # @return [ Hash ] The first document that matches the selector.
105
+ #
106
+ # @since 1.0.0
101
107
  def first
102
108
  reply = session.context.query(
103
109
  operation.database,
@@ -110,113 +116,177 @@ module Moped
110
116
  )
111
117
  reply.documents.first
112
118
  end
113
- alias one first
119
+ alias :one :first
114
120
 
115
- # Iterate through documents matching the query's selector.
121
+ # Initialize the query.
116
122
  #
117
- # @yieldparam [Hash] document each matching document
118
- def each
119
- cursor = Cursor.new(session, operation)
120
- cursor.to_enum.tap do |enum|
121
- enum.each do |document|
122
- yield document
123
- end if block_given?
123
+ # @example Initialize the query.
124
+ # Query.new(collection, selector)
125
+ #
126
+ # @param [ Collection ] collection The query's collection.
127
+ # @param [ Hash ] selector The query's selector.
128
+ #
129
+ # @since 1.0.0
130
+ def initialize(collection, selector)
131
+ @collection, @selector = collection, selector
132
+ @operation = Protocol::Query.new(
133
+ collection.database.name,
134
+ collection.name,
135
+ selector
136
+ )
137
+ end
138
+
139
+ # Set the query's limit.
140
+ #
141
+ # @example Set the limit.
142
+ # db[:people].find.limit(20)
143
+ #
144
+ # @param [ Integer ] limit The number of documents to limit.
145
+ #
146
+ # @return [ Query ] self
147
+ #
148
+ # @since 1.0.0
149
+ def limit(limit)
150
+ operation.limit = limit
151
+ self
152
+ end
153
+
154
+ # Remove a single document matching the query's selector.
155
+ #
156
+ # @example Remove a single document.
157
+ # db[:people].find(name: "John").remove
158
+ #
159
+ # @return [ Hash, nil ] If in safe mode the last error result.
160
+ #
161
+ # @since 1.0.0
162
+ def remove
163
+ session.with(consistency: :strong) do |session|
164
+ session.context.remove(
165
+ operation.database,
166
+ operation.collection,
167
+ operation.selector,
168
+ flags: [ :remove_first ]
169
+ )
124
170
  end
125
171
  end
126
172
 
127
- # Get the distinct values in the collection for the provided key.
173
+ # Remove multiple documents matching the query's selector.
128
174
  #
129
- # @example Get the distinct values.
130
- # query.distinct(:name)
175
+ # @example Remove all matching documents.
176
+ # db[:people].find(name: "John").remove_all
131
177
  #
132
- # @param [ Symbol, String ] key The name of the field.
178
+ # @return [ Hash, nil ] If in safe mode the last error result.
133
179
  #
134
- # @return [ Array<Object ] The distinct values.
135
- def distinct(key)
136
- result = collection.database.command(
137
- distinct: collection.name,
138
- key: key.to_s,
139
- query: selector
140
- )
180
+ # @since 1.0.0
181
+ def remove_all
182
+ session.with(consistency: :strong) do |session|
183
+ session.context.remove(
184
+ operation.database,
185
+ operation.collection,
186
+ operation.selector
187
+ )
188
+ end
189
+ end
141
190
 
142
- result["values"]
191
+ # Set the fields to include or exclude from the query.
192
+ #
193
+ # @example Select the fields to include or exclude.
194
+ # db[:people].find.select(name: 1).one # => { name: "John" }
195
+ #
196
+ # @param [ Hash ] select The inclusions or exclusions.
197
+ #
198
+ # @return [ Query ] self
199
+ #
200
+ # @since 1.0.0
201
+ def select(select)
202
+ operation.fields = select
203
+ self
143
204
  end
144
205
 
145
- # @return [Numeric] the number of documents that match the selector.
146
- def count
147
- result = collection.database.command(
148
- count: collection.name,
149
- query: selector
150
- )
206
+ # Set the number of documents to skip.
207
+ #
208
+ # @example Set the number to skip.
209
+ # db[:people].find.skip(20)
210
+ #
211
+ # @param [ Integer ] skip The number of documents to skip.
212
+ #
213
+ # @return [ Query ] self
214
+ #
215
+ # @since 1.0.0
216
+ def skip(skip)
217
+ operation.skip = skip
218
+ self
219
+ end
151
220
 
152
- result["n"]
221
+ # Set the sort order for the query.
222
+ #
223
+ # @example Set the sort order.
224
+ # db[:people].find.sort(name: 1, age: -1).one
225
+ #
226
+ # @param [ Hash ] sort The order as key/(1/-1) pairs.
227
+ #
228
+ # @return [ Query ] self
229
+ #
230
+ # @since 1.0.0
231
+ def sort(sort)
232
+ operation.selector = { "$query" => selector, "$orderby" => sort }
233
+ self
153
234
  end
154
235
 
155
236
  # Update a single document matching the query's selector.
156
237
  #
157
- # @example
238
+ # @example Update the first matching document.
158
239
  # db[:people].find(_id: 1).update(name: "John")
159
240
  #
160
- # @param [Hash] change the changes to make to the document
161
- # @param [Array] flags an array of operation flags. Valid values are:
241
+ # @param [ Hash ] change The changes to make to the document
242
+ # @param [ Array ] flags An array of operation flags. Valid values are:
162
243
  # +:multi+ and +:upsert+
244
+ #
245
+ # @return [ Hash, nil ] If in safe mode the last error result.
246
+ #
247
+ # @since 1.0.0
163
248
  def update(change, flags = nil)
164
249
  session.with(consistency: :strong) do |session|
165
- session.context.update operation.database,
250
+ session.context.update(
251
+ operation.database,
166
252
  operation.collection,
167
253
  operation.selector,
168
254
  change,
169
255
  flags: flags
256
+ )
170
257
  end
171
258
  end
172
259
 
173
260
  # Update multiple documents matching the query's selector.
174
261
  #
175
- # @example
262
+ # @example Update multiple documents.
176
263
  # db[:people].find(name: "John").update_all(name: "Mary")
177
264
  #
178
- # @param [Hash] change the changes to make to the documents
265
+ # @param [ Hash ] change The changes to make to the documents
266
+ #
267
+ # @return [ Hash, nil ] If in safe mode the last error result.
268
+ #
269
+ # @since 1.0.0
179
270
  def update_all(change)
180
- update change, [:multi]
271
+ update(change, [ :multi ])
181
272
  end
182
273
 
183
274
  # Update an existing document with +change+, otherwise create one.
184
275
  #
185
- # @example
276
+ # @example Upsert the changes.
186
277
  # db[:people].find.entries # => { name: "John" }
187
278
  # db[:people].find(name: "John").upsert(name: "James")
188
279
  # db[:people].find.entries # => { name: "James" }
189
280
  # db[:people].find(name: "John").upsert(name: "Mary")
190
281
  # db[:people].find.entries # => [{ name: "James" }, { name: "Mary" }]
191
282
  #
192
- # @param [Hash] change the changes to make to the the document
193
- def upsert(change)
194
- update change, [:upsert]
195
- end
196
-
197
- # Remove a single document matching the query's selector.
283
+ # @param [ Hash ] change The changes to make to the the document.
198
284
  #
199
- # @example
200
- # db[:people].find(name: "John").remove
201
- def remove
202
- session.with(consistency: :strong) do |session|
203
- session.context.remove operation.database,
204
- operation.collection,
205
- operation.selector,
206
- flags: [:remove_first]
207
- end
208
- end
209
-
210
- # Remove multiple documents matching the query's selector.
285
+ # @return [ Hash, nil ] If in safe mode the last error result.
211
286
  #
212
- # @example
213
- # db[:people].find(name: "John").remove_all
214
- def remove_all
215
- session.with(consistency: :strong) do |session|
216
- session.context.remove operation.database,
217
- operation.collection,
218
- operation.selector
219
- end
287
+ # @since 1.0.0
288
+ def upsert(change)
289
+ update(change, [ :upsert ])
220
290
  end
221
291
 
222
292
  private
data/lib/moped/session.rb CHANGED
@@ -30,54 +30,81 @@ module Moped
30
30
  class Session
31
31
  extend Forwardable
32
32
 
33
- # @return [Hash] this session's options
34
- attr_reader :options
35
-
36
- # @private
37
- # @return [Cluster] this session's cluster
38
- attr_reader :cluster
39
-
40
- # @private
41
- # @return [Context] this session's context
42
- attr_reader :context
43
-
44
- # @param [Array] seeds an of host:port pairs
45
- # @param [Hash] options
46
- # @option options [Boolean] :safe (false) ensure writes are persisted
47
- # @option options [Hash] :safe ensure writes are persisted with the
48
- # specified safety level e.g., "fsync: true", or "w: 2, wtimeout: 5"
49
- # @option options [Symbol, String] :database the database to use
50
- # @option options [:strong, :eventual] :consistency (:eventual)
51
- def initialize(seeds, options = {})
52
- @cluster = Cluster.new(seeds, {})
53
- @context = Context.new(self)
54
- @options = options
55
- @options[:consistency] ||= :eventual
56
- end
33
+ # @attribute [r] cluster The session cluster.
34
+ # @attribute [r] context The session context.
35
+ # @attribute [r] options The session options.
36
+ attr_reader :cluster, :context, :options
57
37
 
58
- # @return [Boolean] whether the current session requires safe operations.
59
- def safe?
60
- !!safety
61
- end
38
+ # @method [](collection)
39
+ # Return +collection+ from the current database.
40
+ #
41
+ # @param (see Moped::Database#[])
42
+ # @return (see Moped::Database#[])
43
+ delegate :"[]" => :current_database
44
+
45
+ # @method command(command)
46
+ # Run +command+ on the current database.
47
+ #
48
+ # @param (see Moped::Database#command)
49
+ # @return (see Moped::Database#command)
50
+ delegate :command => :current_database
62
51
 
63
- # @return [:strong, :eventual] the session's consistency
52
+ # @method drop
53
+ # Drop the current database.
54
+ #
55
+ # @param (see Moped::Database#drop)
56
+ # @return (see Moped::Database#drop)
57
+ delegate :drop => :current_database
58
+
59
+ # @method login(username, password)
60
+ # Log in with +username+ and +password+ on the current database.
61
+ #
62
+ # @param (see Moped::Database#login)
63
+ # @raise (see Moped::Database#login)
64
+ delegate :login => :current_database
65
+
66
+ # @method logout
67
+ # Log out from the current database.
68
+ #
69
+ # @param (see Moped::Database#logout)
70
+ # @raise (see Moped::Database#login)
71
+ delegate :logout => :current_database
72
+
73
+ # Get the session's consistency.
74
+ #
75
+ # @example Get the session consistency.
76
+ # session.consistency
77
+ #
78
+ # @return [ :strong, :eventual ] The session's consistency.
79
+ #
80
+ # @since 1.0.0
64
81
  def consistency
65
82
  options[:consistency]
66
83
  end
67
84
 
68
- # Switch the session's current database.
85
+ # Initialize a new database session.
69
86
  #
70
- # @example
71
- # session.use :moped
72
- # session[:people].find.one # => { :name => "John" }
87
+ # @example Initialize a new session.
88
+ # Session.new([ "localhost:27017" ])
73
89
  #
74
- # @param [String] database the database to use
75
- def use(database)
76
- options[:database] = database
77
- set_current_database database
90
+ # @param [ Array ] seeds an of host:port pairs
91
+ # @param [ Hash ] options
92
+ #
93
+ # @option options [ Boolean ] :safe (false) Ensure writes are persisted.
94
+ # @option options [ Hash ] :safe Ensure writes are persisted with the
95
+ # specified safety level e.g., "fsync: true", or "w: 2, wtimeout: 5".
96
+ # @option options [ Symbol, String ] :database The database to use.
97
+ # @option options [ :strong, :eventual ] :consistency (:eventual).
98
+ #
99
+ # @since 1.0.0
100
+ def initialize(seeds, options = {})
101
+ @cluster = Cluster.new(seeds, {})
102
+ @context = Context.new(self)
103
+ @options = options
104
+ @options[:consistency] ||= :eventual
78
105
  end
79
106
 
80
- # Create a new session with +options+ reusing existing connections.
107
+ # Create a new session with +options+ and use new socket connections.
81
108
  #
82
109
  # @example Change safe mode
83
110
  # session.with(safe: { w: 2 })[:people].insert(name: "Joe")
@@ -100,29 +127,18 @@ module Moped
100
127
  # end
101
128
  # end
102
129
  #
103
- # @yieldparam [Moped::Session] session the new session
104
- # @return [Moped::Session, Object] the new session, or the value returned
105
- # by the block if provided.
106
- def with(options = {})
107
- session = dup
108
- session.options.update options
109
-
110
- if block_given?
111
- yield session
112
- else
113
- session
114
- end
115
- end
116
-
117
- # Create a new session with +options+ and use new socket connections.
130
+ # @param [ Hash ] options The options.
131
+ #
132
+ # @return [ Session ] The new session.
118
133
  #
119
134
  # @see #with
120
- # @yieldparam [Moped::Session] session the new session
121
- # @return [Moped::Session] the new session
135
+ #
136
+ # @since 1.0.0
137
+ #
138
+ # @yieldparam [ Session ] session The new session.
122
139
  def new(options = {})
123
140
  session = with(options)
124
141
  session.instance_variable_set(:@cluster, cluster.dup)
125
-
126
142
  if block_given?
127
143
  yield session
128
144
  else
@@ -130,52 +146,88 @@ module Moped
130
146
  end
131
147
  end
132
148
 
133
- # @method [](collection)
134
- # Return +collection+ from the current database.
149
+ # Is the session operating in safe mode?
135
150
  #
136
- # @param (see Moped::Database#[])
137
- # @return (see Moped::Database#[])
138
- delegate :"[]" => :current_database
139
-
140
- # @method command(command)
141
- # Run +command+ on the current database.
151
+ # @example Is the session operating in safe mode?
152
+ # session.safe?
142
153
  #
143
- # @param (see Moped::Database#command)
144
- # @return (see Moped::Database#command)
145
- delegate :command => :current_database
146
-
147
- # @method drop
148
- # Drop the current database.
154
+ # @return [ true, false ] Whether the current session requires safe
155
+ # operations.
149
156
  #
150
- # @param (see Moped::Database#drop)
151
- # @return (see Moped::Database#drop)
152
- delegate :drop => :current_database
157
+ # @since 1.0.0
158
+ def safe?
159
+ !!safety
160
+ end
153
161
 
154
- # @method login(username, password)
155
- # Log in with +username+ and +password+ on the current database.
162
+ # Get the safety level for the session.
156
163
  #
157
- # @param (see Moped::Database#login)
158
- # @raise (see Moped::Database#login)
159
- delegate :login => :current_database
160
-
161
- # @method logout
162
- # Log out from the current database.
164
+ # @example Get the safety level.
165
+ # session.safety
163
166
  #
164
- # @param (see Moped::Database#logout)
165
- # @raise (see Moped::Database#login)
166
- delegate :logout => :current_database
167
-
168
- # @return [Boolean, Hash] the safety level for this session
167
+ # @return [ Boolean, Hash ] The safety level for this session.
168
+ #
169
+ # @since 1.0.0
169
170
  def safety
170
171
  safe = options[:safe]
171
-
172
172
  case safe
173
- when false
174
- false
175
- when true
176
- { safe: true }
173
+ when false then false
174
+ when true then { safe: true }
175
+ else safe
176
+ end
177
+ end
178
+
179
+ # Switch the session's current database.
180
+ #
181
+ # @example Switch the current database.
182
+ # session.use :moped
183
+ # session[:people].find.one # => { :name => "John" }
184
+ #
185
+ # @param [ String, Symbol ] database The database to use.
186
+ #
187
+ # @since 1.0.0
188
+ def use(database)
189
+ options[:database] = database
190
+ set_current_database database
191
+ end
192
+
193
+ # Create a new session with +options+ reusing existing connections.
194
+ #
195
+ # @example Change safe mode
196
+ # session.with(safe: { w: 2 })[:people].insert(name: "Joe")
197
+ #
198
+ # @example Change safe mode with block
199
+ # session.with(safe: { w: 2 }) do |session|
200
+ # session[:people].insert(name: "Joe")
201
+ # end
202
+ #
203
+ # @example Temporarily change database
204
+ # session.with(database: "admin") do |admin|
205
+ # admin.command ismaster: 1
206
+ # end
207
+ #
208
+ # @example Copy between databases
209
+ # session.use "moped"
210
+ # session.with(database: "backup") do |backup|
211
+ # session[:people].each do |person|
212
+ # backup[:people].insert person
213
+ # end
214
+ # end
215
+ #
216
+ # @param [ Hash ] options The session options.
217
+ #
218
+ # @return [ Session, Object ] The new session, or the value returned
219
+ # by the block if provided.
220
+ #
221
+ # @since 1.0.0
222
+ #
223
+ # @yieldparam [ Session ] session The new session.
224
+ def with(options = {})
225
+ session = dup
226
+ session.options.update(options)
227
+ if block_given?
228
+ yield session
177
229
  else
178
- safe
230
+ session
179
231
  end
180
232
  end
181
233
 
@@ -191,10 +243,6 @@ module Moped
191
243
  end
192
244
  end
193
245
 
194
- def set_current_database(database)
195
- @current_database = Database.new(self, database)
196
- end
197
-
198
246
  def initialize_copy(_)
199
247
  @context = Context.new(self)
200
248
  @options = @options.dup
@@ -203,5 +251,9 @@ module Moped
203
251
  remove_instance_variable :@current_database
204
252
  end
205
253
  end
254
+
255
+ def set_current_database(database)
256
+ @current_database = Database.new(self, database)
257
+ end
206
258
  end
207
259
  end