diff --git a/README.md b/README.md index 2cda480..70e4201 100644 --- a/README.md +++ b/README.md @@ -243,8 +243,8 @@ namespace UnitGenerator { this.Type = typeof(T); this.Options = options; -   } -    } + } + } #endif } ``` @@ -283,11 +283,15 @@ public static bool operator false(Foo x) => !x.value; public static bool operator !(Foo x) => !x.value; ``` -> When type is Guid or [Ulid](https://github.com/Cysharp/Ulid), also implements `New()` and `New***()` static operator. +> When type is Guid or [Ulid](https://github.com/Cysharp/Ulid), also implements `New()` and `New***()` static operator.
+> For Guid type in .NET 9.0 or later, these methods accept an optional `uuidV7` parameter. When `uuidV7` is set to `true`, the methods use `Guid.CreateVersion7()` internally. ```csharp public static GroupId New(); public static GroupId NewGroupId(); +// overload .NET 9.0+ +public static GroupId New(bool uuidV7); +public static GroupId NewGroupId(bool uuidV7); ``` Second parameter `UnitGenerateOptions options` can configure which method to implement, default is `None`. diff --git a/UnitGenerator.sln b/UnitGenerator.sln index 24ed89c..84f73fd 100644 --- a/UnitGenerator.sln +++ b/UnitGenerator.sln @@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileGenerate", "sandbox\Fil EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkApp", "src\EntityFrameworkApp\EntityFrameworkApp.csproj", "{51AE7857-4223-40FE-AEA9-F0E64C5F8238}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitGenerator.NET9.Tests", "tests\UnitGenerator.NET9.Tests\UnitGenerator.NET9.Tests.csproj", "{EAC3A025-E49B-4719-8738-9C3B67484A4A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {51AE7857-4223-40FE-AEA9-F0E64C5F8238}.Debug|Any CPU.Build.0 = Debug|Any CPU {51AE7857-4223-40FE-AEA9-F0E64C5F8238}.Release|Any CPU.ActiveCfg = Release|Any CPU {51AE7857-4223-40FE-AEA9-F0E64C5F8238}.Release|Any CPU.Build.0 = Release|Any CPU + {EAC3A025-E49B-4719-8738-9C3B67484A4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAC3A025-E49B-4719-8738-9C3B67484A4A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAC3A025-E49B-4719-8738-9C3B67484A4A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAC3A025-E49B-4719-8738-9C3B67484A4A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -55,6 +61,7 @@ Global {5DA06D43-A023-4464-B856-8BB42E8E4A05} = {187FBF64-D2AA-444D-AFB1-CE999BC6AD34} {F8353A7A-290E-41D7-A6F8-8D8DBDD44433} = {34EB4113-923D-4855-979C-A0467461B75C} {51AE7857-4223-40FE-AEA9-F0E64C5F8238} = {34EB4113-923D-4855-979C-A0467461B75C} + {EAC3A025-E49B-4719-8738-9C3B67484A4A} = {187FBF64-D2AA-444D-AFB1-CE999BC6AD34} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A64DF779-7829-414F-9E6E-3AF349486508} diff --git a/src/UnitGenerator/SourceGenerator.cs b/src/UnitGenerator/SourceGenerator.cs index 06d47ac..6ffcc4a 100644 --- a/src/UnitGenerator/SourceGenerator.cs +++ b/src/UnitGenerator/SourceGenerator.cs @@ -554,6 +554,18 @@ public bool TryFormat (Span utf8Destination, out int bytesWritten, ReadOnl return new {{unitTypeName}}(Guid.NewGuid()); } +#if NET9_0_OR_GREATER + public static {{unitTypeName}} New(bool uuidV7) + { + return new {{unitTypeName}}(uuidV7 ? Guid.CreateVersion7() : Guid.NewGuid()); + } + + public static {{unitTypeName}} New{{unitTypeName}}(bool uuidV7) + { + return new {{unitTypeName}}(uuidV7 ? Guid.CreateVersion7() : Guid.NewGuid()); + } +#endif + """); } diff --git a/tests/UnitGenerator.NET9.Tests/UnitGenerator.NET9.Tests.csproj b/tests/UnitGenerator.NET9.Tests/UnitGenerator.NET9.Tests.csproj new file mode 100644 index 0000000..4fcb87c --- /dev/null +++ b/tests/UnitGenerator.NET9.Tests/UnitGenerator.NET9.Tests.csproj @@ -0,0 +1,25 @@ + + + + net9.0 + enable + false + + + + + + + + + + + + + + + + + + + diff --git a/tests/UnitGenerator.NET9.Tests/UnitOfGuidTests.cs b/tests/UnitGenerator.NET9.Tests/UnitOfGuidTests.cs new file mode 100644 index 0000000..d6fc7de --- /dev/null +++ b/tests/UnitGenerator.NET9.Tests/UnitOfGuidTests.cs @@ -0,0 +1,35 @@ +using FluentAssertions; +using System; + +namespace UnitGenerator.NET9.Tests; + +public class UnitOfGuidTests +{ + [Fact] + public void Guidv7_v4_Comparison_AsExpected() + { + // v7 + TryGetUuidV7Timestamp(Guidv7Unit.New(uuidV7: true).AsPrimitive(), out var v).Should().BeTrue(); + // ...approximate check + v?.ToString("yyyyMMdd").Should().Be(DateTime.UtcNow.ToString("yyyyMMdd")); + TryGetUuidV7Timestamp(Guidv7Unit.New().AsPrimitive(), out var _).Should().BeFalse(); + } + + static bool TryGetUuidV7Timestamp(Guid uuid, out DateTimeOffset? timestamp) + { + timestamp = null; + var uuidString = uuid.ToString("N"); + // version number is the 13th character + if (uuidString[12] == '7') + { + var timestampHex = uuidString.Substring(0, 12); + var milliseconds = Convert.ToInt64(timestampHex, 16); + timestamp = DateTimeOffset.FromUnixTimeMilliseconds(milliseconds); + return true; + } + else return false; + } +} + +[UnitOf()] +public readonly partial struct Guidv7Unit { }