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
@@ -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.
@@ -34,12 +34,14 @@ module BSON
34
34
  #
35
35
  # @param [ ByteBuffer ] buffer The byte buffer.
36
36
  #
37
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
38
+ #
37
39
  # @return [ nil ] The decoded nil value.
38
40
  #
39
41
  # @see http://bsonspec.org/#/specification
40
42
  #
41
43
  # @since 2.0.0
42
- def from_bson(buffer)
44
+ def from_bson(buffer, **options)
43
45
  nil
44
46
  end
45
47
  end
data/lib/bson/object.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.
@@ -58,6 +58,33 @@ module BSON
58
58
  def to_bson_normalized_value
59
59
  self
60
60
  end
61
+
62
+ # Serializes this object to Extended JSON
63
+ # (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
64
+ #
65
+ # Subclasses should override +as_extended_json+ rather than this method.
66
+ #
67
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
68
+ # (default is canonical extended JSON)
69
+ #
70
+ # @return [ String ] The extended json serialization.
71
+ def to_extended_json(**options)
72
+ as_extended_json(**options).to_json
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.rst).
77
+ #
78
+ # Subclasses should override this method to provide custom serialization
79
+ # to Extended JSON.
80
+ #
81
+ # @option options [ true | false ] :relaxed Whether to produce relaxed
82
+ # extended JSON representation.
83
+ #
84
+ # @return [ Object ] The extended json representation.
85
+ def as_extended_json(**options)
86
+ self
87
+ end
61
88
  end
62
89
 
63
90
  # Raised when trying to serialize an object into a key.
@@ -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.
@@ -71,7 +71,19 @@ module BSON
71
71
  # @return [ Hash ] The object id as a JSON hash.
72
72
  #
73
73
  # @since 2.0.0
74
+ # @deprecated Use as_extended_json instead.
74
75
  def as_json(*args)
76
+ as_extended_json
77
+ end
78
+
79
+ # Converts this object to a representation directly serializable to
80
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
81
+ #
82
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
83
+ # (default is canonical extended JSON)
84
+ #
85
+ # @return [ Hash ] The extended json representation.
86
+ def as_extended_json(**options)
75
87
  { "$oid" => to_s }
76
88
  end
77
89
 
@@ -217,10 +229,12 @@ module BSON
217
229
  #
218
230
  # @param [ ByteBuffer ] buffer The byte buffer.
219
231
  #
232
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
233
+ #
220
234
  # @return [ BSON::ObjectId ] The object id.
221
235
  #
222
236
  # @since 2.0.0
223
- def from_bson(buffer)
237
+ def from_bson(buffer, **options)
224
238
  from_data(buffer.get_bytes(12))
225
239
  end
226
240
 
@@ -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/regexp.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2009-2016 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.
@@ -165,7 +165,13 @@ module BSON
165
165
  #
166
166
  # @since 3.1.0
167
167
  def respond_to?(method, include_private = false)
168
- compile.respond_to?(method, include_private) || super
168
+ if defined?(@pattern)
169
+ compile.respond_to?(method, include_private) || super
170
+ else
171
+ # YAML calls #respond_to? during deserialization, before the object
172
+ # is initialized.
173
+ super
174
+ end
169
175
  end
170
176
 
171
177
  # Encode the Raw Regexp object to BSON.
@@ -205,7 +211,22 @@ module BSON
205
211
  #
206
212
  # @since 4.2.0
207
213
  def as_json(*args)
208
- { "$regex" => source, "$options" => options }
214
+ as_extended_json(mode: :legacy)
215
+ end
216
+
217
+ # Converts this object to a representation directly serializable to
218
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
219
+ #
220
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
221
+ # (default is canonical extended JSON)
222
+ #
223
+ # @return [ Hash ] The extended json representation.
224
+ def as_extended_json(**opts)
225
+ if opts[:mode] == :legacy
226
+ { "$regex" => source, "$options" => options }
227
+ else
228
+ {"$regularExpression" => {'pattern' => source, "options" => options}}
229
+ end
209
230
  end
210
231
 
211
232
  # Check equality of the raw bson regexp against another.
