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.
Files changed (226) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +106 -7
  3. data/Rakefile +86 -43
  4. data/ext/bson/{native-endian.h → bson-endian.h} +14 -107
  5. data/ext/bson/bson-native.h +135 -0
  6. data/ext/bson/bytebuf.c +133 -0
  7. data/ext/bson/endian.c +117 -0
  8. data/ext/bson/extconf.rb +8 -3
  9. data/ext/bson/init.c +364 -0
  10. data/ext/bson/libbson-utf8.c +230 -0
  11. data/ext/bson/read.c +470 -0
  12. data/ext/bson/util.c +250 -0
  13. data/ext/bson/write.c +675 -0
  14. data/lib/bson/active_support.rb +19 -0
  15. data/lib/bson/array.rb +97 -30
  16. data/lib/bson/big_decimal.rb +77 -0
  17. data/lib/bson/binary.rb +510 -70
  18. data/lib/bson/boolean.rb +15 -4
  19. data/lib/bson/code.rb +25 -12
  20. data/lib/bson/code_with_scope.rb +41 -15
  21. data/lib/bson/config.rb +3 -28
  22. data/lib/bson/date.rb +16 -4
  23. data/lib/bson/date_time.rb +6 -4
  24. data/lib/bson/db_pointer.rb +110 -0
  25. data/lib/bson/dbref.rb +154 -0
  26. data/lib/bson/decimal128/builder.rb +456 -0
  27. data/lib/bson/decimal128.rb +272 -0
  28. data/lib/bson/document.rb +177 -7
  29. data/lib/bson/environment.rb +17 -2
  30. data/lib/bson/error/bson_decode_error.rb +11 -0
  31. data/lib/bson/error/ext_json_parse_error.rb +11 -0
  32. data/lib/bson/error/illegal_key.rb +23 -0
  33. data/lib/bson/error/invalid_binary_type.rb +37 -0
  34. data/lib/bson/error/invalid_dbref_argument.rb +12 -0
  35. data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
  36. data/lib/bson/error/invalid_decimal128_range.rb +27 -0
  37. data/lib/bson/error/invalid_decimal128_string.rb +26 -0
  38. data/lib/bson/error/invalid_key.rb +24 -0
  39. data/lib/bson/error/invalid_object_id.rb +11 -0
  40. data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
  41. data/lib/bson/error/unrepresentable_precision.rb +19 -0
  42. data/lib/bson/error/unserializable_class.rb +13 -0
  43. data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
  44. data/lib/bson/error/unsupported_type.rb +11 -0
  45. data/lib/bson/error.rb +22 -0
  46. data/lib/bson/ext_json.rb +389 -0
  47. data/lib/bson/false_class.rb +6 -4
  48. data/lib/bson/float.rb +43 -7
  49. data/lib/bson/hash.rb +152 -37
  50. data/lib/bson/int32.rb +104 -6
  51. data/lib/bson/int64.rb +111 -8
  52. data/lib/bson/integer.rb +43 -9
  53. data/lib/bson/json.rb +3 -1
  54. data/lib/bson/max_key.rb +21 -10
  55. data/lib/bson/min_key.rb +21 -10
  56. data/lib/bson/nil_class.rb +7 -3
  57. data/lib/bson/object.rb +25 -17
  58. data/lib/bson/object_id.rb +98 -113
  59. data/lib/bson/open_struct.rb +59 -0
  60. data/lib/bson/regexp.rb +129 -56
  61. data/lib/bson/registry.rb +7 -10
  62. data/lib/bson/specialized.rb +8 -4
  63. data/lib/bson/string.rb +12 -32
  64. data/lib/bson/symbol.rb +107 -11
  65. data/lib/bson/time.rb +68 -7
  66. data/lib/bson/time_with_zone.rb +67 -0
  67. data/lib/bson/timestamp.rb +50 -10
  68. data/lib/bson/true_class.rb +6 -4
  69. data/lib/bson/undefined.rb +28 -2
  70. data/lib/bson/vector.rb +44 -0
  71. data/lib/bson/version.rb +6 -14
  72. data/lib/bson.rb +22 -12
  73. data/spec/README.md +14 -0
  74. data/spec/bson/array_spec.rb +38 -62
  75. data/spec/bson/big_decimal_spec.rb +328 -0
  76. data/spec/bson/binary_spec.rb +199 -53
  77. data/spec/bson/binary_uuid_spec.rb +190 -0
  78. data/spec/bson/boolean_spec.rb +2 -1
  79. data/spec/bson/byte_buffer_read_spec.rb +198 -0
  80. data/spec/bson/byte_buffer_spec.rb +122 -381
  81. data/spec/bson/byte_buffer_write_spec.rb +855 -0
  82. data/spec/bson/code_spec.rb +6 -4
  83. data/spec/bson/code_with_scope_spec.rb +6 -4
  84. data/spec/bson/config_spec.rb +1 -35
  85. data/spec/bson/date_spec.rb +2 -1
  86. data/spec/bson/date_time_spec.rb +55 -1
  87. data/spec/bson/dbref_legacy_spec.rb +186 -0
  88. data/spec/bson/dbref_spec.rb +487 -0
  89. data/spec/bson/decimal128_spec.rb +1840 -0
  90. data/spec/bson/document_as_spec.rb +61 -0
  91. data/spec/bson/document_spec.rb +205 -32
  92. data/spec/bson/ext_json_parse_spec.rb +346 -0
  93. data/spec/bson/false_class_spec.rb +9 -1
  94. data/spec/bson/float_spec.rb +42 -1
  95. data/spec/bson/hash_as_spec.rb +58 -0
  96. data/spec/bson/hash_spec.rb +318 -66
  97. data/spec/bson/int32_spec.rb +248 -1
  98. data/spec/bson/int64_spec.rb +308 -1
  99. data/spec/bson/integer_spec.rb +61 -3
  100. data/spec/bson/json_spec.rb +2 -1
  101. data/spec/bson/max_key_spec.rb +6 -4
  102. data/spec/bson/min_key_spec.rb +6 -4
  103. data/spec/bson/nil_class_spec.rb +2 -1
  104. data/spec/bson/object_id_spec.rb +95 -5
  105. data/spec/bson/object_spec.rb +3 -2
  106. data/spec/bson/open_struct_spec.rb +87 -0
  107. data/spec/bson/raw_spec.rb +594 -0
  108. data/spec/bson/regexp_spec.rb +61 -8
  109. data/spec/bson/registry_spec.rb +3 -2
  110. data/spec/bson/string_spec.rb +26 -33
  111. data/spec/bson/symbol_raw_spec.rb +70 -0
  112. data/spec/bson/symbol_spec.rb +77 -20
  113. data/spec/bson/time_spec.rb +206 -2
  114. data/spec/bson/time_with_zone_spec.rb +69 -0
  115. data/spec/bson/timestamp_spec.rb +58 -2
  116. data/spec/bson/true_class_spec.rb +9 -1
  117. data/spec/bson/undefined_spec.rb +28 -1
  118. data/spec/bson/vector_spec.rb +33 -0
  119. data/spec/bson_spec.rb +2 -1
  120. data/spec/runners/binary_vector.rb +78 -0
  121. data/spec/runners/common_driver.rb +348 -0
  122. data/spec/runners/corpus.rb +191 -0
  123. data/spec/runners/corpus_legacy.rb +248 -0
  124. data/spec/shared/LICENSE +20 -0
  125. data/spec/shared/bin/get-mongodb-download-url +17 -0
  126. data/spec/shared/bin/s3-copy +45 -0
  127. data/spec/shared/bin/s3-upload +69 -0
  128. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  129. data/spec/shared/lib/mrss/cluster_config.rb +231 -0
  130. data/spec/shared/lib/mrss/constraints.rb +378 -0
  131. data/spec/shared/lib/mrss/docker_runner.rb +298 -0
  132. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  133. data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
  134. data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
  135. data/spec/shared/lib/mrss/release/candidate.rb +281 -0
  136. data/spec/shared/lib/mrss/release/product_data.rb +144 -0
  137. data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
  138. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  139. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  140. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  141. data/spec/shared/lib/mrss/utils.rb +37 -0
  142. data/spec/shared/lib/tasks/candidate.rake +64 -0
  143. data/spec/shared/share/Dockerfile.erb +251 -0
  144. data/spec/shared/share/haproxy-1.conf +16 -0
  145. data/spec/shared/share/haproxy-2.conf +17 -0
  146. data/spec/shared/shlib/config.sh +27 -0
  147. data/spec/shared/shlib/distro.sh +84 -0
  148. data/spec/shared/shlib/server.sh +423 -0
  149. data/spec/shared/shlib/set_env.sh +110 -0
  150. data/spec/spec_helper.rb +61 -1
  151. data/spec/spec_tests/binary_vector_spec.rb +82 -0
  152. data/spec/spec_tests/common_driver_spec.rb +84 -0
  153. data/spec/spec_tests/corpus_legacy_spec.rb +72 -0
  154. data/spec/spec_tests/corpus_spec.rb +134 -0
  155. data/spec/spec_tests/data/binary_vector/README.md +61 -0
  156. data/spec/spec_tests/data/binary_vector/float32.json +65 -0
  157. data/spec/spec_tests/data/binary_vector/int8.json +57 -0
  158. data/spec/spec_tests/data/binary_vector/packed_bit.json +83 -0
  159. data/spec/spec_tests/data/corpus/README.md +15 -0
  160. data/spec/spec_tests/data/corpus/array.json +49 -0
  161. data/spec/spec_tests/data/corpus/binary.json +153 -0
  162. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  163. data/spec/spec_tests/data/corpus/code.json +67 -0
  164. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  165. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  166. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  167. data/spec/spec_tests/data/corpus/dbref.json +51 -0
  168. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  169. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  170. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  171. data/spec/spec_tests/data/corpus/decimal128-4.json +165 -0
  172. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  173. data/spec/spec_tests/data/corpus/decimal128-6.json +131 -0
  174. data/spec/spec_tests/data/corpus/decimal128-7.json +327 -0
  175. data/spec/spec_tests/data/corpus/document.json +60 -0
  176. data/spec/spec_tests/data/corpus/double.json +87 -0
  177. data/spec/spec_tests/data/corpus/int32.json +43 -0
  178. data/spec/spec_tests/data/corpus/int64.json +43 -0
  179. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  180. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  181. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  182. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  183. data/spec/spec_tests/data/corpus/null.json +12 -0
  184. data/spec/spec_tests/data/corpus/oid.json +28 -0
  185. data/spec/spec_tests/data/corpus/regex.json +65 -0
  186. data/spec/spec_tests/data/corpus/string.json +72 -0
  187. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  188. data/spec/spec_tests/data/corpus/timestamp.json +34 -0
  189. data/spec/spec_tests/data/corpus/top.json +262 -0
  190. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  191. data/spec/spec_tests/data/corpus_legacy/array.json +49 -0
  192. data/spec/spec_tests/data/corpus_legacy/binary.json +69 -0
  193. data/spec/spec_tests/data/corpus_legacy/boolean.json +27 -0
  194. data/spec/spec_tests/data/corpus_legacy/code.json +67 -0
  195. data/spec/spec_tests/data/corpus_legacy/code_w_scope.json +78 -0
  196. data/spec/spec_tests/data/corpus_legacy/document.json +36 -0
  197. data/spec/spec_tests/data/corpus_legacy/double.json +69 -0
  198. data/spec/spec_tests/data/corpus_legacy/failures/datetime.json +31 -0
  199. data/spec/spec_tests/data/corpus_legacy/failures/dbpointer.json +42 -0
  200. data/spec/spec_tests/data/corpus_legacy/failures/int64.json +38 -0
  201. data/spec/spec_tests/data/corpus_legacy/failures/symbol.json +62 -0
  202. data/spec/spec_tests/data/corpus_legacy/int32.json +38 -0
  203. data/spec/spec_tests/data/corpus_legacy/maxkey.json +12 -0
  204. data/spec/spec_tests/data/corpus_legacy/minkey.json +12 -0
  205. data/spec/spec_tests/data/corpus_legacy/null.json +12 -0
  206. data/spec/spec_tests/data/corpus_legacy/oid.json +28 -0
  207. data/spec/spec_tests/data/corpus_legacy/regex.json +37 -0
  208. data/spec/spec_tests/data/corpus_legacy/string.json +67 -0
  209. data/spec/spec_tests/data/corpus_legacy/timestamp.json +18 -0
  210. data/spec/spec_tests/data/corpus_legacy/top.json +62 -0
  211. data/spec/spec_tests/data/corpus_legacy/undefined.json +13 -0
  212. data/spec/spec_tests/data/decimal128/decimal128-1.json +363 -0
  213. data/spec/spec_tests/data/decimal128/decimal128-2.json +793 -0
  214. data/spec/spec_tests/data/decimal128/decimal128-3.json +1771 -0
  215. data/spec/spec_tests/data/decimal128/decimal128-4.json +165 -0
  216. data/spec/spec_tests/data/decimal128/decimal128-5.json +402 -0
  217. data/spec/spec_tests/data/decimal128/decimal128-6.json +131 -0
  218. data/spec/spec_tests/data/decimal128/decimal128-7.json +327 -0
  219. data/spec/support/shared_examples.rb +32 -11
  220. data/spec/support/spec_config.rb +17 -0
  221. data/spec/support/utils.rb +58 -0
  222. metadata +284 -45
  223. checksums.yaml.gz.sig +0 -3
  224. data/ext/bson/native.c +0 -722
  225. data.tar.gz.sig +0 -0
  226. metadata.gz.sig +0 -0
