mongo 0.19.1 → 0.19.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,36 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module BSON
18
+
19
+ # JavaScript code to be evaluated by MongoDB.
20
+ class Code < String
21
+
22
+ # Hash mapping identifiers to their values
23
+ attr_accessor :scope
24
+
25
+ # Wrap code to be evaluated by MongoDB.
26
+ #
27
+ # @param [String] code the JavaScript code.
28
+ # @param [Hash] a document mapping identifiers to values, which
29
+ # represent the scope in which the code is to be executed.
30
+ def initialize(code, scope={})
31
+ super(code)
32
+ @scope = scope
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module BSON
18
+
19
+ # A reference to another object in a MongoDB database.
20
+ class DBRef
21
+
22
+ attr_reader :namespace, :object_id
23
+
24
+ # Create a DBRef. Use this class in conjunction with DB#dereference.
25
+ #
26
+ # @param [String] a collection name
27
+ # @param [ObjectID] an object id
28
+ #
29
+ # @core dbrefs constructor_details
30
+ def initialize(namespace, object_id)
31
+ @namespace = namespace
32
+ @object_id = object_id
33
+ end
34
+
35
+ def to_s
36
+ "ns: #{namespace}, id: #{object_id}"
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module BSON
18
+
19
+ # A class representing the BSON MaxKey type. MaxKey will always compare greater than
20
+ # all other BSON types and values.
21
+ #
22
+ # @example Sorting (assume @numbers is a collection):
23
+ #
24
+ # >> @numbers.save({"n" => Mongo::MaxKey.new})
25
+ # >> @numbers.save({"n" => 0})
26
+ # >> @numbers.save({"n" => 5_000_000})
27
+ # >> @numbers.find.sort("n").to_a
28
+ # => [{"_id"=>4b5a050c238d3bace2000004, "n"=>0},
29
+ # {"_id"=>4b5a04e6238d3bace2000002, "n"=>5_000_000},
30
+ # {"_id"=>4b5a04ea238d3bace2000003, "n"=>#<Mongo::MaxKey:0x1014ef410>},
31
+ # ]
32
+ class MaxKey
33
+
34
+ def ==(obj)
35
+ obj.class == MaxKey
36
+ end
37
+ end
38
+
39
+ # A class representing the BSON MinKey type. MinKey will always compare less than
40
+ # all other BSON types and values.
41
+ #
42
+ # @example Sorting (assume @numbers is a collection):
43
+ #
44
+ # >> @numbers.save({"n" => Mongo::MinKey.new})
45
+ # >> @numbers.save({"n" => -1_000_000})
46
+ # >> @numbers.save({"n" => 1_000_000})
47
+ # >> @numbers.find.sort("n").to_a
48
+ # => [{"_id"=>4b5a050c238d3bace2000004, "n"=>#<Mongo::MinKey:0x1014ef410>},
49
+ # {"_id"=>4b5a04e6238d3bace2000002, "n"=>-1_000_000},
50
+ # {"_id"=>4b5a04ea238d3bace2000003, "n"=>1_000_000},
51
+ # ]
52
+ class MinKey
53
+
54
+ def ==(obj)
55
+ obj.class == MinKey
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,180 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'thread'
18
+ require 'socket'
19
+ require 'digest/md5'
20
+
21
+ module BSON
22
+
23
+ # Generates MongoDB object ids.
24
+ #
25
+ # @core objectids
26
+ class ObjectID
27
+ @@lock = Mutex.new
28
+ @@index = 0
29
+
30
+ # Create a new object id. If no parameter is given, an id corresponding
31
+ # to the ObjectID BSON data type will be created. This is a 12-byte value
32
+ # consisting of a 4-byte timestamp, a 3-byte machine id, a 2-byte process id,
33
+ # and a 3-byte counter.
34
+ #
35
+ # @param [Array] data should be an array of bytes. If you want
36
+ # to generate a standard MongoDB object id, leave this argument blank.
37
+ def initialize(data=nil)
38
+ @data = data || generate
39
+ end
40
+
41
+ # Determine if the supplied string is legal. Legal strings will
42
+ # consist of 24 hexadecimal characters.
43
+ #
44
+ # @param [String] str
45
+ #
46
+ # @return [Boolean]
47
+ def self.legal?(str)
48
+ len = 24
49
+ str =~ /([0-9a-f]+)/i
50
+ match = $1
51
+ str && str.length == len && match == str
52
+ end
53
+
54
+ # Create an object id from the given time. This is useful for doing range
55
+ # queries; it works because MongoDB's object ids begin
56
+ # with a timestamp.
57
+ #
58
+ # @param [Time] time a utc time to encode as an object id.
59
+ #
60
+ # @return [Mongo::ObjectID]
61
+ #
62
+ # @example Return all document created before Jan 1, 2010.
63
+ # time = Time.utc(2010, 1, 1)
64
+ # time_id = ObjectID.from_time(time)
65
+ # collection.find({'_id' => {'$lt' => time_id}})
66
+ def self.from_time(time)
67
+ self.new([time.to_i,0,0].pack("NNN").unpack("C12"))
68
+ end
69
+
70
+ # Adds a primary key to the given document if needed.
71
+ #
72
+ # @param [Hash] doc a document requiring an _id.
73
+ #
74
+ # @return [Mongo::ObjectID, Object] returns a newly-created or
75
+ # current _id for the given document.
76
+ def self.create_pk(doc)
77
+ doc.has_key?(:_id) || doc.has_key?('_id') ? doc : doc.merge!(:_id => self.new)
78
+ end
79
+
80
+ # Check equality of this object id with another.
81
+ #
82
+ # @param [Mongo::ObjectID] object_id
83
+ def eql?(object_id)
84
+ @data == object_id.instance_variable_get("@data")
85
+ end
86
+ alias_method :==, :eql?
87
+
88
+ # Get a unique hashcode for this object.
89
+ # This is required since we've defined an #eql? method.
90
+ #
91
+ # @return [Integer]
92
+ def hash
93
+ @data.hash
94
+ end
95
+
96
+ # Get an array representation of the object id.
97
+ #
98
+ # @return [Array]
99
+ def to_a
100
+ @data.dup
101
+ end
102
+
103
+ # Given a string representation of an ObjectID, return a new ObjectID
104
+ # with that value.
105
+ #
106
+ # @param [String] str
107
+ #
108
+ # @return [Mongo::ObjectID]
109
+ def self.from_string(str)
110
+ raise InvalidObjectID, "illegal ObjectID format" unless legal?(str)
111
+ data = []
112
+ 12.times do |i|
113
+ data[i] = str[i * 2, 2].to_i(16)
114
+ end
115
+ self.new(data)
116
+ end
117
+
118
+ # Get a string representation of this object id.
119
+ #
120
+ # @return [String]
121
+ def to_s
122
+ str = ' ' * 24
123
+ 12.times do |i|
124
+ str[i * 2, 2] = '%02x' % @data[i]
125
+ end
126
+ str
127
+ end
128
+
129
+ def inspect
130
+ "ObjectID('#{to_s}')"
131
+ end
132
+
133
+ # Convert to MongoDB extended JSON format. Since JSON includes type information,
134
+ # but lacks an ObjectID type, this JSON format encodes the type using an $id key.
135
+ #
136
+ # @return [String] the object id represented as MongoDB extended JSON.
137
+ def to_json(escaped=false)
138
+ "{\"$oid\": \"#{to_s}\"}"
139
+ end
140
+
141
+ # Return the UTC time at which this ObjectID was generated. This may
142
+ # be used in lieu of a created_at timestamp since this information
143
+ # is always encoded in the object id.
144
+ #
145
+ # @return [Time] the time at which this object was created.
146
+ def generation_time
147
+ Time.at(@data.pack("C4").unpack("N")[0]).utc
148
+ end
149
+
150
+ private
151
+
152
+ # We need to define this method only if CBson isn't loaded.
153
+ unless defined? CBson
154
+ def generate
155
+ oid = ''
156
+
157
+ # 4 bytes current time
158
+ time = Time.new.to_i
159
+ oid += [time].pack("N")
160
+
161
+ # 3 bytes machine
162
+ oid += Digest::MD5.digest(Socket.gethostname)[0, 3]
163
+
164
+ # 2 bytes pid
165
+ oid += [Process.pid % 0xFFFF].pack("n")
166
+
167
+ # 3 bytes inc
168
+ oid += [get_inc].pack("N")[1, 3]
169
+
170
+ oid.unpack("C12")
171
+ end
172
+ end
173
+
174
+ def get_inc
175
+ @@lock.synchronize do
176
+ @@index = (@@index + 1) % 0xFFFFFF
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,45 @@
1
+ # --
2
+ # Copyright (C) 2008-2010 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module BSON
18
+
19
+ # A Regexp that can hold on to extra options and ignore them. Mongo
20
+ # regexes may contain option characters beyond 'i', 'm', and 'x'. (Note
21
+ # that Mongo only uses those three, but that regexes coming from other
22
+ # languages may store different option characters.)
23
+ #
24
+ # Note that you do not have to use this class at all if you wish to
25
+ # store regular expressions in Mongo. The Mongo and Ruby regex option
26
+ # flags are the same. Storing regexes is discouraged, in any case.
27
+ #
28
+ # @deprecated
29
+ class RegexpOfHolding < Regexp
30
+
31
+ attr_accessor :extra_options_str
32
+
33
+ # @deprecated we're no longer supporting this.
34
+ # +str+ and +options+ are the same as Regexp. +extra_options_str+
35
+ # contains all the other flags that were in Mongo but we do not use or
36
+ # understand.
37
+ def initialize(str, options, extra_options_str)
38
+ warn "RegexpOfHolding is deprecated; the modifiers i, m, and x will be stored automatically as BSON." +
39
+ "If you're only storing the options i, m, and x, you can safely ignore this message."
40
+ super(str, options)
41
+ @extra_options_str = extra_options_str
42
+ end
43
+ end
44
+
45
+ end
@@ -1,7 +1,7 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
2
 
