bson 4.2.2 → 4.12.1

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.
Files changed (169) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +25 -7
  5. data/Rakefile +16 -9
  6. data/ext/bson/{native-endian.h → bson-endian.h} +5 -99
  7. data/ext/bson/bson-native.h +125 -0
  8. data/ext/bson/bytebuf.c +133 -0
  9. data/ext/bson/endian.c +117 -0
  10. data/ext/bson/init.c +355 -0
  11. data/ext/bson/libbson-utf8.c +230 -0
  12. data/ext/bson/read.c +411 -0
  13. data/ext/bson/util.c +95 -0
  14. data/ext/bson/write.c +680 -0
  15. data/lib/bson.rb +6 -3
  16. data/lib/bson/active_support.rb +17 -0
  17. data/lib/bson/array.rb +57 -17
  18. data/lib/bson/binary.rb +185 -13
  19. data/lib/bson/boolean.rb +12 -3
  20. data/lib/bson/code.rb +16 -2
  21. data/lib/bson/code_with_scope.rb +32 -5
  22. data/lib/bson/config.rb +1 -1
  23. data/lib/bson/date.rb +12 -2
  24. data/lib/bson/date_time.rb +2 -2
  25. data/lib/bson/db_pointer.rb +110 -0
  26. data/lib/bson/decimal128.rb +17 -3
  27. data/lib/bson/decimal128/builder.rb +1 -1
  28. data/lib/bson/document.rb +152 -5
  29. data/lib/bson/environment.rb +2 -1
  30. data/lib/bson/error.rb +27 -0
  31. data/lib/bson/ext_json.rb +383 -0
  32. data/lib/bson/false_class.rb +1 -1
  33. data/lib/bson/float.rb +48 -2
  34. data/lib/bson/hash.rb +68 -17
  35. data/lib/bson/int32.rb +52 -13
  36. data/lib/bson/int64.rb +59 -15
  37. data/lib/bson/integer.rb +36 -2
  38. data/lib/bson/json.rb +1 -1
  39. data/lib/bson/max_key.rb +13 -1
  40. data/lib/bson/min_key.rb +13 -1
  41. data/lib/bson/nil_class.rb +4 -2
  42. data/lib/bson/object.rb +28 -1
  43. data/lib/bson/object_id.rb +16 -2
  44. data/lib/bson/open_struct.rb +1 -1
  45. data/lib/bson/regexp.rb +27 -4
  46. data/lib/bson/registry.rb +3 -3
  47. data/lib/bson/specialized.rb +4 -2
  48. data/lib/bson/string.rb +5 -3
  49. data/lib/bson/symbol.rb +99 -7
  50. data/lib/bson/time.rb +63 -4
  51. data/lib/bson/time_with_zone.rb +54 -0
  52. data/lib/bson/timestamp.rb +44 -6
  53. data/lib/bson/true_class.rb +1 -1
  54. data/lib/bson/undefined.rb +12 -1
  55. data/lib/bson/version.rb +2 -2
  56. data/spec/bson/array_spec.rb +18 -1
  57. data/spec/bson/binary_spec.rb +100 -3
  58. data/spec/bson/binary_uuid_spec.rb +189 -0
  59. data/spec/bson/boolean_spec.rb +1 -1
  60. data/spec/bson/byte_buffer_read_spec.rb +197 -0
  61. data/spec/bson/byte_buffer_spec.rb +121 -381
  62. data/spec/bson/byte_buffer_write_spec.rb +854 -0
  63. data/spec/bson/code_spec.rb +1 -1
  64. data/spec/bson/code_with_scope_spec.rb +1 -1
  65. data/spec/bson/date_spec.rb +1 -1
  66. data/spec/bson/date_time_spec.rb +54 -1
  67. data/spec/bson/decimal128_spec.rb +35 -35
  68. data/spec/bson/document_as_spec.rb +46 -0
  69. data/spec/bson/document_spec.rb +197 -30
  70. data/spec/bson/ext_json_parse_spec.rb +308 -0
  71. data/spec/bson/false_class_spec.rb +1 -1
  72. data/spec/bson/float_spec.rb +37 -1
  73. data/spec/bson/hash_as_spec.rb +57 -0
  74. data/spec/bson/hash_spec.rb +209 -1
  75. data/spec/bson/int32_spec.rb +180 -6
  76. data/spec/bson/int64_spec.rb +199 -6
  77. data/spec/bson/integer_spec.rb +29 -3
  78. data/spec/bson/json_spec.rb +1 -1
  79. data/spec/bson/max_key_spec.rb +1 -1
  80. data/spec/bson/min_key_spec.rb +1 -1
  81. data/spec/bson/nil_class_spec.rb +1 -1
  82. data/spec/bson/object_id_spec.rb +1 -1
  83. data/spec/bson/object_spec.rb +1 -1
  84. data/spec/bson/open_struct_spec.rb +1 -1
  85. data/spec/bson/raw_spec.rb +34 -2
  86. data/spec/bson/regexp_spec.rb +1 -1
  87. data/spec/bson/registry_spec.rb +1 -1
  88. data/spec/bson/string_spec.rb +19 -1
  89. data/spec/bson/symbol_raw_spec.rb +45 -0
  90. data/spec/bson/symbol_spec.rb +63 -3
  91. data/spec/bson/time_spec.rb +205 -2
  92. data/spec/bson/time_with_zone_spec.rb +68 -0
  93. data/spec/bson/timestamp_spec.rb +56 -1
  94. data/spec/bson/true_class_spec.rb +1 -1
  95. data/spec/bson/undefined_spec.rb +1 -1
  96. data/spec/bson_spec.rb +1 -1
  97. data/spec/{support → runners}/common_driver.rb +1 -1
  98. data/spec/runners/corpus.rb +185 -0
  99. data/spec/{support/corpus.rb → runners/corpus_legacy.rb} +41 -59
  100. data/spec/spec_helper.rb +40 -3
  101. data/spec/{bson/driver_bson_spec.rb → spec_tests/common_driver_spec.rb} +1 -0
  102. data/spec/{bson/corpus_spec.rb → spec_tests/corpus_legacy_spec.rb} +10 -7
  103. data/spec/spec_tests/corpus_spec.rb +124 -0
  104. data/spec/spec_tests/data/corpus/README.md +15 -0
  105. data/spec/spec_tests/data/corpus/array.json +49 -0
  106. data/spec/spec_tests/data/corpus/binary.json +113 -0
  107. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  108. data/spec/spec_tests/data/corpus/code.json +67 -0
  109. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  110. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  111. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  112. data/spec/spec_tests/data/corpus/dbref.json +31 -0
  113. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  114. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  115. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  116. data/spec/spec_tests/data/corpus/decimal128-4.json +117 -0
  117. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  118. data/spec/spec_tests/data/corpus/decimal128-6.json +119 -0
  119. data/spec/spec_tests/data/corpus/decimal128-7.json +323 -0
  120. data/spec/spec_tests/data/corpus/document.json +36 -0
  121. data/spec/spec_tests/data/corpus/double.json +87 -0
  122. data/spec/spec_tests/data/corpus/int32.json +43 -0
  123. data/spec/spec_tests/data/corpus/int64.json +43 -0
  124. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  125. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  126. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  127. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  128. data/spec/spec_tests/data/corpus/null.json +12 -0
  129. data/spec/spec_tests/data/corpus/oid.json +28 -0
  130. data/spec/spec_tests/data/corpus/regex.json +65 -0
  131. data/spec/spec_tests/data/corpus/string.json +72 -0
  132. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  133. data/spec/spec_tests/data/corpus/timestamp.json +34 -0
  134. data/spec/spec_tests/data/corpus/top.json +236 -0
  135. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  136. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/array.json +8 -2
  137. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/binary.json +0 -0
  138. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/boolean.json +0 -0
  139. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code.json +1 -1
  140. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code_w_scope.json +1 -1
  141. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/document.json +1 -1
  142. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/double.json +1 -1
  143. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/datetime.json +0 -0
  144. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/dbpointer.json +0 -0
  145. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/int64.json +0 -0
  146. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/symbol.json +0 -0
  147. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/int32.json +1 -1
  148. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/maxkey.json +1 -1
  149. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/minkey.json +1 -1
  150. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/null.json +1 -1
  151. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/oid.json +0 -0
  152. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/regex.json +1 -1
  153. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/string.json +0 -0
  154. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/timestamp.json +1 -1
  155. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/top.json +0 -0
  156. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/undefined.json +0 -0
  157. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-1.json +0 -0
  158. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-2.json +0 -0
  159. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-3.json +0 -0
  160. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-4.json +0 -0
  161. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-5.json +0 -0
  162. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-6.json +0 -0
  163. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-7.json +0 -0
  164. data/spec/support/shared_examples.rb +3 -5
  165. data/spec/support/spec_config.rb +16 -0
  166. data/spec/support/utils.rb +10 -0
  167. metadata +227 -124
  168. metadata.gz.sig +0 -0
  169. data/ext/bson/bson_native.c +0 -762