data/lib/bson/time.rb CHANGED
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
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.
@@ -17,6 +19,20 @@ module BSON
17
19
  # Injects behaviour for encoding and decoding time values to
18
20
  # and from raw bytes as specified by the BSON spec.
19
21
  #
22
+ # @note
23
+ # Ruby time can have nanosecond precision:
24
+ # +Time.utc(2020, 1, 1, 0, 0, 0, 999_999_999/1000r)+
25
+ # +Time#usec+ returns the number of microseconds in the time, and
26
+ # if the time has nanosecond precision the sub-microsecond part is
27
+ # truncated (the value is floored to the nearest millisecond).
28
+ # MongoDB only supports millisecond precision; we truncate the
29
+ # sub-millisecond part of microseconds (floor to the nearest millisecond).
30
+ # Note that if a time is constructed from a floating point value,
31
+ # the microsecond value may round to the starting floating point value
32
+ # but due to flooring, the time after serialization may end up to
33
+ # be different than the starting floating point value.
34
+ # It is recommended that time calculations use integer math only.
35
+ #
20
36
  # @see http://bsonspec.org/#/specification
21
37
  #
22
38
  # @since 2.0.0
@@ -25,20 +41,63 @@ module BSON
25
41
  # A time is type 0x09 in the BSON spec.