3
3
  module Mongo
4
- VERSION = "0.19.1"
4
+ VERSION = "0.19.2"
5
5
  end
6
6
 
7
7
  begin
@@ -21,8 +21,9 @@ begin
21
21
  end
22
22
 
23
23
  module Mongo
24
- ASCENDING = 1
24
+ ASCENDING = 1
25
25
  DESCENDING = -1
26
+ GEO2D = '2d'
26
27
 
27
28
  module Constants
28
29
  OP_REPLY = 1
@@ -48,6 +49,7 @@ require 'mongo/types/regexp_of_holding'
48
49
  require 'mongo/types/min_max_keys'
49
50
 
50
51
  require 'mongo/util/support'
52
+ require 'mongo/util/core_ext'
51
53
  require 'mongo/util/conversions'
52
54
  require 'mongo/util/server_version'
53
55
  require 'mongo/util/bson_ruby'
@@ -265,13 +265,13 @@ module Mongo
265
265
 
266
266
  if opts[:safe]
267
267
  @connection.send_message_with_safe_check(Mongo::Constants::OP_DELETE, message, @db.name,
268
- "db.#{@db.name}.remove(#{selector.inspect})")
268
+ "#{@db.name}['#{@name}'].remove(#{selector.inspect})")
269
269
  # the return value of send_message_with_safe_check isn't actually meaningful --
