Code/Rest/BsonDocument.cs
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Mongo.Rest;
/// <summary>
/// A BSON document that can be used to interact with the REST API.
/// </summary>
[JsonConverter( typeof(BsonDocumentJsonConverter) )]
public record struct BsonDocument
{
private readonly JsonSerializerOptions _options = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
};
/// <summary>
/// The document id.
/// </summary>
[JsonIgnore]
public string Id { get; private set; } = null!;
/// <summary>
/// The name of the type that this document represents.
/// </summary>
[JsonIgnore]
public string TypeName { get; private set; } = null!;
[JsonIgnore] public object Data { get; private set; } = null!;
private BsonDocument( string json )
{
var data = JsonSerializer.Deserialize<Dictionary<string, object>>( json );
if ( data is null )
{
Log.Error( "Failed to deserialize BsonDocument: " + json );
return;
}
data.TryGetValue( "_id", out var id );
Id = id?.ToString() ?? string.Empty;
data.TryGetValue( "_type", out var typeName );
TypeName = typeName?.ToString() ?? string.Empty;
var type = TypeLibrary.GetType( TypeName );
json = JsonSerializer.Serialize( data, _options );
Data = JsonSerializer.Deserialize( json, type.TargetType )!;
}
private BsonDocument( object value )
{
Data = value;
TypeName = value.GetType().Name;
var type = TypeLibrary.GetType( TypeName );
if ( type is null )
{
Log.Error( "Failed to find type: " + TypeName );
return;
}
// Assign the id property from the value
foreach ( var property in type.Properties.Where( x => x.IsPublic ) )
{
var propertyValue = property.GetValue( value );
if ( propertyValue is null ) continue;
var propertyAttr = property.GetCustomAttribute<JsonPropertyNameAttribute>();
if ( propertyAttr?.Name is "_id" )
Id = propertyValue.ToString()!;
}
}
/// <summary>
/// Removes the "_id" field from the document.
/// </summary>
internal void RemoveId()
{
var type = TypeLibrary.GetType( TypeName );
if ( type is null )
{
Log.Error( "Failed to find type: " + TypeName );
return;
}
foreach ( var property in type.Properties )
{
var propertyValue = property.GetValue( Data );
if ( propertyValue is null ) continue;
var propertyAttr = property.GetCustomAttribute<JsonPropertyNameAttribute>();
if ( propertyAttr?.Name is "_id" )
property.SetValue( Data, null );
}
}
/// <summary>
/// Converts the BSON document to a JSON string.
/// </summary>
/// <returns>A JSON string representation of the BSON document.</returns>
public override string ToString() => JsonSerializer.Serialize( Data, _options );
/// <summary>
/// Converts the BSON document to an object.
/// </summary>
/// <returns>The object representation of the BSON document.</returns>
public JsonDocument ToObject() => JsonDocument.Parse( ToString() );
/// <summary>
/// Parses an object into a BSON document.
/// </summary>
/// <param name="value">The object to parse.</param>
/// <returns>The BSON document parsed from the object.</returns>
public static BsonDocument Parse( object value ) => new(value);
public static BsonDocument Parse( string value ) => new(value);
public static implicit operator BsonDocument( string json ) => new(json);
}