26
42
  #
27
43
  # @since 2.0.0
28
- BSON_TYPE = 9.chr.force_encoding(BINARY).freeze
44
+ BSON_TYPE = ::String.new(9.chr, encoding: BINARY).freeze
29
45
 
30
46
  # Get the time as encoded BSON.
31
47
  #
48
+ # @note The time is floored to the nearest millisecond.
49
+ #
32
50
  # @example Get the time as encoded BSON.
33
51
  # Time.new(2012, 1, 1, 0, 0, 0).to_bson
34
52
  #
35
- # @return [ String ] The encoded string.
53
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
36
54
  #
37
55
  # @see http://bsonspec.org/#/specification
38
56
  #
39
57
  # @since 2.0.0
40
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
41
- buffer.put_int64((to_i * 1000) + (usec / 1000))
58
+ def to_bson(buffer = ByteBuffer.new)
59
+ value = _bson_to_i * 1000 + usec.divmod(1000).first
60
+ buffer.put_int64(value)
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/extended-json.md).
65
+ #
66
+ # @note The time is floored to the nearest millisecond.
67
+ #
68
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
69
+ # (default is canonical extended JSON)
70
+ #
71
+ # @return [ Hash ] The extended json representation.
72
+ def as_extended_json(**options)
73
+ utc_time = utc
74
+ if options[:mode] == :relaxed && (1970..9999).include?(utc_time.year)
75
+ if utc_time.usec != 0
76
+ if utc_time.respond_to?(:floor)
77
+ # Ruby 2.7+
78
+ utc_time = utc_time.floor(3)
79
+ else
80
+ utc_time -= utc_time.usec.divmod(1000).last.to_r / 1000000
81
+ end
82
+ {'$date' => utc_time.strftime('%Y-%m-%dT%H:%M:%S.%LZ')}
83
+ else
84
+ {'$date' => utc_time.strftime('%Y-%m-%dT%H:%M:%SZ')}
85
+ end
86
+ else
87
+ sec = utc_time._bson_to_i
88
+ msec = utc_time.usec.divmod(1000).first
89
+ {'$date' => {'$numberLong' => (sec * 1000 + msec).to_s}}
90
+ end
91
+ end
92
+
93
+ def _bson_to_i
94
+ # Workaround for JRuby's #to_i rounding negative timestamps up
95
+ # rather than down (https://github.com/jruby/jruby/issues/6104)
96
+ if BSON::Environment.jruby?
97
+ (self - usec.to_r/1000000).to_i
98
+ else
99
+ to_i
100
+ end
42
101
  end
