Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ public enum StronglyTypedIdBackingType
Long = 4,
NullableString = 5,
MassTransitNewId = 6,
ObjectId = 7
}
}
5 changes: 5 additions & 0 deletions src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,10 @@ public enum StronglyTypedIdConverter
/// Creates a Dapper TypeHandler for converting to and from the type
/// </summary>
DapperTypeHandler = 32,

/// <summary>
/// Creates a Mongo Serializer for converting string to and from type
/// </summary>
MongoSerializer = 64,
}
}
23 changes: 23 additions & 0 deletions src/StronglyTypedIds/EmbeddedSources.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal static class EmbeddedSources
LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_EfCoreValueConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_DapperTypeHandler.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_IComparable.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_MongoSerializer.cs"),
false
);

Expand All @@ -37,6 +38,7 @@ internal static class EmbeddedSources
LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_EfCoreValueConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_DapperTypeHandler.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_IComparable.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_MongoSerializer.cs"),
false
);

Expand All @@ -49,6 +51,7 @@ internal static class EmbeddedSources
LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_EfCoreValueConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_DapperTypeHandler.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_IComparable.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_MongoSerializer.cs"),
false
);

Expand All @@ -61,6 +64,7 @@ internal static class EmbeddedSources
LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_EfCoreValueConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_DapperTypeHandler.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_IComparable.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_MongoSerializer.cs"),
false
);

Expand All @@ -73,6 +77,7 @@ internal static class EmbeddedSources
LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_EfCoreValueConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_DapperTypeHandler.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_IComparable.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_MongoSerializer.cs"),
true
);

Expand All @@ -85,12 +90,27 @@ internal static class EmbeddedSources
LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_EfCoreValueConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_DapperTypeHandler.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_IComparable.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_MongoSerializer.cs"),
false
);

internal static readonly ResourceCollection ObjectIdResources = new(
AutoGeneratedHeader,
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_Base.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_NewtonsoftJsonConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_SystemTextJsonConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_TypeConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_EfCoreValueConverter.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_DapperTypeHandler.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_IComparable.cs"),
LoadEmbeddedResource("StronglyTypedIds.Templates.ObjectId.ObjectId_MongoSerializer.cs"),
false
);

internal const string TypeConverterAttributeSource = " [System.ComponentModel.TypeConverter(typeof(TESTIDTypeConverter))]";
internal const string NewtonsoftJsonAttributeSource = " [Newtonsoft.Json.JsonConverter(typeof(TESTIDNewtonsoftJsonConverter))]";
internal const string SystemTextJsonAttributeSource = " [System.Text.Json.Serialization.JsonConverter(typeof(TESTIDSystemTextJsonConverter))]";
internal const string MongoSerializerAttributeSource = " [MongoDB.Bson.Serialization.Attributes.BsonSerializer(typeof(TESTIDMongoSerializer))]";

