1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
# frozen_string_literal: true
# rubocop:todo all
# Copyright (C) 2009-2020 MongoDB 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 BSON
# Represents a code with scope, which is a wrapper around javascript code
# with variable scope provided.
#
# @see http://bsonspec.org/#/specification
#
# @since 2.0.0
class CodeWithScope
include JSON
# A code with scope is type 0x0F in the BSON spec.
#
# @since 2.0.0
BSON_TYPE = ::String.new(15.chr, encoding: BINARY).freeze
# @!attribute javascript
# @return [ String ] The javascript code.
# @since 2.0.0
# @!attribute scope
# @return [ Hash ] The variable scope.
# @since 2.0.0
attr_reader :javascript, :scope
# Determine if this code with scope object is equal to another object.
#
# @example Check the code with scope equality.
# code_with_scope == other
#
# @param [ Object ] other The object to compare against.
#
# @return [ true, false ] If the objects are equal.
#
# @since 2.0.0
def ==(other)
return false unless other.is_a?(CodeWithScope)
javascript == other.javascript && scope == other.scope
end
# Return a representation of the object for use in
# application-level JSON serialization. Since BSON::CodeWithScope
# is used exclusively in BSON-related contexts, this
# method returns the canonical Extended JSON representation.
#
# @return [ Hash ] The extended json representation.
def as_json(*_args)
as_extended_json
end
# Converts this object to a representation directly serializable to
# Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
#
# @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
# (default is canonical extended JSON)
#
# @return [ Hash ] The extended json representation.
def as_extended_json(**options)
{ "$code" => javascript, "$scope" => scope.as_extended_json(**options) }
end
# Instantiate the new code with scope.
#
# @example Instantiate the code with scope.
# BSON::CodeWithScope.new("this.value = name", name: "sid")
#
# @param [ String ] javascript The javascript code.
# @param [ Hash ] scope The variable scope.
#
# @since 2.0.0
def initialize(javascript = "", scope = {})
@javascript = javascript
@scope = scope
end
# Encode the javascript code with scope.
#
# @example Encode the code with scope.
# code_with_scope.to_bson
#
# @return [ BSON::ByteBuffer ] The buffer with the encoded object.
#
# @see http://bsonspec.org/#/specification
#
# @since 2.0.0
def to_bson(buffer = ByteBuffer.new)
position = buffer.length
buffer.put_int32(0)
buffer.put_string(javascript)
scope.to_bson(buffer)
buffer.replace_int32(position, buffer.length - position)
end
# Deserialize a code with scope from BSON.
#
# @param [ ByteBuffer ] buffer The byte buffer.
#
# @option options [ nil | :bson ] :mode Decoding mode to use.
#
# @return [ TrueClass, FalseClass ] The decoded code with scope.
#
# @see http://bsonspec.org/#/specification
#
# @since 2.0.0
def self.from_bson(buffer, **options)
# Code with scope has a length (?) field which is not needed for
# decoding, but spec tests want this field validated.
start_position = buffer.read_position
length = buffer.get_int32
javascript = buffer.get_string
scope = if options.empty?
::Hash.from_bson(buffer)
else
::Hash.from_bson(buffer, **options)
end
read_bytes = buffer.read_position - start_position
if read_bytes != length
raise Error::BSONDecodeError, "CodeWithScope invalid: claimed length #{length}, actual length #{read_bytes}"
end
new(javascript, scope)
end
# Register this type when the module is loaded.
#
# @since 2.0.0
Registry.register(BSON_TYPE, self)
end
end
|