data/lib/bson/code.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -55,7 +55,19 @@ module BSON
55
55
  # @return [ Hash ] The code as a JSON hash.
56
56
  #
57
57
  # @since 2.0.0
58
+ # @deprecated Use as_extended_json instead.
58
59
  def as_json(*args)
60
+ as_extended_json
61
+ end
62
+
63
+ # Converts this object to a representation directly serializable to
64
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
65
+ #
66
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
67
+ # (default is canonical extended JSON)
68
+ #
69
+ # @return [ Hash ] The extended json representation.
70
+ def as_extended_json(**options)
59
71
  { "$code" => javascript }
60
72
  end
61
73
 
@@ -89,12 +101,14 @@ module BSON
89
101
  #
90
102
  # @param [ ByteBuffer ] buffer The byte buffer.
91
103
  #
104
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
105
+ #
92
106
  # @return [ TrueClass, FalseClass ] The decoded code.
93
107
  #
94
108
  # @see http://bsonspec.org/#/specification
95
109
  #
96
110
  # @since 2.0.0
97
- def self.from_bson(buffer)
111
+ def self.from_bson(buffer, **options)
98
112
  new(buffer.get_string)
99
113
  end
100
114
 
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -59,8 +59,20 @@ module BSON
59
59
  # @return [ Hash ] The code with scope as a JSON hash.
