bson 4.15.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +4 -4
  4. data/Rakefile +5 -0
  5. data/ext/bson/bson-native.h +12 -4
  6. data/ext/bson/extconf.rb +8 -3
  7. data/ext/bson/init.c +11 -11
  8. data/ext/bson/read.c +21 -6
  9. data/ext/bson/util.c +168 -16
  10. data/ext/bson/write.c +30 -39
  11. data/lib/bson/active_support.rb +1 -0
  12. data/lib/bson/array.rb +57 -31
  13. data/lib/bson/big_decimal.rb +16 -6
  14. data/lib/bson/binary.rb +255 -128
  15. data/lib/bson/boolean.rb +1 -0
  16. data/lib/bson/code.rb +9 -11
  17. data/lib/bson/code_with_scope.rb +8 -10
  18. data/lib/bson/config.rb +1 -27
  19. data/lib/bson/date.rb +2 -1
  20. data/lib/bson/date_time.rb +2 -1
  21. data/lib/bson/db_pointer.rb +11 -12
  22. data/lib/bson/dbref.rb +11 -9
  23. data/lib/bson/decimal128/builder.rb +9 -8
  24. data/lib/bson/decimal128.rb +24 -110
  25. data/lib/bson/document.rb +1 -0
  26. data/lib/bson/environment.rb +1 -0
  27. data/lib/bson/error/bson_decode_error.rb +11 -0
  28. data/lib/bson/error/ext_json_parse_error.rb +11 -0
  29. data/lib/bson/error/illegal_key.rb +23 -0
  30. data/lib/bson/error/invalid_binary_type.rb +37 -0
  31. data/lib/bson/error/invalid_dbref_argument.rb +12 -0
  32. data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
  33. data/lib/bson/error/invalid_decimal128_range.rb +27 -0
  34. data/lib/bson/error/invalid_decimal128_string.rb +26 -0
  35. data/lib/bson/error/invalid_key.rb +24 -0
  36. data/lib/bson/error/invalid_object_id.rb +11 -0
  37. data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
  38. data/lib/bson/error/unrepresentable_precision.rb +19 -0
  39. data/lib/bson/error/unserializable_class.rb +13 -0
  40. data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
  41. data/lib/bson/error/unsupported_type.rb +11 -0
  42. data/lib/bson/error.rb +16 -28
  43. data/lib/bson/ext_json.rb +1 -0
  44. data/lib/bson/false_class.rb +2 -1
  45. data/lib/bson/float.rb +2 -1
  46. data/lib/bson/hash.rb +127 -72
  47. data/lib/bson/int32.rb +16 -4
  48. data/lib/bson/int64.rb +16 -4
  49. data/lib/bson/integer.rb +3 -4
  50. data/lib/bson/json.rb +1 -0
  51. data/lib/bson/max_key.rb +7 -9
  52. data/lib/bson/min_key.rb +7 -9
  53. data/lib/bson/nil_class.rb +1 -0
  54. data/lib/bson/object.rb +5 -25
  55. data/lib/bson/object_id.rb +75 -121
  56. data/lib/bson/open_struct.rb +3 -2
  57. data/lib/bson/regexp.rb +35 -64
  58. data/lib/bson/registry.rb +2 -6
  59. data/lib/bson/specialized.rb +2 -1
  60. data/lib/bson/string.rb +4 -27
  61. data/lib/bson/symbol.rb +22 -19
  62. data/lib/bson/time.rb +2 -1
  63. data/lib/bson/time_with_zone.rb +13 -1
  64. data/lib/bson/timestamp.rb +2 -1
  65. data/lib/bson/true_class.rb +2 -1
  66. data/lib/bson/undefined.rb +14 -0
  67. data/lib/bson/version.rb +2 -1
  68. data/lib/bson.rb +3 -2
  69. data/spec/bson/array_spec.rb +19 -60
  70. data/spec/bson/big_decimal_spec.rb +16 -4
  71. data/spec/bson/binary_spec.rb +83 -74
  72. data/spec/bson/binary_uuid_spec.rb +1 -0
  73. data/spec/bson/boolean_spec.rb +1 -0
  74. data/spec/bson/byte_buffer_read_spec.rb +1 -0
  75. data/spec/bson/byte_buffer_spec.rb +1 -0
  76. data/spec/bson/byte_buffer_write_spec.rb +1 -0
  77. data/spec/bson/code_spec.rb +5 -3
  78. data/spec/bson/code_with_scope_spec.rb +5 -3
  79. data/spec/bson/config_spec.rb +1 -35
  80. data/spec/bson/date_spec.rb +1 -0
  81. data/spec/bson/date_time_spec.rb +1 -0
  82. data/spec/bson/dbref_legacy_spec.rb +20 -3
  83. data/spec/bson/dbref_spec.rb +9 -9
  84. data/spec/bson/decimal128_spec.rb +40 -20
  85. data/spec/bson/document_as_spec.rb +1 -0
  86. data/spec/bson/document_spec.rb +1 -1
  87. data/spec/bson/ext_json_parse_spec.rb +1 -0
  88. data/spec/bson/false_class_spec.rb +8 -0
  89. data/spec/bson/float_spec.rb +8 -3
  90. data/spec/bson/hash_as_spec.rb +1 -0
  91. data/spec/bson/hash_spec.rb +87 -75
  92. data/spec/bson/int32_spec.rb +21 -6
  93. data/spec/bson/int64_spec.rb +21 -6
  94. data/spec/bson/integer_spec.rb +45 -13
  95. data/spec/bson/json_spec.rb +1 -0
  96. data/spec/bson/max_key_spec.rb +5 -3
  97. data/spec/bson/min_key_spec.rb +5 -3
  98. data/spec/bson/nil_class_spec.rb +1 -0
  99. data/spec/bson/object_id_spec.rb +43 -4
  100. data/spec/bson/object_spec.rb +2 -1
  101. data/spec/bson/open_struct_spec.rb +14 -71
  102. data/spec/bson/raw_spec.rb +9 -15
  103. data/spec/bson/regexp_spec.rb +4 -3
  104. data/spec/bson/registry_spec.rb +2 -1
  105. data/spec/bson/string_spec.rb +13 -38
  106. data/spec/bson/symbol_raw_spec.rb +25 -0
  107. data/spec/bson/symbol_spec.rb +15 -18
  108. data/spec/bson/time_spec.rb +1 -0
  109. data/spec/bson/time_with_zone_spec.rb +1 -0
  110. data/spec/bson/timestamp_spec.rb +1 -0
  111. data/spec/bson/true_class_spec.rb +8 -0
  112. data/spec/bson/undefined_spec.rb +27 -0
  113. data/spec/bson_spec.rb +1 -0
  114. data/spec/runners/common_driver.rb +6 -5
  115. data/spec/runners/corpus.rb +6 -0
  116. data/spec/runners/corpus_legacy.rb +1 -0
  117. data/spec/shared/lib/mrss/constraints.rb +8 -16
  118. data/spec/shared/lib/mrss/docker_runner.rb +30 -3
  119. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  120. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  121. data/spec/shared/lib/mrss/lite_constraints.rb +48 -1
  122. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  123. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  124. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  125. data/spec/shared/lib/mrss/utils.rb +28 -6
  126. data/spec/shared/share/Dockerfile.erb +68 -85
  127. data/spec/shared/shlib/config.sh +27 -0
  128. data/spec/shared/shlib/server.sh +73 -24
  129. data/spec/shared/shlib/set_env.sh +39 -1
  130. data/spec/spec_helper.rb +1 -0
  131. data/spec/spec_tests/common_driver_spec.rb +9 -4
  132. data/spec/spec_tests/corpus_legacy_spec.rb +1 -0
  133. data/spec/spec_tests/corpus_spec.rb +13 -3
  134. data/spec/spec_tests/data/corpus/binary.json +5 -0
  135. data/spec/spec_tests/data/corpus/code.json +13 -13
  136. data/spec/spec_tests/data/corpus/decimal128-4.json +48 -0
  137. data/spec/spec_tests/data/corpus/decimal128-6.json +12 -0
  138. data/spec/spec_tests/data/corpus/decimal128-7.json +4 -0
  139. data/spec/spec_tests/data/corpus/document.json +20 -0
  140. data/spec/spec_tests/data/corpus/symbol.json +7 -7
  141. data/spec/spec_tests/data/corpus/top.json +18 -3
  142. data/spec/support/shared_examples.rb +28 -5
  143. data/spec/support/spec_config.rb +1 -0
  144. data/spec/support/utils.rb +49 -1
  145. data.tar.gz.sig +0 -0
  146. metadata +167 -144
  147. metadata.gz.sig +2 -1