internal static string LoadEmbeddedResource(string resourceName)
{
Expand All @@ -116,6 +136,7 @@ public readonly struct ResourceCollection
public string TypeConverter { get; }
public string EfCoreValueConverter { get; }
public string DapperTypeHandler { get; }
public string Mongo { get; }
public string Comparable { get; }

public ResourceCollection(
Expand All @@ -127,6 +148,7 @@ public ResourceCollection(
string efCoreValueConverter,
string dapperTypeHandler,
string comparable,
string mongo,
bool nullableEnable)
{
BaseId = baseId;
Expand All @@ -137,6 +159,7 @@ public ResourceCollection(
DapperTypeHandler = dapperTypeHandler;
Comparable = comparable;
NullableEnable = nullableEnable;
Mongo = mongo;
Header = header;
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/StronglyTypedIds/SourceGenerationHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public static string CreateId(
StronglyTypedIdBackingType.String => EmbeddedSources.StringResources,
StronglyTypedIdBackingType.NullableString => EmbeddedSources.NullableStringResources,
StronglyTypedIdBackingType.MassTransitNewId => EmbeddedSources.NewIdResources,
StronglyTypedIdBackingType.ObjectId => EmbeddedSources.ObjectIdResources,
_ => throw new ArgumentException("Unknown backing type: " + backingType, nameof(backingType)),
};

Expand Down Expand Up @@ -69,6 +70,7 @@ static string CreateId(
var useSystemTextJson = converters.IsSet(StronglyTypedIdConverter.SystemTextJson);
var useEfCoreValueConverter = converters.IsSet(StronglyTypedIdConverter.EfCoreValueConverter);
var useDapperTypeHandler = converters.IsSet(StronglyTypedIdConverter.DapperTypeHandler);
var useMongoSerializer = converters.IsSet(StronglyTypedIdConverter.MongoSerializer);

var useIEquatable = implementations.IsSet(StronglyTypedIdImplementations.IEquatable);
var useIComparable = implementations.IsSet(StronglyTypedIdImplementations.IComparable);
Expand Down Expand Up @@ -121,6 +123,11 @@ static string CreateId(
{
sb.AppendLine(EmbeddedSources.TypeConverterAttributeSource);
}

if (useMongoSerializer)
{
sb.AppendLine(EmbeddedSources.MongoSerializerAttributeSource);
}

sb.Append(resources.BaseId);
ReplaceInterfaces(sb, useIEquatable, useIComparable);
Expand Down Expand Up @@ -156,6 +163,11 @@ static string CreateId(
{
sb.AppendLine(resources.SystemTextJson);
}

if (useMongoSerializer)
{
sb.AppendLine(resources.Mongo);
}

sb.Replace("TESTID", idName);
sb.AppendLine(@" }");
Expand Down
12 changes: 12 additions & 0 deletions src/StronglyTypedIds/Templates/Guid/Guid_MongoSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
 class TESTIDMongoSerializer : MongoDB.Bson.Serialization.Serializers.SerializerBase<TESTID>
{
public override TESTID Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
return new TESTID(new System.Guid(context.Reader.ReadString()));
}

public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, TESTID value)
{
context.Writer.WriteString(value.Value.ToString());
}
}
12 changes: 12 additions & 0 deletions src/StronglyTypedIds/Templates/Int/Int_MongoSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
 class TESTIDMongoSerializer : MongoDB.Bson.Serialization.Serializers.SerializerBase<TESTID>
{
public override TESTID Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
return new TESTID(context.Reader.ReadInt32());
}

public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, TESTID value)
{
context.Writer.WriteInt32(value.Value);
}
}
12 changes: 12 additions & 0 deletions src/StronglyTypedIds/Templates/Long/Long_MongoSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
 class TESTIDMongoSerializer : MongoDB.Bson.Serialization.Serializers.SerializerBase<TESTID>
{
public override TESTID Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
return new TESTID(context.Reader.ReadInt64());
}

public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, TESTID value)
{
context.Writer.WriteInt64(value.Value);
}
}
12 changes: 12 additions & 0 deletions src/StronglyTypedIds/Templates/NewId/NewId_MongoSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
 class TESTIDMongoSerializer : MongoDB.Bson.Serialization.Serializers.SerializerBase<TESTID>
{
public override TESTID Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
return new TESTID(new MassTransit.NewId(context.Reader.ReadString()));
}

public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, TESTID value)
{
context.Writer.WriteString(value.Value.ToString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
 class TESTIDMongoSerializer : MongoDB.Bson.Serialization.Serializers.SerializerBase<TESTID>
{
public override TESTID Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
return new TESTID(context.Reader.ReadString());
}

public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, TESTID value)
{
if (value.Value is null)
{
context.Writer.WriteNull();
}
else
{
context.Writer.WriteString(value.Value);
}
}
}
24 changes: 24 additions & 0 deletions src/StronglyTypedIds/Templates/ObjectId/ObjectId_Base.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
 readonly partial struct TESTID : INTERFACES
{
public MongoDB.Bson.ObjectId Value { get; }

public TESTID(MongoDB.Bson.ObjectId value)
{
Value = value;
}

public static TESTID New() => new TESTID(MongoDB.Bson.ObjectId.GenerateNewId());
public static readonly TESTID Empty = new TESTID(MongoDB.Bson.ObjectId.Empty);

public bool Equals(TESTID other) => this.Value.Equals(other.Value);
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
return obj is TESTID other && Equals(other);
}

