add new code type rather than doing hacks based on field name. use code_w_scope instead of code

This commit is contained in:
Mike Dirolf 2009-03-12 15:34:15 -04:00
parent d3594fe8b5
commit 0f546eb5c5
5 changed files with 87 additions and 13 deletions

View File

@ -16,6 +16,7 @@
require 'mongo/collection'
require 'mongo/message'
require 'mongo/types/code'
module XGen
module Mongo
@ -70,14 +71,16 @@ module XGen
self.fields = return_fields
end
# Set query selector hash. If sel is a string, it will be used as a
# Set query selector hash. If sel is Code/string, it will be used as a
# $where clause. (See Mongo docs for details.)
def selector=(sel)
@selector = case sel
when nil
{}
when String
when Code
{"$where" => sel}
when String
{"$where" => Code.new(sel)}
when Hash
sel
end

34
lib/mongo/types/code.rb Normal file
View File

@ -0,0 +1,34 @@
# --
# Copyright (C) 2008-2009 10gen Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ++
module XGen
module Mongo
module Driver
# JavaScript code to be evaluated by MongoDB
class Code < String
# Hash mapping identifiers to their values
attr_accessor :scope
def initialize(code, scope={})
super(code)
@scope = scope
end
end
end
end
end

View File

@ -95,9 +95,9 @@ class BSON
end
def serialize_key_value(k, v)
type = bson_type(v, k)
type = bson_type(v)
case type
when STRING, CODE, SYMBOL
when STRING, SYMBOL
serialize_string_element(@buf, k, v, type)
when NUMBER, NUMBER_INT
serialize_number_element(@buf, k, v, type)
@ -122,8 +122,7 @@ class BSON
when UNDEFINED
serialize_undefined_element(@buf, k)
when CODE_W_SCOPE
# TODO CODE_W_SCOPE unimplemented; may be removed
raise "unimplemented type #{type}"
serialize_code_w_scope(@buf, k, v)
else
raise "unhandled type #{type}"
end
@ -198,8 +197,8 @@ class BSON
key = deserialize_cstr(@buf)
doc[key] = deserialize_binary_data(@buf)
when CODE_W_SCOPE
# TODO CODE_W_SCOPE unimplemented; may be removed
raise "unimplemented type #{type}"
key = deserialize_cstr(@buf)
doc[key] = deserialize_code_w_scope_data(@buf)
when EOO
break
else
@ -280,6 +279,24 @@ class BSON
str
end
def deserialize_code_w_scope_data(buf)
buf.get_int
len = buf.get_int
code = buf.get(len)[0..-2]
if code.respond_to? "pack"
code = code.pack("C*")
end
if RUBY_VERSION >= '1.9'
code.force_encoding("utf-8")
end
scope_size = buf.get_int
buf.position -= 4
scope = BSON.new().deserialize(buf.get(scope_size))
Code.new(code, scope)
end
def deserialize_oid_data(buf)
ObjectID.new(buf.get(12))
end
@ -416,6 +433,23 @@ class BSON
buf.position = end_pos
end
def serialize_code_w_scope(buf, key, val)
buf.put(CODE_W_SCOPE)
self.class.serialize_cstr(buf, key)
# Make a hole for the length
len_pos = buf.position
buf.put_int(0)
buf.put_int(val.length + 1)
self.class.serialize_cstr(buf, val)
buf.put_array(BSON.new.serialize(val.scope).to_a)
end_pos = buf.position
buf.put_int(end_pos - len_pos, len_pos)
buf.position = end_pos
end
def deserialize_cstr(buf)
chars = ""
while true
@ -429,7 +463,7 @@ class BSON
chars
end
def bson_type(o, key)
def bson_type(o)
case o
when nil
NULL
@ -439,9 +473,10 @@ class BSON
NUMBER
when ByteBuffer
BINARY
when Code
CODE_W_SCOPE
when String
# magic awful stuff - the DB requires that a where clause is sent as CODE
key == "$where" ? CODE : STRING
STRING
when Array
ARRAY
when Regexp

View File

@ -42,8 +42,10 @@ class XMLToRuby
e.text.to_i
when 'number'
e.text.to_f
when 'string', 'code'
when 'string'
e.text.to_s
when 'code'
Code.new (e.text.to_s)
when 'binary'
bin = Binary.new
decoded = Base64.decode64(e.text.to_s)

View File

@ -21,7 +21,7 @@ class BSONTest < Test::Unit::TestCase
end
def test_code
doc = {'$where' => 'this.a.b < this.b'}
doc = {'$where' => Code.new('this.a.b < this.b')}
@b.serialize(doc)
assert_equal doc, @b.deserialize
end