bson 4.1.1 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +106 -7
- data/Rakefile +86 -43
- data/ext/bson/{native-endian.h → bson-endian.h} +14 -107
- data/ext/bson/bson-native.h +135 -0
- data/ext/bson/bytebuf.c +133 -0
- data/ext/bson/endian.c +117 -0
- data/ext/bson/extconf.rb +8 -3
- data/ext/bson/init.c +364 -0
- data/ext/bson/libbson-utf8.c +230 -0
- data/ext/bson/read.c +470 -0
- data/ext/bson/util.c +250 -0
- data/ext/bson/write.c +675 -0
- data/lib/bson/active_support.rb +19 -0
- data/lib/bson/array.rb +97 -30
- data/lib/bson/big_decimal.rb +77 -0
- data/lib/bson/binary.rb +510 -70
- data/lib/bson/boolean.rb +15 -4
- data/lib/bson/code.rb +25 -12
- data/lib/bson/code_with_scope.rb +41 -15
- data/lib/bson/config.rb +3 -28
- data/lib/bson/date.rb +16 -4
- data/lib/bson/date_time.rb +6 -4
- data/lib/bson/db_pointer.rb +110 -0
- data/lib/bson/dbref.rb +154 -0
- data/lib/bson/decimal128/builder.rb +456 -0
- data/lib/bson/decimal128.rb +272 -0
- data/lib/bson/document.rb +177 -7
- data/lib/bson/environment.rb +17 -2
- data/lib/bson/error/bson_decode_error.rb +11 -0
- data/lib/bson/error/ext_json_parse_error.rb +11 -0
- data/lib/bson/error/illegal_key.rb +23 -0
- data/lib/bson/error/invalid_binary_type.rb +37 -0
- data/lib/bson/error/invalid_dbref_argument.rb +12 -0
- data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
- data/lib/bson/error/invalid_decimal128_range.rb +27 -0
- data/lib/bson/error/invalid_decimal128_string.rb +26 -0
- data/lib/bson/error/invalid_key.rb +24 -0
- data/lib/bson/error/invalid_object_id.rb +11 -0
- data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
- data/lib/bson/error/unrepresentable_precision.rb +19 -0
- data/lib/bson/error/unserializable_class.rb +13 -0
- data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
- data/lib/bson/error/unsupported_type.rb +11 -0
- data/lib/bson/error.rb +22 -0
- data/lib/bson/ext_json.rb +389 -0
- data/lib/bson/false_class.rb +6 -4
- data/lib/bson/float.rb +43 -7
- data/lib/bson/hash.rb +152 -37
- data/lib/bson/int32.rb +104 -6
- data/lib/bson/int64.rb +111 -8
- data/lib/bson/integer.rb +43 -9
- data/lib/bson/json.rb +3 -1
- data/lib/bson/max_key.rb +21 -10
- data/lib/bson/min_key.rb +21 -10
- data/lib/bson/nil_class.rb +7 -3
- data/lib/bson/object.rb +25 -17
- data/lib/bson/object_id.rb +98 -113
- data/lib/bson/open_struct.rb +59 -0
- data/lib/bson/regexp.rb +129 -56
- data/lib/bson/registry.rb +7 -10
- data/lib/bson/specialized.rb +8 -4
- data/lib/bson/string.rb +12 -32
- data/lib/bson/symbol.rb +107 -11
- data/lib/bson/time.rb +68 -7
- data/lib/bson/time_with_zone.rb +67 -0
- data/lib/bson/timestamp.rb +50 -10
- data/lib/bson/true_class.rb +6 -4
- data/lib/bson/undefined.rb +28 -2
- data/lib/bson/vector.rb +44 -0
- data/lib/bson/version.rb +6 -14
- data/lib/bson.rb +22 -12
- data/spec/README.md +14 -0
- data/spec/bson/array_spec.rb +38 -62
- data/spec/bson/big_decimal_spec.rb +328 -0
- data/spec/bson/binary_spec.rb +199 -53
- data/spec/bson/binary_uuid_spec.rb +190 -0
- data/spec/bson/boolean_spec.rb +2 -1
- data/spec/bson/byte_buffer_read_spec.rb +198 -0
- data/spec/bson/byte_buffer_spec.rb +122 -381
- data/spec/bson/byte_buffer_write_spec.rb +855 -0
- data/spec/bson/code_spec.rb +6 -4
- data/spec/bson/code_with_scope_spec.rb +6 -4
- data/spec/bson/config_spec.rb +1 -35
- data/spec/bson/date_spec.rb +2 -1
- data/spec/bson/date_time_spec.rb +55 -1
- data/spec/bson/dbref_legacy_spec.rb +186 -0
- data/spec/bson/dbref_spec.rb +487 -0
- data/spec/bson/decimal128_spec.rb +1840 -0
- data/spec/bson/document_as_spec.rb +61 -0
- data/spec/bson/document_spec.rb +205 -32
- data/spec/bson/ext_json_parse_spec.rb +346 -0
- data/spec/bson/false_class_spec.rb +9 -1
- data/spec/bson/float_spec.rb +42 -1
- data/spec/bson/hash_as_spec.rb +58 -0
- data/spec/bson/hash_spec.rb +318 -66
- data/spec/bson/int32_spec.rb +248 -1
- data/spec/bson/int64_spec.rb +308 -1
- data/spec/bson/integer_spec.rb +61 -3
- data/spec/bson/json_spec.rb +2 -1
- data/spec/bson/max_key_spec.rb +6 -4
- data/spec/bson/min_key_spec.rb +6 -4
- data/spec/bson/nil_class_spec.rb +2 -1
- data/spec/bson/object_id_spec.rb +95 -5
- data/spec/bson/object_spec.rb +3 -2
- data/spec/bson/open_struct_spec.rb +87 -0
- data/spec/bson/raw_spec.rb +594 -0
- data/spec/bson/regexp_spec.rb +61 -8
- data/spec/bson/registry_spec.rb +3 -2
- data/spec/bson/string_spec.rb +26 -33
- data/spec/bson/symbol_raw_spec.rb +70 -0
- data/spec/bson/symbol_spec.rb +77 -20
- data/spec/bson/time_spec.rb +206 -2
- data/spec/bson/time_with_zone_spec.rb +69 -0
- data/spec/bson/timestamp_spec.rb +58 -2
- data/spec/bson/true_class_spec.rb +9 -1
- data/spec/bson/undefined_spec.rb +28 -1
- data/spec/bson/vector_spec.rb +33 -0
- data/spec/bson_spec.rb +2 -1
- data/spec/runners/binary_vector.rb +78 -0
- data/spec/runners/common_driver.rb +348 -0
- data/spec/runners/corpus.rb +191 -0
- data/spec/runners/corpus_legacy.rb +248 -0
- data/spec/shared/LICENSE +20 -0
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/bin/s3-copy +45 -0
- data/spec/shared/bin/s3-upload +69 -0
- data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
- data/spec/shared/lib/mrss/cluster_config.rb +231 -0
- data/spec/shared/lib/mrss/constraints.rb +378 -0
- data/spec/shared/lib/mrss/docker_runner.rb +298 -0
- data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
- data/spec/shared/lib/mrss/release/candidate.rb +281 -0
- data/spec/shared/lib/mrss/release/product_data.rb +144 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
- data/spec/shared/lib/mrss/session_registry.rb +69 -0
- data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
- data/spec/shared/lib/mrss/utils.rb +37 -0
- data/spec/shared/lib/tasks/candidate.rake +64 -0
- data/spec/shared/share/Dockerfile.erb +251 -0
- data/spec/shared/share/haproxy-1.conf +16 -0
- data/spec/shared/share/haproxy-2.conf +17 -0
- data/spec/shared/shlib/config.sh +27 -0
- data/spec/shared/shlib/distro.sh +84 -0
- data/spec/shared/shlib/server.sh +423 -0
- data/spec/shared/shlib/set_env.sh +110 -0
- data/spec/spec_helper.rb +61 -1
- data/spec/spec_tests/binary_vector_spec.rb +82 -0
- data/spec/spec_tests/common_driver_spec.rb +84 -0
- data/spec/spec_tests/corpus_legacy_spec.rb +72 -0
- data/spec/spec_tests/corpus_spec.rb +134 -0
- data/spec/spec_tests/data/binary_vector/README.md +61 -0
- data/spec/spec_tests/data/binary_vector/float32.json +65 -0
- data/spec/spec_tests/data/binary_vector/int8.json +57 -0
- data/spec/spec_tests/data/binary_vector/packed_bit.json +83 -0
- data/spec/spec_tests/data/corpus/README.md +15 -0
- data/spec/spec_tests/data/corpus/array.json +49 -0
- data/spec/spec_tests/data/corpus/binary.json +153 -0
- data/spec/spec_tests/data/corpus/boolean.json +27 -0
- data/spec/spec_tests/data/corpus/code.json +67 -0
- data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
- data/spec/spec_tests/data/corpus/datetime.json +42 -0
- data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
- data/spec/spec_tests/data/corpus/dbref.json +51 -0
- data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
- data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
- data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
- data/spec/spec_tests/data/corpus/decimal128-4.json +165 -0
- data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
- data/spec/spec_tests/data/corpus/decimal128-6.json +131 -0
- data/spec/spec_tests/data/corpus/decimal128-7.json +327 -0
- data/spec/spec_tests/data/corpus/document.json +60 -0
- data/spec/spec_tests/data/corpus/double.json +87 -0
- data/spec/spec_tests/data/corpus/int32.json +43 -0
- data/spec/spec_tests/data/corpus/int64.json +43 -0
- data/spec/spec_tests/data/corpus/maxkey.json +12 -0
- data/spec/spec_tests/data/corpus/minkey.json +12 -0
- data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
- data/spec/spec_tests/data/corpus/multi-type.json +11 -0
- data/spec/spec_tests/data/corpus/null.json +12 -0
- data/spec/spec_tests/data/corpus/oid.json +28 -0
- data/spec/spec_tests/data/corpus/regex.json +65 -0
- data/spec/spec_tests/data/corpus/string.json +72 -0
- data/spec/spec_tests/data/corpus/symbol.json +80 -0
- data/spec/spec_tests/data/corpus/timestamp.json +34 -0
- data/spec/spec_tests/data/corpus/top.json +262 -0
- data/spec/spec_tests/data/corpus/undefined.json +15 -0
- data/spec/spec_tests/data/corpus_legacy/array.json +49 -0
- data/spec/spec_tests/data/corpus_legacy/binary.json +69 -0
- data/spec/spec_tests/data/corpus_legacy/boolean.json +27 -0
- data/spec/spec_tests/data/corpus_legacy/code.json +67 -0
- data/spec/spec_tests/data/corpus_legacy/code_w_scope.json +78 -0
- data/spec/spec_tests/data/corpus_legacy/document.json +36 -0
- data/spec/spec_tests/data/corpus_legacy/double.json +69 -0
- data/spec/spec_tests/data/corpus_legacy/failures/datetime.json +31 -0
- data/spec/spec_tests/data/corpus_legacy/failures/dbpointer.json +42 -0
- data/spec/spec_tests/data/corpus_legacy/failures/int64.json +38 -0
- data/spec/spec_tests/data/corpus_legacy/failures/symbol.json +62 -0
- data/spec/spec_tests/data/corpus_legacy/int32.json +38 -0
- data/spec/spec_tests/data/corpus_legacy/maxkey.json +12 -0
- data/spec/spec_tests/data/corpus_legacy/minkey.json +12 -0
- data/spec/spec_tests/data/corpus_legacy/null.json +12 -0
- data/spec/spec_tests/data/corpus_legacy/oid.json +28 -0
- data/spec/spec_tests/data/corpus_legacy/regex.json +37 -0
- data/spec/spec_tests/data/corpus_legacy/string.json +67 -0
- data/spec/spec_tests/data/corpus_legacy/timestamp.json +18 -0
- data/spec/spec_tests/data/corpus_legacy/top.json +62 -0
- data/spec/spec_tests/data/corpus_legacy/undefined.json +13 -0
- data/spec/spec_tests/data/decimal128/decimal128-1.json +363 -0
- data/spec/spec_tests/data/decimal128/decimal128-2.json +793 -0
- data/spec/spec_tests/data/decimal128/decimal128-3.json +1771 -0
- data/spec/spec_tests/data/decimal128/decimal128-4.json +165 -0
- data/spec/spec_tests/data/decimal128/decimal128-5.json +402 -0
- data/spec/spec_tests/data/decimal128/decimal128-6.json +131 -0
- data/spec/spec_tests/data/decimal128/decimal128-7.json +327 -0
- data/spec/support/shared_examples.rb +32 -11
- data/spec/support/spec_config.rb +17 -0
- data/spec/support/utils.rb +58 -0
- metadata +284 -45
- checksums.yaml.gz.sig +0 -3
- data/ext/bson/native.c +0 -722
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
3
|
+
# Copyright (C) 2016-2020 MongoDB Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require 'bigdecimal'
|
|
18
|
+
require 'bson/decimal128/builder'
|
|
19
|
+
|
|
20
|
+
module BSON
|
|
21
|
+
|
|
22
|
+
class Decimal128
|
|
23
|
+
include JSON
|
|
24
|
+
include Comparable
|
|
25
|
+
|
|
26
|
+
# A Decimal128 is type 0x13 in the BSON spec.
|
|
27
|
+
#
|
|
28
|
+
# @since 4.2.0
|
|
29
|
+
BSON_TYPE = ::String.new(19.chr, encoding: BINARY).freeze
|
|
30
|
+
|
|
31
|
+
# Exponent offset.
|
|
32
|
+
#
|
|
33
|
+
# @since 4.2.0
|
|
34
|
+
EXPONENT_OFFSET = 6176
|
|
35
|
+
|
|
36
|
+
# Minimum exponent.
|
|
37
|
+
#
|
|
38
|
+
# @since 4.2.0
|
|
39
|
+
MIN_EXPONENT = -6176
|
|
40
|
+
|
|
41
|
+
# Maximum exponent.
|
|
42
|
+
#
|
|
43
|
+
# @since 4.2.0
|
|
44
|
+
MAX_EXPONENT = 6111
|
|
45
|
+
|
|
46
|
+
# Maximum digits of precision.
|
|
47
|
+
#
|
|
48
|
+
# @since 4.2.0
|
|
49
|
+
MAX_DIGITS_OF_PRECISION = 34
|
|
50
|
+
|
|
51
|
+
# Key for this type when converted to extended json.
|
|
52
|
+
#
|
|
53
|
+
# @since 4.2.0
|
|
54
|
+
EXTENDED_JSON_KEY = "$numberDecimal"
|
|
55
|
+
|
|
56
|
+
# The native type to which this object can be converted.
|
|
57
|
+
#
|
|
58
|
+
# @since 4.2.0
|
|
59
|
+
NATIVE_TYPE = BigDecimal
|
|
60
|
+
|
|
61
|
+
# Return a string representation of the Decimal128 use in standard
|
|
62
|
+
# application-level JSON serialization. Returns nil for non-real
|
|
63
|
+
# numbers such as NaN and Infinity to be compatible with ActiveSupport.
|
|
64
|
+
# This method is intentionally different from #as_extended_json.
|
|
65
|
+
#
|
|
66
|
+
# @example Get the Decimal128 as a JSON-serializable object.
|
|
67
|
+
# decimal.as_json
|
|
68
|
+
#
|
|
69
|
+
# @return [ String | nil ] The decimal128 as a String or nil for non-representable numbers.
|
|
70
|
+
def as_json(*args)
|
|
71
|
+
value = to_s
|
|
72
|
+
value unless %w[NaN Infinity -Infinity].include?(value)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Converts this object to a representation directly serializable to
|
|
76
|
+
# Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
|
|
77
|
+
#
|
|
78
|
+
# @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
|
|
79
|
+
# (default is canonical extended JSON)
|
|
80
|
+
#
|
|
81
|
+
# @return [ Hash ] The extended json representation.
|
|
82
|
+
def as_extended_json(**_options)
|
|
83
|
+
{ EXTENDED_JSON_KEY => to_s }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Check equality of the decimal128 object with another object.
|
|
87
|
+
#
|
|
88
|
+
# @example Check if the decimal128 object is equal to the other.
|
|
89
|
+
# decimal == other
|
|
90
|
+
#
|
|
91
|
+
# @param [ Object ] other The object to check against.
|
|
92
|
+
#
|
|
93
|
+
# @return [ true, false ] If the objects are equal.
|
|
94
|
+
#
|
|
95
|
+
# @since 4.2.0
|
|
96
|
+
def ==(other)
|
|
97
|
+
return false unless other.is_a?(Decimal128)
|
|
98
|
+
@high == other.instance_variable_get(:@high) &&
|
|
99
|
+
@low == other.instance_variable_get(:@low)
|
|
100
|
+
end
|
|
101
|
+
alias :eql? :==
|
|
102
|
+
|
|
103
|
+
def <=>(other)
|
|
104
|
+
to_d <=> case other
|
|
105
|
+
when Decimal128
|
|
106
|
+
other.to_d
|
|
107
|
+
else
|
|
108
|
+
other
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Create a new Decimal128 from a string or a BigDecimal instance.
|
|
113
|
+
#
|
|
114
|
+
# @example Create a Decimal128 from a BigDecimal.
|
|
115
|
+
# Decimal128.new(big_decimal)
|
|
116
|
+
#
|
|
117
|
+
# @param [ String, BigDecimal ] object The BigDecimal or String to use for
|
|
118
|
+
# instantiating a Decimal128.
|
|
119
|
+
#
|
|
120
|
+
# @raise [ BSON::Error::InvalidDecimal128Argument ] When argument is not a String or BigDecimal.
|
|
121
|
+
#
|
|
122
|
+
# @since 4.2.0
|
|
123
|
+
def initialize(object)
|
|
124
|
+
if object.is_a?(String)
|
|
125
|
+
set_bits(*Builder::FromString.new(object).bits)
|
|
126
|
+
elsif object.is_a?(BigDecimal)
|
|
127
|
+
set_bits(*Builder::FromBigDecimal.new(object).bits)
|
|
128
|
+
else
|
|
129
|
+
raise Error::InvalidDecimal128Argument.new
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Get the BSON type for Decimal128.
|
|
134
|
+
def bson_type
|
|
135
|
+
BSON_TYPE
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Get the decimal128 as its raw BSON data.
|
|
139
|
+
#
|
|
140
|
+
# @example Get the raw bson bytes in a buffer.
|
|
141
|
+
# decimal.to_bson
|
|
142
|
+
#
|
|
143
|
+
# @return [ BSON::ByteBuffer ] The buffer with the encoded object.
|
|
144
|
+
#
|
|
145
|
+
# @see http://bsonspec.org/#/specification
|
|
146
|
+
#
|
|
147
|
+
# @since 4.2.0
|
|
148
|
+
def to_bson(buffer = ByteBuffer.new)
|
|
149
|
+
buffer.put_decimal128(@low, @high)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Get the hash value for the decimal128.
|
|
153
|
+
#
|
|
154
|
+
# @example Get the hash value.
|
|
155
|
+
# decimal.hash
|
|
156
|
+
#
|
|
157
|
+
# @return [ Integer ] The hash value.
|
|
158
|
+
#
|
|
159
|
+
# @since 4.2.0
|
|
160
|
+
def hash
|
|
161
|
+
num = @high << 64
|
|
162
|
+
num |= @low
|
|
163
|
+
num.hash
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Get a nice string for use with object inspection.
|
|
167
|
+
#
|
|
168
|
+
# @example Inspect the decimal128 object.
|
|
169
|
+
# decimal128.inspect
|
|
170
|
+
#
|
|
171
|
+
# @return [ String ] The decimal as a string.
|
|
172
|
+
#
|
|
173
|
+
# @since 4.2.0
|
|
174
|
+
def inspect
|
|
175
|
+
"BSON::Decimal128('#{to_s}')"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Get the string representation of the decimal128.
|
|
179
|
+
#
|
|
180
|
+
# @example Get the decimal128 as a string.
|
|
181
|
+
# decimal128.to_s
|
|
182
|
+
#
|
|
183
|
+
# @return [ String ] The decimal128 as a string.
|
|
184
|
+
#
|
|
185
|
+
# @since 4.2.0
|
|
186
|
+
def to_s
|
|
187
|
+
@string ||= Builder::ToString.new(self).string
|
|
188
|
+
end
|
|
189
|
+
alias :to_str :to_s
|
|
190
|
+
|
|
191
|
+
# Get a Ruby BigDecimal object corresponding to this Decimal128.
|
|
192
|
+
# Note that, when converting to a Ruby BigDecimal, non-zero significant digits
|
|
193
|
+
# are preserved but trailing zeroes may be lost.
|
|
194
|
+
# See the following example:
|
|
195
|
+
#
|
|
196
|
+
# @example
|
|
197
|
+
# decimal128 = BSON::Decimal128.new("0.200")
|
|
198
|
+
# => BSON::Decimal128('0.200')
|
|
199
|
+
# big_decimal = decimal128.to_d
|
|
200
|
+
# => #<BigDecimal:7fc619c95388,'0.2E0',9(18)>
|
|
201
|
+
# big_decimal.to_s
|
|
202
|
+
# => "0.2E0"
|
|
203
|
+
#
|
|
204
|
+
# Note that the the BSON::Decimal128 object can represent -NaN, sNaN,
|
|
205
|
+
# and -sNaN while Ruby's BigDecimal cannot.
|
|
206
|
+
#
|
|
207
|
+
# @return [ BigDecimal ] The decimal as a BigDecimal.
|
|
208
|
+
def to_d
|
|
209
|
+
@big_decimal ||= BigDecimal(to_s)
|
|
210
|
+
end
|
|
211
|
+
alias :to_big_decimal :to_d
|
|
212
|
+
|
|
213
|
+
private
|
|
214
|
+
|
|
215
|
+
def set_bits(low, high)
|
|
216
|
+
@low = low
|
|
217
|
+
@high = high
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
class << self
|
|
221
|
+
|
|
222
|
+
# Deserialize the decimal128 from raw BSON bytes.
|
|
223
|
+
#
|
|
224
|
+
# @example Get the decimal128 from BSON.
|
|
225
|
+
# Decimal128.from_bson(bson)
|
|
226
|
+
#
|
|
227
|
+
# @param [ ByteBuffer ] buffer The byte buffer.
|
|
228
|
+
#
|
|
229
|
+
# @option options [ nil | :bson ] :mode Decoding mode to use.
|
|
230
|
+
#
|
|
231
|
+
# @return [ BSON::Decimal128 ] The decimal object.
|
|
232
|
+
#
|
|
233
|
+
# @since 4.2.0
|
|
234
|
+
def from_bson(buffer, **options)
|
|
235
|
+
from_bits(*buffer.get_decimal128_bytes.unpack('Q<*'))
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Instantiate a Decimal128 from a string.
|
|
239
|
+
#
|
|
240
|
+
# @example Create a Decimal128 from a string.
|
|
241
|
+
# BSON::Decimal128.from_string("1.05E+3")
|
|
242
|
+
#
|
|
243
|
+
# @param [ String ] string The string to parse.
|
|
244
|
+
#
|
|
245
|
+
# @raise [ BSON::Error:InvalidDecimal128String ] If the provided string is invalid.
|
|
246
|
+
#
|
|
247
|
+
# @return [ BSON::Decimal128 ] The new decimal128.
|
|
248
|
+
#
|
|
249
|
+
# @since 4.2.0
|
|
250
|
+
def from_string(string)
|
|
251
|
+
from_bits(*Builder::FromString.new(string).bits)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Instantiate a Decimal128 from high and low bits.
|
|
255
|
+
#
|
|
256
|
+
# @example Create a Decimal128 from high and low bits.
|
|
257
|
+
# BSON::Decimal128.from_bits(high, low)
|
|
258
|
+
#
|
|
259
|
+
# @param [ Integer ] high The high order bits.
|
|
260
|
+
# @param [ Integer ] low The low order bits.
|
|
261
|
+
#
|
|
262
|
+
# @return [ BSON::Decimal128 ] The new decimal128.
|
|
263
|
+
#
|
|
264
|
+
# @since 4.2.0
|
|
265
|
+
def from_bits(low, high)
|
|
266
|
+
decimal = allocate
|
|
267
|
+
decimal.send(:set_bits, low, high)
|
|
268
|
+
decimal
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
data/lib/bson/document.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
3
|
+
# Copyright (C) 2009-2020 MongoDB Inc.
|
|
2
4
|
#
|
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
6
|
# you may not use this file except in compliance with the License.
|
|
@@ -35,8 +37,43 @@ module BSON
|
|
|
35
37
|
class Document < ::Hash
|
|
36
38
|
|
|
37
39
|
# Get a value from the document for the provided key. Can use string or
|
|
38
|
-
# symbol access,
|
|
39
|
-
#
|
|
40
|
+
# symbol access, with string access being the faster of the two.
|
|
41
|
+
#
|
|
42
|
+
# @overload fetch(key)
|
|
43
|
+
# Returns a value from the hash for the given key. If the key does
|
|
44
|
+
# not exist, raises KeyError exception.
|
|
45
|
+
#
|
|
46
|
+
# @overload fetch(key, default)
|
|
47
|
+
# Returns a value from the hash for the given key. If the key does not
|
|
48
|
+
# exist, returns *default*.
|
|
49
|
+
#
|
|
50
|
+
# @overload fetch(key, &block)
|
|
51
|
+
# Returns a value from the hash for the given key. If the key does not
|
|
52
|
+
# exist, returns the value of the block called with the key.
|
|
53
|
+
#
|
|
54
|
+
# @example Get an element for the key.
|
|
55
|
+
# document.fetch("field")
|
|
56
|
+
#
|
|
57
|
+
# @example Get an element for the key by symbol with a default.
|
|
58
|
+
# document.fetch(:field, 'foo')
|
|
59
|
+
#
|
|
60
|
+
# @example Get an element for the key by symbol with a block default.
|
|
61
|
+
# document.fetch(:field) { |key| key.upcase }
|
|
62
|
+
#
|
|
63
|
+
# @param [ String, Symbol ] key The key to look up.
|
|
64
|
+
# @param [ Object ] default Returned value if key does not exist.
|
|
65
|
+
# @yield [key] Block returning default value for the given key.
|
|
66
|
+
#
|
|
67
|
+
# @return [ Object ] The found value. Raises KeyError if none found.
|
|
68
|
+
#
|
|
69
|
+
# @since 4.4.0
|
|
70
|
+
def fetch(key, *args, &block)
|
|
71
|
+
key = convert_key(key)
|
|
72
|
+
super(key, *args, &block)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Get a value from the document for the provided key. Can use string or
|
|
76
|
+
# symbol access, with string access being the faster of the two.
|
|
40
77
|
#
|
|
41
78
|
# @example Get an element for the key.
|
|
42
79
|
# document["field"]
|
|
@@ -44,7 +81,7 @@ module BSON
|
|
|
44
81
|
# @example Get an element for the key by symbol.
|
|
45
82
|
# document[:field]
|
|
46
83
|
#
|
|
47
|
-
# @param [ String, Symbol ] key The key to
|
|
84
|
+
# @param [ String, Symbol ] key The key to look up.
|
|
48
85
|
#
|
|
49
86
|
# @return [ Object ] The found value, or nil if none found.
|
|
50
87
|
#
|
|
@@ -53,7 +90,49 @@ module BSON
|
|
|
53
90
|
super(convert_key(key))
|
|
54
91
|
end
|
|
55
92
|
|
|
56
|
-
#
|
|
93
|
+
# Stores a key-value pair in the current document.
|
|
94
|
+
#
|
|
95
|
+
# Since BSON documents provide deep indifferent access (both strings and
|
|
96
|
+
# symbols are accepted as keys, recursively), the value may be converted
|
|
97
|
+
# to facilitate indifferent access. This conversion is performed for
|
|
98
|
+
# built-in Array and Hash classes, and other classes can override
|
|
99
|
+
# +to_bson_normalized_value+ method to provide custom conversion logic.
|
|
100
|
+
# For example:
|
|
101
|
+
#
|
|
102
|
+
# doc = BSON::Document.new
|
|
103
|
+
# doc[:a] = {b: {c: 'd'}}
|
|
104
|
+
# doc['a']['b']['c']
|
|
105
|
+
# # => "d"
|
|
106
|
+
#
|
|
107
|
+
# Note that due to this conversion, the object that is stored in the
|
|
108
|
+
# receiver Document may be different from the object supplied as the
|
|
109
|
+
# right hand side of the assignment. In Ruby, the result of assignment
|
|
110
|
+
# is the right hand side, not the return value of []= method.
|
|
111
|
+
# Because of this, modifying the result of assignment generally does not
|
|
112
|
+
# work as intended:
|
|
113
|
+
#
|
|
114
|
+
# doc = BSON::Document.new
|
|
115
|
+
# foo = (doc[:a] = {b: {c: 'd'}})
|
|
116
|
+
# # foo is original Hash with symbol keys
|
|
117
|
+
# foo['test'] = 'test'
|
|
118
|
+
# # doc is not modified
|
|
119
|
+
# doc
|
|
120
|
+
# # => {"a"=>{"b"=>{"c"=>"d"}}}
|
|
121
|
+
#
|
|
122
|
+
# This behavior can be encountered when defaulting document contents with
|
|
123
|
+
# []= in a method, such as:
|
|
124
|
+
#
|
|
125
|
+
# def foo
|
|
126
|
+
# # @doc is a BSON::Document
|
|
127
|
+
# @doc[:foo] ||= calculation
|
|
128
|
+
# end
|
|
129
|
+
#
|
|
130
|
+
# The above method should be written as follows to allow chaining:
|
|
131
|
+
#
|
|
132
|
+
# def foo
|
|
133
|
+
# # @doc is a BSON::Document
|
|
134
|
+
# @doc[:foo] ||= calculation and @doc[:foo]
|
|
135
|
+
# end
|
|
57
136
|
#
|
|
58
137
|
# @example Set a value on the document.
|
|
59
138
|
# document[:test] = "value"
|
|
@@ -144,7 +223,7 @@ module BSON
|
|
|
144
223
|
#
|
|
145
224
|
# @param [ BSON::Document, Hash ] other The document/hash to merge with.
|
|
146
225
|
#
|
|
147
|
-
# @
|
|
226
|
+
# @return [ BSON::Document ] The result of the merge.
|
|
148
227
|
#
|
|
149
228
|
# @since 3.0.0
|
|
150
229
|
def merge(other, &block)
|
|
@@ -159,7 +238,7 @@ module BSON
|
|
|
159
238
|
#
|
|
160
239
|
# @param [ BSON::Document, Hash ] other The document/hash to merge with.
|
|
161
240
|
#
|
|
162
|
-
# @
|
|
241
|
+
# @return [ BSON::Document ] The result of the merge.
|
|
163
242
|
#
|
|
164
243
|
# @since 3.0.0
|
|
165
244
|
def merge!(other)
|
|
@@ -172,6 +251,97 @@ module BSON
|
|
|
172
251
|
|
|
173
252
|
alias :update :merge!
|
|
174
253
|
|
|
254
|
+
if instance_methods.include?(:dig)
|
|
255
|
+
# Retrieves the value object corresponding to the each key objects repeatedly.
|
|
256
|
+
# Will normalize symbol keys into strings.
|
|
257
|
+
#
|
|
258
|
+
# @example Get value from nested sub-documents, handling missing levels.
|
|
259
|
+
# document # => { :key1 => { "key2" => "value"}}
|
|
260
|
+
# document.dig(:key1, :key2) # => "value"
|
|
261
|
+
# document.dig("key1", "key2") # => "value"
|
|
262
|
+
# document.dig("foo", "key2") # => nil
|
|
263
|
+
#
|
|
264
|
+
# @param [ Array<String, Symbol> ] *keys Keys, which constitute a "path" to the nested value.
|
|
265
|
+
#
|
|
266
|
+
# @return [ Object, NilClass ] The requested value or nil.
|
|
267
|
+
#
|
|
268
|
+
# @since 3.0.0
|
|
269
|
+
def dig(*keys)
|
|
270
|
+
super(*keys.map{|key| convert_key(key)})
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Slices a document to include only the given keys.
|
|
275
|
+
# Will normalize symbol keys into strings.
|
|
276
|
+
# (this method is backported from ActiveSupport::Hash)
|
|
277
|
+
#
|
|
278
|
+
# @example Get a document/hash with only the `name` and `age` fields present
|
|
279
|
+
# document # => { _id: <ObjectId>, :name => "John", :age => 30, :location => "Earth" }
|
|
280
|
+
# document.slice(:name, 'age') # => { "name": "John", "age" => 30 }
|
|
281
|
+
# document.slice('name') # => { "name" => "John" }
|
|
282
|
+
# document.slice(:foo) # => {}
|
|
283
|
+
#
|
|
284
|
+
# @param [ Array<String, Symbol> ] *keys Keys, that will be kept in the resulting document
|
|
285
|
+
#
|
|
286
|
+
# @return [ BSON::Document ] The document with only the selected keys
|
|
287
|
+
#
|
|
288
|
+
# @since 4.3.1
|
|
289
|
+
def slice(*keys)
|
|
290
|
+
keys.each_with_object(self.class.new) do |key, hash|
|
|
291
|
+
if key?(key)
|
|
292
|
+
hash[key] = self[key]
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Returns a new document consisting of the current document minus the
|
|
298
|
+
# specified keys.
|
|
299
|
+
#
|
|
300
|
+
# The keys to be removed can be specified as either strings or symbols.
|
|
301
|
+
#
|
|
302
|
+
# @example Get a document/hash with only the `name` and `age` fields removed
|
|
303
|
+
# document # => { _id: <ObjectId>, :name => 'John', :age => 30, :location => 'Earth' }
|
|
304
|
+
# document.except(:name, 'age') # => { _id: <ObjectId>, location: 'Earth' }
|
|
305
|
+
#
|
|
306
|
+
# @param [ Array<String, Symbol> ] *keys Keys, that will be removed in the resulting document
|
|
307
|
+
#
|
|
308
|
+
# @return [ BSON::Document ] The document with the specified keys removed.
|
|
309
|
+
#
|
|
310
|
+
# @note This method is always defined, even if Hash already contains a
|
|
311
|
+
# definition of #except, because ActiveSupport unconditionally defines
|
|
312
|
+
# its version of #except which doesn't work for BSON::Document which
|
|
313
|
+
# causes problems if ActiveSupport is loaded after bson-ruby is.
|
|
314
|
+
def except(*keys)
|
|
315
|
+
copy = dup
|
|
316
|
+
keys.each {|key| copy.delete(key)}
|
|
317
|
+
copy
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def symbolize_keys!
|
|
321
|
+
raise ArgumentError, 'symbolize_keys! is not supported on BSON::Document instances. Please convert the document to hash first (using #to_h), then call #symbolize_keys! on the Hash instance'
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def deep_symbolize_keys!
|
|
325
|
+
warn <<~WARN
|
|
326
|
+
[DEPRECATION] `deep_symbolize_keys!` is not supported on BSON::Document instances.
|
|
327
|
+
Please convert the document to a Hash first (using `#to_h`), then call `#deep_symbolize_keys!` on the Hash.
|
|
328
|
+
This will raise an error starting with the v6.0.0 release.
|
|
329
|
+
WARN
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# Override the Hash implementation of to_bson_normalized_value.
|
|
333
|
+
#
|
|
334
|
+
# BSON::Document is already of the correct type and already provides
|
|
335
|
+
# indifferent access to keys, hence no further conversions are necessary.
|
|
336
|
+
#
|
|
337
|
+
# Attempting to perform Hash's conversion on Document instances converts
|
|
338
|
+
# DBRefs to Documents which is wrong.
|
|
339
|
+
#
|
|
340
|
+
# @return [ BSON::Document ] The normalized hash.
|
|
341
|
+
def to_bson_normalized_value
|
|
342
|
+
self
|
|
343
|
+
end
|
|
344
|
+
|
|
175
345
|
private
|
|
176
346
|
|
|
177
347
|
def convert_key(key)
|
data/lib/bson/environment.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
3
|
+
# Copyright (C) 2009-2020 MongoDB Inc.
|
|
2
4
|
#
|
|
3
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
6
|
# you may not use this file except in compliance with the License.
|
|
@@ -30,7 +32,20 @@ module BSON
|
|
|
30
32
|
#
|
|
31
33
|
# @since 2.0.0
|
|
32
34
|
def jruby?
|
|
33
|
-
defined?(JRUBY_VERSION)
|
|
35
|
+
@jruby ||= defined?(JRUBY_VERSION)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Determine if we are using Ruby version 1.9.
|
|
39
|
+
#
|
|
40
|
+
# @example Are we running with Ruby version 1.9?
|
|
41
|
+
# Environment.ruby_1_9?
|
|
42
|
+
#
|
|
43
|
+
# @return [ true, false ] If the Ruby version is 1.9.
|
|
44
|
+
#
|
|
45
|
+
# @since 4.2.0
|
|
46
|
+
# @deprecated
|
|
47
|
+
def ruby_1_9?
|
|
48
|
+
@ruby_1_9 ||= RUBY_VERSION < '2.0.0'
|
|
34
49
|
end
|
|
35
50
|
end
|
|
36
51
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
3
|
+
|
|
4
|
+
module BSON
|
|
5
|
+
class Error
|
|
6
|
+
|
|
7
|
+
# Raised when validating keys and a key is illegal in MongoDB
|
|
8
|
+
class IllegalKey < Error
|
|
9
|
+
|
|
10
|
+
# Instantiate the exception.
|
|
11
|
+
#
|
|
12
|
+
# @example Instantiate the exception.
|
|
13
|
+
# BSON::Error::IllegalKey.new(string)
|
|
14
|
+
#
|
|
15
|
+
# @param [ String ] string The illegal string.
|
|
16
|
+
#
|
|
17
|
+
# @api private
|
|
18
|
+
def initialize(string)
|
|
19
|
+
super("'#{string}' is an illegal key in MongoDB. Keys may not start with '$' or contain a '.'.")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
3
|
+
|
|
4
|
+
module BSON
|
|
5
|
+
class Error
|
|
6
|
+
|
|
7
|
+
# Raised when providing an invalid type to the Binary.
|
|
8
|
+
class InvalidBinaryType < Error
|
|
9
|
+
|
|
10
|
+
# @return [ Object ] The invalid type.
|
|
11
|
+
attr_reader :type
|
|
12
|
+
|
|
13
|
+
# Instantiate the new error.
|
|
14
|
+
#
|
|
15
|
+
# @example Instantiate the error.
|
|
16
|
+
# InvalidBinaryType.new(:error)
|
|
17
|
+
#
|
|
18
|
+
# @param [ Object ] type The invalid type.
|
|
19
|
+
#
|
|
20
|
+
# @api private
|
|
21
|
+
def initialize(type)
|
|
22
|
+
@type = type
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get the custom error message for the exception.
|
|
26
|
+
#
|
|
27
|
+
# @example Get the message.
|
|
28
|
+
# error.message
|
|
29
|
+
#
|
|
30
|
+
# @return [ String ] The error message.
|
|
31
|
+
def message
|
|
32
|
+
"#{type.inspect} is not a valid binary type. " +
|
|
33
|
+
"Please use one of #{BSON::Binary::SUBTYPES.keys.map(&:inspect).join(", ")}."
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
3
|
+
|
|
4
|
+
module BSON
|
|
5
|
+
class Error
|
|
6
|
+
|
|
7
|
+
# Raised when trying to create a Decimal128 from an object that is neither a String nor a BigDecimal.
|
|
8
|
+
class InvalidDecimal128Argument < Error
|
|
9
|
+
|
|
10
|
+
# The custom error message for this error.
|
|
11
|
+
MESSAGE = 'A Decimal128 can only be created from a String or BigDecimal.'
|
|
12
|
+
|
|
13
|
+
# Get the custom error message for the exception.
|
|
14
|
+
#
|
|
15
|
+
# @example Get the message.
|
|
16
|
+
# error.message
|
|
17
|
+
#
|
|
18
|
+
# @return [ String ] The error message.
|
|
19
|
+
def message
|
|
20
|
+
MESSAGE
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rubocop:todo all
|
|
3
|
+
|
|
4
|
+
module BSON
|
|
5
|
+
class Error
|
|
6
|
+
|
|
7
|
+
# Raised when the exponent is outside the valid range.
|
|
8
|
+
class InvalidDecimal128Range < Error
|
|
9
|
+
|
|
10
|
+
# The custom error message for this error.
|
|
11
|
+
#
|
|
12
|
+
# @deprecated
|
|
13
|
+
MESSAGE = 'Value out of range for Decimal128 representation.'
|
|
14
|
+
|
|
15
|
+
# Get the custom error message for the exception.
|
|
16
|
+
#
|
|
17
|
+
# @example Get the message.
|
|
18
|
+
# error.message
|
|
19
|
+
#
|
|
20
|
+
# @return [ String ] The error message.
|
|
21
|
+
def message
|
|
22
|
+
MESSAGE
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|