data/lib/bson/binary.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # Copyright (C) 2009-2020 MongoDB Inc.
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +17,6 @@
16
17
  require 'base64'
17
18
 
18
19
  module BSON
19
-
20
20
  # Represents binary data.
21
21
  #
22
22
  # @see http://bsonspec.org/#/specification
@@ -40,17 +40,21 @@ module BSON
40
40
  #
41
41
  # @since 2.0.0
42
42
  SUBTYPES = {
43
- :generic => 0.chr,
44
- :function => 1.chr,
45
- :old => 2.chr,
46
- :uuid_old => 3.chr,
47
- :uuid => 4.chr,
48
- :md5 => 5.chr,
49
- :ciphertext => 6.chr,
50
- :column => 7.chr,
51
- :user => 128.chr,
43
+ generic: 0.chr,
44
+ function: 1.chr,
45
+ old: 2.chr,
46
+ uuid_old: 3.chr,
47
+ uuid: 4.chr,
48
+ md5: 5.chr,
49
+ ciphertext: 6.chr,
50
+ column: 7.chr,
51
+ sensitive: 8.chr,
52
+ user: 128.chr,
52
53
  }.freeze
53
54
 
55
+ # The starting point of the user-defined subtype range.
56
+ USER_SUBTYPE = 0x80
57
+
54
58
  # The mappings of single byte subtypes to their symbol counterparts.