@@ -248,12 +269,14 @@ module BSON
248
269
  #
249
270
  # @param [ ByteBuffer ] buffer The byte buffer.
250
271
  #
272
+ # @option opts [ nil | :bson ] :mode Decoding mode to use.
273
+ #
251
274
  # @return [ Regexp ] The decoded regular expression.
252
275
  #
253
276
  # @see http://bsonspec.org/#/specification
254
277
  #
255
278
  # @since 2.0.0
256
- def from_bson(buffer)
279
+ def from_bson(buffer, **opts)
257
280
  pattern = buffer.get_cstring
258
281
  options = buffer.get_cstring
259
282
  Raw.new(pattern, options)
data/lib/bson/registry.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.
@@ -40,7 +40,7 @@ module BSON
40
40
  #
41
41
  # @since 2.0.0
42
42
  def get(byte, field = nil)
43
- if type = MAPPINGS[byte]
43
+ if type = MAPPINGS[byte] || (byte.is_a?(String) && type = MAPPINGS[byte.ord])
44
44
  type
45
45
  else
46
46
  handle_unsupported_type!(byte, field)
@@ -59,7 +59,7 @@ module BSON
59
59
  #
60
60
  # @since 2.0.0
61
61
  def register(byte, type)
62
- MAPPINGS.store(byte, type)
62
+ MAPPINGS[byte.ord] = type
63
63
  define_type_reader(type)
64
64
  end
65
65
 
@@ -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.
@@ -61,12 +61,14 @@ module BSON
61
61
  #
62
62
  # @param [ ByteBuffer ] buffer The byte buffer.
63
63
  #
64
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
65
+ #
64
66
  # @return [ Specialized ] The decoded specialized class.
65
67
  #
66
68
  # @see http://bsonspec.org/#/specification
67
69
  #
68
70
  # @since 2.0.0
69
- def from_bson(buffer)
71
+ def from_bson(buffer, **options)
70
72
  new
71
73
  end
72
74
  end
data/lib/bson/string.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
- # Copyright (C) 2009-2014 MongoDB Inc.
2
+ # Copyright (C) 2009-2020 MongoDB Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -79,7 +79,7 @@ module BSON
79
79
  #
80
80
  # @note This is used for repairing legacy bson data.
81
81
  #
82
- # @raise [ InvalidObjectId ] If the string is not 12 elements.
82
+ # @raise [ BSON::ObjectId::Invalid ] If the string is not 12 elements.
83
83
  #
84
84
  # @return [ String ] The raw object id bytes.
85
85
  #
@@ -124,12 +124,14 @@ module BSON
124
124
  #
125
125
  # @param [ ByteBuffer ] buffer The byte buffer.
126
126
  #
127
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
128
+ #
127
129
  # @return [ Regexp ] The decoded string.
128
130
  #
129
131
  # @see http://bsonspec.org/#/specification
130
132
  #
131
133
  # @since 2.0.0
132
- def from_bson(buffer)
134
+ def from_bson(buffer, **options)
133
135
  buffer.get_string
134
136
  end
135
137
  end
data/lib/bson/symbol.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.
@@ -57,7 +57,7 @@ module BSON
57
57
  #
58
58
  # @since 2.0.0
59
59
  def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
60
- to_s.to_bson(buffer)
60
+ buffer.put_symbol(self)
61
61
  end
62
62
 
63
63
  # Get the symbol as a BSON key name encoded C symbol.
@@ -71,7 +71,10 @@ module BSON
71
71
  #
72
72
  # @since 2.0.0
73
73
  def to_bson_key(validating_keys = Config.validating_keys?)
74
- to_s.to_bson_key(validating_keys)
74
+ if validating_keys
75
+ raise BSON::String::IllegalKey.new(self) if BSON::String::ILLEGAL_KEY =~ self
76
+ end
77
+ self
75
78
  end
76
79
 
77
80
  # Converts the symbol to a normalized key in a BSON document.
@@ -86,26 +89,115 @@ module BSON
86
89
  to_s
87
90
  end
88
91
 