60
60
  #
61
61
  # @since 2.0.0
62
+ # @deprecated Use as_extended_json instead.
62
63
  def as_json(*args)
63
- { "$code" => javascript, "$scope" => scope }
64
+ as_extended_json
65
+ end
66
+
67
+ # Converts this object to a representation directly serializable to
68
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
69
+ #
70
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
71
+ # (default is canonical extended JSON)
72
+ #
73
+ # @return [ Hash ] The extended json representation.
74
+ def as_extended_json(**options)
75
+ { "$code" => javascript, "$scope" => scope.as_extended_json(**options) }
64
76
  end
65
77
 
66
78
  # Instantiate the new code with scope.
@@ -99,14 +111,29 @@ module BSON
99
111
  #
100
112
  # @param [ ByteBuffer ] buffer The byte buffer.
101
113
  #
114
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
115
+ #
102
116
  # @return [ TrueClass, FalseClass ] The decoded code with scope.
103
117
  #
104
118
  # @see http://bsonspec.org/#/specification
105
119
  #
106
120
  # @since 2.0.0
107
- def self.from_bson(buffer)
108
- buffer.get_int32 # Throw away the total length.
109
- new(buffer.get_string, ::Hash.from_bson(buffer))
121
+ def self.from_bson(buffer, **options)
122
+ # Code with scope has a length (?) field which is not needed for
123
+ # decoding, but spec tests want this field validated.
124
+ start_position = buffer.read_position
125
+ length = buffer.get_int32
126
+ javascript = buffer.get_string
127
+ scope = if options.empty?
128
+ ::Hash.from_bson(buffer)
129
+ else
130
+ ::Hash.from_bson(buffer, **options)
131
+ end
132
+ read_bytes = buffer.read_position - start_position
133
+ if read_bytes != length
134
+ raise Error::BSONDecodeError, "CodeWithScope invalid: claimed length #{length}, actual length #{read_bytes}"
135
+ end
136
+ new(javascript, scope)
110
137
  end
111
138
 
112
139
  # Register this type when the module is loaded.
data/lib/bson/config.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016 MongoDB Inc.
1
+ # Copyright (C) 2016-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
data/lib/bson/date.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -16,6 +16,16 @@ require 'date'
16
16
 
17
17
  module BSON
18
18
 
19
+ # Julian day of Date 1970-01-01 - UNIX timestamp reference.
20
+ #
21
+ # @api private
22
+ DATE_REFERENCE = ::Date.new(1970, 1, 1).jd
23
+
24
+ # Number of miliseconds in a day.
25
+ #
26
+ # @api private
27
+ MILLISECONDS_IN_DAY = 60 * 60 * 24 * 1_000
28
+
19
29
  # Injects behaviour for encoding date values to raw bytes as specified by
20
30
  # the BSON spec for time.
21
31
  #