55
59
  #
56
60
  # @since 2.0.0
@@ -64,10 +68,11 @@ module BSON
64
68
  attr_reader :data
65
69
 
66
70
  # @return [ Symbol ] The binary type.
67
- #
68
- # @since 2.0.0
69
71
  attr_reader :type
70
72
 
73
+ # @return [ String ] The raw type value, as an encoded integer.
74
+ attr_reader :raw_type
75
+
71
76
  # Determine if this binary object is equal to another object.
72
77
  #
73
78
  # @example Check the binary equality.
@@ -80,6 +85,7 @@ module BSON
80
85
  # @since 2.0.0
81
86
  def ==(other)
82
87
  return false unless other.is_a?(Binary)
88
+
83
89
  type == other.type && data == other.data
84
90
  end
85
91
  alias eql? ==
@@ -92,19 +98,16 @@ module BSON
92
98
  #
93
99
  # @since 2.3.1
94
100
  def hash
95
- data.hash + type.hash
101
+ [ data, type ].hash
96
102
  end
97
103
 
98
- # Get the binary as JSON hash data.
99
- #
100
- # @example Get the binary as a JSON hash.
101
- # binary.as_json
104
+ # Return a representation of the object for use in
105
+ # application-level JSON serialization. Since BSON::Binary
106
+ # is used exclusively in BSON-related contexts, this
107
+ # method returns the canonical Extended JSON representation.
102
108
  #
103
- # @return [ Hash ] The binary as a JSON hash.
104
- #
105
- # @since 2.0.0
106
- # @deprecated Use as_extended_json instead.
107
- def as_json(*args)
109
+ # @return [ Hash ] The extended json representation.
110
+ def as_json(*_args)
108
111
  as_extended_json
109
112
  end
110
113
 
@@ -116,17 +119,15 @@ module BSON
116
119
  #
117
120
  # @return [ Hash ] The extended json representation.
118
121
  def as_extended_json(**options)
119
- subtype = SUBTYPES[type].each_byte.map { |c| c.to_s(16) }.join
120
- if subtype.length == 1
121
- subtype = "0#{subtype}"
122
- end
122
+ subtype = @raw_type.each_byte.map { |c| c.to_s(16) }.join
123
+ subtype = "0#{subtype}" if subtype.length == 1
123
124
 
124
125
  value = Base64.encode64(data).strip
125
126
 
126
127
  if options[:mode] == :legacy
127
- { "$binary" => value, "$type" => subtype }
128
+ { '$binary' => value, '$type' => subtype }
128
129
  else
129
- { "$binary" => {'base64' => value, "subType" => subtype }}
130
+ { '$binary' => { 'base64' => value, 'subType' => subtype } }
130
131
  end