92
+ # Converts this object to a representation directly serializable to
93
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
94
+ #
95
+ # @option options [ true | false ] :relaxed Whether to produce relaxed
96
+ # extended JSON representation.
97
+ #
98
+ # @return [ Hash ] The extended json representation.
99
+ def as_extended_json(**options)
100
+ { "$symbol" => to_s }
101
+ end
102
+
103
+ class Raw
104
+ # Create a BSON Symbol
105
+ #
106
+ # @param [ String | Symbol ] str_or_sym The symbol represented by this
107
+ # object. Can be specified as a Symbol or a String.
108
+ #
109
+ # @see http://bsonspec.org/#/specification
110
+ def initialize(str_or_sym)
111
+ unless str_or_sym.is_a?(String) || str_or_sym.is_a?(Symbol)
112
+ raise ArgumentError, "BSON::Symbol::Raw must be given a symbol or a string, not #{str_or_sym}"
113
+ end
114
+
115
+ @symbol = str_or_sym.to_sym
116
+ end
117
+
118
+ # Get the underlying symbol as a Ruby symbol.
119
+ #
120
+ # @return [ Symbol ] The symbol represented by this BSON object.
121
+ def to_sym
122
+ @symbol
123
+ end
124
+
125
+ # Get the underlying symbol as a Ruby string.
126
+ #
127
+ # @return [ String ] The symbol as a string.
128
+ def to_s
129
+ @symbol.to_s
130
+ end
131
+
132
+ # Check equality of the raw bson symbol against another.
133
+ #
134
+ # @param [ Object ] other The object to check against.
135
+ #
136
+ # @return [ true, false ] If the objects are equal.
137
+ def ==(other)
138
+ return false unless other.is_a?(Raw)
139
+ to_sym == other.to_sym
140
+ end
141
+ alias :eql? :==
142
+
143
+ # Get the symbol as encoded BSON.
144
+ #
145
+ # @raise [ EncodingError ] If the symbol is not UTF-8.
146
+ #
147
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
148
+ #
149
+ # @see http://bsonspec.org/#/specification
150
+ def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
151
+ buffer.put_string(to_s)
152
+ end
153
+
154
+ def bson_type
155
+ Symbol::BSON_TYPE
156
+ end
157
+
158
+ # Converts this object to a representation directly serializable to
159
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
160
+ #
161
+ # This method returns the integer value if relaxed representation is
162
+ # requested, otherwise a $numberLong hash.
163
+ #
164
+ # @option options [ true | false ] :relaxed Whether to produce relaxed
165
+ # extended JSON representation.
166
+ #
167
+ # @return [ Hash | Integer ] The extended json representation.
168
+ def as_extended_json(**options)
169
+ {'$symbol' => to_s}
170
+ end
171
+ end
172
+
89
173
  module ClassMethods
90
174
 
91
175
  # Deserialize a symbol from BSON.
92
176
  #
93
177
  # @param [ ByteBuffer ] buffer The byte buffer.
94
178
  #
95
- # @return [ Regexp ] The decoded symbol.
179
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
180
+ #
181
+ # @return [ Symbol | BSON::Symbol::Raw ] The decoded symbol.
96
182
  #
97
183
  # @see http://bsonspec.org/#/specification
98
184
  #
99
185
  # @since 2.0.0
100
- def from_bson(buffer)
101
- buffer.get_string.intern
186
+ def from_bson(buffer, **options)
187
+ sym = buffer.get_string.intern
188
+
189
+ if options[:mode] == :bson
190
+ Raw.new(sym)
191
+ else
192
+ sym
193
+ end
102
194
  end
103
195
  end
104
196
 
105
197
  # Register this type when the module is loaded.
106
198
  #
107
199
  # @since 2.0.0
108
- Registry::MAPPINGS.store(BSON_TYPE, ::Symbol)
200
+ Registry::MAPPINGS[BSON_TYPE.ord] = ::Symbol
109
201
  end
110
202
 
111
203
  # Enrich the core Symbol class with this module.
data/lib/bson/time.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.
@@ -17,6 +17,20 @@ module BSON
17
17
  # Injects behaviour for encoding and decoding time values to
18
18
  # and from raw bytes as specified by the BSON spec.