270
270
  # only the fact that it didn't raise an error is -- so just return true
271
271
  true
272
272
  else
273
273
  @connection.send_message(Mongo::Constants::OP_DELETE, message,
274
- "db.#{@db.name}.remove(#{selector.inspect})")
274
+ "#{@db.name}['#{@name}'].remove(#{selector.inspect})")
275
275
  end
276
276
  end
277
277
 
@@ -307,41 +307,82 @@ module Mongo
307
307
  message.put_array(BSON.serialize(document, false, true).to_a)
308
308
  if options[:safe]
309
309
  @connection.send_message_with_safe_check(Mongo::Constants::OP_UPDATE, message, @db.name,
310
- "db.#{@name}.update(#{selector.inspect}, #{document.inspect})")
310
+ "#{@db.name}['#{@name}'].update(#{selector.inspect}, #{document.inspect})")
311
311
  else
312
312
  @connection.send_message(Mongo::Constants::OP_UPDATE, message,
313
- "db.#{@name}.update(#{selector.inspect}, #{document.inspect})")
313
+ "#{@db.name}['#{@name}'].update(#{selector.inspect}, #{document.inspect})")
314
314
  end
315
315
  end
316
316
 
317
317
  # Create a new index.
318
318
  #
319
- # @param [String, Array] field_or_spec
319
+ # @param [String, Array] spec
320
320
  # should be either a single field name or an array of
321
- # [field name, direction] pairs. Directions should be specified as Mongo::ASCENDING or Mongo::DESCENDING.
321
+ # [field name, direction] pairs. Directions should be specified
322
+ # as Mongo::ASCENDING, Mongo::DESCENDING, or Mongo::GEO2D.
322
323
  #