131
132
  end
132
133
 
@@ -146,20 +147,17 @@ module BSON
146
147
  # @param [ Symbol ] type The binary type.
147
148
  #
148
149
  # @since 2.0.0
149
- def initialize(data = "", type = :generic)
150
- validate_type!(type)
151
-
152
- # The Binary class used to force encoding to BINARY when serializing to
153
- # BSON. Instead of doing that during serialization, perform this
154
- # operation during Binary construction to make it clear that once
155
- # the string is given to the Binary, the data is treated as a binary
156
- # string and not a text string in any encoding.
157
- unless data.encoding == Encoding.find('BINARY')
158
- data = data.dup.force_encoding('BINARY')
159
- end
150
+ def initialize(data = '', type = :generic)
151
+ initialize_instance(data, type)
152
+ end
160
153
 
161
- @data = data
162
- @type = type
154
+ # For legacy deserialization support where BSON::Binary objects are
155
+ # expected to have a specific internal representation (with only
156
+ # @type and @data instance variables).
157
+ #
158
+ # @api private
159
+ def init_with(coder)
160
+ initialize_instance(coder['data'], coder['type'])
163
161
  end
164
162
 
165
163
  # Get a nice string for use with object inspection.
@@ -202,37 +200,15 @@ module BSON
202
200
  # @api experimental
203
201
  def to_uuid(representation = nil)
204
202
  if representation.is_a?(String)
205
- raise ArgumentError, "Representation must be given as a symbol: #{representation}"
203
+ raise ArgumentError,
204
+ "Representation must be given as a symbol: #{representation.inspect}"
206
205
  end
206
+
207
207
  case type
208
208
  when :uuid
209
- if representation && representation != :standard
210
- raise ArgumentError, "Binary of type :uuid can only be stringified to :standard representation, requested: #{representation.inspect}"
211
- end
212
-
213
- data.split('').map { |n| '%02x' % n.ord }.join.sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5')
209
+ from_uuid_to_uuid(representation || :standard)
214
210
  when :uuid_old
215
- if representation.nil?
216
- raise ArgumentError, 'Representation must be specified for BSON::Binary objects of type :uuid_old'
217
- end
218
-
219
- hex = data.split('').map { |n| '%02x' % n.ord }.join
220
-
221
- case representation
222
- when :standard
223
- raise ArgumentError, 'BSON::Binary objects of type :uuid_old cannot be stringified to :standard representation'
224
- when :csharp_legacy
225
- hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(.{16})\z/, '\4\3\2\1\6\5\8\7\9')
226
- when :java_legacy
227
- hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)\z/) do |m|
228
- "#{$8}#{$7}#{$6}#{$5}#{$4}#{$3}#{$2}#{$1}" +
229
- "#{$16}#{$15}#{$14}#{$13}#{$12}#{$11}#{$10}#{$9}"
230
- end
231
- when :python_legacy
232
- hex
233
- else
234
- raise ArgumentError, "Invalid representation: #{representation}"
235
- end.sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5')
211
+ from_uuid_old_to_uuid(representation)
236
212
  else
237
213
  raise TypeError, "The type of Binary must be :uuid or :uuid_old, this object is: #{type.inspect}"
238
214
  end
@@ -248,10 +224,10 @@ module BSON
248
224
  # @see http://bsonspec.org/#/specification
249
225
  #
250
226
  # @since 2.0.0
251
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
227
+ def to_bson(buffer = ByteBuffer.new)
252
228
  position = buffer.length
253
229
  buffer.put_int32(0)
254
- buffer.put_byte(SUBTYPES[type])
230
+ buffer.put_byte(@raw_type)
255
231
  buffer.put_int32(data.bytesize) if type == :old
256
232
  buffer.put_bytes(data)
257
233
  buffer.replace_int32(position, buffer.length - position - 5)
@@ -268,13 +244,19 @@ module BSON
268
244
  # @see http://bsonspec.org/#/specification
269
245
  #
270
246
  # @since 2.0.0
271
- def self.from_bson(buffer, **options)
247
+ def self.from_bson(buffer, **_options)
272
248
  length = buffer.get_int32
273
249
  type_byte = buffer.get_byte
