Description
So i discovered that the default conversion the C# Guid type is not correct when trying to round-trip the type through a string:
using Medo;
Uuid7 id = Uuid7.NewUuid7();
Console.WriteLine($"uuid7:\t{id.ToString()}");
Console.WriteLine($"MsSql:\t{id.ToGuidMsSql().ToString()}");
Console.WriteLine($"ToGuid:\t{id.ToGuid().ToString()}");
output:
PS D:\development\uuidv7test> dotnet run
uuid7: 01899148-b29e-703a-848b-af5e76f5e9c2
MsSql: 01899148-b29e-703a-848b-af5e76f5e9c2
ToGuid: 48918901-9eb2-3a70-848b-af5e76f5e9c2
The internal Guid type is stored in a little endian format, however there is a new constructor to convert big endian bytes to little endian when this gets released in a .net version:
https://github.com/dotnet/runtime/blob/d389ab955dbb65547643fa1aed52669b02c04294/src/libraries/System.Private.CoreLib/src/System/Guid.cs#L69
dotnet/runtime#87993
For now a manual conversion is required though.
The current code manually converts to little endian for the ToGuidMsSql function but this should be done all the time IMO.
Additionally if you try to round trip through bytes to guid and back it works from the uuid side but it's still not correct. Since it's just interpreting the big endian bytes as little endian and then reading those back exactly as they were input. But if you round-trip through ToGuidMsSql it's also wrong because they don't get flipped on the way back into uuid7
Uuid7 idRt = new Uuid7(id.ToGuid());
Uuid7 idRtMs = new Uuid7(id.ToGuidMsSql());
Console.WriteLine($"rt:\t{idRt.ToString()}");
Console.WriteLine($"rt2:\t{idRtMs.ToString()}");
rt: 01899148-b29e-703a-848b-af5e76f5e9c2
rtMsSql: 48918901-9eb2-3a70-848b-af5e76f5e9c2
So this is what the proper conversion should look like:
// Read and rewrite values to flip to what Guid expects
var flip = (Span<byte> bytes) =>
{
var aPos = bytes.Slice(0, 4);
var bPos = bytes.Slice(4, 2);
var cPos = bytes.Slice(6, 2);
int a = BinaryPrimitives.ReadInt32BigEndian(aPos);
short b = BinaryPrimitives.ReadInt16BigEndian(bPos);
short c = BinaryPrimitives.ReadInt16BigEndian(cPos);
BinaryPrimitives.WriteInt32LittleEndian(aPos, a);
BinaryPrimitives.WriteInt16LittleEndian(bPos, b);
BinaryPrimitives.WriteInt16LittleEndian(cPos, c);
};
// Correct manual conversion:
Span<byte> bytes = stackalloc byte[16];
id.TryWriteBytes(bytes);
// flip to little endian for Guid
flip(bytes);
var fixedGuid = new Guid(bytes);
Span<byte> guidBytes = stackalloc byte[16];
fixedGuid.TryWriteBytes(guidBytes);
// flip to big endian for Uuid7
flip(guidBytes);
var uuid7Rt = new Uuid7(guidBytes);
Console.WriteLine($"guid--rt:\t{fixedGuid.ToString()}");
Console.WriteLine($"uuid7-rt:\t{uuid7Rt.ToString()}");
guid--rt: 01899148-b29e-703a-848b-af5e76f5e9c2
uuid7-rt: 01899148-b29e-703a-848b-af5e76f5e9c2