@@ -35,7 +45,7 @@ module BSON
35
45
  #
36
46
  # @since 2.1.0
37
47
  def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
38
- ::Time.utc(year, month, day).to_bson(buffer)
48
+ buffer.put_int64((jd - DATE_REFERENCE) * MILLISECONDS_IN_DAY)
39
49
  end
40
50
 
41
51
  # Get the BSON type for the date.
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@ module BSON
35
35
  #
36
36
  # @since 2.1.0
37
37
  def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
38
- to_time.to_bson(buffer)
38
+ gregorian.to_time.to_bson(buffer)
39
39
  end
40
40
  end
41
41
 
@@ -0,0 +1,110 @@
1
+ # Copyright (C) 2020 MongoDB Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module BSON
16
+
17
+ # Injects behaviour for encoding and decoding DBPointer values to and from
18
+ # raw bytes as specified by the BSON spec.
19
+ #
20
+ # @see http://bsonspec.org/#/specification
21
+ class DbPointer
22
+ include JSON
23
+
24
+ # A DBPointer is type 0x0C in the BSON spec.
25
+ BSON_TYPE = 0x0C.chr.force_encoding(BINARY).freeze
26
+
27
+ # Create a new DBPointer object.
28
+ #
29
+ # @param [ String ] ref The database collection name.
30
+ # @param [ BSON::ObjectId ] id The DBPointer id.
31
+ def initialize(ref, id)
32
+ @ref = ref
33
+ @id = id
34
+ end
35
+
36
+ # Return the collection name.
37
+ #
38
+ # @return [ String ] The database collection name.
39
+ attr_reader :ref
40
+
41
+ # Return the DbPointer's id.
42
+ #
43
+ # @return [ BSON::ObjectId ] The id of the DbPointer instance
44
+ attr_reader :id
45
+
46
+ # Determine if this DBPointer object is equal to another object.
47
+ #
48
+ # @param [ Object ] other The object to compare against.
49
+ #
50
+ # @return [ true | false ] If the objects are equal
51
+ def ==(other)
52
+ return false unless other.is_a?(DbPointer)
53
+ ref == other.ref && id == other.id
54
+ end
55
+
56
+ # Get the DBPointer as JSON hash data
57
+ #
58
+ # @return [ Hash ] The DBPointer as a JSON hash.
59
+ #
60
+ # @deprecated Use as_extended_json instead.
61
+ def as_json(*args)
62
+ as_extended_json
63
+ end
64
+
65
+ # Converts this object to a representation directly serializable to
66
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
67
+ #
68
+ # @option options [ true | false ] :relaxed Whether to produce relaxed
69
+ # extended JSON representation.
70
+ #
71
+ # @return [ Hash ] The extended json representation.
72
+ def as_extended_json(**options)
73
+ {'$dbPointer' => { "$ref" => ref, '$id' => id.as_extended_json }}
74
+ end
75
+
76
+ # Encode the DBPointer.
77
+ #
78
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
79
+ #
80
+ # @see http://bsonspec.org/#/specification
81
+ def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
82
+ buffer.put_string(ref)
83
+ id.to_bson(buffer, validating_keys)
84
+ buffer
85
+ end
86
+
87
+ # Deserialize a DBPointer from BSON.
88
+ #
89
+ # @param [ ByteBuffer ] buffer The byte buffer.
90
+ # @param [ Hash ] options
91
+ #
92
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
93
+ #
94
+ # @return [ BSON::DbPointer ] The decoded DBPointer.
95
+ #
96
+ # @see http://bsonspec.org/#/specification
97
+ def self.from_bson(buffer, **options)
98
+ ref = buffer.get_string
99
+ id = if options.empty?
100
+ ObjectId.from_bson(buffer)
101
+ else
102
+ ObjectId.from_bson(buffer, **options)
103
+ end
104
+ new(ref, id)
105
+ end
106
+
107
+ # Register this type when the module is loaded.
108
+ Registry.register(BSON_TYPE, self)
109
+ end
110
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016 MongoDB Inc.
1
+ # Copyright (C) 2016-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -63,7 +63,19 @@ module BSON
63
63
  # @return [ Hash ] The number as a JSON hash.
64
64
  #
65
65
  # @since 4.2.0
66
+ # @deprecated Use as_extended_json instead.
66
67
  def as_json(*args)