274
- type = TYPES[type_byte]
275
- if type.nil?
276
- raise Error::UnsupportedBinarySubtype,
277
- "BSON data contains unsupported binary subtype #{'0x%02x' % type_byte.ord}"
250
+
251
+ if type_byte.bytes.first < USER_SUBTYPE
252
+ type = TYPES[type_byte]
253
+
254
+ if type.nil?
255
+ raise Error::UnsupportedBinarySubtype,
256
+ "BSON data contains unsupported binary subtype #{'0x%02x' % type_byte.ord}"
257
+ end
258
+ else
259
+ type = type_byte
278
260
  end
279
261
 
280
262
  length = buffer.get_int32 if type == :old
@@ -308,66 +290,166 @@ module BSON
308
290
  #
309
291
  # @api experimental
310
292
  def self.from_uuid(uuid, representation = nil)
311
- if representation.is_a?(String)
312
- raise ArgumentError, "Representation must be given as a symbol: #{representation}"
293
+ raise ArgumentError, "Representation must be given as a symbol: #{representation}" if representation.is_a?(String)
294
+
295
+ uuid_binary = uuid.delete('-').scan(/../).map(&:hex).map(&:chr).join
296
+ representation ||= :standard
297
+
298
+ handler = :"from_#{representation}_uuid"
299
+ raise ArgumentError, "Invalid representation: #{representation}" unless respond_to?(handler)
300
+
301
+ send(handler, uuid_binary)
302
+ end
303
+
304
+ # Constructs a new binary object from a standard-format binary UUID
305
+ # representation.
306
+ #
307
+ # @param [ String ] uuid_binary the UUID data
308
+ #
309
+ # @return [ BSON::Binary ] the Binary object
310
+ #
311
+ # @api private
312
+ def self.from_standard_uuid(uuid_binary)
313
+ new(uuid_binary, :uuid)
314
+ end
315
+
316
+ # Constructs a new binary object from a csharp legacy-format binary UUID
317
+ # representation.
318
+ #
319
+ # @param [ String ] uuid_binary the UUID data
320
+ #
321
+ # @return [ BSON::Binary ] the Binary object
322
+ #
323
+ # @api private
324
+ def self.from_csharp_legacy_uuid(uuid_binary)
325
+ uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.{8})\z/, '\4\3\2\1\6\5\8\7\9')
326
+ new(uuid_binary, :uuid_old)
327
+ end
328
+
329
+ # Constructs a new binary object from a java legacy-format binary UUID
330
+ # representation.
331
+ #
332
+ # @param [ String ] uuid_binary the UUID data
333
+ #
334
+ # @return [ BSON::Binary ] the Binary object
335
+ #
336
+ # @api private
337
+ def self.from_java_legacy_uuid(uuid_binary)
338
+ uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\z/) do
339
+ (::Regexp.last_match[1..8].reverse + ::Regexp.last_match[9..16].reverse).join
313
340
  end
314
- uuid_binary = uuid.gsub('-', '').scan(/../).map(&:hex).map(&:chr).join
315
- case representation && representation
316
- when nil, :standard
317
- new(uuid_binary, :uuid)
318
- when :csharp_legacy
319
- uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.{8})\z/, '\4\3\2\1\6\5\8\7\9')
320
- new(uuid_binary, :uuid_old)
321
- when :java_legacy
322
- uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\z/) do |m|
323
- "#{$8}#{$7}#{$6}#{$5}#{$4}#{$3}#{$2}#{$1}" +
324
- "#{$16}#{$15}#{$14}#{$13}#{$12}#{$11}#{$10}#{$9}"
325
- end
326
- new(uuid_binary, :uuid_old)
327
- when :python_legacy
328
- new(uuid_binary, :uuid_old)
329
- else
330
- raise ArgumentError, "Invalid representation: #{representation}"
341
+ new(uuid_binary, :uuid_old)
342
+ end
343
+
344
+ # Constructs a new binary object from a python legacy-format binary UUID
345
+ # representation.
346
+ #
347
+ # @param [ String ] uuid_binary the UUID data
348
+ #
349
+ # @return [ BSON::Binary ] the Binary object
350
+ #
351
+ # @api private
352
+ def self.from_python_legacy_uuid(uuid_binary)
353
+ new(uuid_binary, :uuid_old)
354
+ end
355
+
356
+ private
357
+
358
+ # initializes an instance of BSON::Binary.
359
+ #
360
+ # @param [ String ] data the data to initialize the object with
361
+ # @param [ Symbol ] type the type to assign the binary object
362
+ def initialize_instance(data, type)
363
+ @type = validate_type!(type)
364
+
365
+ # The Binary class used to force encoding to BINARY when serializing to
366
+ # BSON. Instead of doing that during serialization, perform this
367
+ # operation during Binary construction to make it clear that once
368
+ # the string is given to the Binary, the data is treated as a binary
369
+ # string and not a text string in any encoding.
370
+ data = data.dup.force_encoding('BINARY') unless data.encoding == Encoding.find('BINARY')
371
+
372
+ @data = data
373
+ end
374
+
375
+ # Converts the Binary UUID object to a UUID of the given representation.
376
+ # Currently, only :standard representation is supported.
377
+ #
378
+ # @param [ Symbol ] representation The representation to target (must be
379
+ # :standard)
380
+ #
381
+ # @return [ String ] the UUID as a string
382
+ def from_uuid_to_uuid(representation)
383
+ if representation != :standard
384
+ raise ArgumentError,
385
+ 'Binary of type :uuid can only be stringified to :standard representation, ' \
386
+ "requested: #{representation.inspect}"
331
387
  end