43
102
 
44
103
  module ClassMethods
@@ -47,13 +106,15 @@ module BSON
47
106
  #
48
107
  # @param [ ByteBuffer ] buffer The byte buffer.
49
108
  #
109
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
110
+ #
50
111
  # @return [ Time ] The decoded UTC datetime.
51
112
  #
52
113
  # @see http://bsonspec.org/#/specification
53
114
  #
54
115
  # @since 2.0.0
55
- def from_bson(buffer)
56
- seconds, fragment = Int64.from_bson(buffer).divmod(1000)
116
+ def from_bson(buffer, **options)
117
+ seconds, fragment = Int64.from_bson(buffer, mode: nil).divmod(1000)
57
118
  at(seconds, fragment * 1000).utc
58
119
  end
59
120
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ # rubocop:todo all
3
+ # Copyright (C) 2018-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 "active_support/time_with_zone"
18
+
19
+ module BSON
20
+
21
+ # Injects behaviour for encoding ActiveSupport::TimeWithZone values to
22
+ # raw bytes as specified by the BSON spec for time.
23
+ #
24
+ # @see http://bsonspec.org/#/specification
25
+ #
26
+ # @since 4.4.0
27
+ module TimeWithZone
28
+
29
+ # Get the ActiveSupport::TimeWithZone as encoded BSON.
30
+ #
31
+ # @example Get the ActiveSupport::TimeWithZone as encoded BSON.
32
+ # Time.utc(2012, 12, 12, 0, 0, 0).in_time_zone("Pacific Time (US & Canada)").to_bson
33
+ #
34
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
35
+ #
36
+ # @see http://bsonspec.org/#/specification
37
+ #
38
+ # @since 4.4.0
39
+ def to_bson(buffer = ByteBuffer.new)
40
+ buffer.put_int64((to_i * 1000) + (usec / 1000))
41
+ end
42
+
43
+ # Get the BSON type for the ActiveSupport::TimeWithZone.
44
+ #
45
+ # As the ActiveSupport::TimeWithZone is converted to a time, this returns
46
+ # the BSON type for time.
47
+ def bson_type
48
+ ::Time::BSON_TYPE
49
+ end
50
+
51
+ # @api private
52
+ def _bson_to_i
53
+ # Workaround for JRuby's #to_i rounding negative timestamps up
54
+ # rather than down (https://github.com/jruby/jruby/issues/6104)
55
+ if BSON::Environment.jruby?
56
+ (self - usec.to_r/1000000).to_i
57
+ else
58
+ to_i
59
+ end
60
+ end
61
+ end
62
+
63
+ # Enrich the ActiveSupport::TimeWithZone class with this module.
64
+ #
65
+ # @since 4.4.0
66
+ ActiveSupport::TimeWithZone.send(:include, TimeWithZone)
67
+ end
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
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.
@@ -21,11 +23,17 @@ module BSON
21
23
  # @since 2.0.0