68
+ as_extended_json
69
+ end
70
+
71
+ # Converts this object to a representation directly serializable to
72
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
73
+ #
74
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
75
+ # (default is canonical extended JSON)
76
+ #
77
+ # @return [ Hash ] The extended json representation.
78
+ def as_extended_json(**options)
67
79
  { EXTENDED_JSON_KEY => to_s }
68
80
  end
69
81
 
@@ -178,7 +190,7 @@ module BSON
178
190
  #
179
191
  # @since 4.2.0
180
192
  def to_big_decimal
181
- @big_decimal ||= BigDecimal.new(to_s)
193
+ @big_decimal ||= BigDecimal(to_s)
182
194
  end
183
195
 
184
196
  private
@@ -197,10 +209,12 @@ module BSON
197
209
  #
198
210
  # @param [ ByteBuffer ] buffer The byte buffer.
199
211
  #
212
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
213
+ #
200
214
  # @return [ BSON::Decimal128 ] The decimal object.
201
215
  #
202
216
  # @since 4.2.0
203
- def from_bson(buffer)
217
+ def from_bson(buffer, **options)
204
218
  from_bits(*buffer.get_decimal128_bytes.unpack('Q<*'))
205
219
  end
206
220
 
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2016 MongoDB Inc.
1
+ # Copyright (C) 2016-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
data/lib/bson/document.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -35,8 +35,43 @@ module BSON
35
35
  class Document < ::Hash
36
36
 
37
37
  # Get a value from the document for the provided key. Can use string or
38
- # symbol access, but the fastest will be to always provide a key that is of
39
- # the same type as the stored keys.
38
+ # symbol access, with string access being the faster of the two.
39
+ #
40
+ # @overload fetch(key)
41
+ # Returns a value from the hash for the given key. If the key does
42
+ # not exist, raises KeyError exception.
43
+ #
44
+ # @overload fetch(key, default)
45
+ # Returns a value from the hash for the given key. If the key does not
46
+ # exist, returns *default*.
47
+ #
48
+ # @overload fetch(key, &block)
49
+ # Returns a value from the hash for the given key. If the key does not
50
+ # exist, returns the value of the block called with the key.
51
+ #
52
+ # @example Get an element for the key.
53
+ # document.fetch("field")
54
+ #
55
+ # @example Get an element for the key by symbol with a default.
56
+ # document.fetch(:field, 'foo')
57
+ #
58
+ # @example Get an element for the key by symbol with a block default.
59
+ # document.fetch(:field) { |key| key.upcase }
60
+ #
61
+ # @param [ String, Symbol ] key The key to look up.
62
+ # @param [ Object ] default Returned value if key does not exist.
63
+ # @yield [key] Block returning default value for the given key.
64
+ #
65
+ # @return [ Object ] The found value. Raises KeyError if none found.
66
+ #
67
+ # @since 4.4.0
68
+ def fetch(key, *args, &block)
69
+ key = convert_key(key)
70
+ super(key, *args, &block)
71
+ end
72
+
73
+ # Get a value from the document for the provided key. Can use string or
74
+ # symbol access, with string access being the faster of the two.
40
75
  #
41
76
  # @example Get an element for the key.
42
77
  # document["field"]
@@ -44,7 +79,7 @@ module BSON
44
79
  # @example Get an element for the key by symbol.
45
80
  # document[:field]
46
81
  #
47
- # @param [ String, Symbol ] key The key to lookup.
82
+ # @param [ String, Symbol ] key The key to look up.
48
83
  #
49
84
  # @return [ Object ] The found value, or nil if none found.
50
85
  #
@@ -53,7 +88,49 @@ module BSON
53
88
  super(convert_key(key))
54
89
  end
55
90
 