388
+
389
+ data
390
+ .chars
391
+ .map { |n| '%02x' % n.ord }
392
+ .join
393
+ .sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5')
332
394
  end
333
395
 
334
- # Raised when providing an invalid type to the Binary.
396
+ # Converts the UUID-old object to a UUID of the given representation.
335
397
  #
336
- # @since 2.0.0
337
- class InvalidType < RuntimeError
338
-
339
- # @!attribute type
340
- # @return [ Object ] The invalid type.
341
- # @since 2.0.0
342
- attr_reader :type
343
-
344
- # Instantiate the new error.
345
- #
346
- # @example Instantiate the error.
347
- # InvalidType.new(:error)
348
- #
349
- # @param [ Object ] type The invalid type.
350
- #
351
- # @since 2.0.0
352
- def initialize(type)
353
- @type = type
398
+ # @param [ Symbol ] representation The representation to target
399
+ #
400
+ # @return [ String ] the UUID as a string
401
+ def from_uuid_old_to_uuid(representation)
402
+ if representation.nil?
403
+ raise ArgumentError, 'Representation must be specified for BSON::Binary objects of type :uuid_old'
354
404
  end
355
405
 
356
- # Get the custom error message for the exception.
357
- #
358
- # @example Get the message.
359
- # error.message
360
- #
361
- # @return [ String ] The error message.
362
- #
363
- # @since 2.0.0
364
- def message
365
- "#{type.inspect} is not a valid binary type. " +
366
- "Please use one of #{SUBTYPES.keys.map(&:inspect).join(", ")}."
406
+ hex = data.chars.map { |n| '%02x' % n.ord }.join
407
+ handler = :"from_uuid_old_to_#{representation}_uuid"
408
+
409
+ raise ArgumentError, "Invalid representation: #{representation}" unless respond_to?(handler, true)
410
+
411
+ send(handler, hex)
412
+ .sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5')
413
+ end
414
+
415
+ # Tries to convert a UUID-old object to a standard representation, which is
416
+ # not supported.
417
+ #
418
+ # @param [ String ] hex The hexadecimal string to convert
419
+ #
420
+ # @raise [ ArgumentError ] because standard representation is not supported
421
+ def from_uuid_old_to_standard_uuid(_hex)
422
+ raise ArgumentError, 'BSON::Binary objects of type :uuid_old cannot be stringified to :standard representation'
423
+ end
424
+
425
+ # Converts a UUID-old object to a csharp-legacy representation.
426
+ #
427
+ # @param [ String ] hex The hexadecimal string to convert
428
+ #
429
+ # @return [ String ] the csharp-legacy-formatted UUID
430
+ def from_uuid_old_to_csharp_legacy_uuid(hex)
431
+ hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(.{16})\z/, '\4\3\2\1\6\5\8\7\9')
432
+ end
433
+
434
+ # Converts a UUID-old object to a java-legacy representation.
435
+ #
436
+ # @param [ String ] hex The hexadecimal string to convert
437
+ #
438
+ # @return [ String ] the java-legacy-formatted UUID
439
+ def from_uuid_old_to_java_legacy_uuid(hex)
440
+ hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)\z/) do
441
+ (::Regexp.last_match[1..8].reverse + ::Regexp.last_match[9..16].reverse).join
367
442
  end