22
24
  class Timestamp
23
25
  include JSON
26
+ include Comparable
24
27
 
25
28
  # A timestamp is type 0x11 in the BSON spec.
26
29
  #
27
30
  # @since 2.0.0
28
- BSON_TYPE = 17.chr.force_encoding(BINARY).freeze
31
+ BSON_TYPE = ::String.new(17.chr, encoding: BINARY).freeze
32
+
33
+ # Error message if an object other than a Timestamp is compared with this object.
34
+ #
35
+ # @since 4.3.0
36
+ COMPARISON_ERROR_MESSAGE = 'comparison of %s with Timestamp failed'
29
37
 
30
38
  # @!attribute seconds
31
39
  # @return [ Integer ] The number of seconds.
@@ -52,6 +60,24 @@ module BSON
52
60
  seconds == other.seconds && increment == other.increment
53
61
  end
54
62
 
63
+ # Determine if this timestamp is greater or less than another object.
64
+ #
65
+ # @example Compare the timestamp.
66
+ # timestamp < other
67
+ #
68
+ # @param [ Object ] other The object to compare against.
69
+ #
70
+ # @return [ true, false ] The result of the comparison.
71
+ #
72
+ # @since 4.3.0
73
+ def <=>(other)
74
+ raise ArgumentError.new(COMPARISON_ERROR_MESSAGE % other.class) unless other.is_a?(Timestamp)
75
+ return 0 if self == other
76
+ a = [ seconds, increment ]
77
+ b = [ other.seconds, other.increment ]
78
+ [ a, b ].sort[0] == a ? -1 : 1
79
+ end
80
+
55
81
  # Get the timestamp as JSON hash data.
56
82
  #
57
83
  # @example Get the timestamp as a JSON hash.
@@ -60,8 +86,20 @@ module BSON
60
86
  # @return [ Hash ] The timestamp as a JSON hash.
61
87
  #
62
88
  # @since 2.0.0
89
+ # @deprecated Use as_extended_json instead.
63
90
  def as_json(*args)
64
- { "t" => seconds, "i" => increment }
91
+ as_extended_json
92
+ end
93
+
94
+ # Converts this object to a representation directly serializable to
95
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
96
+ #
97
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
98
+ # (default is canonical extended JSON)
99
+ #
100
+ # @return [ Hash ] The extended json representation.
101
+ def as_extended_json(**options)
102
+ { "$timestamp" => { "t" => seconds, "i" => increment } }
65
103
  end
66
104
 
67
105
  # Instantiate the new timestamp.
@@ -82,28 +120,30 @@ module BSON
82
120
  # @example Get the timestamp as BSON.