public override int GetHashCode() => Value.GetHashCode();

public override string ToString() => Value.ToString();
public static bool operator ==(TESTID a, TESTID b) => a.Equals(b);
public static bool operator !=(TESTID a, TESTID b) => !(a == b);
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler<TESTID>
{
public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value)
{
parameter.Value = value.Value.ToString();
}

public override TESTID Parse(object value)
{
return value switch
{
string stringValue when !string.IsNullOrEmpty(stringValue) => new TESTID(new MongoDB.Bson.ObjectId(stringValue)),
_ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter<TESTID, string>
{
public EfCoreValueConverter() : this(null) { }
public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null)
: base(
id => id.Value.ToString(),
value => new TESTID(new MongoDB.Bson.ObjectId(value)),
mappingHints
) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
 public int CompareTo(TESTID other) => Value.CompareTo(other.Value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
 class TESTIDMongoSerializer : MongoDB.Bson.Serialization.Serializers.SerializerBase<TESTID>
{
public override TESTID Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
return new TESTID(context.Reader.ReadObjectId());
}

public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, TESTID value)
{
context.Writer.WriteObjectId(value.Value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

class TESTIDNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(System.Type objectType)
{
return objectType == typeof(TESTID);
}

public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
{
var id = (TESTID)value;
serializer.Serialize(writer, id.Value.ToString());
}

public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
var result = serializer.Deserialize<string>(reader);
return string.IsNullOrEmpty(result) ? null : new TESTID(new MongoDB.Bson.ObjectId(result));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter<TESTID>
{
public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
var result = reader.GetString();
return string.IsNullOrEmpty(result) ? TESTID.Empty : new TESTID(new MongoDB.Bson.ObjectId(result));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a discrepancy in the way you're handling null/empty string in these serializers. Some return null, some return TESTID.Empty, and some defer to the default handler

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ups, you have right. I will correct it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @marspion, so it looks like you've made add the serializers return TESTID.Empty if the object can't be parsed? I'm not sure if that's the best behaviour. I'd expect a serializer to throw if it can't be parsed I think? Otherwise you could get unexpected behaviour?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @andrewlock

Sorry for my mistake but I mixed some cases and I noticed that serializers should not be responsible for it. Definitely it was bad idea to return TESTID.Empty. Now serializers assume that value should be valid otherwise they will throw.

}

public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options)
{
writer.WriteStringValue(value.Value.ToString());
}
}
42 changes: 42 additions & 0 deletions src/StronglyTypedIds/Templates/ObjectId/ObjectId_TypeConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

class TESTIDTypeConverter : System.ComponentModel.TypeConverter
{
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
{
return sourceType == typeof(MongoDB.Bson.ObjectId) || sourceType == typeof(string) || base.CanConvertFrom
(context, sourceType);
}

public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
return value switch
{
MongoDB.Bson.ObjectId objectIdValue => new TESTID(objectIdValue),
string stringValue when !string.IsNullOrEmpty(stringValue) => new TESTID(new MongoDB.Bson.ObjectId(stringValue)),
_ => base.ConvertFrom(context, culture, value),
};
}

public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
{
return sourceType == typeof(MongoDB.Bson.ObjectId) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType);
}

public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
{
if (value is TESTID idValue)
{
if (destinationType == typeof(MongoDB.Bson.ObjectId))
{
return idValue.Value;
}

if (destinationType == typeof(string))
{
return idValue.Value.ToString();
}
}

return base.ConvertTo(context, culture, value, destinationType);
}
}
12 changes: 12 additions & 0 deletions src/StronglyTypedIds/Templates/String/String_MongoSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
 class TESTIDMongoSerializer : MongoDB.Bson.Serialization.Serializers.SerializerBase<TESTID>
{
public override TESTID Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
{
return new TESTID(context.Reader.ReadString());
}

public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, TESTID value)
{
context.Writer.WriteString(value.Value);
}
}
Loading