368
443
  end
369
444
 
370
- private
445
+ # Converts a UUID-old object to a python-legacy representation.
446
+ #
447
+ # @param [ String ] hex The hexadecimal string to convert
448
+ #
449
+ # @return [ String ] the python-legacy-formatted UUID
450
+ def from_uuid_old_to_python_legacy_uuid(hex)
451
+ hex
452
+ end
371
453
 
372
454
  # Validate the provided type is a valid type.
373
455
  #
@@ -376,13 +458,58 @@ module BSON
376
458
  # @example Validate the type.
377
459
  # binary.validate_type!(:user)
378
460
  #
379
- # @param [ Object ] type The provided type.
461
+ # @param [ Symbol | String | Integer ] type The provided type.
380
462
  #
381
- # @raise [ InvalidType ] The the type is invalid.
463
+ # @return [ Symbol ] the symbolic type corresponding to the argument.
464
+ #
465
+ # @raise [ BSON::Error::InvalidBinaryType ] The the type is invalid.
382
466
  #
383
467
  # @since 2.0.0
384
468
  def validate_type!(type)
385
- raise InvalidType.new(type) unless SUBTYPES.has_key?(type)
469
+ case type
470
+ when Integer then validate_integer_type!(type)
471
+ when String
472
+ if type.length > 1
473
+ validate_symbol_type!(type.to_sym)
474
+ else
475
+ validate_integer_type!(type.bytes.first)
476
+ end
477
+ when Symbol then validate_symbol_type!(type)
478
+ else raise BSON::Error::InvalidBinaryType, type
479
+ end
480
+ end
481
+
482
+ # Test that the given integer type is valid.
483
+ #
484
+ # @param [ Integer ] type the provided type
485
+ #
486
+ # @return [ Symbol ] the symbolic type corresponding to the argument.
487
+ #
488
+ # @raise [ BSON::Error::InvalidBinaryType] if the type is invalid.
489
+ def validate_integer_type!(type)
490
+ @raw_type = type.chr.force_encoding('BINARY').freeze
491
+
492
+ if type < USER_SUBTYPE
493
+ raise BSON::Error::InvalidBinaryType, type unless TYPES.key?(@raw_type)
494
+
495
+ return TYPES[@raw_type]
496
+ end
497
+
498
+ :user
499
+ end
500
+
501
+ # Test that the given symbol type is valid.
502
+ #
503
+ # @param [ Symbol ] type the provided type
504
+ #
505
+ # @return [ Symbol ] the symbolic type corresponding to the argument.
506
+ #
507
+ # @raise [ BSON::Error::InvalidBinaryType] if the type is invalid.
508
+ def validate_symbol_type!(type)
509
+ raise BSON::Error::InvalidBinaryType, type unless SUBTYPES.key?(type)
510
+
511
+ @raw_type = SUBTYPES[type]
512
+ type
386
513
  end
387
514
 
388
515
  # Register this type when the module is loaded.
data/lib/bson/boolean.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:todo all
2
3
  # Copyright (C) 2009-2020 MongoDB Inc.
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
data/lib/bson/code.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:todo all
2
3
  # Copyright (C) 2009-2020 MongoDB Inc.
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,16 +49,13 @@ module BSON
48
49
  javascript == other.javascript
49
50
  end
50
51
 
51
- # Get the code as JSON hash data.
52
+ # Return a representation of the object for use in
53
+ # application-level JSON serialization. Since BSON::Code
54
+ # is used exclusively in BSON-related contexts, this
55
+ # method returns the canonical Extended JSON representation.
52
56
  #
53
- # @example Get the code as a JSON hash.
54
- # code.as_json
55
- #
56
- # @return [ Hash ] The code as a JSON hash.
57
- #
58
- # @since 2.0.0
59
- # @deprecated Use as_extended_json instead.
60
- def as_json(*args)
57
+ # @return [ Hash ] The extended json representation.
58
+ def as_json(*_args)
61
59
  as_extended_json