83
121
  # timestamp.to_bson
84
122
  #
85
- # @return [ String ] The raw BSON bytes.
123
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
86
124
  #
87
125
  # @see http://bsonspec.org/#/specification
88
126
  #
89
127
  # @since 2.0.0
90
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
91
- buffer.put_int32(increment)
92
- buffer.put_int32(seconds)
128
+ def to_bson(buffer = ByteBuffer.new)
129
+ buffer.put_uint32(increment)
130
+ buffer.put_uint32(seconds)
93
131
  end
94
132
 
95
133
  # Deserialize timestamp from BSON.
96
134
  #
97
135
  # @param [ ByteBuffer ] buffer The byte buffer.
98
136
  #
137
+ # @option options [ nil | :bson ] :mode Decoding mode to use.
138
+ #
99
139
  # @return [ Timestamp ] The decoded timestamp.
100
140
  #
101
141
  # @see http://bsonspec.org/#/specification
102
142
  #
103
143
  # @since 2.0.0
104
- def self.from_bson(buffer)
105
- increment = buffer.get_int32
106
- seconds = buffer.get_int32
144
+ def self.from_bson(buffer, **options)
145
+ increment = buffer.get_uint32
146
+ seconds = buffer.get_uint32
107
147
  new(seconds, increment)
108
148
  end
109
149
 
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
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.
@@ -25,7 +27,7 @@ module BSON
25
27
  # A true value in the BSON spec is 0x01.
26
28
  #
27
29
  # @since 2.0.0
28
- TRUE_BYTE = 1.chr.force_encoding(BINARY).freeze
30
+ TRUE_BYTE = ::String.new(1.chr, encoding: BINARY).freeze
29
31
 
30
32
  # The BSON type for true values is the general boolean type of 0x08.
31
33
  #
@@ -44,12 +46,12 @@ module BSON
44
46
  # @example Get the true boolean as encoded BSON.
45
47
  # true.to_bson
46
48
  #
47
- # @return [ String ] The encoded string.
49
+ # @return [ BSON::ByteBuffer ] The buffer with the encoded object.
48
50
  #
49
51
  # @see http://bsonspec.org/#/specification
50
52
  #
51
53
  # @since 2.0.0
52
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
54
+ def to_bson(buffer = ByteBuffer.new)
53
55
  buffer.put_byte(TRUE_BYTE)
54
56
  end
55
57
  end
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
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.
@@ -20,12 +22,13 @@ module BSON
20
22
  #
21
23
  # @since 2.0.0
22
24
  class Undefined
25
+ include JSON
23
26
  include Specialized
24
27
 
25
28
  # Undefined is type 0x06 in the BSON spec.
26
29
  #
27
30
  # @since 2.0.0
28
- BSON_TYPE = 6.chr.force_encoding(BINARY).freeze
31
+ BSON_TYPE = ::String.new(6.chr, encoding: BINARY).freeze
29
32
 
30
33
  # Determine if undefined is equal to another object.
31
34
  #
@@ -41,6 +44,29 @@ module BSON
41
44
  self.class == other.class
42
45
  end
43
46
 
47
+ # Return a string representation of the BSON::Undefined for use in
48
+ # application-level JSON serialization. This method is intentionally
49
+ # different from #as_extended_json.
50
+ #
51
+ # @example Get the undefined as a JSON-serializable object.
52
+ # undefined.as_json
53
+ #
54
+ # @return [ nil ] The undefined as nil.
55
+ def as_json(*args)
56
+ nil
57
+ end
58
+
59
+ # Converts this object to a representation directly serializable to
60
+ # Extended JSON (https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
61
+ #
62
+ # @option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
63
+ # (default is canonical extended JSON)
64
+ #
65
+ # @return [ Hash ] The extended json representation.
66
+ def as_extended_json(**options)
67
+ { "$undefined" => true }
68
+ end
69
+
44
70
  # Register this type when the module is loaded.
45
71
  #
