lib/bson/dbref.rb
# frozen_string_literal: true
# rubocop:todo all
# Copyright (C) 2015-2021 MongoDB Inc.
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module BSON
# Represents a DBRef document in the database.
class DBRef < Document
include JSON
# The constant for the collection reference field.
#
# @deprecated
COLLECTION = '$ref'.freeze
# The constant for the id field.
#
# @deprecated
ID = '$id'.freeze
# The constant for the database field.
#
# @deprecated
DATABASE = '$db'.freeze
# @return [ String ] collection The collection name.
def collection
self['$ref']
end
# @return [ BSON::ObjectId ] id The referenced document id.
def id
self['$id']
end
# @return [ String ] database The database name.
def database
self['$db']
end
# Get the DBRef as a JSON document
#
# @example Get the DBRef as a JSON hash.
# dbref.as_json
#
# @return [ Hash ] The max key as a JSON hash.
def as_json(*args)
{}.update(self)
end
# Instantiate a new DBRef.
#
# @example Create the DBRef - hash API.
# BSON::DBRef.new({'$ref' => 'users', '$id' => id, '$db' => 'database'})
#
# @example Create the DBRef - legacy API.
# BSON::DBRef.new('users', id, 'database')
#
# @param [ Hash | String ] hash_or_collection The DBRef hash, when using
# the hash API. It must contain $ref and $id. When using the legacy API,
# this parameter must be a String containing the collection name.
# @param [ Object ] id The object id, when using the legacy API.
# @param [ String ] database The database name, when using the legacy API.
#
# @raise [ BSON::Error::InvalidDBRefArgument ] if giving invalid arguments
# to the constructor.
def initialize(hash_or_collection, id = nil, database = nil)
if hash_or_collection.is_a?(Hash)
hash = hash_or_collection
unless id.nil? && database.nil?
raise Error::InvalidDBRefArgument, 'When using the hash API, DBRef constructor accepts only one argument'
end
else
warn("BSON::DBRef constructor called with the legacy API - please use the hash API instead")
if id.nil?
raise Error::InvalidDBRefArgument, 'When using the legacy constructor API, id must be provided'
end
hash = {
:$ref => hash_or_collection,
:$id => id,
:$db => database,
}
end
hash = reorder_fields(hash)
%w($ref $id).each do |key|
unless hash[key]
raise Error::InvalidDBRefArgument, "DBRef must have #{key}: #{hash}"
end
end
unless hash['$ref'].is_a?(String)
raise Error::InvalidDBRefArgument, "The value for key $ref must be a string, got: #{hash['$ref']}"
end
if db = hash['$db']
unless db.is_a?(String)
raise Error::InvalidDBRefArgument, "The value for key $db must be a string, got: #{hash['$db']}"
end
end
super(hash)
end
# Converts the DBRef to raw BSON.
#
# @example Convert the DBRef to raw BSON.
# dbref.to_bson
#
# @param [ BSON::ByteBuffer ] buffer The encoded BSON buffer to append to.
#
# @return [ BSON::ByteBuffer ] The buffer with the encoded object.
def to_bson(buffer = ByteBuffer.new)
as_json.to_bson(buffer)
end
private
# Reorder the fields of the given Hash to have $ref first, $id second,
# and $db third. The rest of the fields in the hash can come in any
# order after that.
#
# @param [ Hash ] hash The input hash. Must be a valid dbref.
#
# @return [ Hash ] The hash with it's fields reordered.
def reorder_fields(hash)
hash = BSON::Document.new(hash)
reordered = {}
reordered['$ref'] = hash.delete('$ref')
reordered['$id'] = hash.delete('$id')
if db = hash.delete('$db')
reordered['$db'] = db
end
reordered.update(hash)
end
end
end