62
60
  end
63
61
 
@@ -68,7 +66,7 @@ module BSON
68
66
  # (default is canonical extended JSON)
69
67
  #
70
68
  # @return [ Hash ] The extended json representation.
71
- def as_extended_json(**options)
69
+ def as_extended_json(**_options)
72
70
  { "$code" => javascript }
73
71
  end
74
72
 
@@ -94,7 +92,7 @@ module BSON
94
92
  # @see http://bsonspec.org/#/specification
95
93
  #
96
94
  # @since 2.0.0
97
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
95
+ def to_bson(buffer = ByteBuffer.new)
98
96
  buffer.put_string(javascript) # @todo: was formerly to_bson_string
99
97
  end
100
98
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:todo all
2
3
  # Copyright (C) 2009-2020 MongoDB Inc.
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -52,16 +53,13 @@ module BSON
52
53
  javascript == other.javascript && scope == other.scope
53
54
  end
54
55
 
55
- # Get the code with scope as JSON hash data.
56
+ # Return a representation of the object for use in
57
+ # application-level JSON serialization. Since BSON::CodeWithScope
58
+ # is used exclusively in BSON-related contexts, this
59
+ # method returns the canonical Extended JSON representation.
56
60
  #
57
- # @example Get the code with scope as a JSON hash.
58
- # code_with_scope.as_json
59
- #
60
- # @return [ Hash ] The code with scope as a JSON hash.
61
- #
62
- # @since 2.0.0
63
- # @deprecated Use as_extended_json instead.
64
- def as_json(*args)
61
+ # @return [ Hash ] The extended json representation.
62
+ def as_json(*_args)
65
63
  as_extended_json
66
64
  end
67
65
 
@@ -100,7 +98,7 @@ module BSON
100
98
  # @see http://bsonspec.org/#/specification
101
99
  #
102
100
  # @since 2.0.0
103
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
101
+ def to_bson(buffer = ByteBuffer.new)
104
102
  position = buffer.length
105
103
  buffer.put_int32(0)
106
104
  buffer.put_string(javascript)
data/lib/bson/config.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:todo all
2
3
  # Copyright (C) 2016-2020 MongoDB Inc.
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,32 +22,5 @@ module BSON
21
22
  module Config
22
23
  extend self
23
24
 
24
- # Set the configuration option for BSON to validate keys or not.
25
- #
26
- # @example Set the config option.
27
- # BSON::Config.validating_keys = true
28
- #
29
- # @param [ true, false ] value The value to set.
30
- #
31
- # @return [ true, false ] The value.
32
- #
33
- # @since 4.1.0
34
- def validating_keys=(value)
35
- @validating_keys = value
36
- end
37
-
38
- # Returns true if BSON will validate the document keys on serialization to
39
- # determine if they contain invalid MongoDB values. Invalid keys start with
40
- # '$' or contain a '.' in them.
41
- #
42
- # @example Is BSON validating keys?
43
- # BSON::Config.validating_keys?
44
- #
45
- # @return [ true, false ] If BSON is validating keys?
46
- #
47
- # @since 4.1.0
48
- def validating_keys?
49
- !!(@validating_keys||=nil)
50
- end
51
25
  end
52
26
  end
data/lib/bson/date.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:todo all
2
3
  # Copyright (C) 2009-2020 MongoDB Inc.
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -45,7 +46,7 @@ module BSON
45
46
  # @see http://bsonspec.org/#/specification
46
47
  #
47
48
  # @since 2.1.0
48
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
49
+ def to_bson(buffer = ByteBuffer.new)
49
50
  buffer.put_int64((jd - DATE_REFERENCE) * MILLISECONDS_IN_DAY)
50
51
  end
51
52
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # rubocop:todo all
2
3
  # Copyright (C) 2009-2020 MongoDB Inc.
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,7 +36,7 @@ module BSON
35
36
  # @see http://bsonspec.org/#/specification
36
37
  #
37
38
  # @since 2.1.0
38
- def to_bson(buffer = ByteBuffer.new, validating_keys = Config.validating_keys?)
39
+ def to_bson(buffer = ByteBuffer.new)
39
40
  gregorian.to_time.to_bson(buffer)
40
41
  end
41
42
  end