46
72
  # @since 2.0.0
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025-present 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
+ module BSON
18
+ # Vector of numbers along with metadata for binary interoperability.
19
+ class Vector < ::Array
20
+ # @return [ Integer ] The data type stored in the vector.
21
+ attr_reader :dtype
22
+
23
+ # @return [ Integer ] The number of bits in the final byte that are to
24
+ # be ignored when a vector element's size is less than a byte
25
+ # and the length of the vector is not a multiple of 8.
26
+ attr_reader :padding
27
+
28
+ # @return [ BSON::ByteBuffer ] The data in the vector.
29
+ def data
30
+ self
31
+ end
32
+
33
+ # @param [ ::Array ] data The data to initialize the vector with.
34
+ # @param [ Integer ] dtype The data type of the vector.
35
+ # @param [ Integer ] padding The number of bits in the final byte that are to
36
+ # be ignored when a vector element's size is less than a byte
37
+ # and the length of the vector is not a multiple of 8.
38
+ def initialize(data, dtype, padding = 0)
39
+ @dtype = dtype
40
+ @padding = padding
41
+ super(data.dup)
42
+ end
43
+ end
44
+ end
data/lib/bson/version.rb CHANGED
@@ -1,17 +1,9 @@
1
- # Copyright (C) 2009-2015 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.
1
+ # frozen_string_literal: true
14
2
 
15
3
  module BSON
16
- VERSION = "4.1.1".freeze
4
+ # The current version of the library.
5
+ #
6
+ # NOTE: this file is automatically updated via `rake candidate:create`.
7
+ # Manual changes to this file may be overwritten by that rake task.
8
+ VERSION = '5.2.0'
17
9
  end
data/lib/bson.rb CHANGED
@@ -1,4 +1,6 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
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.
@@ -26,7 +28,7 @@ module BSON
26
28
  #
27
29
  # @param [ String ] string The string to create the id from.
28
30
  #
29
- # @raise [ BSON::ObjectId::Invalid ] If the provided string is invalid.
31
+ # @raise [ BSON::Error::InvalidObjectId ] If the provided string is invalid.
30
32
  #
31
33
  # @return [ BSON::ObjectId ] The new object id.
32
34
  #
@@ -38,25 +40,26 @@ module BSON
38
40
  # Constant for binary string encoding.
39
41
  #
40
42
  # @since 2.0.0
41
- BINARY = "BINARY".freeze
43
+ BINARY = "BINARY"
42
44
 
43
45
  # Constant for bson types that don't actually serialize a value.
44
46
  #
45
47
  # @since 2.0.0
46
- NO_VALUE = "".force_encoding(BINARY).freeze
48
+ NO_VALUE = ::String.new(encoding: BINARY).freeze
47
49
 
48
50
  # Constant for a null byte (0x00).
49
51
  #
50
52
  # @since 2.0.0
51
- NULL_BYTE = 0.chr.force_encoding(BINARY).freeze
53
+ NULL_BYTE = ::String.new(0.chr, encoding: BINARY).freeze
52
54
 
53
55
  # Constant for UTF-8 string encoding.
54
56
  #
55
57
  # @since 2.0.0
56
- UTF8 = "UTF-8".freeze
58
+ UTF8 = "UTF-8"
57
59
  end
58
60
 
59
61
  require "bson/config"
62
+ require "bson/error"
60
63
  require "bson/registry"
61
64
  require "bson/specialized"
62
65
  require "bson/json"
@@ -70,10 +73,16 @@ require "bson/code"
70
73
  require "bson/code_with_scope"
71
74
  require "bson/date"
72
75
  require "bson/date_time"
76
+ require "bson/db_pointer"
77
+ require "bson/decimal128"
78
+ require "bson/big_decimal"
73
79
  require "bson/document"
80
+ require "bson/ext_json"
74
81
  require "bson/false_class"
75
82
  require "bson/float"
76
83
  require "bson/hash"
84
+ require "bson/dbref"
85
+ require "bson/open_struct"
77
86
  require "bson/max_key"
78
87
  require "bson/min_key"
79
88
  require "bson/nil_class"
@@ -86,20 +95,21 @@ require "bson/time"
86
95
  require "bson/timestamp"
87
96
  require "bson/true_class"
88
97
  require "bson/undefined"
98
+ require "bson/vector"
89
99
  require "bson/version"
90
100
 
91
101
  # If we are using JRuby, attempt to load the Java extensions, if we are using
92
- # MRI or Rubinius, attempt to load the C extenstions. If either of these fail,
93
- # we revert back to a pure Ruby implementation of the Buffer class.
102
+ # MRI or Rubinius, attempt to load the C extensions.
94
103
  #
95
104
  # @since 2.0.0
96
105
  begin
97
106
  if BSON::Environment.jruby?
98
107
  require "bson-ruby.jar"
99
- org.bson.NativeService.new.basicLoad(JRuby.runtime)
108
+ JRuby::Util.load_ext("org.bson_ruby.NativeService")
100
109
  else
101
- require "native"
110
+ require "bson_native"
102
111
  end
103
- rescue LoadError
104
- $stderr.puts("BSON is using the pure Ruby implementation.")
112
+ rescue LoadError => e
113
+ $stderr.puts("Failed to load the necessary extensions: #{e.class}: #{e}")
114
+ raise
105
115
  end