19
19
  #
20
+ # @note
21
+ # Ruby time can have nanosecond precision:
22
+ # +Time.utc(2020, 1, 1, 0, 0, 0, 999_999_999/1000r)+
23
+ # +Time#usec+ returns the number of microseconds in the time, and
24
+ # if the time has nanosecond precision the sub-microsecond part is
25
+ # truncated (the value is floored to the nearest millisecond).
26
+ # MongoDB only supports millisecond precision; we truncate the
27
+ # sub-millisecond part of microseconds (floor to the nearest millisecond).
28
+ # Note that if a time is constructed from a floating point value,
29
+ # the microsecond value may round to the starting floating point value
30
+ # but due to flooring, the time after serialization may end up to
31
+ # be different than the starting floating point value.
32
+ # It is recommended that time calculations use integer math only.
33
+ #
20
34
  # @see http://bsonspec.org/#/specification
21
35
  #
22
36
  # @since 2.0.0
@@ -29,6 +43,8 @@ module BSON
29
43
 
30
44
  # Get the time as encoded BSON.
31
45
  #
46
+ # @note The time is floored to the nearest millisecond.
47
+ #
32
48
  # @example Get the time as encoded BSON.
33
49
  # Time.new(2012, 1, 1, 0, 0, 0).to_bson
34
50
  #
@@ -38,7 +54,48 @@ module BSON
38
54
  #
39
55
  # @since 2.0.0
40
56
  def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
41
- buffer.put_int64((to_i * 1000) + (usec / 1000))
57
+ value = _bson_to_i * 1000 + usec.divmod(1000).first
58
+ buffer.put_int64(value)
59
+ end
60
+
61
+ # Converts this object to a representation directly serializable to
62
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json.rst).
63
+ #
64
+ # @note The time is floored to the nearest millisecond.
65
+ #
66
+ # @option options [ true | false ] :relaxed Whether to produce relaxed
67
+ # extended JSON representation.
68
+ #
69
+ # @return [ Hash ] The extended json representation.
70
+ def as_extended_json(**options)
71
+ utc_time = utc
72
+ if options[:mode] == :relaxed && (1970..9999).include?(utc_time.year)
73
+ if utc_time.usec != 0
74
+ if utc_time.respond_to?(:floor)
75
+ # Ruby 2.7+
76
+ utc_time = utc_time.floor(3)
77
+ else
78
+ utc_time -= utc_time.usec.divmod(1000).last.to_r / 1000000
79
+ end
80
+ {'$date' => utc_time.strftime('%Y-%m-%dT%H:%M:%S.%LZ')}
81
+ else
82
+ {'$date' => utc_time.strftime('%Y-%m-%dT%H:%M:%SZ')}
83
+ end
84
+ else
85
+ sec = utc_time._bson_to_i
86
+ msec = utc_time.usec.divmod(1000).first
87
+ {'$date' => {'$numberLong' => (sec * 1000 + msec).to_s}}
88
+ end
89
+ end
90
+
91
+ def _bson_to_i
92
+ # Workaround for JRuby's #to_i rounding negative timestamps up
93
+ # rather than down (https://github.com/jruby/jruby/issues/6104)
94
+ if BSON::Environment.jruby?
95
+ (self - usec.to_r/1000000).to_i
96
+ else
97
+ to_i
98
+ end
42
99
  end
43
100
 
44
101
  module ClassMethods
@@ -47,13 +104,15 @@ module BSON
47
104
  #
48
105
  # @param [ ByteBuffer ] buffer The byte buffer.
49
106
  #
107
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
108
+ #
50
109
  # @return [ Time ] The decoded UTC datetime.
51
110
  #
52
111
  # @see http://bsonspec.org/#/specification
53
112
  #
54
113
  # @since 2.0.0
55
- def from_bson(buffer)
56
- seconds, fragment = Int64.from_bson(buffer).divmod(1000)
114
+ def from_bson(buffer, **options)
115
+ seconds, fragment = Int64.from_bson(buffer, mode: nil).divmod(1000)
57
116
  at(seconds, fragment * 1000).utc
58
117
  end
59
118
  end