56
- # Set a value on the document. Will normalize symbol keys into strings.
91
+ # Stores a key-value pair in the current document.
92
+ #
93
+ # Since BSON documents provide deep indifferent access (both strings and
94
+ # symbols are accepted as keys, recursively), the value may be converted
95
+ # to facilitate indifferent access. This conversion is performed for
96
+ # built-in Array and Hash classes, and other classes can override
97
+ # +to_bson_normalized_value+ method to provide custom conversion logic.
98
+ # For example:
99
+ #
100
+ # doc = BSON::Document.new
101
+ # doc[:a] = {b: {c: 'd'}}
102
+ # doc['a']['b']['c']
103
+ # # => "d"
104
+ #
105
+ # Note that due to this conversion, the object that is stored in the
106
+ # receiver Document may be different from the object supplied as the
107
+ # right hand side of the assignment. In Ruby, the result of assignment
108
+ # is the right hand side, not the return value of []= method.
109
+ # Because of this, modifying the result of assignment generally does not
110
+ # work as intended:
111
+ #
112
+ # doc = BSON::Document.new
113
+ # foo = (doc[:a] = {b: {c: 'd'}})
114
+ # # foo is original Hash with symbol keys
115
+ # foo['test'] = 'test'
116
+ # # doc is not modified
117
+ # doc
118
+ # # => {"a"=>{"b"=>{"c"=>"d"}}}
119
+ #
120
+ # This behavior can be encountered when defaulting document contents with
121
+ # []= in a method, such as:
122
+ #
123
+ # def foo
124
+ # # @doc is a BSON::Document
125
+ # @doc[:foo] ||= calculation
126
+ # end
127
+ #
128
+ # The above method should be written as follows to allow chaining:
129
+ #
130
+ # def foo
131
+ # # @doc is a BSON::Document
132
+ # @doc[:foo] ||= calculation and @doc[:foo]
133
+ # end
57
134
  #
58
135
  # @example Set a value on the document.
59
136
  # document[:test] = "value"
@@ -172,6 +249,76 @@ module BSON
172
249
 
173
250
  alias :update :merge!
174
251
 
252
+ if instance_methods.include?(:dig)
253
+ # Retrieves the value object corresponding to the each key objects repeatedly.
254
+ # Will normalize symbol keys into strings.
255
+ #
256
+ # @example Get value from nested sub-documents, handling missing levels.
257
+ # document # => { :key1 => { "key2" => "value"}}
258
+ # document.dig(:key1, :key2) # => "value"
259
+ # document.dig("key1", "key2") # => "value"
260
+ # document.dig("foo", "key2") # => nil
261
+ #
262
+ # @param [ Array<String, Symbol> ] *keys Keys, which constitute a "path" to the nested value.
263
+ #
264
+ # @return [ Object, NilClass ] The requested value or nil.
265
+ #
266
+ # @since 3.0.0
267
+ def dig(*keys)
268
+ super(*keys.map{|key| convert_key(key)})
269
+ end
270
+ end
271
+
272
+ # Slices a document to include only the given keys.
273
+ # Will normalize symbol keys into strings.
274
+ # (this method is backported from ActiveSupport::Hash)
275
+ #
276
+ # @example Get a document/hash with only the `name` and `age` fields present
277
+ # document # => { _id: <ObjectId>, :name => "John", :age => 30, :location => "Earth" }
278
+ # document.slice(:name, 'age') # => { "name": "John", "age" => 30 }
279
+ # document.slice('name') # => { "name" => "John" }
280
+ # document.slice(:foo) # => {}
281
+ #
282
+ # @param [ Array<String, Symbol> ] *keys Keys, that will be kept in the resulting document
283
+ #
284
+ # @return [ BSON::Document ] The document with only the selected keys
285
+ #
286
+ # @since 4.3.1
287
+ def slice(*keys)
288
+ keys.each_with_object(self.class.new) do |key, hash|
289
+ if key?(key)
290
+ hash[key] = self[key]
291
+ end
292
+ end
293
+ end
294
+
295
+ # Returns a new document consisting of the current document minus the
296
+ # specified keys.
297
+ #
298
+ # The keys to be removed can be specified as either strings or symbols.
299
+ #
300
+ # @example Get a document/hash with only the `name` and `age` fields removed
301
+ # document # => { _id: <ObjectId>, :name => 'John', :age => 30, :location => 'Earth' }
302
+ # document.except(:name, 'age') # => { _id: <ObjectId>, location: 'Earth' }
303
+ #
304
+ # @param [ Array<String, Symbol> ] *keys Keys, that will be removed in the resulting document
305
+ #
306
+ # @return [ BSON::Document ] The document with the specified keys removed.
307
+ #
308
+ # @note This method is always defined, even if Hash already contains a
309
+ # definition of #except, because ActiveSupport unconditionally defines
310
+ # its version of #except which doesn't work for BSON::Document which
311
+ # causes problems if ActiveSupport is loaded after bson-ruby is.
312
+ def except(*keys)
313
+ copy = dup
314
+ keys.each {|key| copy.delete(key)}
315
+ copy
316
+ end
317
+
318
+ def symbolize_keys!
319
+ 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'
320
+ end
321
+
175
322
  private
176
323
 
177
324
  def convert_key(key)