Support binary subtypes in Ruby driver. Bumped patch version number.
Binary type is now a subclass of ByteArray with an additional subtype value that defaults to 2. BSON special-cases subtype 2 to write out the extra length int.
This commit is contained in:
parent
b1ef64c81f
commit
28daeb6600
|
@ -14,21 +14,29 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ++
|
||||
|
||||
require 'mongo/util/byte_buffer'
|
||||
|
||||
module XGen
|
||||
module Mongo
|
||||
module Driver
|
||||
|
||||
# An array of binary bytes. The only reason this exists is so that the
|
||||
# BSON encoder will know to output the Mongo BINARY type.
|
||||
class Binary < String; end
|
||||
# An array of binary bytes with a Mongo subtype value.
|
||||
class Binary < ByteBuffer
|
||||
|
||||
SUBTYPE_BYTES = 0x02
|
||||
SUBTYPE_UUID = 0x03
|
||||
SUBTYPE_MD5 = 0x05
|
||||
SUBTYPE_USER_DEFINED = 0x80
|
||||
|
||||
# One of the SUBTYPE_* constants. Default is SUBTYPE_BYTES.
|
||||
attr_accessor :subtype
|
||||
|
||||
def initialize(initial_data=[], subtype=SUBTYPE_BYTES)
|
||||
super(initial_data)
|
||||
@subtype = subtype
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class String
|
||||
# Convert a string into a XGen::Mongo::Driver::Binary
|
||||
def to_mongo_binary
|
||||
XGen::Mongo::Driver::Binary.new(self)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,8 +46,6 @@ class BSON
|
|||
NUMBER_INT = 16
|
||||
MAXKEY = 127
|
||||
|
||||
BYTE_TYPE = 2
|
||||
|
||||
if RUBY_VERSION >= '1.9'
|
||||
def self.to_utf8(str)
|
||||
str.encode("utf-8")
|
||||
|
@ -266,13 +264,10 @@ class BSON
|
|||
end
|
||||
|
||||
def deserialize_binary_data(buf)
|
||||
buf.get_int # length + 4; ignored
|
||||
buf.get # byte type; ignored
|
||||
len = buf.get_int
|
||||
bytes = buf.get(len)
|
||||
str = ''
|
||||
bytes.each { |c| str << c.chr }
|
||||
str.to_mongo_binary
|
||||
type = buf.get
|
||||
len = buf.get_int if type == XGen::Mongo::Driver::Binary::SUBTYPE_BYTES
|
||||
XGen::Mongo::Driver::Binary.new(buf.get(len), type)
|
||||
end
|
||||
|
||||
def serialize_eoo_element(buf)
|
||||
|
@ -293,24 +288,19 @@ class BSON
|
|||
buf.put(BINARY)
|
||||
self.class.serialize_cstr(buf, key)
|
||||
|
||||
bytes = case val
|
||||
when ByteBuffer
|
||||
val.to_a
|
||||
else
|
||||
if RUBY_VERSION >= '1.9'
|
||||
val.bytes.to_a
|
||||
else
|
||||
a = []
|
||||
val.each_byte { |byte| a << byte }
|
||||
a
|
||||
end
|
||||
end
|
||||
|
||||
bytes = val.to_a
|
||||
num_bytes = bytes.length
|
||||
buf.put_int(num_bytes + 4)
|
||||
buf.put(BYTE_TYPE)
|
||||
buf.put_int(num_bytes)
|
||||
buf.put_array(bytes)
|
||||
subtype = val.respond_to?(:subtype) ? val.subtype : XGen::Mongo::Driver::Binary::SUBTYPE_BYTES
|
||||
if subtype == XGen::Mongo::Driver::Binary::SUBTYPE_BYTES
|
||||
buf.put_int(num_bytes + 4)
|
||||
buf.put(subtype)
|
||||
buf.put_int(num_bytes)
|
||||
buf.put_array(bytes)
|
||||
else
|
||||
buf.put_int(num_bytes)
|
||||
buf.put(subtype)
|
||||
buf.put_array(bytes)
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_undefined_element(buf, key)
|
||||
|
@ -420,7 +410,7 @@ class BSON
|
|||
NUMBER_INT
|
||||
when Numeric
|
||||
NUMBER
|
||||
when XGen::Mongo::Driver::Binary, ByteBuffer # must be before String
|
||||
when ByteBuffer
|
||||
BINARY
|
||||
when String
|
||||
# magic awful stuff - the DB requires that a where clause is sent as CODE
|
||||
|
|
|
@ -45,7 +45,10 @@ class XMLToRuby
|
|||
when 'string', 'code'
|
||||
e.text.to_s
|
||||
when 'binary'
|
||||
Base64.decode64(e.text.to_s).to_mongo_binary
|
||||
bin = Binary.new
|
||||
decoded = Base64.decode64(e.text.to_s)
|
||||
decoded.each_byte { |b| bin.put(b) }
|
||||
bin
|
||||
when 'symbol'
|
||||
e.text.to_s.intern
|
||||
when 'boolean'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Gem::Specification.new do |s|
|
||||
s.name = 'mongo'
|
||||
s.version = '0.4.4'
|
||||
s.version = '0.4.5'
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.summary = 'Simple pure-Ruby driver for the 10gen Mongo DB'
|
||||
s.description = 'A pure-Ruby driver for the 10gen Mongo DB. For more information about Mongo, see http://www.mongodb.org.'
|
||||
|
|
|
@ -113,25 +113,40 @@ class BSONTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_binary
|
||||
bin = 'binstring'.to_mongo_binary
|
||||
assert_kind_of Binary, bin
|
||||
bin = Binary.new
|
||||
'binstring'.each_byte { |b| bin.put(b) }
|
||||
|
||||
doc = {'bin' => bin}
|
||||
@b.serialize(doc)
|
||||
doc2 = @b.deserialize
|
||||
assert_equal 'binstring', doc2['bin']
|
||||
bin2 = doc2['bin']
|
||||
assert_kind_of Binary, bin2
|
||||
assert_equal 'binstring', bin2.to_s
|
||||
end
|
||||
|
||||
def test_binary_type
|
||||
bin = Binary.new([1, 2, 3, 4, 5], Binary::SUBTYPE_USER_DEFINED)
|
||||
|
||||
doc = {'bin' => bin}
|
||||
@b.serialize(doc)
|
||||
doc2 = @b.deserialize
|
||||
bin2 = doc2['bin']
|
||||
assert_kind_of Binary, bin2
|
||||
assert_equal [1, 2, 3, 4, 5], bin2.to_a
|
||||
assert_equal Binary::SUBTYPE_USER_DEFINED, bin2.subtype
|
||||
end
|
||||
|
||||
def test_binary_byte_buffer
|
||||
bb = ByteBuffer.new
|
||||
10.times { |i| bb.put(i) }
|
||||
5.times { |i| bb.put(i + 1) }
|
||||
|
||||
doc = {'bin' => bb}
|
||||
@b.serialize(doc)
|
||||
doc2 = @b.deserialize
|
||||
|
||||
doc2_bytes = []
|
||||
doc2['bin'].each_byte { |b| doc2_bytes << b }
|
||||
assert_equal bb.to_a, doc2_bytes
|
||||
bin2 = doc2['bin']
|
||||
assert_kind_of Binary, bin2
|
||||
assert_equal [1, 2, 3, 4, 5], bin2.to_a
|
||||
assert_equal Binary::SUBTYPE_BYTES, bin2.subtype
|
||||
end
|
||||
|
||||
def test_undefined
|
||||
|
|
Loading…
Reference in New Issue