323
- # @param [Boolean] unique if true, this index will enforce a uniqueness constraint.
324
+ # Note that geospatial indexing only works with versions of MongoDB >= 1.3.3+. Keep in mind, too,
325
+ # that in order to geo-index a given field, that field must reference either an array or a sub-object
326
+ # where the first two values represent x- and y-coordinates. Examples can be seen below.
327
+ #
328
+ # Also note that it is permissible to create compound indexes that include a geospatial index as
329
+ # long as the geospatial index comes first.
330
+ #
331
+ # @param [Boolean] unique if true, this index will enforce a uniqueness constraint. DEPRECATED. Future
332
+ # versions of this driver will specify the uniqueness constraint using a hash param.
333
+ #
334
+ # @option opts [Boolean] :unique (false) if true, this index will enforce a uniqueness constraint.
335
+ # @option opts [Boolean] :background (false) indicate that the index should be built in the background. This
336
+ # feature is only available in MongoDB >= 1.3.2.
337
+ # @option opts [Boolean] :dropDups If creating a unique index on a collection with pre-existing records,
338
+ # this option will keep the first document the database indexes and drop all subsequent with duplicate values.
339
+ # @option opts [Integer] :min specify the minimum longitude and latitude for a geo index.
340
+ # @option opts [Integer] :max specify the maximum longitude and latitude for a geo index.
341
+ #
342
+ # @example Creating a compound index:
343
+ # @posts.create_index([['subject', Mongo::ASCENDING], ['created_at', Mongo::DESCENDING]])
344
+ #
345
+ # @example Creating a geospatial index:
346
+ # @restaurants.create_index([['location', Mongo::GEO2D]])
347
+ #
348
+ # # Note that this will work only if 'location' represents x,y coordinates:
349
+ # {'location': [0, 50]}
350
+ # {'location': {'x' => 0, 'y' => 50}}
351
+ # {'location': {'latitude' => 0, 'longitude' => 50}}
352
+ #
353
+ # @example A geospatial index with alternate longitude and latitude:
354
+ # @restaurants.create_index([['location', Mongo::GEO2D]], :min => 500, :max => 500)
324
355
  #
325
356
  # @return [String] the name of the index created.
326
357
  #
327
358
  # @core indexes create_index-instance_method
328
- def create_index(field_or_spec, unique=false)
329
- field_h = OrderedHash.new
330
- if field_or_spec.is_a?(String) || field_or_spec.is_a?(Symbol)
331
- field_h[field_or_spec.to_s] = 1
359
+ def create_index(spec, opts={})
360
+ opts.assert_valid_keys(:min, :max, :background, :unique, :dropDups) if opts.is_a?(Hash)
361
+ field_spec = OrderedHash.new
362
+ if spec.is_a?(String) || spec.is_a?(Symbol)
363
+ field_spec[spec.to_s] = 1
364
+ elsif spec.is_a?(Array) && spec.all? {|field| field.is_a?(Array) }
365
+ spec.each { |f| field_spec[f[0].to_s] = f[1] }
332
366
  else
333
- field_or_spec.each { |f| field_h[f[0].to_s] = f[1] }
367
+ raise MongoArgumentError, "Invalid index specification #{spec.inspect}; " +
368
+ "should be either a string, symbol, or an array of arrays."
369
+ end
370
+
371
+ name = generate_index_name(field_spec)
372
+ if opts == true || opts == false
373
+ warn "For Collection#create_index, the method for specifying a unique index has changed." +
374
+ "Please pass :unique => true to the method instead."
334
375
  end
335
- name = generate_index_names(field_h)
336
376
  sel = {
337
377
  :name => name,
338
378
  :ns => "#{@db.name}.#{@name}",
339
- :key => field_h,
340
- :unique => unique }
379
+ :key => field_spec,
380
+ :unique => (opts == true ? true : false) }
381
+ sel.merge!(opts) if opts.is_a?(Hash)
341
382
  begin
342
- insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
383
+ response = insert_documents([sel], Mongo::DB::SYSTEM_INDEX_COLLECTION, false, true)
343
384
  rescue Mongo::OperationFailure
344
- raise Mongo::OperationFailure, "Failed to create index #{sel.inspect}."
385
+ raise Mongo::OperationFailure, "Failed to create index #{sel.inspect} with the following errors: #{response}"
345
386
  end
346
387
  name
347
388
  end
@@ -593,15 +634,15 @@ module Mongo
593
634
  documents.each { |doc| message.put_array(BSON.serialize(doc, check_keys, true).to_a) }
594
635
  if safe
595
636
  @connection.send_message_with_safe_check(Mongo::Constants::OP_INSERT, message, @db.name,
596
- "db.#{collection_name}.insert(#{documents.inspect})")
637
+ "#{@db.name}['#{collection_name}'].insert(#{documents.inspect})")
597
638
  else
598
639
  @connection.send_message(Mongo::Constants::OP_INSERT, message,
599
- "db.#{collection_name}.insert(#{documents.inspect})")
640
+ "#{@db.name}['#{collection_name}'].insert(#{documents.inspect})")
600
641
  end
601
642
  documents.collect { |o| o[:_id] || o['_id'] }
602
643
  end
603
644
 
604
- def generate_index_names(spec)
645
+ def generate_index_name(spec)
605
646
  indexes = []
606
647
  spec.each_pair do |field, direction|
607
648
  indexes.push("#{field}_#{direction}")