data/spec/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # Running BSON Ruby Tests
2
+
3
+ ## Quick Start
4
+
5
+ The test suite requires shared tooling that is stored in a separate repository
6
+ and is referenced as a submodule. After checking out the desired bson-ruby
7
+ branch, check out the matching submodules:
8
+
9
+ git submodule init
10
+ git submodule update
11
+
12
+ Then, to run the test suite:
13
+
14
+ rake
@@ -1,4 +1,5 @@
1
- # Copyright (C) 2009-2014 MongoDB Inc.
1
+ # rubocop:todo all
2
+ # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
4
5
  # you may not use this file except in compliance with the License.
@@ -34,65 +35,6 @@ describe Array do
34
35
  [ { "$testing" => "value" } ]
35
36
  end
36
37
 
37
- context "when validating keys" do
38
-
39
- context "when validating globally" do
40
-
41
- before do
42
- BSON::Config.validating_keys = true
43
- end
44
-
45
- after do
46
- BSON::Config.validating_keys = false
47
- end
48
-
49
- it "raises an error" do
50
- expect {
51
- obj.to_bson
52
- }.to raise_error(BSON::String::IllegalKey)
53
- end
54
- end
55
-
56
- context "when validating locally" do
57
-
58
- it "raises an error" do
59
- expect {
60
- obj.to_bson(BSON::ByteBuffer.new, true)
61
- }.to raise_error(BSON::String::IllegalKey)
62
- end
63
-
64
- context "when serializing different types" do
65
-
66
- let(:obj) do
67
- [ BSON::Binary.new("testing", :generic),
68
- BSON::Code.new("this.value = 5"),
69
- BSON::CodeWithScope.new("this.value = val", "test"),
70
- Date.new(2012, 1, 1),
71
- Time.utc(2012, 1, 1),
72
- DateTime.new(2012, 1, 1, 0, 0, 0),
73
- false,
74
- 1.2332,
75
- Integer::MAX_32BIT - 1,
76
- BSON::ObjectId.new,
77
- /\W+/i,
78
- 'a string',
79
- :a_symbol,
80
- Time.utc(2012, 1, 1, 0, 0, 0),
81
- BSON::Timestamp.new(1, 10),
82
- true,
83
- { "$testing" => "value" }
84
- ]
85
- end
86
-
87
- it "raises an error" do
88
- expect {
89
- obj.to_bson(BSON::ByteBuffer.new, true)
90
- }.to raise_error(BSON::String::IllegalKey)
91
- end
92
- end
93
- end
94
- end
95
-
96
38
  context "when not validating keys" do
97
39
 
98
40
  let(:bson) do
@@ -127,11 +69,28 @@ describe Array do
127
69
  end
128
70
 
129
71
  it "serializes the hash" do
130
- expect(obj.to_bson.length).to eq(251)
72
+ expect(obj.to_bson.length).to eq(252)
131
73
  end
132
74
  end
133
75
  end
134
76
  end
77
+
78
+ context 'when array contains value of an unserializable class' do
79
+ class ArraySpecUnserializableClass
80
+ end
81
+
82
+ let(:obj) do
83
+ [ArraySpecUnserializableClass.new]
84
+ end
85
+
86
+ it 'raises UnserializableClass' do
87
+ lambda do
88
+ obj.to_bson
89
+ end.should raise_error(BSON::Error::UnserializableClass,
90
+ # C extension does not provide element position in the exception message.
91
+ /(Array element at position 0|Value) does not define its BSON serialized type:.*ArraySpecUnserializableClass/)
92
+ end
93
+ end
135
94
  end
136
95
 
137
96
  describe "#to_bson_normalized_value" do
@@ -169,8 +128,25 @@ describe Array do
169
128
  it "raises an exception" do
170
129
  expect {
171
130
  [ 1 ].to_bson_object_id
172
- }.to raise_error(BSON::ObjectId::Invalid)
131
+ }.to raise_error(BSON::Error::InvalidObjectId)
173
132
  end
174
133
  end
175
134
  end
135
+
136
+ describe '#as_extended_json' do
137
+
138
+ let(:object) do
139
+ ['one', :two, 3, 4.0, nil]
140
+ end
141
+
142
+ let(:expected) do
143
+ ["one", { "$symbol" => "two" }, { "$numberInt" => "3" }, { "$numberDouble"=> "4.0" }, nil]
144
+ end
145
+
146
+ it 'returns the extended serialization' do
147
+ expect(object.as_extended_json).to eq(expected)
148
+ end
149
+
150
+ it_behaves_like 'an Extended JSON serializable object'
151
+ end
176
152
  end