From 63d6de05a7c10c6bc4eb8d31082e276f402f3dd4 Mon Sep 17 00:00:00 2001 From: Andrew Lock Date: Wed, 15 Nov 2023 20:14:57 +0100 Subject: [PATCH] Fundamental redesign to allow complete customisation (#117) * Use ForAttributeWithMetadataName APIs Fix duplicate test problem Add new diagnostic for duplicate assembly attributes * wip * wip * Add long and .net 8 support * Add string (and fix bugs) * Add Nullable String * Add NewId template * Update snapshots * Lots of fixes * Fix packaging (and remove other package) * Delete old files * Remove unused diagnostics * Add invalid template name diagnostic * Update handling of unknown templates (adds a diagnostic) * Don't do special behaviour for custom templates + add diagnostic for invalid templates * Add codefixprovider (need to try it) * Fix nullability warning * Make the analyzer return an error instead * Revert accidental hacking aroudn * Make nullable ID an extended type * Move to separate templates NuGet folder * Add some optional "partial" templates * Try to fix tests * Remove the built-in templates from the generator tests They just add noise * Support adding multiple templates in one attribute * Add unit tests for multiple templates * Fix StringBuilder re-use bug * Add missing templates * Add guid converter templates tests * Add LongId tests * Add string integration tests * Fix typos * Update diagnostics to ensure unique (breaking change) * Remove unused includes * Fix templates package * Show the additional templates in the project * Add 8.0.x to Github actions * Tweak codefix action * Fix windows-specific paths * Ensure we test both in-project IDs and "external" IDs * Make all the converts public by default It doesn't really make sense that their not... * Add source generator tests for GuidIds * Use Ordinal Comparisons instead of culture-specific in string IDs * Add test for the nullable * Make all converters partial * Add comparison operators * Fix typo --- .github/workflows/BuildAndPack.yml | 3 + .gitignore | 3 + NuGet.integration-tests.config | 12 + StronglyTypedId.sln | 45 ++ .../StronglyTypedIdAttribute.cs | 65 +- .../StronglyTypedIdBackingType.cs | 22 - .../StronglyTypedIdConverter.cs | 50 -- .../StronglyTypedIdDefaultsAttribute.cs | 68 +- .../StronglyTypedIdImplementations.cs | 37 - src/StronglyTypedIds.Attributes/Template.cs | 28 + .../StronglyTypedId.Templates.targets | 8 + .../StronglyTypedIds.Templates.csproj | 17 + .../guid-dapper.typedid | 20 + .../guid-efcore.typedid | 13 + .../guid-full.typedid | 254 +++++++ .../guid-newtonsoftjson.typedid | 22 + .../int-dapper.typedid | 21 + .../int-efcore.typedid | 13 + .../int-full.typedid | 250 +++++++ .../int-newtonsoftjson.typedid | 22 + .../long-dapper.typedid | 22 + .../long-efcore.typedid | 13 + .../long-full.typedid | 251 +++++++ .../long-newtonsoftjson.typedid | 22 + .../newid-full.typedid | 257 +++++++ .../nullablestring-full.typedid | 246 +++++++ .../string-dapper.typedid | 19 + .../string-efcore.typedid | 13 + .../string-full.typedid | 243 ++++++ .../string-newtonsoftjson.typedid | 28 + src/StronglyTypedIds/DiagnosticInfo.cs | 19 + .../Diagnostics/DiagnosticHelper.cs | 41 ++ .../InvalidBackingTypeDiagnostic.cs | 17 - .../Diagnostics/InvalidConverterDiagnostic.cs | 17 - .../InvalidImplementationsDiagnostic.cs | 17 - .../InvalidTemplateNameDiagnostic.cs | 15 + .../MultipleAssemblyAttributeDiagnostic.cs | 15 + .../Diagnostics/NotPartialDiagnostic.cs | 7 +- .../UnknownTemplateCodeFixProvider.cs | 125 ++++ .../Diagnostics/UnknownTemplateDiagnostic.cs | 21 + src/StronglyTypedIds/EmbeddedSources.Guid.cs | 210 ++++++ src/StronglyTypedIds/EmbeddedSources.Int.cs | 205 ++++++ src/StronglyTypedIds/EmbeddedSources.Long.cs | 205 ++++++ .../EmbeddedSources.String.cs | 194 +++++ src/StronglyTypedIds/EmbeddedSources.cs | 184 ++--- src/StronglyTypedIds/EquatableArray.cs | 110 +++ src/StronglyTypedIds/HashCode.cs | 383 ++++++++++ src/StronglyTypedIds/ParentClass.cs | 17 - src/StronglyTypedIds/Parser.cs | 491 ++++++------- .../SourceGenerationHelper.cs | 194 ++--- .../StronglyTypedIdConfiguration.cs | 68 -- .../StronglyTypedIdConverterExtensions.cs | 27 - .../StronglyTypedIdGenerator.cs | 316 ++++++-- src/StronglyTypedIds/StronglyTypedIds.csproj | 11 + src/StronglyTypedIds/StructToGenerate.cs | 64 ++ .../Templates/AutoGeneratedHeader.cs | 1 + .../Templates/Guid/Guid_Base.cs | 24 - .../Templates/Guid/Guid_DapperTypeHandler.cs | 18 - .../Guid/Guid_EfCoreValueConverter.cs | 11 - .../Templates/Guid/Guid_IComparable.cs | 1 - .../Guid/Guid_NewtonsoftJsonConverter.cs | 20 - .../Guid/Guid_SystemTextJsonConverter.cs | 13 - .../Templates/Guid/Guid_TypeConverter.cs | 41 -- .../Templates/Int/Int_Base.cs | 23 - .../Templates/Int/Int_DapperTypeHandler.cs | 19 - .../Templates/Int/Int_EfCoreValueConverter.cs | 11 - .../Templates/Int/Int_IComparable.cs | 1 - .../Int/Int_NewtonsoftJsonConverter.cs | 20 - .../Int/Int_SystemTextJsonConverter.cs | 13 - .../Templates/Int/Int_TypeConverter.cs | 41 -- .../Templates/Long/Long_Base.cs | 23 - .../Templates/Long/Long_DapperTypeHandler.cs | 20 - .../Long/Long_EfCoreValueConverter.cs | 11 - .../Templates/Long/Long_IComparable.cs | 1 - .../Long/Long_NewtonsoftJsonConverter.cs | 20 - .../Long/Long_SystemTextJsonConverter.cs | 13 - .../Templates/Long/Long_TypeConverter.cs | 43 -- .../Templates/NewId/NewId_Base.cs | 24 - .../NewId/NewId_DapperTypeHandler.cs | 18 - .../NewId/NewId_EfCoreValueConverter.cs | 11 - .../Templates/NewId/NewId_IComparable.cs | 1 - .../NewId/NewId_NewtonsoftJsonConverter.cs | 20 - .../NewId/NewId_SystemTextJsonConverter.cs | 13 - .../Templates/NewId/NewId_TypeConverter.cs | 49 -- .../NullableString/NullableString_Base.cs | 31 - .../NullableString_DapperTypeHandler.cs | 19 - .../NullableString_EfCoreValueConverter.cs | 11 - .../NullableString_IComparable.cs | 10 - .../NullableString_NewtonsoftJsonConverter.cs | 26 - .../NullableString_SystemTextJsonConverter.cs | 20 - .../NullableString_TypeConverter.cs | 42 -- .../Templates/String/String_Base.cs | 32 - .../String/String_DapperTypeHandler.cs | 17 - .../String/String_EfCoreValueConverter.cs | 11 - .../Templates/String/String_IComparable.cs | 10 - .../String/String_NewtonsoftJsonConverter.cs | 26 - .../String/String_SystemTextJsonConverter.cs | 13 - .../Templates/String/String_TypeConverter.cs | 37 - test/IntegrationLibraries.props | 12 +- ...pedIds.IntegrationTests.ExternalIds.csproj | 25 + .../xunit.runner.json | 4 + .../Enums.cs | 74 ++ ...nglyTypedIds.IntegrationTests.Types.csproj | 22 + .../DapperTypeHandlers.cs | 16 +- .../DefaultIdTests.cs | 123 +--- .../Enums.cs | 74 ++ .../GuidIdTests.cs | 410 ++++++++--- .../IntIdTests.cs | 691 +++++++++++------- .../LongIdTests.cs | 373 +++++++--- .../MassTransitNewIdTests.cs | 186 +++-- .../NullableStringIdTests.cs | 200 ++--- .../StringIdTests.cs | 388 +++++++--- .../StronglyTypedIds.IntegrationTests.csproj | 3 +- .../SystemTextJsonSerializerContext.cs | 38 + .../Types/DefaultId.cs | 41 -- .../Types/GuidId.cs | 40 - .../Types/IntId.cs | 37 - .../Types/LongId.cs | 37 - .../Types/NewIdId.cs | 40 - .../Types/NullableStringId.cs | 37 - .../Types/StringId.cs | 37 - ...s.Nuget.Attributes.IntegrationTests.csproj | 4 +- ...nglyTypedIds.Nuget.IntegrationTests.csproj | 4 +- .../InvalidBackingTypeDiagnosticTests.cs | 25 - .../InvalidConverterDiagnosticTests.cs | 25 - .../Diagnostics/NotPartialDiagnosticTests.cs | 23 - .../DiagnosticsTests.cs | 79 ++ .../EmbeddedResourceTests.cs | 6 +- test/StronglyTypedIds.Tests/EnumHelper.cs | 66 -- test/StronglyTypedIds.Tests/EqualityTests.cs | 152 ++++ ...urce=StronglyTypedIdAttribute.verified.txt | 56 +- ...urce=StronglyTypedIdConverter.verified.txt | 64 -- ...onglyTypedIdDefaultsAttribute.verified.txt | 59 +- ...tronglyTypedIdImplementations.verified.txt | 51 -- ...edResource_resource=Template.verified.txt} | 21 +- ...atesFullIdCorrectly_type=Guid.verified.txt | 143 ---- ...ratesFullIdCorrectly_type=Int.verified.txt | 143 ---- ...atesFullIdCorrectly_type=Long.verified.txt | 146 ---- ...rrectly_type=MassTransitNewId.verified.txt | 151 ---- ...Correctly_type=NullableString.verified.txt | 175 ----- ...esFullIdCorrectly_type=String.verified.txt | 161 ---- ...id_c=DapperTypeHandler_i=None.verified.txt | 54 -- ...c=EfCoreValueConverter_i=None.verified.txt | 47 -- ...=Guid_c=NewtonsoftJson_i=None.verified.txt | 57 -- ...ype=Guid_c=None_i=IComparable.verified.txt | 37 - ...type=Guid_c=None_i=IEquatable.verified.txt | 36 - ...ectly_type=Guid_c=None_i=None.verified.txt | 36 - ...=Guid_c=SystemTextJson_i=None.verified.txt | 50 -- ...e=Guid_c=TypeConverter_i=None.verified.txt | 78 -- ...nt_c=DapperTypeHandler_i=None.verified.txt | 54 -- ...c=EfCoreValueConverter_i=None.verified.txt | 46 -- ...e=Int_c=NewtonsoftJson_i=None.verified.txt | 56 -- ...type=Int_c=None_i=IComparable.verified.txt | 36 - ..._type=Int_c=None_i=IEquatable.verified.txt | 35 - ...rectly_type=Int_c=None_i=None.verified.txt | 35 - ...e=Int_c=SystemTextJson_i=None.verified.txt | 49 -- ...pe=Int_c=TypeConverter_i=None.verified.txt | 77 -- ...ng_c=DapperTypeHandler_i=None.verified.txt | 55 -- ...c=EfCoreValueConverter_i=None.verified.txt | 46 -- ...=Long_c=NewtonsoftJson_i=None.verified.txt | 56 -- ...ype=Long_c=None_i=IComparable.verified.txt | 36 - ...type=Long_c=None_i=IEquatable.verified.txt | 35 - ...ectly_type=Long_c=None_i=None.verified.txt | 35 - ...=Long_c=SystemTextJson_i=None.verified.txt | 49 -- ...e=Long_c=TypeConverter_i=None.verified.txt | 79 -- ...Id_c=DapperTypeHandler_i=None.verified.txt | 54 -- ...c=EfCoreValueConverter_i=None.verified.txt | 47 -- ...NewId_c=NewtonsoftJson_i=None.verified.txt | 57 -- ...sitNewId_c=None_i=IComparable.verified.txt | 37 - ...nsitNewId_c=None_i=IEquatable.verified.txt | 36 - ...assTransitNewId_c=None_i=None.verified.txt | 36 - ...NewId_c=SystemTextJson_i=None.verified.txt | 50 -- ...tNewId_c=TypeConverter_i=None.verified.txt | 86 --- ...ng_c=DapperTypeHandler_i=None.verified.txt | 63 -- ...c=EfCoreValueConverter_i=None.verified.txt | 55 -- ...tring_c=NewtonsoftJson_i=None.verified.txt | 71 -- ...leString_c=None_i=IComparable.verified.txt | 54 -- ...bleString_c=None_i=IEquatable.verified.txt | 44 -- ...=NullableString_c=None_i=None.verified.txt | 44 -- ...tring_c=SystemTextJson_i=None.verified.txt | 65 -- ...String_c=TypeConverter_i=None.verified.txt | 87 --- ...ng_c=DapperTypeHandler_i=None.verified.txt | 61 -- ...c=EfCoreValueConverter_i=None.verified.txt | 55 -- ...tring_c=NewtonsoftJson_i=None.verified.txt | 71 -- ...e=String_c=None_i=IComparable.verified.txt | 54 -- ...pe=String_c=None_i=IEquatable.verified.txt | 44 -- ...tly_type=String_c=None_i=None.verified.txt | 44 -- ...tring_c=SystemTextJson_i=None.verified.txt | 58 -- ...String_c=TypeConverter_i=None.verified.txt | 82 --- ...sCorrectly_nestedClassCount=0.verified.txt | 56 -- ...sCorrectly_nestedClassCount=1.verified.txt | 59 -- ...sCorrectly_nestedClassCount=2.verified.txt | 62 -- ...ateDefaultIdInGlobalNamespace.verified.txt | 393 ++++------ ....CanGenerateForCustomTemplate.verified.txt | 272 +++++++ ...yNestedIdInFileScopeNamespace.verified.txt | 227 ++++++ ...nerateIdInFileScopedNamespace.verified.txt | 393 ++++------ ...ests.CanGenerateIdInNamespace.verified.txt | 393 ++++------ ...ewtonsoftJson, SystemTextJson.verified.txt | 293 -------- ...Guid_converter=NewtonsoftJson.verified.txt | 279 ------- ...Guid_converter=SystemTextJson.verified.txt | 272 ------- ...=Guid_converter=TypeConverter.verified.txt | 300 -------- ...ckingType=Guid_converter=null.verified.txt | 321 -------- ...ewtonsoftJson, SystemTextJson.verified.txt | 293 -------- ...Guid_converter=NewtonsoftJson.verified.txt | 279 ------- ...Guid_converter=SystemTextJson.verified.txt | 272 ------- ...=Guid_converter=TypeConverter.verified.txt | 300 -------- ...ckingType=Guid_converter=null.verified.txt | 321 -------- ...nerateMultipleIdsWithSameName.verified.txt | 566 +++++++------- ...eMultipleTemplatesWithBuiltIn.verified.txt | 276 +++++++ ...ltipleTemplatesWithoutBuiltIn.verified.txt | 58 ++ ...eNestedIdInFileScopeNamespace.verified.txt | 395 ++++------ ...nerateNonDefaultIdInNamespace.verified.txt | 215 ++++++ ...yNestedIdInFileScopeNamespace.verified.txt | 399 ++++------ ...eDefaultsUsingGlobalAttribute.verified.txt | 254 ------- ...mTemplateUsingGlobalAttribute.verified.txt | 269 +++++++ ...hTemplateUsingGlobalAttribute.verified.txt | 212 ++++++ ...sts.UsesBuiltInTemplates_Guid.verified.txt | 264 +++++++ ...ests.UsesBuiltInTemplates_Int.verified.txt | 260 +++++++ ...sts.UsesBuiltInTemplates_Long.verified.txt | 261 +++++++ ...s.UsesBuiltInTemplates_String.verified.txt | 253 +++++++ .../SourceGenerationHelperSnapshotTests.cs | 298 ++++---- .../StronglyTypedIdConfiguration.cs | 211 ------ .../StronglyTypedIdGeneratorTests.cs | 251 +++++-- .../StronglyTypedIds.Tests.csproj | 16 +- test/StronglyTypedIds.Tests/TestHelpers.cs | 134 +++- 225 files changed, 10226 insertions(+), 12031 deletions(-) delete mode 100644 src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs delete mode 100644 src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs delete mode 100644 src/StronglyTypedIds.Attributes/StronglyTypedIdImplementations.cs create mode 100644 src/StronglyTypedIds.Attributes/Template.cs create mode 100644 src/StronglyTypedIds.Templates/StronglyTypedId.Templates.targets create mode 100644 src/StronglyTypedIds.Templates/StronglyTypedIds.Templates.csproj create mode 100644 src/StronglyTypedIds.Templates/guid-dapper.typedid create mode 100644 src/StronglyTypedIds.Templates/guid-efcore.typedid create mode 100644 src/StronglyTypedIds.Templates/guid-full.typedid create mode 100644 src/StronglyTypedIds.Templates/guid-newtonsoftjson.typedid create mode 100644 src/StronglyTypedIds.Templates/int-dapper.typedid create mode 100644 src/StronglyTypedIds.Templates/int-efcore.typedid create mode 100644 src/StronglyTypedIds.Templates/int-full.typedid create mode 100644 src/StronglyTypedIds.Templates/int-newtonsoftjson.typedid create mode 100644 src/StronglyTypedIds.Templates/long-dapper.typedid create mode 100644 src/StronglyTypedIds.Templates/long-efcore.typedid create mode 100644 src/StronglyTypedIds.Templates/long-full.typedid create mode 100644 src/StronglyTypedIds.Templates/long-newtonsoftjson.typedid create mode 100644 src/StronglyTypedIds.Templates/newid-full.typedid create mode 100644 src/StronglyTypedIds.Templates/nullablestring-full.typedid create mode 100644 src/StronglyTypedIds.Templates/string-dapper.typedid create mode 100644 src/StronglyTypedIds.Templates/string-efcore.typedid create mode 100644 src/StronglyTypedIds.Templates/string-full.typedid create mode 100644 src/StronglyTypedIds.Templates/string-newtonsoftjson.typedid create mode 100644 src/StronglyTypedIds/DiagnosticInfo.cs create mode 100644 src/StronglyTypedIds/Diagnostics/DiagnosticHelper.cs delete mode 100644 src/StronglyTypedIds/Diagnostics/InvalidBackingTypeDiagnostic.cs delete mode 100644 src/StronglyTypedIds/Diagnostics/InvalidConverterDiagnostic.cs delete mode 100644 src/StronglyTypedIds/Diagnostics/InvalidImplementationsDiagnostic.cs create mode 100644 src/StronglyTypedIds/Diagnostics/InvalidTemplateNameDiagnostic.cs create mode 100644 src/StronglyTypedIds/Diagnostics/MultipleAssemblyAttributeDiagnostic.cs create mode 100644 src/StronglyTypedIds/Diagnostics/UnknownTemplateCodeFixProvider.cs create mode 100644 src/StronglyTypedIds/Diagnostics/UnknownTemplateDiagnostic.cs create mode 100644 src/StronglyTypedIds/EmbeddedSources.Guid.cs create mode 100644 src/StronglyTypedIds/EmbeddedSources.Int.cs create mode 100644 src/StronglyTypedIds/EmbeddedSources.Long.cs create mode 100644 src/StronglyTypedIds/EmbeddedSources.String.cs create mode 100644 src/StronglyTypedIds/EquatableArray.cs create mode 100644 src/StronglyTypedIds/HashCode.cs delete mode 100644 src/StronglyTypedIds/ParentClass.cs delete mode 100644 src/StronglyTypedIds/StronglyTypedIdConfiguration.cs delete mode 100644 src/StronglyTypedIds/StronglyTypedIdConverterExtensions.cs create mode 100644 src/StronglyTypedIds/StructToGenerate.cs delete mode 100644 src/StronglyTypedIds/Templates/Guid/Guid_Base.cs delete mode 100644 src/StronglyTypedIds/Templates/Guid/Guid_DapperTypeHandler.cs delete mode 100644 src/StronglyTypedIds/Templates/Guid/Guid_EfCoreValueConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Guid/Guid_IComparable.cs delete mode 100644 src/StronglyTypedIds/Templates/Guid/Guid_NewtonsoftJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Guid/Guid_SystemTextJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Guid/Guid_TypeConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Int/Int_Base.cs delete mode 100644 src/StronglyTypedIds/Templates/Int/Int_DapperTypeHandler.cs delete mode 100644 src/StronglyTypedIds/Templates/Int/Int_EfCoreValueConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Int/Int_IComparable.cs delete mode 100644 src/StronglyTypedIds/Templates/Int/Int_NewtonsoftJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Int/Int_SystemTextJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Int/Int_TypeConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Long/Long_Base.cs delete mode 100644 src/StronglyTypedIds/Templates/Long/Long_DapperTypeHandler.cs delete mode 100644 src/StronglyTypedIds/Templates/Long/Long_EfCoreValueConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Long/Long_IComparable.cs delete mode 100644 src/StronglyTypedIds/Templates/Long/Long_NewtonsoftJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Long/Long_SystemTextJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/Long/Long_TypeConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NewId/NewId_Base.cs delete mode 100644 src/StronglyTypedIds/Templates/NewId/NewId_DapperTypeHandler.cs delete mode 100644 src/StronglyTypedIds/Templates/NewId/NewId_EfCoreValueConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NewId/NewId_IComparable.cs delete mode 100644 src/StronglyTypedIds/Templates/NewId/NewId_NewtonsoftJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NewId/NewId_SystemTextJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NewId/NewId_TypeConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NullableString/NullableString_Base.cs delete mode 100644 src/StronglyTypedIds/Templates/NullableString/NullableString_DapperTypeHandler.cs delete mode 100644 src/StronglyTypedIds/Templates/NullableString/NullableString_EfCoreValueConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NullableString/NullableString_IComparable.cs delete mode 100644 src/StronglyTypedIds/Templates/NullableString/NullableString_NewtonsoftJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NullableString/NullableString_SystemTextJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/NullableString/NullableString_TypeConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/String/String_Base.cs delete mode 100644 src/StronglyTypedIds/Templates/String/String_DapperTypeHandler.cs delete mode 100644 src/StronglyTypedIds/Templates/String/String_EfCoreValueConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/String/String_IComparable.cs delete mode 100644 src/StronglyTypedIds/Templates/String/String_NewtonsoftJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/String/String_SystemTextJsonConverter.cs delete mode 100644 src/StronglyTypedIds/Templates/String/String_TypeConverter.cs create mode 100644 test/StronglyTypedIds.IntegrationTests.ExternalIds/StronglyTypedIds.IntegrationTests.ExternalIds.csproj create mode 100644 test/StronglyTypedIds.IntegrationTests.ExternalIds/xunit.runner.json create mode 100644 test/StronglyTypedIds.IntegrationTests.Types/Enums.cs create mode 100644 test/StronglyTypedIds.IntegrationTests.Types/StronglyTypedIds.IntegrationTests.Types.csproj create mode 100644 test/StronglyTypedIds.IntegrationTests/Enums.cs create mode 100644 test/StronglyTypedIds.IntegrationTests/SystemTextJsonSerializerContext.cs delete mode 100644 test/StronglyTypedIds.IntegrationTests/Types/DefaultId.cs delete mode 100644 test/StronglyTypedIds.IntegrationTests/Types/GuidId.cs delete mode 100644 test/StronglyTypedIds.IntegrationTests/Types/IntId.cs delete mode 100644 test/StronglyTypedIds.IntegrationTests/Types/LongId.cs delete mode 100644 test/StronglyTypedIds.IntegrationTests/Types/NewIdId.cs delete mode 100644 test/StronglyTypedIds.IntegrationTests/Types/NullableStringId.cs delete mode 100644 test/StronglyTypedIds.IntegrationTests/Types/StringId.cs delete mode 100644 test/StronglyTypedIds.Tests/Diagnostics/InvalidBackingTypeDiagnosticTests.cs delete mode 100644 test/StronglyTypedIds.Tests/Diagnostics/InvalidConverterDiagnosticTests.cs delete mode 100644 test/StronglyTypedIds.Tests/Diagnostics/NotPartialDiagnosticTests.cs create mode 100644 test/StronglyTypedIds.Tests/DiagnosticsTests.cs delete mode 100644 test/StronglyTypedIds.Tests/EnumHelper.cs create mode 100644 test/StronglyTypedIds.Tests/EqualityTests.cs delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdConverter.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdImplementations.verified.txt rename test/StronglyTypedIds.Tests/Snapshots/{EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdBackingType.verified.txt => EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=Template.verified.txt} (59%) delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Guid.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Int.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Long.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=MassTransitNewId.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=NullableString.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=String.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=DapperTypeHandler_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=EfCoreValueConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=NewtonsoftJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IComparable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IEquatable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=SystemTextJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=TypeConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=DapperTypeHandler_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=EfCoreValueConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=NewtonsoftJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IComparable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IEquatable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=SystemTextJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=TypeConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=DapperTypeHandler_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=EfCoreValueConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=NewtonsoftJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IComparable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IEquatable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=SystemTextJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=TypeConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=DapperTypeHandler_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=EfCoreValueConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=NewtonsoftJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IComparable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IEquatable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=SystemTextJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=TypeConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=DapperTypeHandler_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=EfCoreValueConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=NewtonsoftJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IComparable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IEquatable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=SystemTextJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=TypeConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=DapperTypeHandler_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=EfCoreValueConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=NewtonsoftJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IComparable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IEquatable.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=SystemTextJson_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=TypeConverter_i=None.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=0.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=1.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=2.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateForCustomTemplate.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateGenericVeryNestedIdInFileScopeNamespace.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=SystemTextJson.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=TypeConverter.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=null.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=SystemTextJson.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=TypeConverter.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=null.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithoutBuiltIn.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNonDefaultIdInNamespace.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsUsingGlobalAttribute.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithCustomTemplateUsingGlobalAttribute.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithTemplateUsingGlobalAttribute.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Guid.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Int.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Long.verified.txt create mode 100644 test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_String.verified.txt delete mode 100644 test/StronglyTypedIds.Tests/StronglyTypedIdConfiguration.cs diff --git a/.github/workflows/BuildAndPack.yml b/.github/workflows/BuildAndPack.yml index cdd141ece..60e5a5e3e 100644 --- a/.github/workflows/BuildAndPack.yml +++ b/.github/workflows/BuildAndPack.yml @@ -36,6 +36,7 @@ jobs: - uses: actions/setup-dotnet@v3 with: dotnet-version: | + 8.0.x 7.0.x 6.0.x 5.0.x @@ -66,6 +67,7 @@ jobs: - uses: actions/setup-dotnet@v3 with: dotnet-version: | + 8.0.x 7.0.x 6.0.x 5.0.x @@ -96,6 +98,7 @@ jobs: - uses: actions/setup-dotnet@v3 with: dotnet-version: | + 8.0.x 7.0.x 6.0.x 5.0.x diff --git a/.gitignore b/.gitignore index d662c941d..71494e00d 100644 --- a/.gitignore +++ b/.gitignore @@ -245,3 +245,6 @@ ModelManifest.xml .fake/ tools/* !tools/packages.config + +# NuGet testing +globalPackagesFolder \ No newline at end of file diff --git a/NuGet.integration-tests.config b/NuGet.integration-tests.config index 59eaf0656..c71f27319 100644 --- a/NuGet.integration-tests.config +++ b/NuGet.integration-tests.config @@ -1,8 +1,20 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/StronglyTypedId.sln b/StronglyTypedId.sln index cd44309c6..4620315b7 100644 --- a/StronglyTypedId.sln +++ b/StronglyTypedId.sln @@ -32,6 +32,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Nuget.Inte EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Nuget.Attributes.IntegrationTests", "test\StronglyTypedIds.Nuget.Attributes.IntegrationTests\StronglyTypedIds.Nuget.Attributes.IntegrationTests.csproj", "{19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.Templates", "src\StronglyTypedIds.Templates\StronglyTypedIds.Templates.csproj", "{336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.IntegrationTests.Types", "test\StronglyTypedIds.IntegrationTests.Types\StronglyTypedIds.IntegrationTests.Types.csproj", "{A5804404-E5A5-4F05-86E2-B2A11D370498}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StronglyTypedIds.IntegrationTests.ExternalIds", "test\StronglyTypedIds.IntegrationTests.ExternalIds\StronglyTypedIds.IntegrationTests.ExternalIds.csproj", "{07875BB0-EFEE-4F90-AAB8-4B11F78C8047}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -104,6 +110,42 @@ Global {19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|Any CPU.ActiveCfg = Release|Any CPU {19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|x64.ActiveCfg = Release|Any CPU {19A9B323-8C0B-4D1B-A20C-8CECFFD37F23}.Release|x86.ActiveCfg = Release|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x64.ActiveCfg = Debug|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x64.Build.0 = Debug|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x86.ActiveCfg = Debug|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Debug|x86.Build.0 = Debug|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|Any CPU.Build.0 = Release|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x64.ActiveCfg = Release|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x64.Build.0 = Release|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x86.ActiveCfg = Release|Any CPU + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C}.Release|x86.Build.0 = Release|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x64.ActiveCfg = Debug|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x64.Build.0 = Debug|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x86.ActiveCfg = Debug|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Debug|x86.Build.0 = Debug|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|Any CPU.Build.0 = Release|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x64.ActiveCfg = Release|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x64.Build.0 = Release|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x86.ActiveCfg = Release|Any CPU + {A5804404-E5A5-4F05-86E2-B2A11D370498}.Release|x86.Build.0 = Release|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x64.ActiveCfg = Debug|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x64.Build.0 = Debug|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x86.ActiveCfg = Debug|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Debug|x86.Build.0 = Debug|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|Any CPU.Build.0 = Release|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x64.ActiveCfg = Release|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x64.Build.0 = Release|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x86.ActiveCfg = Release|Any CPU + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -115,6 +157,9 @@ Global {F25F6E67-E62A-4075-86CF-4C4EDD7E4883} = {EE1258BD-3422-4F55-B9CF-B4D6C95DAD68} {A7355210-7DDC-4968-84B7-79002113EA6E} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64} {19A9B323-8C0B-4D1B-A20C-8CECFFD37F23} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64} + {336D7EE4-90BA-4BFC-99F6-D70B8D494E8C} = {EE1258BD-3422-4F55-B9CF-B4D6C95DAD68} + {A5804404-E5A5-4F05-86E2-B2A11D370498} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64} + {07875BB0-EFEE-4F90-AAB8-4B11F78C8047} = {D1907D86-8FFC-4178-A3DB-0ADBDD282C64} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8D1F0534-B8AD-4CFA-9C14-CBC757BCB1E1} diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs index 68ec67dc9..6f6ea829d 100644 --- a/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs +++ b/src/StronglyTypedIds.Attributes/StronglyTypedIdAttribute.cs @@ -1,48 +1,49 @@ -using System; +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable namespace StronglyTypedIds { /// /// Place on partial structs to make the type a strongly-typed ID /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - public sealed class StronglyTypedIdAttribute : Attribute + [global::System.AttributeUsage(global::System.AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] + [global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] + public sealed class StronglyTypedIdAttribute : global::System.Attribute { /// - /// Make the struct a strongly typed ID + /// Make the struct a strongly typed ID. /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) + /// The built-in template to use to generate the ID. + /// The names of additional custom templates to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdAttribute(global::StronglyTypedIds.Template template, params string[] templateNames) { - BackingType = backingType; - Converters = converters; - Implementations = implementations; } /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value + /// Make the struct a strongly typed ID. /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } + /// The names of the template to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// If no templates are provided, the default value is used, as specified by + /// , or alternatively the + /// template. + /// + public StronglyTypedIdAttribute(params string[] templateNames) + { + } } } \ No newline at end of file diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs deleted file mode 100644 index 0016511b6..000000000 --- a/src/StronglyTypedIds.Attributes/StronglyTypedIdBackingType.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - public enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs deleted file mode 100644 index 599a51409..000000000 --- a/src/StronglyTypedIds.Attributes/StronglyTypedIdConverter.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - public enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs index f7cde494b..c4518e1ef 100644 --- a/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs +++ b/src/StronglyTypedIds.Attributes/StronglyTypedIdDefaultsAttribute.cs @@ -1,46 +1,58 @@ -using System; +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable namespace StronglyTypedIds { /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID + /// Used to control the default strongly typed ID values. Apply to an assembly using + /// [assembly:StronglyTypedIdDefaults(Template.Int)] for example /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - public sealed class StronglyTypedIdDefaultsAttribute : Attribute + [global::System.AttributeUsage(global::System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] + [global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] + public sealed class StronglyTypedIdDefaultsAttribute : global::System.Attribute { /// - /// Set the default values used for strongly typed ids + /// Set the default template to use for strongly typed IDs /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) + /// The built-in template to use to generate the ID. + /// The names of additional custom templates to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdDefaultsAttribute(global::StronglyTypedIds.Template template, params string[] templateNames) { - BackingType = backingType; - Converters = converters; - Implementations = implementations; } /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. + /// Set the default template to use for strongly typed IDs /// - public StronglyTypedIdConverter Converters { get; } + /// The name of the template to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdDefaultsAttribute(string templateName) + { + } /// - /// Interfaces and patterns the strongly typed id should implement + /// Set the default template to use for strongly typed IDs /// - public StronglyTypedIdImplementations Implementations { get; } + /// The name of the template to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdDefaultsAttribute(string templateName, params string[] templateNames) + { + } } } \ No newline at end of file diff --git a/src/StronglyTypedIds.Attributes/StronglyTypedIdImplementations.cs b/src/StronglyTypedIds.Attributes/StronglyTypedIdImplementations.cs deleted file mode 100644 index d0900fc4f..000000000 --- a/src/StronglyTypedIds.Attributes/StronglyTypedIdImplementations.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - public enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds.Attributes/Template.cs b/src/StronglyTypedIds.Attributes/Template.cs new file mode 100644 index 000000000..3ac8cfa8a --- /dev/null +++ b/src/StronglyTypedIds.Attributes/Template.cs @@ -0,0 +1,28 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + +using System; + +namespace StronglyTypedIds +{ + /// + /// The built-in template to use to generate the strongly-typed ID + /// + public enum Template + { + Guid, + Int, + String, + Long, + } +} \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/StronglyTypedId.Templates.targets b/src/StronglyTypedIds.Templates/StronglyTypedId.Templates.targets new file mode 100644 index 000000000..b7db8fde5 --- /dev/null +++ b/src/StronglyTypedIds.Templates/StronglyTypedId.Templates.targets @@ -0,0 +1,8 @@ + + + + + true + + + diff --git a/src/StronglyTypedIds.Templates/StronglyTypedIds.Templates.csproj b/src/StronglyTypedIds.Templates/StronglyTypedIds.Templates.csproj new file mode 100644 index 000000000..a720ced3a --- /dev/null +++ b/src/StronglyTypedIds.Templates/StronglyTypedIds.Templates.csproj @@ -0,0 +1,17 @@ + + + + netstandard2.0 + false + enable + StronglyTypedId.Templates + A collection of templates for generating strongly-typed IDs by decorating with a [StronglyTypedId] attribute + latest + + + + + + + + \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/guid-dapper.typedid b/src/StronglyTypedIds.Templates/guid-dapper.typedid new file mode 100644 index 000000000..2453e2c83 --- /dev/null +++ b/src/StronglyTypedIds.Templates/guid-dapper.typedid @@ -0,0 +1,20 @@ + partial struct PLACEHOLDERID + { + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new PLACEHOLDERID(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/guid-efcore.typedid b/src/StronglyTypedIds.Templates/guid-efcore.typedid new file mode 100644 index 000000000..f6a59d0a5 --- /dev/null +++ b/src/StronglyTypedIds.Templates/guid-efcore.typedid @@ -0,0 +1,13 @@ + partial struct PLACEHOLDERID + { + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/guid-full.typedid b/src/StronglyTypedIds.Templates/guid-full.typedid new file mode 100644 index 000000000..00a1d2f47 --- /dev/null +++ b/src/StronglyTypedIds.Templates/guid-full.typedid @@ -0,0 +1,254 @@ + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::System.Guid Value { get; } + + public PLACEHOLDERID(global::System.Guid value) + { + Value = value; + } + + public static PLACEHOLDERID New() => new PLACEHOLDERID(global::System.Guid.NewGuid()); + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(global::System.Guid.Empty); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::System.Guid guidValue => new PLACEHOLDERID(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new PLACEHOLDERID(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var guid = serializer.Deserialize(reader); + return guid.HasValue ? new PLACEHOLDERID(guid.Value) : null; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/guid-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/guid-newtonsoftjson.typedid new file mode 100644 index 000000000..8fae4b82a --- /dev/null +++ b/src/StronglyTypedIds.Templates/guid-newtonsoftjson.typedid @@ -0,0 +1,22 @@ + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID + { + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var guid = serializer.Deserialize(reader); + return guid.HasValue ? new PLACEHOLDERID(guid.Value) : null; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/int-dapper.typedid b/src/StronglyTypedIds.Templates/int-dapper.typedid new file mode 100644 index 000000000..277a4e1f1 --- /dev/null +++ b/src/StronglyTypedIds.Templates/int-dapper.typedid @@ -0,0 +1,21 @@ + partial struct PLACEHOLDERID + { + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + int intValue => new PLACEHOLDERID(intValue), + long longValue when longValue < int.MaxValue => new PLACEHOLDERID((int)longValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/int-efcore.typedid b/src/StronglyTypedIds.Templates/int-efcore.typedid new file mode 100644 index 000000000..c1f8fb3c6 --- /dev/null +++ b/src/StronglyTypedIds.Templates/int-efcore.typedid @@ -0,0 +1,13 @@ + partial struct PLACEHOLDERID + { + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/int-full.typedid b/src/StronglyTypedIds.Templates/int-full.typedid new file mode 100644 index 000000000..7fb419868 --- /dev/null +++ b/src/StronglyTypedIds.Templates/int-full.typedid @@ -0,0 +1,250 @@ + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public int Value { get; } + + public PLACEHOLDERID(int value) + { + Value = value; + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + int intValue => new PLACEHOLDERID(intValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(int)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(int) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt32()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(int.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(int.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(int.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (int.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(int.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(int.Parse(input, provider)); +#else + => new(int.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { +#if NET7_0_OR_GREATER + if (int.TryParse(input, provider, out var guid)) +#else + if (int.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + int intValue => new PLACEHOLDERID(intValue), + long longValue when longValue < int.MaxValue => new PLACEHOLDERID((int)longValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var result = serializer.Deserialize(reader); + return result.HasValue ? new PLACEHOLDERID(result.Value) : null; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/int-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/int-newtonsoftjson.typedid new file mode 100644 index 000000000..22de7b015 --- /dev/null +++ b/src/StronglyTypedIds.Templates/int-newtonsoftjson.typedid @@ -0,0 +1,22 @@ + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID + { + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var result = serializer.Deserialize(reader); + return result.HasValue ? new PLACEHOLDERID(result.Value) : null; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/long-dapper.typedid b/src/StronglyTypedIds.Templates/long-dapper.typedid new file mode 100644 index 000000000..3310653e6 --- /dev/null +++ b/src/StronglyTypedIds.Templates/long-dapper.typedid @@ -0,0 +1,22 @@ + partial struct PLACEHOLDERID + { + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + long longValue => new PLACEHOLDERID(longValue), + int intValue => new PLACEHOLDERID(intValue), + short shortValue => new PLACEHOLDERID(shortValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/long-efcore.typedid b/src/StronglyTypedIds.Templates/long-efcore.typedid new file mode 100644 index 000000000..ef88f8b7d --- /dev/null +++ b/src/StronglyTypedIds.Templates/long-efcore.typedid @@ -0,0 +1,13 @@ + partial struct PLACEHOLDERID + { + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/long-full.typedid b/src/StronglyTypedIds.Templates/long-full.typedid new file mode 100644 index 000000000..616e8a259 --- /dev/null +++ b/src/StronglyTypedIds.Templates/long-full.typedid @@ -0,0 +1,251 @@ + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public long Value { get; } + + public PLACEHOLDERID(long value) + { + Value = value; + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + long intValue => new PLACEHOLDERID(intValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(long)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(long) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt32()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(long.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(long.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(long.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (long.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(long.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(long.Parse(input, provider)); +#else + => new(long.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { +#if NET7_0_OR_GREATER + if (long.TryParse(input, provider, out var guid)) +#else + if (long.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + long longValue => new PLACEHOLDERID(longValue), + int intValue => new PLACEHOLDERID(intValue), + short shortValue => new PLACEHOLDERID(shortValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var result = serializer.Deserialize(reader); + return result.HasValue ? new PLACEHOLDERID(result.Value) : null; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/long-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/long-newtonsoftjson.typedid new file mode 100644 index 000000000..ba37cc152 --- /dev/null +++ b/src/StronglyTypedIds.Templates/long-newtonsoftjson.typedid @@ -0,0 +1,22 @@ + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID + { + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var result = serializer.Deserialize(reader); + return result.HasValue ? new PLACEHOLDERID(result.Value) : null; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/newid-full.typedid b/src/StronglyTypedIds.Templates/newid-full.typedid new file mode 100644 index 000000000..d55f97530 --- /dev/null +++ b/src/StronglyTypedIds.Templates/newid-full.typedid @@ -0,0 +1,257 @@ + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::MassTransit.NewId Value { get; } + + public PLACEHOLDERID(global::MassTransit.NewId value) + { + Value = value; + } + + public static PLACEHOLDERID New() => new PLACEHOLDERID(global::MassTransit.NewId.Next()); + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(global::MassTransit.NewId.Empty); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId) + || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::MassTransit.NewId newIdValue => new PLACEHOLDERID(newIdValue), + global::System.Guid guidValue => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(guidValue)), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(result)), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId) + || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(global::MassTransit.NewId)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value.ToGuid(); + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToGuid().ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(string) || typeToConvert == typeof(global::System.Guid) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (global::MassTransit.NewId.FromGuid(reader.GetGuid())); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value.ToGuid()); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToGuid().ToString()); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider))); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(global::MassTransit.NewId.FromGuid(guid)); + return true; + } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString(string? format, global::System.IFormatProvider? formatProvider) + => Value.ToGuid().ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider))); +#else + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(global::MassTransit.NewId.FromGuid(guid)); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.ToGuid().TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.ToGuid().TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value.ToGuid(); + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(guidValue)), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(result)), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value.ToGuid(), + value => new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(value)), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var guid = serializer.Deserialize(reader); + return guid.HasValue ? new PLACEHOLDERID(global::MassTransit.NewId.FromGuid(guid.Value)) : null; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/nullablestring-full.typedid b/src/StronglyTypedIds.Templates/nullablestring-full.typedid new file mode 100644 index 000000000..6c06d57c1 --- /dev/null +++ b/src/StronglyTypedIds.Templates/nullablestring-full.typedid @@ -0,0 +1,246 @@ + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public string? Value { get; } + + public PLACEHOLDERID(string? value) + { + Value = value; + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(string.Empty); + + /// + public bool Equals(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => true, + (null, _) => false, + (_, null) => false, + (_, _) => Value.Equals(other.Value, global::System.StringComparison.Ordinal), + }; + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value?.GetHashCode() ?? 0; + + public override string? ToString() => Value; + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => 0, + (null, _) => -1, + (_, null) => 1, + (_, _) => string.CompareOrdinal(Value, other.Value), + }; + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + => value switch + { + null => new PLACEHOLDERID(null), + string x => new PLACEHOLDERID(x), + _ => base.ConvertFrom(context, culture, value), + }; + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(string)) + { + return idValue.Value; + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetString()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + { + if (value.Value is null) + { + writer.WriteNullValue(); + } + else + { + writer.WriteStringValue(value.Value); + } + } + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(reader.GetString()); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value ?? string.Empty); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(input); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(input); + + /// + public static bool TryParse( + string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + result = new(input); + return true; + } +#endif + + /// + public string ToString(string? format, global::System.IFormatProvider? formatProvider) + => Value ?? string.Empty; + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(input.ToString()); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) + => new(input.ToString()); + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { + result = new(input.ToString()); + return true; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format = default) + { + if (Value is not null && destination.Length > Value.Length) + { + global::System.MemoryExtensions.AsSpan(Value).CopyTo(destination); + charsWritten = Value.Length; + return true; + } + + charsWritten = default; + return false; + } +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + null => new PLACEHOLDERID(null), + System.DBNull => new PLACEHOLDERID(null), + string stringValue => new PLACEHOLDERID(stringValue), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + if (objectType == typeof(PLACEHOLDERID?)) + { + var value = serializer.Deserialize(reader); + + return new PLACEHOLDERID(value); + } + + return new PLACEHOLDERID(serializer.Deserialize(reader)); + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/string-dapper.typedid b/src/StronglyTypedIds.Templates/string-dapper.typedid new file mode 100644 index 000000000..4af050343 --- /dev/null +++ b/src/StronglyTypedIds.Templates/string-dapper.typedid @@ -0,0 +1,19 @@ + partial struct PLACEHOLDERID + { + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + string stringValue => new PLACEHOLDERID(stringValue), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/string-efcore.typedid b/src/StronglyTypedIds.Templates/string-efcore.typedid new file mode 100644 index 000000000..6fd5fc403 --- /dev/null +++ b/src/StronglyTypedIds.Templates/string-efcore.typedid @@ -0,0 +1,13 @@ + partial struct PLACEHOLDERID + { + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/string-full.typedid b/src/StronglyTypedIds.Templates/string-full.typedid new file mode 100644 index 000000000..be8e396f3 --- /dev/null +++ b/src/StronglyTypedIds.Templates/string-full.typedid @@ -0,0 +1,243 @@ + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public string Value { get; } + + public PLACEHOLDERID(string value) + { + Value = value ?? throw new global::System.ArgumentNullException(nameof(value)); + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(string.Empty); + + /// + public bool Equals(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => true, + (null, _) => false, + (_, null) => false, + (_, _) => Value.Equals(other.Value, global::System.StringComparison.Ordinal), + }; + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value; + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => 0, + (null, _) => -1, + (_, null) => 1, + (_, _) => string.CompareOrdinal(Value, other.Value), + }; + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + if (value is string stringValue) + { + return new PLACEHOLDERID(stringValue); + } + + return base.ConvertFrom(context, culture, value); + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(string)) + { + return idValue.Value; + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetString()!); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(input); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(input); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + result = new(input); + return true; + } +#endif + + /// + public string ToString(string? format, global::System.IFormatProvider? formatProvider) + => Value; + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(input.ToString()); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) + => new(input.ToString()); + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { + result = new(input.ToString()); + return true; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format = default) + { + if (destination.Length > Value.Length) + { + global::System.MemoryExtensions.AsSpan(Value).CopyTo(destination); + charsWritten = Value.Length; + return true; + } + + charsWritten = default; + return false; + } +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + string stringValue => new PLACEHOLDERID(stringValue), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + if (objectType == typeof(PLACEHOLDERID?)) + { + var value = serializer.Deserialize(reader); + + return value is null ? null : new PLACEHOLDERID(value); + } + + return new PLACEHOLDERID(serializer.Deserialize(reader)!); + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds.Templates/string-newtonsoftjson.typedid b/src/StronglyTypedIds.Templates/string-newtonsoftjson.typedid new file mode 100644 index 000000000..4711a24ec --- /dev/null +++ b/src/StronglyTypedIds.Templates/string-newtonsoftjson.typedid @@ -0,0 +1,28 @@ + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID + { + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + if (objectType == typeof(PLACEHOLDERID?)) + { + var value = serializer.Deserialize(reader); + + return value is null ? null : new PLACEHOLDERID(value); + } + + return new PLACEHOLDERID(serializer.Deserialize(reader)!); + } + } + } \ No newline at end of file diff --git a/src/StronglyTypedIds/DiagnosticInfo.cs b/src/StronglyTypedIds/DiagnosticInfo.cs new file mode 100644 index 000000000..ce57b8bf3 --- /dev/null +++ b/src/StronglyTypedIds/DiagnosticInfo.cs @@ -0,0 +1,19 @@ +using Microsoft.CodeAnalysis; + +namespace StronglyTypedIds; + +internal sealed record DiagnosticInfo +{ + public DiagnosticInfo(DiagnosticDescriptor descriptor, Location location, string? messageArg = null, EquatableArray<(string, string)> properties = default) + { + Descriptor = descriptor; + Location = location; + MessageArg = messageArg; + Properties = properties; + } + + public DiagnosticDescriptor Descriptor { get; } + public Location Location { get; } + public string? MessageArg { get; } + public EquatableArray<(string, string)> Properties { get; } +} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/DiagnosticHelper.cs b/src/StronglyTypedIds/Diagnostics/DiagnosticHelper.cs new file mode 100644 index 000000000..71e81a024 --- /dev/null +++ b/src/StronglyTypedIds/Diagnostics/DiagnosticHelper.cs @@ -0,0 +1,41 @@ +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; + +namespace StronglyTypedIds.Diagnostics; + +internal static class DiagnosticHelper +{ + public static void ReportDiagnostic(this SourceProductionContext context, DiagnosticInfo info) + { + var diagnostic = CreateDiagnostic(info); + + context.ReportDiagnostic(diagnostic); + } + + public static Diagnostic CreateDiagnostic(DiagnosticInfo info) + { + var messageArgs = info.MessageArg is { } arg + ? new object[] {arg} + : null; + + ImmutableDictionary? properties = null; + if (info.Properties is {Count: > 0} props) + { + var dict = ImmutableDictionary.CreateBuilder(); + foreach (var prop in props.GetArray()!) + { + dict.Add(prop.Item1, prop.Item2); + } + + properties = dict.ToImmutable()!; + } + + + var diagnostic = Diagnostic.Create( + descriptor: info.Descriptor, + location: info.Location, + messageArgs: messageArgs, + properties: properties); + return diagnostic; + } +} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/InvalidBackingTypeDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidBackingTypeDiagnostic.cs deleted file mode 100644 index b052e0302..000000000 --- a/src/StronglyTypedIds/Diagnostics/InvalidBackingTypeDiagnostic.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.CodeAnalysis; - -namespace StronglyTypedIds.Diagnostics -{ - internal static class InvalidBackingTypeDiagnostic - { - internal const string Id = "STI4"; - internal const string Message = "The StronglyTypedIdBackingType value provided is not a valid combination of flags"; - internal const string Title = "Invalid backing type"; - - public static Diagnostic Create(SyntaxNode currentNode) => - Diagnostic.Create( - new DiagnosticDescriptor( - Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true), - currentNode.GetLocation()); - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/InvalidConverterDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidConverterDiagnostic.cs deleted file mode 100644 index bf601c518..000000000 --- a/src/StronglyTypedIds/Diagnostics/InvalidConverterDiagnostic.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.CodeAnalysis; - -namespace StronglyTypedIds.Diagnostics -{ - internal static class InvalidConverterDiagnostic - { - internal const string Id = "STI3"; - internal const string Message = "The StronglyTypedIdConverter value provided is not a valid combination of flags"; - internal const string Title = "Invalid converter"; - - public static Diagnostic Create(SyntaxNode currentNode) => - Diagnostic.Create( - new DiagnosticDescriptor( - Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true), - currentNode.GetLocation()); - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/InvalidImplementationsDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidImplementationsDiagnostic.cs deleted file mode 100644 index dc4388613..000000000 --- a/src/StronglyTypedIds/Diagnostics/InvalidImplementationsDiagnostic.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.CodeAnalysis; - -namespace StronglyTypedIds.Diagnostics -{ - internal static class InvalidImplementationsDiagnostic - { - internal const string Id = "STI5"; - internal const string Message = "The StronglyTypedIdImplementations value provided is not a valid combination of flags"; - internal const string Title = "Invalid implementations value"; - - public static Diagnostic Create(SyntaxNode currentNode) => - Diagnostic.Create( - new DiagnosticDescriptor( - Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true), - currentNode.GetLocation()); - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/InvalidTemplateNameDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/InvalidTemplateNameDiagnostic.cs new file mode 100644 index 000000000..0cf8f4137 --- /dev/null +++ b/src/StronglyTypedIds/Diagnostics/InvalidTemplateNameDiagnostic.cs @@ -0,0 +1,15 @@ +using Microsoft.CodeAnalysis; + +namespace StronglyTypedIds.Diagnostics; + +internal static class InvalidTemplateNameDiagnostic +{ + internal const string Id = "STRONGID001"; + internal const string Message = "The template name must not be null or whitespace."; + internal const string Title = "Invalid template name"; + + public static DiagnosticInfo CreateInfo(LocationInfo location) + => new(new DiagnosticDescriptor( + Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true), + location.ToLocation()); +} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/MultipleAssemblyAttributeDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/MultipleAssemblyAttributeDiagnostic.cs new file mode 100644 index 000000000..98ecc2126 --- /dev/null +++ b/src/StronglyTypedIds/Diagnostics/MultipleAssemblyAttributeDiagnostic.cs @@ -0,0 +1,15 @@ +using Microsoft.CodeAnalysis; + +namespace StronglyTypedIds.Diagnostics; + +internal static class MultipleAssemblyAttributeDiagnostic +{ + internal const string Id = "STRONGID004"; + internal const string Message = "You may only have one instance of the StronglyTypedIdDefaults assembly attribute"; + internal const string Title = "Multiple assembly attributes"; + + public static DiagnosticInfo CreateInfo(SyntaxNode currentNode) => + new(new DiagnosticDescriptor( + Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true), + currentNode.GetLocation()); +} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs index 6c8435da1..dd50465be 100644 --- a/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs +++ b/src/StronglyTypedIds/Diagnostics/NotPartialDiagnostic.cs @@ -4,7 +4,7 @@ namespace StronglyTypedIds.Diagnostics { internal static class NotPartialDiagnostic { - internal const string Id = "STI2"; + internal const string Id = "STRONGID003"; internal const string Message = "The target of the StronglyTypedId attribute must be declared as partial."; internal const string Title = "Must be partial"; @@ -13,5 +13,10 @@ public static Diagnostic Create(SyntaxNode currentNode) => new DiagnosticDescriptor( Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true), currentNode.GetLocation()); + + public static DiagnosticInfo CreateInfo(SyntaxNode currentNode) + => new(new DiagnosticDescriptor( + Id, Title, Message, category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true), + currentNode.GetLocation()); } } \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/UnknownTemplateCodeFixProvider.cs b/src/StronglyTypedIds/Diagnostics/UnknownTemplateCodeFixProvider.cs new file mode 100644 index 000000000..282571b30 --- /dev/null +++ b/src/StronglyTypedIds/Diagnostics/UnknownTemplateCodeFixProvider.cs @@ -0,0 +1,125 @@ +// Based on https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/1dd5ced072d7d870f6dd698a6c02ad509a122452/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/Settings/UnknownTemplateCodeFixProvider.cs + +#nullable disable + +using System; +using System.Collections.Immutable; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; + +namespace StronglyTypedIds.Diagnostics; + +[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UnknownTemplateCodeFixProvider)), Shared] +internal class UnknownTemplateCodeFixProvider : CodeFixProvider +{ + internal const string DefaultHeader = + """" + // ACTION REQUIRED: This file was automatically added to your project, but it + // will not take effect until additional steps are taken to enable it. See + // https://github.com/dotnet/roslyn/issues/4655 for more details. + // + // To enable the template, in Visual Studio 2017, 2019, and 2022: + // 1. Select the file in Solution Explorer. + // 2. In the 'Properties' window, set the value for 'Build Action' + // to one of the following (whichever is available): + // - For .NET Core and .NET Standard projects: 'C# analyzer additional file' + // - For other projects: 'AdditionalFiles' + // + // Any instances of PLACEHOLDERID will be replaced with the target ID name + // when generating code from this template. + + + """"; + + /// + public override ImmutableArray FixableDiagnosticIds { get; } = + ImmutableArray.Create(Diagnostics.UnknownTemplateDiagnostic.Id); + + /// + public override Task RegisterCodeFixesAsync(CodeFixContext context) + { + var project = context.Document.Project; + var workspace = project.Solution.Workspace; + + // if we can't add extra documents, there's nothing we can do + if (!workspace.CanApplyChange(ApplyChangesKind.AddAdditionalDocument)) + { + return Task.CompletedTask; + } + + foreach (var diagnostic in context.Diagnostics) + { + if(!diagnostic.Properties.TryGetValue(UnknownTemplateDiagnostic.TemplateName, out var templateName)) + { + // This shouldn't happen, but play it safe + continue; + } + + // check if the template file already exists + var alreadyAdded = false; + foreach (var document in project.AdditionalDocuments) + { + if (document.Name.Equals(templateName, StringComparison.OrdinalIgnoreCase)) + { + alreadyAdded = true; + break; + } + } + + if (alreadyAdded) + { + continue; + } + + context.RegisterCodeFix( + CodeAction.Create( + $"Add '{templateName}.typedid' template to the project", + cancellationToken => GetTransformedSolutionAsync(context.Document, templateName, cancellationToken), + nameof(UnknownTemplateCodeFixProvider)), + diagnostic); + } + + return Task.CompletedTask; + } + + /// + public override FixAllProvider GetFixAllProvider() + { + // This code fix does not support fix all actions. + return null; + } + + private static Task GetTransformedSolutionAsync(Document document, string templateName, CancellationToken cancellationToken) + { + // Currently unused + _ = cancellationToken; + + var project = document.Project; + var solution = project.Solution; + + var newDocumentId = DocumentId.CreateNewId(project.Id); + + var templateContent = GetTemplateContent(templateName); + + var newSolution = solution.AddAdditionalDocument(newDocumentId, $"{templateName}.typedid", templateContent); + + return Task.FromResult(newSolution); + } + + internal static string GetTemplateContent(string templateName) + { + var templateContent = templateName switch + { + { } x when x.Contains("int", StringComparison.OrdinalIgnoreCase) => EmbeddedSources.LoadEmbeddedTypedId("int-full.typedid"), + { } x when x.Contains("long", StringComparison.OrdinalIgnoreCase) => EmbeddedSources.LoadEmbeddedTypedId("long-full.typedid"), + { } x when x.Contains("string", StringComparison.OrdinalIgnoreCase) => EmbeddedSources.LoadEmbeddedTypedId("string-full.typedid"), + _ => EmbeddedSources.LoadEmbeddedTypedId("guid-full.typedid"), + }; + + return DefaultHeader + templateContent; + } +} \ No newline at end of file diff --git a/src/StronglyTypedIds/Diagnostics/UnknownTemplateDiagnostic.cs b/src/StronglyTypedIds/Diagnostics/UnknownTemplateDiagnostic.cs new file mode 100644 index 000000000..7347efd9d --- /dev/null +++ b/src/StronglyTypedIds/Diagnostics/UnknownTemplateDiagnostic.cs @@ -0,0 +1,21 @@ +using Microsoft.CodeAnalysis; + +namespace StronglyTypedIds.Diagnostics; + +internal static class UnknownTemplateDiagnostic +{ + internal const string Id = "STRONGID002"; + internal const string Title = "Unknown .typedid template"; + internal const string TemplateName = nameof(TemplateName); + + public static DiagnosticInfo CreateInfo(LocationInfo location, string name) + => new(CreateDescriptor(), + location.ToLocation(), + name, + new EquatableArray<(string, string)>(new[] {(TemplateName, name)})); + + public static DiagnosticDescriptor CreateDescriptor() + => new( + Id, Title, "Could not find '{0}.typedid' template. Ensure the template exists in the project and has a build action of 'Additional Files'.", + category: Constants.Usage, defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); +} \ No newline at end of file diff --git a/src/StronglyTypedIds/EmbeddedSources.Guid.cs b/src/StronglyTypedIds/EmbeddedSources.Guid.cs new file mode 100644 index 000000000..63ca8556a --- /dev/null +++ b/src/StronglyTypedIds/EmbeddedSources.Guid.cs @@ -0,0 +1,210 @@ +namespace StronglyTypedIds; + +internal static partial class EmbeddedSources +{ + private const string GuidTemplate = """ + partial struct PLACEHOLDERID : + #if NET6_0_OR_GREATER + global::System.ISpanFormattable, + #endif + #if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, + #endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::System.Guid Value { get; } + + public PLACEHOLDERID(global::System.Guid value) + { + Value = value; + } + + public static PLACEHOLDERID New() => new PLACEHOLDERID(global::System.Guid.NewGuid()); + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(global::System.Guid.Empty); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::System.Guid guidValue => new PLACEHOLDERID(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + + #if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); + #endif + } + + public static PLACEHOLDERID Parse(string input) + => new(global::System.Guid.Parse(input)); + + #if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } + #endif + + /// + public string ToString( + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] + #endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + + #if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); + #endif + + #if NET6_0_OR_GREATER + #if NET7_0_OR_GREATER + /// + #endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) + #if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); + #else + => new(global::System.Guid.Parse(input)); + #endif + + #if NET7_0_OR_GREATER + /// + #endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { + #if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) + #else + if (global::System.Guid.TryParse(input, out var guid)) + #endif + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] + #endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] + #endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); + #endif + } + """; +} \ No newline at end of file diff --git a/src/StronglyTypedIds/EmbeddedSources.Int.cs b/src/StronglyTypedIds/EmbeddedSources.Int.cs new file mode 100644 index 000000000..2690ad76b --- /dev/null +++ b/src/StronglyTypedIds/EmbeddedSources.Int.cs @@ -0,0 +1,205 @@ +namespace StronglyTypedIds; + +internal static partial class EmbeddedSources +{ + private const string IntTemplate = """ + partial struct PLACEHOLDERID : + #if NET6_0_OR_GREATER + global::System.ISpanFormattable, + #endif + #if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, + #endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public int Value { get; } + + public PLACEHOLDERID(int value) + { + Value = value; + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + int intValue => new PLACEHOLDERID(intValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(int)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(int) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt32()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + + #if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(int.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + #endif + } + + public static PLACEHOLDERID Parse(string input) + => new(int.Parse(input)); + + #if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(int.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (int.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } + #endif + + /// + public string ToString( + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.NumericFormat)] + #endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + + #if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(int.Parse(input)); + #endif + + #if NET6_0_OR_GREATER + #if NET7_0_OR_GREATER + /// + #endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) + #if NET7_0_OR_GREATER + => new(int.Parse(input, provider)); + #else + => new(int.Parse(input)); + #endif + + #if NET7_0_OR_GREATER + /// + #endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { + #if NET7_0_OR_GREATER + if (int.TryParse(input, provider, out var value)) + #else + if (int.TryParse(input, out var value)) + #endif + { + result = new(value); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] + #endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] + #endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); + #endif + } + """; +} \ No newline at end of file diff --git a/src/StronglyTypedIds/EmbeddedSources.Long.cs b/src/StronglyTypedIds/EmbeddedSources.Long.cs new file mode 100644 index 000000000..c3a3bd3f2 --- /dev/null +++ b/src/StronglyTypedIds/EmbeddedSources.Long.cs @@ -0,0 +1,205 @@ +namespace StronglyTypedIds; + +internal static partial class EmbeddedSources +{ + private const string LongTemplate = """ + partial struct PLACEHOLDERID : + #if NET6_0_OR_GREATER + global::System.ISpanFormattable, + #endif + #if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, + #endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public long Value { get; } + + public PLACEHOLDERID(long value) + { + Value = value; + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + long longValue => new PLACEHOLDERID(longValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(long)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(long) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt64()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + + #if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(long.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); + #endif + } + + public static PLACEHOLDERID Parse(string input) + => new(long.Parse(input)); + + #if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(long.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (long.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } + #endif + + /// + public string ToString( + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.NumericFormat)] + #endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + + #if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(long.Parse(input)); + #endif + + #if NET6_0_OR_GREATER + #if NET7_0_OR_GREATER + /// + #endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) + #if NET7_0_OR_GREATER + => new(long.Parse(input, provider)); + #else + => new(long.Parse(input)); + #endif + + #if NET7_0_OR_GREATER + /// + #endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { + #if NET7_0_OR_GREATER + if (long.TryParse(input, provider, out var value)) + #else + if (long.TryParse(input, out var value)) + #endif + { + result = new(value); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] + #endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + #if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] + #endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); + #endif + } + """; +} \ No newline at end of file diff --git a/src/StronglyTypedIds/EmbeddedSources.String.cs b/src/StronglyTypedIds/EmbeddedSources.String.cs new file mode 100644 index 000000000..30d260a4e --- /dev/null +++ b/src/StronglyTypedIds/EmbeddedSources.String.cs @@ -0,0 +1,194 @@ +namespace StronglyTypedIds; + +internal static partial class EmbeddedSources +{ + private const string StringTemplate = """ + partial struct PLACEHOLDERID : + #if NET6_0_OR_GREATER + global::System.ISpanFormattable, + #endif + #if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, + #endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public string Value { get; } + + public PLACEHOLDERID(string value) + { + Value = value ?? throw new global::System.ArgumentNullException(nameof(value)); + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(string.Empty); + + /// + public bool Equals(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => true, + (null, _) => false, + (_, null) => false, + (_, _) => Value.Equals(other.Value, global::System.StringComparison.Ordinal), + }; + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value; + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + public static bool operator > (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) > 0; + public static bool operator < (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) < 0; + public static bool operator >= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) >= 0; + public static bool operator <= (PLACEHOLDERID a, PLACEHOLDERID b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => 0, + (null, _) => -1, + (_, null) => 1, + (_, _) => string.CompareOrdinal(Value, other.Value), + }; + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + if (value is string stringValue) + { + return new PLACEHOLDERID(stringValue); + } + + return base.ConvertFrom(context, culture, value); + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(string)) + { + return idValue.Value; + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetString()!); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + + #if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value); + #endif + } + + public static PLACEHOLDERID Parse(string input) + => new(input); + + #if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(input); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + result = new(input); + return true; + } + #endif + + /// + public string ToString(string? format, global::System.IFormatProvider? formatProvider) + => Value; + + #if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(input.ToString()); + #endif + + #if NET6_0_OR_GREATER + #if NET7_0_OR_GREATER + /// + #endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) + => new(input.ToString()); + + #if NET7_0_OR_GREATER + /// + #endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { + result = new(input.ToString()); + return true; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format = default) + { + if (destination.Length > Value.Length) + { + global::System.MemoryExtensions.AsSpan(Value).CopyTo(destination); + charsWritten = Value.Length; + return true; + } + + charsWritten = default; + return false; + } + #endif + } + """; +} \ No newline at end of file diff --git a/src/StronglyTypedIds/EmbeddedSources.cs b/src/StronglyTypedIds/EmbeddedSources.cs index e1f229779..e54f812ab 100644 --- a/src/StronglyTypedIds/EmbeddedSources.cs +++ b/src/StronglyTypedIds/EmbeddedSources.cs @@ -3,154 +3,60 @@ using System.Reflection; using System.Text; -namespace StronglyTypedIds -{ - internal static class EmbeddedSources - { - private static readonly Assembly ThisAssembly = typeof(EmbeddedSources).Assembly; - internal static readonly string StronglyTypedIdAttributeSource = LoadTemplateForEmitting("StronglyTypedIdAttribute"); - internal static readonly string StronglyTypedIdDefaultsAttributeSource = LoadTemplateForEmitting("StronglyTypedIdDefaultsAttribute"); - internal static readonly string StronglyTypedIdBackingTypeSource = LoadTemplateForEmitting("StronglyTypedIdBackingType"); - internal static readonly string StronglyTypedIdConverterSource = LoadTemplateForEmitting("StronglyTypedIdConverter"); - internal static readonly string StronglyTypedIdImplementationsSource = LoadTemplateForEmitting("StronglyTypedIdImplementations"); - - private static readonly string AutoGeneratedHeader = LoadEmbeddedResource("StronglyTypedIds.Templates.AutoGeneratedHeader.cs"); - - internal static readonly ResourceCollection GuidResources = new( - AutoGeneratedHeader, - LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_Base.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_NewtonsoftJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_SystemTextJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_TypeConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_EfCoreValueConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_DapperTypeHandler.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Guid.Guid_IComparable.cs"), - false - ); - - internal static readonly ResourceCollection IntResources = new( - AutoGeneratedHeader, - LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_Base.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_NewtonsoftJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_SystemTextJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_TypeConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_EfCoreValueConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_DapperTypeHandler.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Int.Int_IComparable.cs"), - false - ); +namespace StronglyTypedIds; - internal static readonly ResourceCollection LongResources = new( - AutoGeneratedHeader, - LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_Base.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_NewtonsoftJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_SystemTextJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_TypeConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_EfCoreValueConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_DapperTypeHandler.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.Long.Long_IComparable.cs"), - false - ); - - internal static readonly ResourceCollection StringResources = new( - AutoGeneratedHeader, - LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_Base.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_NewtonsoftJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_SystemTextJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_TypeConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_EfCoreValueConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_DapperTypeHandler.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.String.String_IComparable.cs"), - false - ); - - internal static readonly ResourceCollection NullableStringResources = new( - AutoGeneratedHeader, - LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_Base.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_NewtonsoftJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_SystemTextJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_TypeConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_EfCoreValueConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_DapperTypeHandler.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NullableString.NullableString_IComparable.cs"), - true - ); - - internal static readonly ResourceCollection NewIdResources = new( - AutoGeneratedHeader, - LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_Base.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_NewtonsoftJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_SystemTextJsonConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_TypeConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_EfCoreValueConverter.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_DapperTypeHandler.cs"), - LoadEmbeddedResource("StronglyTypedIds.Templates.NewId.NewId_IComparable.cs"), - false - ); +internal static partial class EmbeddedSources +{ + private static readonly Assembly ThisAssembly = typeof(EmbeddedSources).Assembly; + internal static readonly string StronglyTypedIdAttributeSource = LoadAttributeTemplateForEmitting("StronglyTypedIdAttribute"); + internal static readonly string StronglyTypedIdDefaultsAttributeSource = LoadAttributeTemplateForEmitting("StronglyTypedIdDefaultsAttribute"); + internal static readonly string TemplateSource = LoadAttributeTemplateForEmitting("Template"); - 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 static readonly string AutoGeneratedHeader = LoadEmbeddedResource("StronglyTypedIds.Templates.AutoGeneratedHeader.cs"); - internal static string LoadEmbeddedResource(string resourceName) + internal static string GetTemplate(Template template) + => template switch { - var resourceStream = ThisAssembly.GetManifestResourceStream(resourceName); - if (resourceStream is null) - { - var existingResources = ThisAssembly.GetManifestResourceNames(); - throw new ArgumentException($"Could not find embedded resource {resourceName}. Available names: {string.Join(", ", existingResources)}"); - } + Template.Guid => GuidTemplate, + Template.Int => IntTemplate, + Template.Long => LongTemplate, + Template.String => StringTemplate, + _ => string.Empty, + }; - using var reader = new StreamReader(resourceStream, Encoding.UTF8); + internal static string LoadEmbeddedTypedId(string templateName) + => LoadEmbeddedResource($"StronglyTypedIds.Templates.{templateName}"); - return reader.ReadToEnd(); - } - - public readonly struct ResourceCollection + internal static string LoadEmbeddedResource(string resourceName) + { + var resourceStream = ThisAssembly.GetManifestResourceStream(resourceName); + if (resourceStream is null) { - public string Header { get; } - public bool NullableEnable { get; } - public string BaseId { get; } - public string Newtonsoft { get; } - public string SystemTextJson { get; } - public string TypeConverter { get; } - public string EfCoreValueConverter { get; } - public string DapperTypeHandler { get; } - public string Comparable { get; } - - public ResourceCollection( - string header, - string baseId, - string newtonsoft, - string systemTextJson, - string typeConverter, - string efCoreValueConverter, - string dapperTypeHandler, - string comparable, - bool nullableEnable) - { - BaseId = baseId; - Newtonsoft = newtonsoft; - SystemTextJson = systemTextJson; - TypeConverter = typeConverter; - EfCoreValueConverter = efCoreValueConverter; - DapperTypeHandler = dapperTypeHandler; - Comparable = comparable; - NullableEnable = nullableEnable; - Header = header; - } + var existingResources = ThisAssembly.GetManifestResourceNames(); + throw new ArgumentException($"Could not find embedded resource {resourceName}. Available names: {string.Join(", ", existingResources)}"); } - internal static string LoadTemplateForEmitting(string resourceName) - { - var resource = LoadEmbeddedResource($"StronglyTypedIds.Templates.Sources.{resourceName}.cs"); - return AutoGeneratedHeader + @"#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES + using var reader = new StreamReader(resourceStream, Encoding.UTF8); -" + resource - .Replace("public sealed", "internal sealed") - .Replace("public enum", "internal enum") - + @" -#endif"; - } + return reader.ReadToEnd(); + } + + internal static string LoadAttributeTemplateForEmitting(string resourceName) + { + var resource = LoadEmbeddedResource($"StronglyTypedIds.Templates.Sources.{resourceName}.cs"); + // AutoGeneratedHeader is included directly in the file + // so that it's there if you're directly referencing the attributes package too + return resource + .Replace("#nullable enable", """ + #nullable enable + + #if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES + """) + .Replace("public sealed", "internal sealed") + .Replace("public enum", "internal enum") + + """ + + #endif + """; } } \ No newline at end of file diff --git a/src/StronglyTypedIds/EquatableArray.cs b/src/StronglyTypedIds/EquatableArray.cs new file mode 100644 index 000000000..70c1030e0 --- /dev/null +++ b/src/StronglyTypedIds/EquatableArray.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace StronglyTypedIds; + +/// +/// An immutable, equatable array. This is equivalent to but with value equality support. +/// +/// The type of values in the array. +internal readonly struct EquatableArray : IEquatable>, IEnumerable + where T : IEquatable +{ + public static readonly EquatableArray Empty = new(Array.Empty()); + + /// + /// The underlying array. + /// + private readonly T[]? _array; + + /// + /// Creates a new instance. + /// + /// The input to wrap. + public EquatableArray(T[] array) + { + _array = array; + } + + /// + public bool Equals(EquatableArray array) + { + return AsSpan().SequenceEqual(array.AsSpan()); + } + + /// + public override bool Equals(object? obj) + { + return obj is EquatableArray array && Equals(this, array); + } + + /// + public override int GetHashCode() + { + if (_array is not T[] array) + { + return 0; + } + + HashCode hashCode = default; + + foreach (T item in array) + { + hashCode.Add(item); + } + + return hashCode.ToHashCode(); + } + + /// + /// Returns a wrapping the current items. + /// + /// A wrapping the current items. + public ReadOnlySpan AsSpan() + { + return _array.AsSpan(); + } + + /// + /// Gets the underlying array if there is one + /// + public T[]? GetArray() => _array; + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)(_array ?? Array.Empty())).GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)(_array ?? Array.Empty())).GetEnumerator(); + } + + public int Count => _array?.Length ?? 0; + + /// + /// Checks whether two values are the same. + /// + /// The first value. + /// The second value. + /// Whether and are equal. + public static bool operator ==(EquatableArray left, EquatableArray right) + { + return left.Equals(right); + } + + /// + /// Checks whether two values are not the same. + /// + /// The first value. + /// The second value. + /// Whether and are not equal. + public static bool operator !=(EquatableArray left, EquatableArray right) + { + return !left.Equals(right); + } +} \ No newline at end of file diff --git a/src/StronglyTypedIds/HashCode.cs b/src/StronglyTypedIds/HashCode.cs new file mode 100644 index 000000000..4a2ca9ea3 --- /dev/null +++ b/src/StronglyTypedIds/HashCode.cs @@ -0,0 +1,383 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace StronglyTypedIds; + +/// +/// Polyfill for .NET 6 HashCode +/// +internal struct HashCode +{ + private static readonly uint s_seed = GenerateGlobalSeed(); + + private const uint Prime1 = 2654435761U; + private const uint Prime2 = 2246822519U; + private const uint Prime3 = 3266489917U; + private const uint Prime4 = 668265263U; + private const uint Prime5 = 374761393U; + + private uint _v1, _v2, _v3, _v4; + private uint _queue1, _queue2, _queue3; + private uint _length; + + private static uint GenerateGlobalSeed() + { + var buffer = new byte[sizeof(uint)]; + new Random().NextBytes(buffer); + return BitConverter.ToUInt32(buffer, 0); + } + + public static int Combine(T1 value1) + { + // Provide a way of diffusing bits from something with a limited + // input hash space. For example, many enums only have a few + // possible hashes, only using the bottom few bits of the code. Some + // collections are built on the assumption that hashes are spread + // over a larger space, so diffusing the bits may help the + // collection work more efficiently. + + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + + uint hash = MixEmptyState(); + hash += 4; + + hash = QueueRound(hash, hc1); + + hash = MixFinal(hash); + return (int)hash; + } + + public static int Combine(T1 value1, T2 value2) + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + + uint hash = MixEmptyState(); + hash += 8; + + hash = QueueRound(hash, hc1); + hash = QueueRound(hash, hc2); + + hash = MixFinal(hash); + return (int)hash; + } + + public static int Combine(T1 value1, T2 value2, T3 value3) + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + + uint hash = MixEmptyState(); + hash += 12; + + hash = QueueRound(hash, hc1); + hash = QueueRound(hash, hc2); + hash = QueueRound(hash, hc3); + + hash = MixFinal(hash); + return (int)hash; + } + + public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4) + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 16; + + hash = MixFinal(hash); + return (int)hash; + } + + public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 20; + + hash = QueueRound(hash, hc5); + + hash = MixFinal(hash); + return (int)hash; + } + + public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + uint hc6 = (uint)(value6?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 24; + + hash = QueueRound(hash, hc5); + hash = QueueRound(hash, hc6); + + hash = MixFinal(hash); + return (int)hash; + } + + public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + uint hc6 = (uint)(value6?.GetHashCode() ?? 0); + uint hc7 = (uint)(value7?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + uint hash = MixState(v1, v2, v3, v4); + hash += 28; + + hash = QueueRound(hash, hc5); + hash = QueueRound(hash, hc6); + hash = QueueRound(hash, hc7); + + hash = MixFinal(hash); + return (int)hash; + } + + public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8) + { + uint hc1 = (uint)(value1?.GetHashCode() ?? 0); + uint hc2 = (uint)(value2?.GetHashCode() ?? 0); + uint hc3 = (uint)(value3?.GetHashCode() ?? 0); + uint hc4 = (uint)(value4?.GetHashCode() ?? 0); + uint hc5 = (uint)(value5?.GetHashCode() ?? 0); + uint hc6 = (uint)(value6?.GetHashCode() ?? 0); + uint hc7 = (uint)(value7?.GetHashCode() ?? 0); + uint hc8 = (uint)(value8?.GetHashCode() ?? 0); + + Initialize(out uint v1, out uint v2, out uint v3, out uint v4); + + v1 = Round(v1, hc1); + v2 = Round(v2, hc2); + v3 = Round(v3, hc3); + v4 = Round(v4, hc4); + + v1 = Round(v1, hc5); + v2 = Round(v2, hc6); + v3 = Round(v3, hc7); + v4 = Round(v4, hc8); + + uint hash = MixState(v1, v2, v3, v4); + hash += 32; + + hash = MixFinal(hash); + return (int)hash; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4) + { + v1 = s_seed + Prime1 + Prime2; + v2 = s_seed + Prime2; + v3 = s_seed; + v4 = s_seed - Prime1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Round(uint hash, uint input) + { + return RotateLeft(hash + input * Prime2, 13) * Prime1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint QueueRound(uint hash, uint queuedValue) + { + return RotateLeft(hash + queuedValue * Prime3, 17) * Prime4; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint MixState(uint v1, uint v2, uint v3, uint v4) + { + return RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); + } + + private static uint MixEmptyState() + { + return s_seed + Prime5; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint MixFinal(uint hash) + { + hash ^= hash >> 15; + hash *= Prime2; + hash ^= hash >> 13; + hash *= Prime3; + hash ^= hash >> 16; + return hash; + } + + public void Add(T value) + { + Add(value?.GetHashCode() ?? 0); + } + + public void Add(T value, IEqualityComparer? comparer) + { + Add(value is null ? 0 : (comparer?.GetHashCode(value) ?? value.GetHashCode())); + } + + private void Add(int value) + { + // The original xxHash works as follows: + // 0. Initialize immediately. We can't do this in a struct (no + // default ctor). + // 1. Accumulate blocks of length 16 (4 uints) into 4 accumulators. + // 2. Accumulate remaining blocks of length 4 (1 uint) into the + // hash. + // 3. Accumulate remaining blocks of length 1 into the hash. + + // There is no need for #3 as this type only accepts ints. _queue1, + // _queue2 and _queue3 are basically a buffer so that when + // ToHashCode is called we can execute #2 correctly. + + // We need to initialize the xxHash32 state (_v1 to _v4) lazily (see + // #0) nd the last place that can be done if you look at the + // original code is just before the first block of 16 bytes is mixed + // in. The xxHash32 state is never used for streams containing fewer + // than 16 bytes. + + // To see what's really going on here, have a look at the Combine + // methods. + + uint val = (uint)value; + + // Storing the value of _length locally shaves of quite a few bytes + // in the resulting machine code. + uint previousLength = _length++; + uint position = previousLength % 4; + + // Switch can't be inlined. + + if (position == 0) + _queue1 = val; + else if (position == 1) + _queue2 = val; + else if (position == 2) + _queue3 = val; + else // position == 3 + { + if (previousLength == 3) + Initialize(out _v1, out _v2, out _v3, out _v4); + + _v1 = Round(_v1, _queue1); + _v2 = Round(_v2, _queue2); + _v3 = Round(_v3, _queue3); + _v4 = Round(_v4, val); + } + } + + public int ToHashCode() + { + // Storing the value of _length locally shaves of quite a few bytes + // in the resulting machine code. + uint length = _length; + + // position refers to the *next* queue position in this method, so + // position == 1 means that _queue1 is populated; _queue2 would have + // been populated on the next call to Add. + uint position = length % 4; + + // If the length is less than 4, _v1 to _v4 don't contain anything + // yet. xxHash32 treats this differently. + + uint hash = length < 4 ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4); + + // _length is incremented once per Add(Int32) and is therefore 4 + // times too small (xxHash length is in bytes, not ints). + + hash += length * 4; + + // Mix what remains in the queue + + // Switch can't be inlined right now, so use as few branches as + // possible by manually excluding impossible scenarios (position > 1 + // is always false if position is not > 0). + if (position > 0) + { + hash = QueueRound(hash, _queue1); + if (position > 1) + { + hash = QueueRound(hash, _queue2); + if (position > 2) + hash = QueueRound(hash, _queue3); + } + } + + hash = MixFinal(hash); + return (int)hash; + } + +#pragma warning disable 0809 + // Obsolete member 'memberA' overrides non-obsolete member 'memberB'. + // Disallowing GetHashCode and Equals is by design + + // * We decided to not override GetHashCode() to produce the hash code + // as this would be weird, both naming-wise as well as from a + // behavioral standpoint (GetHashCode() should return the object's + // hash code, not the one being computed). + + // * Even though ToHashCode() can be called safely multiple times on + // this implementation, it is not part of the contract. If the + // implementation has to change in the future we don't want to worry + // about people who might have incorrectly used this type. + + [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", error: true)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => throw new NotSupportedException("Hash code not supported"); + + [Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object? obj) => throw new NotSupportedException("Equality not supported"); +#pragma warning restore 0809 + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint RotateLeft(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); +} \ No newline at end of file diff --git a/src/StronglyTypedIds/ParentClass.cs b/src/StronglyTypedIds/ParentClass.cs deleted file mode 100644 index 012c41274..000000000 --- a/src/StronglyTypedIds/ParentClass.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace StronglyTypedIds; - -internal class ParentClass -{ - public ParentClass(string keyword, string name, string constraints, ParentClass? child) - { - Keyword = keyword; - Name = name; - Constraints = constraints; - Child = child; - } - - public ParentClass? Child { get; } - public string Keyword { get; } - public string Name { get; } - public string Constraints { get; } -} \ No newline at end of file diff --git a/src/StronglyTypedIds/Parser.cs b/src/StronglyTypedIds/Parser.cs index 39fc96f93..2f4162f89 100644 --- a/src/StronglyTypedIds/Parser.cs +++ b/src/StronglyTypedIds/Parser.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; @@ -14,356 +13,294 @@ internal static class Parser public const string StronglyTypedIdAttribute = "StronglyTypedIds.StronglyTypedIdAttribute"; public const string StronglyTypedIdDefaultsAttribute = "StronglyTypedIds.StronglyTypedIdDefaultsAttribute"; - public static bool IsStructTargetForGeneration(SyntaxNode node) - => node is StructDeclarationSyntax m && m.AttributeLists.Count > 0; - - public static bool IsAttributeTargetForGeneration(SyntaxNode node) - => node is AttributeListSyntax attributeList - && attributeList.Target is not null - && attributeList.Target.Identifier.IsKind(SyntaxKind.AssemblyKeyword); - - public static StructDeclarationSyntax? GetStructSemanticTargetForGeneration(GeneratorSyntaxContext context) + public static Result<(StructToGenerate info, bool valid)> GetStructSemanticTarget(GeneratorAttributeSyntaxContext ctx, CancellationToken ct) { - // we know the node is a EnumDeclarationSyntax thanks to IsSyntaxTargetForGeneration - var structDeclarationSyntax = (StructDeclarationSyntax)context.Node; - - // loop through all the attributes on the method - foreach (AttributeListSyntax attributeListSyntax in structDeclarationSyntax.AttributeLists) + var structSymbol = ctx.TargetSymbol as INamedTypeSymbol; + if (structSymbol is null) { - foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) - { - if (ModelExtensions.GetSymbolInfo(context.SemanticModel, attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) - { - // weird, we couldn't get the symbol, ignore it - continue; - } - - INamedTypeSymbol attributeContainingTypeSymbol = attributeSymbol.ContainingType; - string fullName = attributeContainingTypeSymbol.ToDisplayString(); - - // Is the attribute the [StronglyTypedId] attribute? - if (fullName == StronglyTypedIdAttribute) - { - // return the enum - return structDeclarationSyntax; - } - } + return Result.Fail(); } - // we didn't find the attribute we were looking for - return null; - } + var structSyntax = (StructDeclarationSyntax)ctx.TargetNode; - public static AttributeSyntax? GetAssemblyAttributeSemanticTargetForGeneration(GeneratorSyntaxContext context) - { - // we know the node is a AttributeListSyntax thanks to IsSyntaxTargetForGeneration - var attributeListSyntax = (AttributeListSyntax)context.Node; + var hasMisconfiguredInput = false; + List? diagnostics = null; + Template? template = null; + string[]? templateNames = null; + LocationInfo? attributeLocation = null; - // loop through all the attributes in the list - foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) + foreach (AttributeData attribute in structSymbol.GetAttributes()) { - if (ModelExtensions.GetSymbolInfo(context.SemanticModel, attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) + if (!((attribute.AttributeClass?.Name == "StronglyTypedIdAttribute" || + attribute.AttributeClass?.Name == "StronglyTypedId") && + attribute.AttributeClass.ToDisplayString() == StronglyTypedIdAttribute)) { - // weird, we couldn't get the symbol, ignore it + // wrong attribute continue; } - INamedTypeSymbol attributeContainingTypeSymbol = attributeSymbol.ContainingType; - string fullName = attributeContainingTypeSymbol.ToDisplayString(); + (var result, (template, templateNames)) = GetConstructorValues(attribute); + hasMisconfiguredInput |= result; - // Is the attribute the [StronglyTypedIdDefaultsAttribute] attribute? - if (fullName == StronglyTypedIdDefaultsAttribute) + if (attribute.ApplicationSyntaxReference?.GetSyntax() is { } s) { - // return the attribute - return attributeSyntax; + attributeLocation = LocationInfo.CreateFrom(s); } } - // we didn't find the attribute we were looking for - return null; - } - - public static List<(string Name, string NameSpace, StronglyTypedIdConfiguration Config, ParentClass? Parent)> GetTypesToGenerate( - Compilation compilation, - ImmutableArray targets, - Action reportDiagnostic, - CancellationToken ct) - { - var idsToGenerate = new List<(string Name, string NameSpace, StronglyTypedIdConfiguration Config, ParentClass? Parent)>(); - INamedTypeSymbol? idAttribute = compilation.GetTypeByMetadataName(StronglyTypedIdAttribute); - if (idAttribute == null) + var hasPartialModifier = false; + foreach (var modifier in structSyntax.Modifiers) { - // nothing to do if this type isn't available - return idsToGenerate; - } - - foreach (StructDeclarationSyntax structDeclarationSyntax in targets) - { - // stop if we're asked to - ct.ThrowIfCancellationRequested(); - - SemanticModel semanticModel = compilation.GetSemanticModel(structDeclarationSyntax.SyntaxTree); - if (semanticModel.GetDeclaredSymbol(structDeclarationSyntax) is not INamedTypeSymbol structSymbol) + if (modifier.IsKind(SyntaxKind.PartialKeyword)) { - // something went wrong - continue; + hasPartialModifier = true; + break; } + } - StronglyTypedIdConfiguration? config = null; - var hasMisconfiguredInput = false; - - foreach (AttributeData attribute in structSymbol.GetAttributes()) - { - if (!idAttribute.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default)) - { - continue; - } - - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default; - StronglyTypedIdConverter converter = StronglyTypedIdConverter.Default; - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default; - - if (!attribute.ConstructorArguments.IsEmpty) - { - // make sure we don't have any errors - ImmutableArray args = attribute.ConstructorArguments; - - foreach (TypedConstant arg in args) - { - if (arg.Kind == TypedConstantKind.Error) - { - // have an error, so don't try and do any generation - hasMisconfiguredInput = true; - } - } - - switch (args.Length) - { - case 3: - implementations = (StronglyTypedIdImplementations)args[2].Value!; - goto case 2; - case 2: - converter = (StronglyTypedIdConverter)args[1].Value!; - goto case 1; - case 1: - backingType = (StronglyTypedIdBackingType)args[0].Value!; - break; - } - } - - if (!attribute.NamedArguments.IsEmpty) - { - foreach (KeyValuePair arg in attribute.NamedArguments) - { - TypedConstant typedConstant = arg.Value; - if (typedConstant.Kind == TypedConstantKind.Error) - { - hasMisconfiguredInput = true; - } - else - { - switch (arg.Key) - { - case "backingType": - backingType = (StronglyTypedIdBackingType)typedConstant.Value!; - break; - case "converters": - converter = (StronglyTypedIdConverter)typedConstant.Value!; - break; - case "implementations": - implementations = (StronglyTypedIdImplementations)typedConstant.Value!; - break; - } - } - } + if (!hasPartialModifier) + { + diagnostics ??= new(); + diagnostics.Add(NotPartialDiagnostic.CreateInfo(structSyntax)); + } + var errors = diagnostics is null + ? EquatableArray.Empty + : new EquatableArray(diagnostics.ToArray()); - } + if (hasMisconfiguredInput) + { + return new Result<(StructToGenerate, bool)>((default, false), errors); + } - if (hasMisconfiguredInput) - { - // skip further generator execution and let compiler generate the errors - break; - } + string nameSpace = GetNameSpace(structSyntax); + ParentClass? parentClass = GetParentClasses(structSyntax); + var name = structSymbol.Name; - if (!converter.IsValidFlags()) - { - reportDiagnostic(InvalidConverterDiagnostic.Create(structDeclarationSyntax)); - } + var toGenerate =new StructToGenerate( + name: name, + nameSpace: nameSpace, + template: template, + templateNames: templateNames, + templateLocation: attributeLocation!, + parent: parentClass); - if (!Enum.IsDefined(typeof(StronglyTypedIdBackingType), backingType)) - { - reportDiagnostic(InvalidBackingTypeDiagnostic.Create(structDeclarationSyntax)); - } + return new Result<(StructToGenerate, bool)>((toGenerate, true), errors); + } - if (!implementations.IsValidFlags()) - { - reportDiagnostic(InvalidImplementationsDiagnostic.Create(structDeclarationSyntax)); - } + public static Result<(Defaults defaults, bool valid)> GetDefaults( + GeneratorAttributeSyntaxContext ctx, CancellationToken ct) + { + var assemblyAttributes = ctx.TargetSymbol.GetAttributes(); + if (assemblyAttributes.IsDefaultOrEmpty) + { + return Result.Fail(); + } - config = new StronglyTypedIdConfiguration(backingType, converter, implementations); - break; - } + // We only return the first config that we find + string[]? templateNames = null; + Template? template = null; + LocationInfo? attributeLocation = null; + List? diagnostics = null; + bool hasMisconfiguredInput = false; + bool hasMultiple = false; - if (config is null || hasMisconfiguredInput) + // if we have multiple attributes we still check them, so that we can add extra diagnostics if necessary + // the "first" one found won't be flagged as a duplicate though. + foreach (AttributeData attribute in assemblyAttributes) + { + if (!((attribute.AttributeClass?.Name == "StronglyTypedIdDefaultsAttribute" || + attribute.AttributeClass?.Name == "StronglyTypedIdDefaults") && + attribute.AttributeClass.ToDisplayString() == StronglyTypedIdDefaultsAttribute)) { - continue; // name clash, or error + // wrong attribute + continue; } - var hasPartialModifier = false; - foreach (var modifier in structDeclarationSyntax.Modifiers) + var syntax = attribute.ApplicationSyntaxReference?.GetSyntax(); + if (templateNames is not null || template.HasValue || hasMisconfiguredInput) { - if (modifier.IsKind(SyntaxKind.PartialKeyword)) + hasMultiple = true; + if (syntax is not null) { - hasPartialModifier = true; - break; + diagnostics ??= new(); + diagnostics.Add(MultipleAssemblyAttributeDiagnostic.CreateInfo(syntax)); } } - if (!hasPartialModifier) + (var result, (template, templateNames)) = GetConstructorValues(attribute); + hasMisconfiguredInput |= result; + + if (syntax is not null) { - reportDiagnostic(NotPartialDiagnostic.Create(structDeclarationSyntax)); + attributeLocation = LocationInfo.CreateFrom(syntax); } + } - string nameSpace = GetNameSpace(structDeclarationSyntax); - var parentClass = GetParentClasses(structDeclarationSyntax); - var name = structSymbol.Name; + var errors = diagnostics is null + ? EquatableArray.Empty + : new EquatableArray(diagnostics.ToArray()); - idsToGenerate.Add((Name: name, NameSpace: nameSpace, Config: config.Value, Parent: parentClass)); + if (hasMisconfiguredInput) + { + return new Result<(Defaults, bool)>((default, false), errors); } - return idsToGenerate; + var defaults = new Defaults(template, templateNames, attributeLocation!, hasMultiple); + + return new Result<(Defaults, bool)>((defaults, true), errors); } - public static StronglyTypedIdConfiguration? GetDefaults( - ImmutableArray defaults, - Compilation compilation, - Action reportDiagnostic) + private static (bool HasMisconfiguredInput, (Template? Template, string[]? TemplateNames)) GetConstructorValues(AttributeData attribute) { - if (defaults.IsDefaultOrEmpty) - { - // No global defaults - return null; - } + (Template? Template, string? Name, string[]? Names)? results1 = null; + (Template? Template, string? Name, string[]? Names)? results2 = null; - var assemblyAttributes = compilation.Assembly.GetAttributes(); - if (assemblyAttributes.IsDefaultOrEmpty) + if (attribute.ConstructorArguments is { IsEmpty: false } args) { - return null; - } + // we should have at most 2 args (params count as one arg) + if (args.Length > 2) + { + // have an error, so don't try and do any generation + return (true, default); + } - INamedTypeSymbol? defaultsAttribute = compilation.GetTypeByMetadataName(StronglyTypedIdDefaultsAttribute); - if (defaultsAttribute is null) - { - // The attribute isn't part of the compilation for some reason... - return null; - } + // Should always have at least one arg, but it might be an empty array + var (success, results) = TryGetTypedConstant(args[0]); - foreach (AttributeData attribute in assemblyAttributes) - { - if (!defaultsAttribute.Equals(attribute.AttributeClass, SymbolEqualityComparer.Default)) + if (success) { - continue; + results1 = results; + } + else + { + // have an error, so don't try and do any generation + return (true, default); } - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default; - StronglyTypedIdConverter converter = StronglyTypedIdConverter.Default; - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default; - bool hasMisconfiguredInput = false; - - if (!attribute.ConstructorArguments.IsEmpty) + if (args.Length == 2) { - // make sure we don't have any errors - ImmutableArray args = attribute.ConstructorArguments; + (success, results) = TryGetTypedConstant(args[1]); - foreach (TypedConstant arg in args) + if (success) { - if (arg.Kind == TypedConstantKind.Error) - { - // have an error, so don't try and do any generation - hasMisconfiguredInput = true; - } + results2 = results; } - - switch (args.Length) + else { - case 3: - implementations = (StronglyTypedIdImplementations)args[2].Value!; - goto case 2; - case 2: - converter = (StronglyTypedIdConverter)args[1].Value!; - goto case 1; - case 1: - backingType = (StronglyTypedIdBackingType)args[0].Value!; - break; + // have an error, so don't try and do any generation + return (true, default); } } - - if (!attribute.NamedArguments.IsEmpty) + } + + if (attribute.NamedArguments is { IsEmpty: false } namedArgs) + { + foreach (KeyValuePair arg in namedArgs) { - foreach (KeyValuePair arg in attribute.NamedArguments) + // Should always have at least one arg, but it might be an empty array + var (success, results) = TryGetTypedConstant(arg.Value); + + if (success) { - TypedConstant typedConstant = arg.Value; - if (typedConstant.Kind == TypedConstantKind.Error) + if (results1 is null) + { + results1 = results; + } + else if(results2 is null) { - hasMisconfiguredInput = true; + results2 = results; } else { - switch (arg.Key) - { - case "backingType": - backingType = (StronglyTypedIdBackingType)typedConstant.Value!; - break; - case "converters": - converter = (StronglyTypedIdConverter)typedConstant.Value!; - break; - case "implementations": - implementations = (StronglyTypedIdImplementations)typedConstant.Value!; - break; - } + // must be an error + return (true, default); } } + else + { + // have an error, so don't try and do any generation + return (true, default); + } + } + } + + + // consolidate + var template = results1?.Template ?? results2?.Template; + var name = results1?.Name ?? results2?.Name; + var names = results1?.Names ?? results2?.Names; + + if (name is not null) + { + if (names is {Length: > 0} ns) + { + names = new string[ns.Length + 1]; + ns.CopyTo(names, 0); + names[^1] = name; + } + else + { + names = new[] {name}; } + } + + return (false, (template, names)); - if (hasMisconfiguredInput) + static (bool IsValid, (Template? Template, string? Name, string[]? Names)) TryGetTypedConstant(in TypedConstant arg) + { + if (arg.Kind is TypedConstantKind.Error) { - // skip further generator execution and let compiler generate the errors - break; + return (false, default); } - SyntaxNode? syntax = null; - if (!converter.IsValidFlags()) + if (arg.Kind is TypedConstantKind.Primitive + && arg.Value is string stringValue) { - syntax = attribute.ApplicationSyntaxReference?.GetSyntax(); - if (syntax is not null) - { - reportDiagnostic(InvalidConverterDiagnostic.Create(syntax)); - } + var name = string.IsNullOrWhiteSpace(stringValue) + ? string.Empty + : stringValue; + + return (true, (null, name, null)); } - if (!Enum.IsDefined(typeof(StronglyTypedIdBackingType), backingType)) + if (arg.Kind is TypedConstantKind.Enum + && arg.Value is int intValue) { - syntax ??= attribute.ApplicationSyntaxReference?.GetSyntax(); - if (syntax is not null) - { - reportDiagnostic(InvalidBackingTypeDiagnostic.Create(syntax)); - } + return (true, ((Template) intValue, null, null)); } - if (!implementations.IsValidFlags()) + if (arg.Kind is TypedConstantKind.Array) { - syntax ??= attribute.ApplicationSyntaxReference?.GetSyntax(); - if (syntax is not null) + var values = arg.Values; + + // if null is passed, it's treated the same as an empty array + if (values.IsDefaultOrEmpty) + { + return (true, (null, null, Array.Empty())); + } + + var names = new string[values.Length]; + for (var i = 0; i < values.Length; i++) { - reportDiagnostic(InvalidImplementationsDiagnostic.Create(syntax)); + if (values[i].Kind == TypedConstantKind.Error) + { + // Abandon generation + return (false, default); + } + + var value = values[i].Value as string; + names[i] = string.IsNullOrWhiteSpace(value) + ? string.Empty + : value!; } + + return (true, (null, null, names)); } - return new StronglyTypedIdConfiguration(backingType, converter, implementations); + // Some other type, weird, shouldn't be able to get this + return (false, default); } - - return null; } private static string GetNameSpace(StructDeclarationSyntax structSymbol) @@ -403,11 +340,22 @@ potentialNamespaceParent is not NamespaceDeclarationSyntax while (parentIdClass != null && IsAllowedKind(parentIdClass.Kind())) { + var keyword = parentIdClass is RecordDeclarationSyntax record + ? record.ClassOrStructKeyword.Kind() switch + { + SyntaxKind.StructKeyword => "record struct", + SyntaxKind.ClassKeyword => "record class", + _ => "record", + } + : parentIdClass.Keyword.ValueText; + parentClass = new ParentClass( - keyword: parentIdClass.Keyword.ValueText, - name: parentIdClass.Identifier.ToString() + parentIdClass.TypeParameterList, - constraints: parentIdClass.ConstraintClauses.ToString(), - child: parentClass); + Modifiers: parentIdClass.Modifiers.ToString(), + Keyword: keyword, + Name: parentIdClass.Identifier.ToString() + parentIdClass.TypeParameterList, + Constraints: parentIdClass.ConstraintClauses.ToString(), + Child: parentClass, + IsGeneric: parentIdClass.Arity > 0); parentIdClass = (parentIdClass.Parent as TypeDeclarationSyntax); } @@ -417,6 +365,7 @@ potentialNamespaceParent is not NamespaceDeclarationSyntax static bool IsAllowedKind(SyntaxKind kind) => kind == SyntaxKind.ClassDeclaration || kind == SyntaxKind.StructDeclaration || + kind == SyntaxKind.RecordStructDeclaration || kind == SyntaxKind.RecordDeclaration; } } \ No newline at end of file diff --git a/src/StronglyTypedIds/SourceGenerationHelper.cs b/src/StronglyTypedIds/SourceGenerationHelper.cs index e33515310..af784f95a 100644 --- a/src/StronglyTypedIds/SourceGenerationHelper.cs +++ b/src/StronglyTypedIds/SourceGenerationHelper.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Text; namespace StronglyTypedIds @@ -10,41 +9,8 @@ public static string CreateId( string idNamespace, string idName, ParentClass? parentClass, - StronglyTypedIdConverter converters, - StronglyTypedIdBackingType backingType, - StronglyTypedIdImplementations implementations) - => CreateId(idNamespace, idName, parentClass, converters, backingType, implementations, null); - - public static string CreateId( - string idNamespace, - string idName, - ParentClass? parentClass, - StronglyTypedIdConverter converters, - StronglyTypedIdBackingType backingType, - StronglyTypedIdImplementations implementations, - StringBuilder? sb) - { - var resources = backingType switch - { - StronglyTypedIdBackingType.Guid => EmbeddedSources.GuidResources, - StronglyTypedIdBackingType.Int => EmbeddedSources.IntResources, - StronglyTypedIdBackingType.Long => EmbeddedSources.LongResources, - StronglyTypedIdBackingType.String => EmbeddedSources.StringResources, - StronglyTypedIdBackingType.NullableString => EmbeddedSources.NullableStringResources, - StronglyTypedIdBackingType.MassTransitNewId => EmbeddedSources.NewIdResources, - _ => throw new ArgumentException("Unknown backing type: " + backingType, nameof(backingType)), - }; - - return CreateId(idNamespace, idName, parentClass, converters, implementations, resources, sb); - } - - static string CreateId( - string idNamespace, - string idName, - ParentClass? parentClass, - StronglyTypedIdConverter converters, - StronglyTypedIdImplementations implementations, - EmbeddedSources.ResourceCollection resources, + string template, + bool addDefaultAttributes, StringBuilder? sb) { if (string.IsNullOrEmpty(idName)) @@ -52,36 +18,20 @@ static string CreateId( throw new ArgumentException("Value cannot be null or empty.", nameof(idName)); } - if (converters == StronglyTypedIdConverter.Default) - { - throw new ArgumentException("Cannot use default converter - must provide concrete values or None", nameof(converters)); - } - - if (implementations == StronglyTypedIdImplementations.Default) - { - throw new ArgumentException("Cannot use default implementations - must provide concrete values or None", nameof(implementations)); - } - var hasNamespace = !string.IsNullOrEmpty(idNamespace); - var useTypeConverter = converters.IsSet(StronglyTypedIdConverter.TypeConverter); - var useNewtonsoftJson = converters.IsSet(StronglyTypedIdConverter.NewtonsoftJson); - var useSystemTextJson = converters.IsSet(StronglyTypedIdConverter.SystemTextJson); - var useEfCoreValueConverter = converters.IsSet(StronglyTypedIdConverter.EfCoreValueConverter); - var useDapperTypeHandler = converters.IsSet(StronglyTypedIdConverter.DapperTypeHandler); - - var useIEquatable = implementations.IsSet(StronglyTypedIdImplementations.IEquatable); - var useIComparable = implementations.IsSet(StronglyTypedIdImplementations.IComparable); - var parentsCount = 0; - sb ??= new StringBuilder(); - sb.Append(resources.Header); - - if (resources.NullableEnable) + if (sb is null) { - sb.AppendLine("#nullable enable"); + sb = new StringBuilder(); } + else + { + sb.Clear(); + } + + sb.Append(EmbeddedSources.AutoGeneratedHeader); if (hasNamespace) { @@ -92,73 +42,43 @@ static string CreateId( {"); } - while (parentClass is not null) + var hasGenericParent = false; + while (parentClass is { } parent) { + sb.Append(" "); + + if (!string.IsNullOrEmpty(parent.Modifiers)) + { + sb.Append(parent.Modifiers).Append(' '); + } + + if (parent.Modifiers.IndexOf("partial", StringComparison.Ordinal) == -1) + { + sb.Append("partial "); + } + sb - .Append(" partial ") - .Append(parentClass.Keyword) + .Append(parent.Keyword) .Append(' ') - .Append(parentClass.Name) + .Append(parent.Name) .Append(' ') - .Append(parentClass.Constraints) + .Append(parent.Constraints) .AppendLine(@" {"); parentsCount++; - parentClass = parentClass.Child; + hasGenericParent |= parent.IsGeneric; + parentClass = parent.Child; } - - if (useNewtonsoftJson) + + if (addDefaultAttributes && !hasGenericParent) { - sb.AppendLine(EmbeddedSources.NewtonsoftJsonAttributeSource); + sb.AppendLine(" [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))]"); + sb.AppendLine(" [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))]"); } - if (useSystemTextJson) - { - sb.AppendLine(EmbeddedSources.SystemTextJsonAttributeSource); - } + sb.AppendLine(template); - if (useTypeConverter) - { - sb.AppendLine(EmbeddedSources.TypeConverterAttributeSource); - } - - sb.Append(resources.BaseId); - ReplaceInterfaces(sb, useIEquatable, useIComparable); - - // IEquatable is already implemented whether or not the interface is implemented - - if (useIComparable) - { - sb.AppendLine(resources.Comparable); - } - - if (useEfCoreValueConverter) - { - sb.AppendLine(resources.EfCoreValueConverter); - } - - if (useDapperTypeHandler) - { - sb.AppendLine(resources.DapperTypeHandler); - } - - if (useTypeConverter) - { - sb.AppendLine(resources.TypeConverter); - } - - if (useNewtonsoftJson) - { - sb.AppendLine(resources.Newtonsoft); - } - - if (useSystemTextJson) - { - sb.AppendLine(resources.SystemTextJson); - } - - sb.Replace("TESTID", idName); - sb.AppendLine(@" }"); + sb.Replace("PLACEHOLDERID", idName); for (int i = 0; i < parentsCount; i++) { @@ -173,44 +93,28 @@ static string CreateId( return sb.ToString(); } - private static void ReplaceInterfaces(StringBuilder sb, bool useIEquatable, bool useIComparable) + internal static string CreateSourceName(StringBuilder sb, string nameSpace, ParentClass? parent, string name, string template) { - var interfaces = new List(); - - if (useIComparable) - { - interfaces.Add("System.IComparable"); - } - - if (useIEquatable) - { - interfaces.Add("System.IEquatable"); - } - - if (interfaces.Count > 0) - { - sb.Replace("INTERFACES", string.Join(", ", interfaces)); - } - else + sb.Clear(); + sb.Append(nameSpace).Append('.'); + while (parent is { } p) { - sb.Replace(": INTERFACES", string.Empty); - } - } - - internal static string CreateSourceName(string nameSpace, ParentClass? parent, string name) - { - var sb = new StringBuilder(nameSpace).Append('.'); - while (parent != null) - { - var s = parent.Name + var s = p.Name .Replace(" ", "") .Replace(",", "") .Replace("<", "__") .Replace(">", ""); sb.Append(s).Append('.'); - parent = parent.Child; + parent = p.Child; + } + + sb.Append(name); + if (!string.IsNullOrEmpty(template)) + { + sb.Append('.').Append(template); } - return sb.Append(name).Append(".g.cs").ToString(); + + return sb.Append(".g.cs").ToString(); } } } diff --git a/src/StronglyTypedIds/StronglyTypedIdConfiguration.cs b/src/StronglyTypedIds/StronglyTypedIdConfiguration.cs deleted file mode 100644 index 0c4860cd2..000000000 --- a/src/StronglyTypedIds/StronglyTypedIdConfiguration.cs +++ /dev/null @@ -1,68 +0,0 @@ - -namespace StronglyTypedIds -{ - internal readonly struct StronglyTypedIdConfiguration - { - public StronglyTypedIdBackingType BackingType { get; } - - public StronglyTypedIdConverter Converters { get; } - - public StronglyTypedIdImplementations Implementations { get; } - - public StronglyTypedIdConfiguration( - StronglyTypedIdBackingType backingType, - StronglyTypedIdConverter converters, - StronglyTypedIdImplementations implementations) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// Gets the default values for when a default attribute is not used. - /// Should be kept in sync with the default values referenced in - /// and , but should always be "definite" values (not "Default") - /// - public static readonly StronglyTypedIdConfiguration Defaults = new( - backingType: StronglyTypedIdBackingType.Guid, - converters: StronglyTypedIdConverter.TypeConverter | StronglyTypedIdConverter.NewtonsoftJson, - implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable); - - /// - /// Combines multiple values associated - /// with a given , returning definite values. - /// - /// - public static StronglyTypedIdConfiguration Combine( - StronglyTypedIdConfiguration attributeValues, - StronglyTypedIdConfiguration? globalValues) - { - var backingType = (attributeValues.BackingType, globalValues?.BackingType) switch - { - (StronglyTypedIdBackingType.Default, null) => Defaults.BackingType, - (StronglyTypedIdBackingType.Default, StronglyTypedIdBackingType.Default) => Defaults.BackingType, - (StronglyTypedIdBackingType.Default, var globalDefault) => globalDefault.Value, - (var specificValue, _) => specificValue - }; - - var converter = (attributeValues.Converters, globalValues?.Converters) switch - { - (StronglyTypedIdConverter.Default, null) => Defaults.Converters, - (StronglyTypedIdConverter.Default, StronglyTypedIdConverter.Default) => Defaults.Converters, - (StronglyTypedIdConverter.Default, var globalDefault) => globalDefault.Value, - (var specificValue, _) => specificValue - }; - - var implementations = (attributeValues.Implementations, globalValues?.Implementations) switch - { - (StronglyTypedIdImplementations.Default, null) => Defaults.Implementations, - (StronglyTypedIdImplementations.Default, StronglyTypedIdImplementations.Default) => Defaults.Implementations, - (StronglyTypedIdImplementations.Default, var globalDefault) => globalDefault.Value, - (var specificValue, _) => specificValue - }; - - return new StronglyTypedIdConfiguration(backingType, converter, implementations); - } - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds/StronglyTypedIdConverterExtensions.cs b/src/StronglyTypedIds/StronglyTypedIdConverterExtensions.cs deleted file mode 100644 index 63d4174b2..000000000 --- a/src/StronglyTypedIds/StronglyTypedIdConverterExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Linq; - -namespace StronglyTypedIds -{ - internal static class StronglyTypedIdConverterExtensions - { - private static readonly int _maxConverterId = Enum.GetValues(typeof(StronglyTypedIdConverter)).Cast().Max() * 2; - private static readonly int _maxImplementationsId = Enum.GetValues(typeof(StronglyTypedIdImplementations)).Cast().Max() * 2; - - public static bool IsSet(this StronglyTypedIdConverter value, StronglyTypedIdConverter flag) - => (value & flag) == flag; - - public static bool IsValidFlags(this StronglyTypedIdConverter value) - { - return (int)value >= 0 && (int)value < _maxConverterId; - } - - public static bool IsSet(this StronglyTypedIdImplementations value, StronglyTypedIdImplementations flag) - => (value & flag) == flag; - - public static bool IsValidFlags(this StronglyTypedIdImplementations value) - { - return (int)value >= 0 && (int)value < _maxImplementationsId; - } - } -} \ No newline at end of file diff --git a/src/StronglyTypedIds/StronglyTypedIdGenerator.cs b/src/StronglyTypedIds/StronglyTypedIdGenerator.cs index 6a299ad78..4bb290537 100644 --- a/src/StronglyTypedIds/StronglyTypedIdGenerator.cs +++ b/src/StronglyTypedIds/StronglyTypedIdGenerator.cs @@ -1,9 +1,14 @@ -using System.Collections.Generic; +using System; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; using System.Text; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; +using StronglyTypedIds.Diagnostics; namespace StronglyTypedIds { @@ -11,6 +16,8 @@ namespace StronglyTypedIds [Generator] public class StronglyTypedIdGenerator : IIncrementalGenerator { + const string TemplateSuffix = ".typedid"; + /// public void Initialize(IncrementalGeneratorInitializationContext context) { @@ -19,71 +26,284 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { i.AddSource("StronglyTypedIdAttribute.g.cs", EmbeddedSources.StronglyTypedIdAttributeSource); i.AddSource("StronglyTypedIdDefaultsAttribute.g.cs", EmbeddedSources.StronglyTypedIdDefaultsAttributeSource); - i.AddSource("StronglyTypedIdBackingType.g.cs", EmbeddedSources.StronglyTypedIdBackingTypeSource); - i.AddSource("StronglyTypedIdConverter.g.cs", EmbeddedSources.StronglyTypedIdConverterSource); - i.AddSource("StronglyTypedIdImplementations.g.cs", EmbeddedSources.StronglyTypedIdImplementationsSource); + i.AddSource("Template.g.cs", EmbeddedSources.TemplateSource); }); - IncrementalValuesProvider structDeclarations = context.SyntaxProvider - .CreateSyntaxProvider( - predicate: static (s, _) => Parser.IsStructTargetForGeneration(s), - transform: static (ctx, _) => Parser.GetStructSemanticTargetForGeneration(ctx)) - .Where(static m => m is not null)!; + IncrementalValuesProvider<(string Path, string Name, string? Content)> allTemplates = context.AdditionalTextsProvider + .Where(template => Path.GetExtension(template.Path).Equals(TemplateSuffix, StringComparison.OrdinalIgnoreCase)) + .Select((template, ct) => ( + Path: template.Path, + Name: Path.GetFileNameWithoutExtension(template.Path), + Content: template.GetText(ct)?.ToString())); - IncrementalValuesProvider defaultAttributesDeclarations = context.SyntaxProvider - .CreateSyntaxProvider( - predicate: static (s, _) => Parser.IsAttributeTargetForGeneration(s), - transform: static (ctx, _) => Parser.GetAssemblyAttributeSemanticTargetForGeneration(ctx)) - .Where(static m => m is not null)!; + var templates = allTemplates + .Where(template => !string.IsNullOrWhiteSpace(template.Name) && template.Content is not null) + .Collect(); + + IncrementalValuesProvider> structAndDiagnostics = context.SyntaxProvider + .ForAttributeWithMetadataName( + Parser.StronglyTypedIdAttribute, + predicate: (node, _) => node is StructDeclarationSyntax, + transform: Parser.GetStructSemanticTarget) + .Where(static m => m is not null); - IncrementalValueProvider<(ImmutableArray, ImmutableArray)> targetsAndDefaultAttributes - = structDeclarations.Collect().Combine(defaultAttributesDeclarations.Collect()); + IncrementalValuesProvider> defaultsAndDiagnostics = context.SyntaxProvider + .ForAttributeWithMetadataName( + Parser.StronglyTypedIdDefaultsAttribute, + predicate: (node, _) => node is CompilationUnitSyntax, + transform: Parser.GetDefaults) + .Where(static m => m is not null); - IncrementalValueProvider<(Compilation Left, (ImmutableArray, ImmutableArray) Right)> compilationAndValues - = context.CompilationProvider.Combine(targetsAndDefaultAttributes); + context.RegisterSourceOutput( + structAndDiagnostics.SelectMany((x, _) => x.Errors), + static (context, info) => context.ReportDiagnostic(info)); - context.RegisterSourceOutput(compilationAndValues, - static (spc, source) => Execute(source.Item1, source.Item2.Item1, source.Item2.Item2, spc)); - } + context.RegisterSourceOutput( + defaultsAndDiagnostics.SelectMany((x, _) => x.Errors), + static (context, info) => context.ReportDiagnostic(info)); + + IncrementalValuesProvider structs = structAndDiagnostics + .Where(static x => x.Value.valid) + .Select((result, _) => result.Value.info); + + IncrementalValueProvider<(EquatableArray<(string Name, string Content)> Content, bool isValid, DiagnosticInfo? Diagnostic)> defaultTemplateContent = defaultsAndDiagnostics + .Where(static x => x.Value.valid) + .Select((result, _) => result.Value.defaults) + .Collect() + .Combine(templates) + .Select(ProcessDefaults); + + var structsWithDefaultsAndTemplates = structs + .Combine(templates) + .Combine(defaultTemplateContent); - static void Execute( - Compilation compilation, - ImmutableArray structs, - ImmutableArray defaults, + context.RegisterSourceOutput(structsWithDefaultsAndTemplates, + static (spc, source) => Execute(source.Left.Left, source.Left.Right, source.Right, spc)); + } + private static void Execute( + StructToGenerate idToGenerate, + ImmutableArray<(string Path, string Name, string? Content)> templates, + (EquatableArray<(string Name, string Content)>, bool IsValid, DiagnosticInfo? Diagnostic) defaults, SourceProductionContext context) { - if (structs.IsDefaultOrEmpty) + if (defaults.Diagnostic is { } diagnostic) + { + // report error with the default template + context.ReportDiagnostic(diagnostic); + } + + if (!TryGetTemplateContent(idToGenerate, templates, defaults, in context, out var templateContents)) { - // nothing to do yet return; } - List<(string Name, string NameSpace, StronglyTypedIdConfiguration Config, ParentClass? Parent)> idsToGenerate = - Parser.GetTypesToGenerate(compilation, structs, context.ReportDiagnostic, context.CancellationToken); + var sb = new StringBuilder(); + foreach (var (name, content) in templateContents.Distinct()) + { + var result = SourceGenerationHelper.CreateId( + idToGenerate.NameSpace, + idToGenerate.Name, + idToGenerate.Parent, + content, + addDefaultAttributes: string.IsNullOrEmpty(name), + sb); + + var fileName = SourceGenerationHelper.CreateSourceName( + sb, + idToGenerate.NameSpace, + idToGenerate.Parent, + idToGenerate.Name, + name); + + context.AddSource(fileName, SourceText.From(result, Encoding.UTF8)); + } + } + - if (idsToGenerate.Count > 0) + private static (EquatableArray<(string Name, string Content)>, bool, DiagnosticInfo?) ProcessDefaults((ImmutableArray Left, ImmutableArray<(string Path, string Name, string? Content)> Right) all, CancellationToken _) + { + if (all.Left.IsDefaultOrEmpty) { - StronglyTypedIdConfiguration? globalDefaults = Parser.GetDefaults(defaults, compilation, context.ReportDiagnostic); - StringBuilder sb = new StringBuilder(); - foreach (var idToGenerate in idsToGenerate) + // no default attributes, valid, but no content + return (EquatableArray<(string Name, string Content)>.Empty, true, null); + } + + // technically we can never have more than one `Defaults` here + // but check for it just in case + if (all.Left is {IsDefaultOrEmpty: false, Length: > 1}) + { + return (EquatableArray<(string Name, string Content)>.Empty, false, null); + } + + var defaults = all.Left[0]; + if (defaults.HasMultiple) + { + // not valid + return (EquatableArray<(string Name, string Content)>.Empty, false, null); + } + + (string, string)? builtInTemplate = null; + if (defaults.Template is { } templateId) + { + // Explicit template + builtInTemplate = (string.Empty, EmbeddedSources.GetTemplate(templateId)); + } + + var templateNames = defaults.TemplateNames.GetArray(); + if (templateNames is null or {Length: 0}) + { + if (builtInTemplate.HasValue) { - sb.Clear(); - var values = StronglyTypedIdConfiguration.Combine(idToGenerate.Config, globalDefaults); - var result = SourceGenerationHelper.CreateId( - idToGenerate.NameSpace, - idToGenerate.Name, - idToGenerate.Parent, - values.Converters, - values.BackingType, - values.Implementations, - sb); - var fileName = SourceGenerationHelper.CreateSourceName( - idToGenerate.NameSpace, - idToGenerate.Parent, - idToGenerate.Name); - context.AddSource(fileName, SourceText.From(result, Encoding.UTF8)); + // valid, only built-in + var template = new EquatableArray<(string Name, string Content)>(new[] {builtInTemplate.Value}); + return (template, true, (DiagnosticInfo?) null); } + + // not valid, need something + return (EquatableArray<(string Name, string Content)>.Empty, false, null); } + + // We have already checked for null/empty template name and flagged it as an error + if (!GetContent(templateNames, defaults.TemplateLocation!, builtInTemplate.HasValue, in all.Right, out var contents, out var diagnostic)) + { + return (EquatableArray<(string Name, string Content)>.Empty, false, diagnostic); + } + + if (builtInTemplate.HasValue) + { + contents[^1] = builtInTemplate.Value; + } + + // Ok, we have all the templates + return (new EquatableArray<(string Name, string Content)>(contents), true, null); + } + + private static bool TryGetTemplateContent( + in StructToGenerate idToGenerate, + in ImmutableArray<(string Path, string Name, string? Content)> templates, + (EquatableArray<(string Name, string Content)> Contents, bool IsValid, DiagnosticInfo? Diagnostics) defaults, + in SourceProductionContext context, + [NotNullWhen(true)] out (string Name, string Content)[]? templateContents) + { + (string, string)? builtIn = null; + if (idToGenerate.Template is { } templateId) + { + // built-in template specified + var content = EmbeddedSources.GetTemplate(templateId); + builtIn = (string.Empty, content); + } + + if (idToGenerate.TemplateNames.GetArray() is {Length: > 0} templateNames) + { + // custom template specified + if (GetContent( + templateNames, + idToGenerate.TemplateLocation, + builtIn.HasValue, + in templates, + out templateContents, + out var diagnostic)) + { + if (builtIn.HasValue) + { + templateContents[^1] = builtIn.Value; + } + + return true; + } + + // One of the templates wasn't found, so it must be invalid. Don't generate anything + if (diagnostic is { }) + { + context.ReportDiagnostic(diagnostic); + } + + templateContents = null; + return false; + } + + if (builtIn.HasValue) + { + templateContents = new[] {builtIn.Value}; + return true; + } + + // nothing specified, use the defaults (if we have them) + if (defaults.IsValid) + { + if (defaults.Contents.GetArray() is {Length: > 0} allContent) + { + templateContents = allContent; + } + else + { + templateContents = new[] {(string.Empty, EmbeddedSources.GetTemplate(Template.Guid))}; + } + + return true; + } + + // not valid + templateContents = null; + return false; + } + + private static string GetEmptyTemplateContent(string templateName) + => $"// The {templateName}.typeid template was empty, you'll need to add some content"; + + private static bool GetContent( + string[] templateNames, + LocationInfo? location, + bool haveStandardTemplate, + in ImmutableArray<(string Path, string Name, string? Content)> templates, + [NotNullWhen(true)] out (string Name, string Content)[]? output, + out DiagnosticInfo? diagnostic) + { + // Length + 1 to optionally add the extra template + var totalTemplates = haveStandardTemplate ? templateNames.Length + 1 : templateNames.Length; + (string, string)[]? contents = null; + for (int i = 0; i < templateNames.Length; i++) + { + var templateName = templateNames[i]; + if (string.IsNullOrEmpty(templateName)) + { + output = null; + diagnostic = location is not null + ? InvalidTemplateNameDiagnostic.CreateInfo(location) + : null; + return false; + } + + var foundTemplate = false; + + foreach (var templateDetails in templates) + { + if (string.Equals(templateDetails.Name, templateName, StringComparison.Ordinal)) + { + // This _could_ be empty, but we use it anyway (and add a comment in the template) + var content = templateDetails.Content ?? GetEmptyTemplateContent(templateName); + contents ??= new (string, string)[totalTemplates]; + contents[i] = (templateName, content); + foundTemplate = true; + break; + } + } + + if (!foundTemplate) + { + // Template name specified, but we don't have a template for it + // bail out early + output = null; + diagnostic = location is not null + ? UnknownTemplateDiagnostic.CreateInfo(location, templateName) + : null; + return false; + } + } + + output = contents!; // only case this wouldn't be true is if templateNames is empty + diagnostic = null; + return true; } } } \ No newline at end of file diff --git a/src/StronglyTypedIds/StronglyTypedIds.csproj b/src/StronglyTypedIds/StronglyTypedIds.csproj index 64f63c39f..a61535bd3 100644 --- a/src/StronglyTypedIds/StronglyTypedIds.csproj +++ b/src/StronglyTypedIds/StronglyTypedIds.csproj @@ -6,17 +6,28 @@ enable StronglyTypedId A source generator for creating strongly-typed IDs by decorating with a [StronglyTypedId] attribute + latest + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/src/StronglyTypedIds/StructToGenerate.cs b/src/StronglyTypedIds/StructToGenerate.cs new file mode 100644 index 000000000..2f2a666c7 --- /dev/null +++ b/src/StronglyTypedIds/StructToGenerate.cs @@ -0,0 +1,64 @@ +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +namespace StronglyTypedIds; + +internal readonly record struct StructToGenerate +{ + public StructToGenerate(string name, string nameSpace, Template? template, string[]? templateNames, ParentClass? parent, LocationInfo templateLocation) + { + Name = name; + NameSpace = nameSpace; + TemplateNames = templateNames is null ? EquatableArray.Empty : new EquatableArray(templateNames); + Template = template; + Parent = parent; + TemplateLocation = templateLocation; + } + + public string Name { get; } + public string NameSpace { get; } + public EquatableArray TemplateNames { get; } + public Template? Template { get; } + public ParentClass? Parent { get; } + public LocationInfo? TemplateLocation { get; } +} + +internal sealed record Result(TValue Value, EquatableArray Errors) + where TValue : IEquatable? +{ + public static Result<(TValue, bool)> Fail() + => new((default!, false), EquatableArray.Empty); +} + + +internal readonly record struct Defaults +{ + public Defaults(Template? template, string[]? templateNames, LocationInfo location, bool hasMultiple) + { + TemplateNames = templateNames is null ? EquatableArray.Empty : new EquatableArray(templateNames); + HasMultiple = hasMultiple; + Template = template; + TemplateLocation = location; + } + + public EquatableArray TemplateNames { get; } + public Template? Template { get; } + public LocationInfo? TemplateLocation { get; } + public bool HasMultiple { get; } +} + +internal record ParentClass(string Modifiers, string Keyword, string Name, string Constraints, ParentClass? Child, bool IsGeneric); + +internal record LocationInfo(string FilePath, TextSpan TextSpan, LinePositionSpan LineSpan) +{ + public Location ToLocation() + => Location.Create(FilePath, TextSpan, LineSpan); + + public static LocationInfo CreateFrom(SyntaxNode node) + { + var location = node.GetLocation(); + // assuming that source tree is always non-null here... hopefully that's the case + return new LocationInfo(location.SourceTree!.FilePath, location.SourceSpan, location.GetLineSpan().Span); + } +} \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs b/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs index 76952553c..b782f6438 100644 --- a/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs +++ b/src/StronglyTypedIds/Templates/AutoGeneratedHeader.cs @@ -9,3 +9,4 @@ #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_Base.cs b/src/StronglyTypedIds/Templates/Guid/Guid_Base.cs deleted file mode 100644 index 200147a15..000000000 --- a/src/StronglyTypedIds/Templates/Guid/Guid_Base.cs +++ /dev/null @@ -1,24 +0,0 @@ - readonly partial struct TESTID : INTERFACES - { - public System.Guid Value { get; } - - public TESTID(System.Guid value) - { - Value = value; - } - - public static TESTID New() => new TESTID(System.Guid.NewGuid()); - public static readonly TESTID Empty = new TESTID(System.Guid.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); diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/Guid/Guid_DapperTypeHandler.cs deleted file mode 100644 index 7d94a235e..000000000 --- a/src/StronglyTypedIds/Templates/Guid/Guid_DapperTypeHandler.cs +++ /dev/null @@ -1,18 +0,0 @@ - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value) - { - parameter.Value = value.Value; - } - - public override TESTID Parse(object value) - { - return value switch - { - System.Guid guidValue => new TESTID(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"), - }; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_EfCoreValueConverter.cs deleted file mode 100644 index 18e4d5d61..000000000 --- a/src/StronglyTypedIds/Templates/Guid/Guid_EfCoreValueConverter.cs +++ /dev/null @@ -1,11 +0,0 @@ - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new TESTID(value), - mappingHints - ) { } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_IComparable.cs b/src/StronglyTypedIds/Templates/Guid/Guid_IComparable.cs deleted file mode 100644 index e0696ee2a..000000000 --- a/src/StronglyTypedIds/Templates/Guid/Guid_IComparable.cs +++ /dev/null @@ -1 +0,0 @@ - public int CompareTo(TESTID other) => Value.CompareTo(other.Value); \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_NewtonsoftJsonConverter.cs deleted file mode 100644 index 9b96b63b2..000000000 --- a/src/StronglyTypedIds/Templates/Guid/Guid_NewtonsoftJsonConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ - - 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); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new TESTID(guid.Value) : null; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_SystemTextJsonConverter.cs deleted file mode 100644 index 4dc733db9..000000000 --- a/src/StronglyTypedIds/Templates/Guid/Guid_SystemTextJsonConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ - - class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new TESTID(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Guid/Guid_TypeConverter.cs b/src/StronglyTypedIds/Templates/Guid/Guid_TypeConverter.cs deleted file mode 100644 index 6ae7eb06b..000000000 --- a/src/StronglyTypedIds/Templates/Guid/Guid_TypeConverter.cs +++ /dev/null @@ -1,41 +0,0 @@ - - class TESTIDTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - System.Guid guidValue => new TESTID(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || 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(System.Guid)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Int/Int_Base.cs b/src/StronglyTypedIds/Templates/Int/Int_Base.cs deleted file mode 100644 index 08ce1fca6..000000000 --- a/src/StronglyTypedIds/Templates/Int/Int_Base.cs +++ /dev/null @@ -1,23 +0,0 @@ - readonly partial struct TESTID : INTERFACES - { - public int Value { get; } - - public TESTID(int value) - { - Value = value; - } - - public static readonly TESTID Empty = new TESTID(0); - - 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); diff --git a/src/StronglyTypedIds/Templates/Int/Int_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/Int/Int_DapperTypeHandler.cs deleted file mode 100644 index 8e3dc42c9..000000000 --- a/src/StronglyTypedIds/Templates/Int/Int_DapperTypeHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value) - { - parameter.Value = value.Value; - } - - public override TESTID Parse(object value) - { - return value switch - { - int intValue => new TESTID(intValue), - long longValue when longValue < int.MaxValue => new TESTID((int)longValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new TESTID(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"), - }; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Int/Int_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_EfCoreValueConverter.cs deleted file mode 100644 index 2245e6cf1..000000000 --- a/src/StronglyTypedIds/Templates/Int/Int_EfCoreValueConverter.cs +++ /dev/null @@ -1,11 +0,0 @@ - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new TESTID(value), - mappingHints - ) { } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Int/Int_IComparable.cs b/src/StronglyTypedIds/Templates/Int/Int_IComparable.cs deleted file mode 100644 index e0696ee2a..000000000 --- a/src/StronglyTypedIds/Templates/Int/Int_IComparable.cs +++ /dev/null @@ -1 +0,0 @@ - public int CompareTo(TESTID other) => Value.CompareTo(other.Value); \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Int/Int_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_NewtonsoftJsonConverter.cs deleted file mode 100644 index 56409d73b..000000000 --- a/src/StronglyTypedIds/Templates/Int/Int_NewtonsoftJsonConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ - - 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); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var result = serializer.Deserialize(reader); - return result.HasValue ? new TESTID(result.Value) : null; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Int/Int_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_SystemTextJsonConverter.cs deleted file mode 100644 index e388d1e8e..000000000 --- a/src/StronglyTypedIds/Templates/Int/Int_SystemTextJsonConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ - - class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new TESTID(reader.GetInt32()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteNumberValue(value.Value); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Int/Int_TypeConverter.cs b/src/StronglyTypedIds/Templates/Int/Int_TypeConverter.cs deleted file mode 100644 index 23cc26327..000000000 --- a/src/StronglyTypedIds/Templates/Int/Int_TypeConverter.cs +++ /dev/null @@ -1,41 +0,0 @@ - - class TESTIDTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - int intValue => new TESTID(intValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new TESTID(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(int) || 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(int)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Long/Long_Base.cs b/src/StronglyTypedIds/Templates/Long/Long_Base.cs deleted file mode 100644 index 38d9fc5a6..000000000 --- a/src/StronglyTypedIds/Templates/Long/Long_Base.cs +++ /dev/null @@ -1,23 +0,0 @@ - readonly partial struct TESTID : INTERFACES - { - public long Value { get; } - - public TESTID(long value) - { - Value = value; - } - - public static readonly TESTID Empty = new TESTID(0); - - 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); diff --git a/src/StronglyTypedIds/Templates/Long/Long_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/Long/Long_DapperTypeHandler.cs deleted file mode 100644 index 42dac85c9..000000000 --- a/src/StronglyTypedIds/Templates/Long/Long_DapperTypeHandler.cs +++ /dev/null @@ -1,20 +0,0 @@ - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value) - { - parameter.Value = value.Value; - } - - public override TESTID Parse(object value) - { - return value switch - { - long longValue => new TESTID(longValue), - int intValue => new TESTID(intValue), - short shortValue => new TESTID(shortValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new TESTID(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"), - }; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Long/Long_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_EfCoreValueConverter.cs deleted file mode 100644 index 96422f377..000000000 --- a/src/StronglyTypedIds/Templates/Long/Long_EfCoreValueConverter.cs +++ /dev/null @@ -1,11 +0,0 @@ - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new TESTID(value), - mappingHints - ) { } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Long/Long_IComparable.cs b/src/StronglyTypedIds/Templates/Long/Long_IComparable.cs deleted file mode 100644 index e0696ee2a..000000000 --- a/src/StronglyTypedIds/Templates/Long/Long_IComparable.cs +++ /dev/null @@ -1 +0,0 @@ - public int CompareTo(TESTID other) => Value.CompareTo(other.Value); \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Long/Long_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_NewtonsoftJsonConverter.cs deleted file mode 100644 index f1bcb6a98..000000000 --- a/src/StronglyTypedIds/Templates/Long/Long_NewtonsoftJsonConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ - - 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); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var result = serializer.Deserialize(reader); - return result.HasValue ? new TESTID(result.Value) : null; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Long/Long_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_SystemTextJsonConverter.cs deleted file mode 100644 index 5cf5825eb..000000000 --- a/src/StronglyTypedIds/Templates/Long/Long_SystemTextJsonConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ - - class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new TESTID(reader.GetInt64()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteNumberValue(value.Value); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/Long/Long_TypeConverter.cs b/src/StronglyTypedIds/Templates/Long/Long_TypeConverter.cs deleted file mode 100644 index 4785b648f..000000000 --- a/src/StronglyTypedIds/Templates/Long/Long_TypeConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ - - class TESTIDTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(long) || sourceType == typeof(int) || sourceType == typeof(short) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - long longValue => new TESTID(longValue), - int intValue => new TESTID(intValue), - short shortValue => new TESTID(shortValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new TESTID(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(long) || 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(long)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_Base.cs b/src/StronglyTypedIds/Templates/NewId/NewId_Base.cs deleted file mode 100644 index 854cd477a..000000000 --- a/src/StronglyTypedIds/Templates/NewId/NewId_Base.cs +++ /dev/null @@ -1,24 +0,0 @@ - readonly partial struct TESTID : INTERFACES - { - public MassTransit.NewId Value { get; } - - public TESTID(MassTransit.NewId value) - { - Value = value; - } - - public static TESTID New() => new TESTID(MassTransit.NewId.Next()); - public static readonly TESTID Empty = new TESTID(MassTransit.NewId.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); diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/NewId/NewId_DapperTypeHandler.cs deleted file mode 100644 index 8d4af7b02..000000000 --- a/src/StronglyTypedIds/Templates/NewId/NewId_DapperTypeHandler.cs +++ /dev/null @@ -1,18 +0,0 @@ - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value) - { - parameter.Value = value.Value.ToGuid(); - } - - public override TESTID Parse(object value) - { - return value switch - { - System.Guid guidValue => new TESTID(MassTransit.NewId.FromGuid(guidValue)), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(MassTransit.NewId.FromGuid(result)), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"), - }; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_EfCoreValueConverter.cs deleted file mode 100644 index 6b838a340..000000000 --- a/src/StronglyTypedIds/Templates/NewId/NewId_EfCoreValueConverter.cs +++ /dev/null @@ -1,11 +0,0 @@ - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value.ToGuid(), - value => new TESTID(MassTransit.NewId.FromGuid(value)), - mappingHints - ) { } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_IComparable.cs b/src/StronglyTypedIds/Templates/NewId/NewId_IComparable.cs deleted file mode 100644 index e0696ee2a..000000000 --- a/src/StronglyTypedIds/Templates/NewId/NewId_IComparable.cs +++ /dev/null @@ -1 +0,0 @@ - public int CompareTo(TESTID other) => Value.CompareTo(other.Value); \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_NewtonsoftJsonConverter.cs deleted file mode 100644 index f3e02dafc..000000000 --- a/src/StronglyTypedIds/Templates/NewId/NewId_NewtonsoftJsonConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ - - 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.ToGuid()); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new TESTID(MassTransit.NewId.FromGuid(guid.Value)) : null; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_SystemTextJsonConverter.cs deleted file mode 100644 index 082fef2ba..000000000 --- a/src/StronglyTypedIds/Templates/NewId/NewId_SystemTextJsonConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ - - class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new TESTID(MassTransit.NewId.FromGuid(reader.GetGuid())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value.ToGuid()); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NewId/NewId_TypeConverter.cs b/src/StronglyTypedIds/Templates/NewId/NewId_TypeConverter.cs deleted file mode 100644 index f923c90ab..000000000 --- a/src/StronglyTypedIds/Templates/NewId/NewId_TypeConverter.cs +++ /dev/null @@ -1,49 +0,0 @@ - - class TESTIDTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) || - sourceType == typeof(string) || base.CanConvertFrom - (context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - MassTransit.NewId newIdValue => new TESTID(newIdValue), - System.Guid guidValue => new TESTID(MassTransit.NewId.FromGuid(guidValue)), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new TESTID(MassTransit.NewId.FromGuid(result)), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) || 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(MassTransit.NewId)) - { - return idValue.Value; - } - - if (destinationType == typeof(System.Guid)) - { - return idValue.Value.ToGuid(); - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToGuid().ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_Base.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_Base.cs deleted file mode 100644 index 94a6eaffb..000000000 --- a/src/StronglyTypedIds/Templates/NullableString/NullableString_Base.cs +++ /dev/null @@ -1,31 +0,0 @@ - readonly partial struct TESTID : INTERFACES - { - public string? Value { get; } - - public TESTID(string? value) - { - Value = value; - } - - public static readonly TESTID Empty = new TESTID(string.Empty); - - public bool Equals(TESTID other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => 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() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(TESTID a, TESTID b) => a.Equals(b); - public static bool operator !=(TESTID a, TESTID b) => !(a == b); diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_DapperTypeHandler.cs deleted file mode 100644 index 1524a13b1..000000000 --- a/src/StronglyTypedIds/Templates/NullableString/NullableString_DapperTypeHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value) - { - parameter.Value = value.Value; - } - - public override TESTID Parse(object value) - { - return value switch - { - null => new TESTID(null), - System.DBNull => new TESTID(null), - string stringValue => new TESTID(stringValue), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"), - }; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_EfCoreValueConverter.cs deleted file mode 100644 index 443ad1aa0..000000000 --- a/src/StronglyTypedIds/Templates/NullableString/NullableString_EfCoreValueConverter.cs +++ /dev/null @@ -1,11 +0,0 @@ - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) - : base( - id => id.Value!, - value => new TESTID(value), - mappingHints - ) { } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_IComparable.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_IComparable.cs deleted file mode 100644 index 5cdc51ac9..000000000 --- a/src/StronglyTypedIds/Templates/NullableString/NullableString_IComparable.cs +++ /dev/null @@ -1,10 +0,0 @@ - public int CompareTo(TESTID other) - { - return (Value, other.Value) switch - { - (null, null) => 0, - (null, _) => -1, - (_, null) => 1, - (_, _) => Value.CompareTo(other.Value), - }; - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_NewtonsoftJsonConverter.cs deleted file mode 100644 index 9d536aa49..000000000 --- a/src/StronglyTypedIds/Templates/NullableString/NullableString_NewtonsoftJsonConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ - - 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) - { - if (value is null) - { - serializer.Serialize(writer, null); - } - else - { - var id = (TESTID)value; - serializer.Serialize(writer, id.Value); - } - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object? existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - return new TESTID(serializer.Deserialize(reader)); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_SystemTextJsonConverter.cs deleted file mode 100644 index 9f2f7cf1e..000000000 --- a/src/StronglyTypedIds/Templates/NullableString/NullableString_SystemTextJsonConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ - - class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new TESTID(reader.GetString()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options) - { - if (value.Value is null) - { - writer.WriteNullValue(); - } - else - { - writer.WriteStringValue(value.Value); - } - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/NullableString/NullableString_TypeConverter.cs b/src/StronglyTypedIds/Templates/NullableString/NullableString_TypeConverter.cs deleted file mode 100644 index b0f90cc19..000000000 --- a/src/StronglyTypedIds/Templates/NullableString/NullableString_TypeConverter.cs +++ /dev/null @@ -1,42 +0,0 @@ - - class TESTIDTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object? ConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object value) - { - if (value is null) - { - return new TESTID(null); - } - - var stringValue = value as string; - if (stringValue is not null) - { - return new TESTID(stringValue); - } - - return base.ConvertFrom(context, culture, value); - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Type? sourceType) - { - return 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(string)) - { - return idValue.Value; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/String/String_Base.cs b/src/StronglyTypedIds/Templates/String/String_Base.cs deleted file mode 100644 index 023df780b..000000000 --- a/src/StronglyTypedIds/Templates/String/String_Base.cs +++ /dev/null @@ -1,32 +0,0 @@ - readonly partial struct TESTID : INTERFACES - { - public string Value { get; } - - public TESTID(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly TESTID Empty = new TESTID(string.Empty); - - public bool Equals(TESTID other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => 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; - public static bool operator ==(TESTID a, TESTID b) => a.Equals(b); - public static bool operator !=(TESTID a, TESTID b) => !(a == b); diff --git a/src/StronglyTypedIds/Templates/String/String_DapperTypeHandler.cs b/src/StronglyTypedIds/Templates/String/String_DapperTypeHandler.cs deleted file mode 100644 index 93d6ff7bf..000000000 --- a/src/StronglyTypedIds/Templates/String/String_DapperTypeHandler.cs +++ /dev/null @@ -1,17 +0,0 @@ - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, TESTID value) - { - parameter.Value = value.Value; - } - - public override TESTID Parse(object value) - { - return value switch - { - string stringValue => new TESTID(stringValue), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to TESTID"), - }; - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/String/String_EfCoreValueConverter.cs b/src/StronglyTypedIds/Templates/String/String_EfCoreValueConverter.cs deleted file mode 100644 index 76a2b7a63..000000000 --- a/src/StronglyTypedIds/Templates/String/String_EfCoreValueConverter.cs +++ /dev/null @@ -1,11 +0,0 @@ - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new TESTID(value), - mappingHints - ) { } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/String/String_IComparable.cs b/src/StronglyTypedIds/Templates/String/String_IComparable.cs deleted file mode 100644 index 5cdc51ac9..000000000 --- a/src/StronglyTypedIds/Templates/String/String_IComparable.cs +++ /dev/null @@ -1,10 +0,0 @@ - public int CompareTo(TESTID other) - { - return (Value, other.Value) switch - { - (null, null) => 0, - (null, _) => -1, - (_, null) => 1, - (_, _) => Value.CompareTo(other.Value), - }; - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/String/String_NewtonsoftJsonConverter.cs b/src/StronglyTypedIds/Templates/String/String_NewtonsoftJsonConverter.cs deleted file mode 100644 index e331c4bdc..000000000 --- a/src/StronglyTypedIds/Templates/String/String_NewtonsoftJsonConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ - - 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); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - if (objectType == typeof(TESTID?)) - { - var value = serializer.Deserialize(reader); - - return value is null ? null : new TESTID(value); - } - - return new TESTID(serializer.Deserialize(reader)); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/String/String_SystemTextJsonConverter.cs b/src/StronglyTypedIds/Templates/String/String_SystemTextJsonConverter.cs deleted file mode 100644 index f5cf488e2..000000000 --- a/src/StronglyTypedIds/Templates/String/String_SystemTextJsonConverter.cs +++ /dev/null @@ -1,13 +0,0 @@ - - class TESTIDSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override TESTID Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new TESTID(reader.GetString()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, TESTID value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } \ No newline at end of file diff --git a/src/StronglyTypedIds/Templates/String/String_TypeConverter.cs b/src/StronglyTypedIds/Templates/String/String_TypeConverter.cs deleted file mode 100644 index 52e9c128f..000000000 --- a/src/StronglyTypedIds/Templates/String/String_TypeConverter.cs +++ /dev/null @@ -1,37 +0,0 @@ - - class TESTIDTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - var stringValue = value as string; - if (stringValue is not null) - { - return new TESTID(stringValue); - } - - return base.ConvertFrom(context, culture, value); - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return 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(string)) - { - return idValue.Value; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } \ No newline at end of file diff --git a/test/IntegrationLibraries.props b/test/IntegrationLibraries.props index 8ba7bf0b0..148bedfde 100644 --- a/test/IntegrationLibraries.props +++ b/test/IntegrationLibraries.props @@ -1,14 +1,22 @@ + + + + + - - + + + + + diff --git a/test/StronglyTypedIds.IntegrationTests.ExternalIds/StronglyTypedIds.IntegrationTests.ExternalIds.csproj b/test/StronglyTypedIds.IntegrationTests.ExternalIds/StronglyTypedIds.IntegrationTests.ExternalIds.csproj new file mode 100644 index 000000000..833c1281f --- /dev/null +++ b/test/StronglyTypedIds.IntegrationTests.ExternalIds/StronglyTypedIds.IntegrationTests.ExternalIds.csproj @@ -0,0 +1,25 @@ + + + + netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + net48;$(TargetFrameworks) + false + true + + + + + + + + + + + + + + + + + + diff --git a/test/StronglyTypedIds.IntegrationTests.ExternalIds/xunit.runner.json b/test/StronglyTypedIds.IntegrationTests.ExternalIds/xunit.runner.json new file mode 100644 index 000000000..533ef25c1 --- /dev/null +++ b/test/StronglyTypedIds.IntegrationTests.ExternalIds/xunit.runner.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "shadowCopy": false +} \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests.Types/Enums.cs b/test/StronglyTypedIds.IntegrationTests.Types/Enums.cs new file mode 100644 index 000000000..033a09cce --- /dev/null +++ b/test/StronglyTypedIds.IntegrationTests.Types/Enums.cs @@ -0,0 +1,74 @@ +#nullable enable +using System; + +namespace StronglyTypedIds.IntegrationTests.Types; + + +[StronglyTypedId] +public partial struct DefaultId1 { } + +[StronglyTypedId] +public partial struct DefaultId2 { } + +[StronglyTypedId(Template.Guid)] +public partial struct GuidId1 { } + +[StronglyTypedId("guid-full")] +public partial struct ConvertersGuidId { } + +[StronglyTypedId(Template.Guid, "guid-efcore", "guid-dapper", "guid-newtonsoftjson")] +public partial struct ConvertersGuidId2 { } + +[StronglyTypedId(Template.Guid)] +public partial struct GuidId2 { } + +[StronglyTypedId(Template.Int)] +public partial struct IntId { } + +[StronglyTypedId("int-full")] +public partial struct ConvertersIntId { } + +[StronglyTypedId(Template.Int, "int-efcore", "int-dapper", "int-newtonsoftjson")] +public partial struct ConvertersIntId2 { } + +[StronglyTypedId(Template.Long)] +public partial struct LongId { } + +[StronglyTypedId("long-full")] +public partial struct ConvertersLongId { } + +[StronglyTypedId(Template.Long, "long-efcore", "long-dapper", "long-newtonsoftjson")] +public partial struct ConvertersLongId2 { } + +[StronglyTypedId("newid-full")] +public partial struct NewIdId1 { } + +[StronglyTypedId("newid-full")] +public partial struct NewIdId2 { } + +[StronglyTypedId(Template.String)] +public partial struct StringId { } + +[StronglyTypedId("string-full")] +public partial struct ConvertersStringId { } + +[StronglyTypedId(Template.String, "string-efcore", "string-dapper", "string-newtonsoftjson")] +public partial struct ConvertersStringId2 { } + +[StronglyTypedId("nullablestring-full")] +public partial struct NullableStringId { } + +public partial class SomeType where T : new() +{ + public partial record struct NestedType + { + public partial struct MoreNesting + { + [StronglyTypedId] + public readonly partial struct VeryNestedId + { + } + } + } +} + diff --git a/test/StronglyTypedIds.IntegrationTests.Types/StronglyTypedIds.IntegrationTests.Types.csproj b/test/StronglyTypedIds.IntegrationTests.Types/StronglyTypedIds.IntegrationTests.Types.csproj new file mode 100644 index 000000000..e07b7f3de --- /dev/null +++ b/test/StronglyTypedIds.IntegrationTests.Types/StronglyTypedIds.IntegrationTests.Types.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 + net48;$(TargetFrameworks) + false + true + false + + + + + + + + + + + + + + diff --git a/test/StronglyTypedIds.IntegrationTests/DapperTypeHandlers.cs b/test/StronglyTypedIds.IntegrationTests/DapperTypeHandlers.cs index 0ce1ce679..517239aea 100644 --- a/test/StronglyTypedIds.IntegrationTests/DapperTypeHandlers.cs +++ b/test/StronglyTypedIds.IntegrationTests/DapperTypeHandlers.cs @@ -9,12 +9,16 @@ public static class DapperTypeHandlers [ModuleInitializer] public static void AddHandlers() { - SqlMapper.AddTypeHandler(new DapperGuidId.DapperTypeHandler()); - SqlMapper.AddTypeHandler(new DapperIntId.DapperTypeHandler()); - SqlMapper.AddTypeHandler(new DapperStringId.DapperTypeHandler()); - SqlMapper.AddTypeHandler(new DapperLongId.DapperTypeHandler()); - SqlMapper.AddTypeHandler(new DapperNullableStringId.DapperTypeHandler()); - SqlMapper.AddTypeHandler(new DapperNewIdId.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersGuidId.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersGuidId2.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersIntId.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersIntId2.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersLongId.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersLongId2.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersStringId.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new ConvertersStringId2.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new NullableStringId.DapperTypeHandler()); + SqlMapper.AddTypeHandler(new NewIdId1.DapperTypeHandler()); } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/DefaultIdTests.cs b/test/StronglyTypedIds.IntegrationTests/DefaultIdTests.cs index b374909c3..e850196bd 100644 --- a/test/StronglyTypedIds.IntegrationTests/DefaultIdTests.cs +++ b/test/StronglyTypedIds.IntegrationTests/DefaultIdTests.cs @@ -71,134 +71,17 @@ public void CantCreateEmptyGeneratedId1() Assert.NotEqual((object)bar, (object)foo); } - [Fact] - public void WhenNoTypeConverter_SerializesWithValueProperty() - { - var foo = DefaultId1.New(); - - var newtonsoft = SystemTextJsonSerializer.Serialize(foo); - var systemText = SystemTextJsonSerializer.Serialize(foo); - - var expected = "{\"Value\":\"" + foo.Value + "\"}"; - - Assert.Equal(expected, newtonsoft); - Assert.Equal(expected, systemText); - } - - [Fact] - public void WhenEfCoreValueConverterUsesValueConverter() - { - var connection = new SqliteConnection("DataSource=:memory:"); - connection.Open(); - - var options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - using (var context = new TestDbContext(options)) - { - context.Database.EnsureCreated(); - context.Entities.Add( - new TestEntity { Id = EfCoreDefaultId.New() }); - context.SaveChanges(); - } - using (var context = new TestDbContext(options)) - { - var all = context.Entities.ToList(); - Assert.Single(all); - } - } - [Theory] [InlineData("78104553-f1cd-41ec-bcb6-d3a8ff8d994d")] public void TypeConverter_CanConvertToAndFrom(string value) { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonDefaultId)); + var converter = TypeDescriptor.GetConverter(typeof(DefaultId1)); var id = converter.ConvertFrom(value); - Assert.IsType(id); - Assert.Equal(new NoJsonDefaultId(Guid.Parse(value)), id); + Assert.IsType(id); + Assert.Equal(new DefaultId1(Guid.Parse(value)), id); var reconverted = converter.ConvertTo(id, value.GetType()); Assert.Equal(value, reconverted); } - -#if NET6_0_OR_GREATER - [Fact] - public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() - { - var connection = new SqliteConnection("DataSource=:memory:"); - connection.Open(); - - var options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - using (var context = new ConventionsDbContext(options)) - { - context.Database.EnsureCreated(); - context.Entities.Add( - new TestEntity { Id = EfCoreDefaultId.New() }); - context.SaveChanges(); - } - using (var context = new ConventionsDbContext(options)) - { - var all = context.Entities.ToList(); - Assert.Single(all); - } - } - - public class ConventionsDbContext : DbContext - { - public DbSet Entities { get; set; } - - public ConventionsDbContext(DbContextOptions options) : base(options) - { - } - - protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) - { - configurationBuilder - .Properties() - .HaveConversion(); - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder - .Entity(builder => - { - builder - .Property(x => x.Id) - .ValueGeneratedNever(); - }); - } - } -#endif - - public class TestDbContext : DbContext - { - public DbSet Entities { get; set; } - - public TestDbContext(DbContextOptions options) : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder - .Entity(builder => - { - builder - .Property(x => x.Id) - .HasConversion(new EfCoreDefaultId.EfCoreValueConverter()) - .ValueGeneratedNever(); - }); - } - } - - public class TestEntity - { - public EfCoreDefaultId Id { get; set; } - } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/Enums.cs b/test/StronglyTypedIds.IntegrationTests/Enums.cs new file mode 100644 index 000000000..66e88e574 --- /dev/null +++ b/test/StronglyTypedIds.IntegrationTests/Enums.cs @@ -0,0 +1,74 @@ +#nullable enable +using System; + +namespace StronglyTypedIds.IntegrationTests.Types; + + +[StronglyTypedId] +internal partial struct DefaultId1 { } + +[StronglyTypedId] +internal partial struct DefaultId2 { } + +[StronglyTypedId(Template.Guid)] +internal partial struct GuidId1 { } + +[StronglyTypedId("guid-full")] +internal partial struct ConvertersGuidId { } + +[StronglyTypedId(Template.Guid, "guid-efcore", "guid-dapper", "guid-newtonsoftjson")] +internal partial struct ConvertersGuidId2 { } + +[StronglyTypedId(Template.Guid)] +internal partial struct GuidId2 { } + +[StronglyTypedId(Template.Int)] +internal partial struct IntId { } + +[StronglyTypedId("int-full")] +internal partial struct ConvertersIntId { } + +[StronglyTypedId(Template.Int, "int-efcore", "int-dapper", "int-newtonsoftjson")] +internal partial struct ConvertersIntId2 { } + +[StronglyTypedId(Template.Long)] +internal partial struct LongId { } + +[StronglyTypedId("long-full")] +internal partial struct ConvertersLongId { } + +[StronglyTypedId(Template.Long, "long-efcore", "long-dapper", "long-newtonsoftjson")] +internal partial struct ConvertersLongId2 { } + +[StronglyTypedId("newid-full")] +internal partial struct NewIdId1 { } + +[StronglyTypedId("newid-full")] +internal partial struct NewIdId2 { } + +[StronglyTypedId(Template.String)] +internal partial struct StringId { } + +[StronglyTypedId("string-full")] +internal partial struct ConvertersStringId { } + +[StronglyTypedId(Template.String, "string-efcore", "string-dapper", "string-newtonsoftjson")] +internal partial struct ConvertersStringId2 { } + +[StronglyTypedId("nullablestring-full")] +internal partial struct NullableStringId { } + +internal partial class SomeType where T : new() +{ + internal partial record struct NestedType + { + internal partial struct MoreNesting + { + [StronglyTypedId] + internal readonly partial struct VeryNestedId + { + } + } + } +} + diff --git a/test/StronglyTypedIds.IntegrationTests/GuidIdTests.cs b/test/StronglyTypedIds.IntegrationTests/GuidIdTests.cs index 2905f70e6..49460b9b1 100644 --- a/test/StronglyTypedIds.IntegrationTests/GuidIdTests.cs +++ b/test/StronglyTypedIds.IntegrationTests/GuidIdTests.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Dapper; using Microsoft.Data.Sqlite; @@ -30,7 +32,6 @@ public void EmptyValueIsEmpty() Assert.Equal(GuidId1.Empty.Value, Guid.Empty); } - [Fact] public void DifferentValuesAreUnequal() { @@ -77,7 +78,7 @@ public void CantCreateEmptyGeneratedId1() [Fact] public void CanSerializeToGuid_WithTypeConverter() { - var foo = NewtonsoftJsonGuidId.New(); + var foo = GuidId1.New(); var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); var serializedGuid = NewtonsoftJsonSerializer.SerializeObject(foo.Value); @@ -88,7 +89,7 @@ public void CanSerializeToGuid_WithTypeConverter() [Fact] public void CanSerializeToGuid_WithSystemTextJsonProvider() { - var foo = SystemTextJsonGuidId.New(); + var foo = GuidId1.New(); var serializedFoo = SystemTextJsonSerializer.Serialize(foo); var serializedGuid = SystemTextJsonSerializer.Serialize(foo.Value); @@ -97,92 +98,219 @@ public void CanSerializeToGuid_WithSystemTextJsonProvider() } [Fact] - public void CanDeserializeFromGuid_WithNewtonsoftJsonProvider() + public void CanDeserializeFromGuid_WithSystemTextJsonProvider() { var value = Guid.NewGuid(); - var foo = new NewtonsoftJsonGuidId(value); - var serializedGuid = NewtonsoftJsonSerializer.SerializeObject(value); + var foo = new GuidId1(value); + var serializedGuid = SystemTextJsonSerializer.Serialize(value); - var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedGuid); + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedGuid); Assert.Equal(foo, deserializedFoo); } +#if NET6_0_OR_GREATER [Fact] - public void CanSerializeToNullableInt_WithNewtonsoftJsonProvider() + public void CanDeserializeDictionaryKeys_WithSystemTextJsonProvider() { - var entity = new EntityWithNullableId { Id = null }; + var value = new TypeWithDictionaryKeys() + { + Values = new() + }; + var guid = new GuidId1(Guid.Parse("78104553-f1cd-41ec-bcb6-d3a8ff8d994d")); + value.Values.Add(guid, "My Value"); + var opts = new JsonSerializerOptions + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + var serialized = SystemTextJsonSerializer.Serialize(value, opts); + + var expected = $$""" + { + "values": { + "78104553-f1cd-41ec-bcb6-d3a8ff8d994d": "My Value" + } + } + """; + Assert.Equal(serialized, expected); + + var deserialized = SystemTextJsonSerializer.Deserialize(serialized, opts); + + Assert.NotNull(deserialized.Values); + Assert.True(deserialized.Values.ContainsKey(guid)); + Assert.Equal("My Value", deserialized.Values[guid]); + } - var json = NewtonsoftJsonSerializer.SerializeObject(entity); - var deserialize = NewtonsoftJsonSerializer.DeserializeObject(json); + [Fact] + public void CanSerializeToGuid_WithSystemTextJsonProvider_WithSourceGenerator() + { + var foo = GuidId1.New(); - Assert.NotNull(deserialize); - Assert.Null(deserialize.Id); + var serializedFoo = SystemTextJsonSerializer.Serialize(foo, SystemTextJsonSerializerContext.Custom.GuidId1); + var serializedGuid = SystemTextJsonSerializer.Serialize(foo.Value); + + Assert.Equal(serializedFoo, serializedGuid); } [Fact] - public void CanDeserializeFromGuid_WithSystemTextJsonProvider() + public void CanDeserializeFromGuid_WithSystemTextJsonProvider_WithSourceGenerator() { var value = Guid.NewGuid(); - var foo = new SystemTextJsonGuidId(value); + var foo = new GuidId1(value); var serializedGuid = SystemTextJsonSerializer.Serialize(value); - var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedGuid); + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedGuid, SystemTextJsonSerializerContext.Custom.GuidId1); Assert.Equal(foo, deserializedFoo); } + [Fact(Skip = "This one doesn't seem to work, but I'm not sure if it's a source-generator limitation or a bug...")] + public void CanDeserializeDictionaryKeys_WithSystemTextJsonProvider_WithSourceGenerator() + { + var value = new TypeWithDictionaryKeys() + { + Values = new() + }; + var guid = new GuidId1(Guid.Parse("78104553-f1cd-41ec-bcb6-d3a8ff8d994d")); + value.Values.Add(guid, "My Value"); + var serialized = SystemTextJsonSerializer.Serialize(value, SystemTextJsonSerializerContext.Web.TypeWithDictionaryKeys); + + var expected = $$""" + { + "values": { + "78104553-f1cd-41ec-bcb6-d3a8ff8d994d": "My Value" + } + } + """; + Assert.Equal(serialized, expected); + + var deserialized = SystemTextJsonSerializer.Deserialize(serialized, SystemTextJsonSerializerContext.Web.TypeWithDictionaryKeys); + + Assert.NotNull(deserialized.Values); + Assert.True(deserialized.Values.ContainsKey(guid)); + Assert.Equal("My Value", deserialized.Values[guid]); + } +#endif + [Fact] - public void CanSerializeToGuid_WithBothJsonConverters() + public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() { - var foo = BothJsonGuidId.New(); + var foo = GuidId1.New(); - var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedGuid1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); - var serializedGuid2 = SystemTextJsonSerializer.Serialize(foo.Value); + var expected = $"\"{foo.Value}\""; - Assert.Equal(serializedFoo1, serializedGuid1); - Assert.Equal(serializedFoo2, serializedGuid2); + Assert.Equal(expected, serialized); + } + + [Theory] + [InlineData("78104553-f1cd-41ec-bcb6-d3a8ff8d994d")] + public void TypeConverter_CanConvertToAndFrom(string value) + { + var converter = TypeDescriptor.GetConverter(typeof(GuidId1)); + var id = converter.ConvertFrom(value); + Assert.IsType(id); + Assert.Equal(new GuidId1(Guid.Parse(value)), id); + + var reconverted = converter.ConvertTo(id, value.GetType()); + Assert.Equal(value, reconverted); } [Fact] - public void WhenNoJsonConverter_SystemTextJsonSerializesWithValueProperty() + public void CanCompareDefaults() { - var foo = NoJsonGuidId.New(); + GuidId1 original = default; + var other = GuidId1.Empty; - var serialized = SystemTextJsonSerializer.Serialize(foo); + var compare1 = original.CompareTo(other); + var compare2 = other.CompareTo(original); + Assert.Equal(compare1, -compare2); + } - var expected = "{\"Value\":\"" + foo.Value + "\"}"; + [Fact] + public void CanEquateDefaults() + { + GuidId1 original = default; + var other = GuidId1.Empty; - Assert.Equal(expected, serialized); + var equals1 = (original as IEquatable).Equals(other); + var equals2 = (other as IEquatable).Equals(original); + + Assert.Equal(equals1, equals2); } [Fact] - public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() + public void ImplementsInterfaces() { - var foo = NoJsonGuidId.New(); + Assert.IsAssignableFrom>(GuidId1.Empty); + Assert.IsAssignableFrom>(GuidId1.Empty); + Assert.IsAssignableFrom(GuidId1.Empty); + +#pragma warning disable CS0183 +#pragma warning disable 184 + Assert.True(GuidId1.Empty is IComparable); + Assert.True(GuidId1.Empty is IEquatable); +#pragma warning restore 184 +#pragma warning restore CS0183 - var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); +#if NET6_0_OR_GREATER + Assert.IsAssignableFrom(GuidId1.Empty); +#endif +#if NET7_0_OR_GREATER + // doesn't compile if doesn't implement it + ParseAs(Guid.NewGuid().ToString()); + ParseSpan(Guid.NewGuid().ToString().AsSpan()); - var expected = $"\"{foo.Value}\""; + T ParseAs(string s) where T: IParsable { + return T.Parse(s, null); + } - Assert.Equal(expected, serialized); + T ParseSpan(ReadOnlySpan s) where T: ISpanParsable { + return T.Parse(s, null); + } +#endif } +#region ConvertersGuidId [Fact] - public void WhenNoTypeConverter_SerializesWithValueProperty() + public void CanDeserializeFromGuid_WithNewtonsoftJsonProvider() { - var foo = NoConverterGuidId.New(); - - var newtonsoft = SystemTextJsonSerializer.Serialize(foo); - var systemText = SystemTextJsonSerializer.Serialize(foo); + var value = Guid.NewGuid(); + var foo = new ConvertersGuidId(value); + var serializedGuid = NewtonsoftJsonSerializer.SerializeObject(value); + + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedGuid); + + Assert.Equal(foo, deserializedFoo); + } - var expected = "{\"Value\":\"" + foo.Value + "\"}"; + [Fact] + public void CanSerializeToNullableInt_WithNewtonsoftJsonProvider() + { + var entity = new EntityWithNullableId { Id = null }; + + var json = NewtonsoftJsonSerializer.SerializeObject(entity); + var deserialize = NewtonsoftJsonSerializer.DeserializeObject(json); + + Assert.NotNull(deserialize); + Assert.Null(deserialize.Id); + } - Assert.Equal(expected, newtonsoft); - Assert.Equal(expected, systemText); + [Fact] + public void CanSerializeToGuid_WithBothJsonConverters() + { + var foo = ConvertersGuidId.New(); + + var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedGuid1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + + var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); + var serializedGuid2 = SystemTextJsonSerializer.Serialize(foo.Value); + + Assert.Equal(serializedFoo1, serializedGuid1); + Assert.Equal(serializedFoo2, serializedGuid2); } [Fact] @@ -190,16 +318,16 @@ public void WhenEfCoreValueConverterUsesValueConverter() { var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); - + var options = new DbContextOptionsBuilder() .UseSqlite(connection) .Options; - + using (var context = new TestDbContext(options)) { context.Database.EnsureCreated(); context.Entities.Add( - new TestEntity { Id = EfCoreGuidId.New() }); + new TestEntity { Id = ConvertersGuidId.New() }); context.SaveChanges(); } using (var context = new TestDbContext(options)) @@ -214,67 +342,119 @@ public async Task WhenDapperValueConverterUsesValueConverter() { using var connection = new SqliteConnection("DataSource=:memory:"); await connection.OpenAsync(); - - var results = await connection.QueryAsync("SELECT '5640dad4-862a-4738-9e3c-c76dc227eb66'"); - + + var results = await connection.QueryAsync("SELECT '5640dad4-862a-4738-9e3c-c76dc227eb66'"); + var value = Assert.Single(results); - Assert.Equal(value, new DapperGuidId(Guid.Parse("5640dad4-862a-4738-9e3c-c76dc227eb66"))); + Assert.Equal(value, new ConvertersGuidId(Guid.Parse("5640dad4-862a-4738-9e3c-c76dc227eb66"))); } - [Theory] - [InlineData("78104553-f1cd-41ec-bcb6-d3a8ff8d994d")] - public void TypeConverter_CanConvertToAndFrom(string value) +#if NET6_0_OR_GREATER + [Fact] + public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonGuidId)); - var id = converter.ConvertFrom(value); - Assert.IsType(id); - Assert.Equal(new NoJsonGuidId(Guid.Parse(value)), id); + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); - var reconverted = converter.ConvertTo(id, value.GetType()); - Assert.Equal(value, reconverted); + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + using (var context = new ConventionsDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities.Add( + new TestEntity { Id = ConvertersGuidId.New() }); + context.SaveChanges(); + } + using (var context = new ConventionsDbContext(options)) + { + var all = context.Entities.ToList(); + Assert.Single(all); + } } +#endif +#endregion +#region ConvertersGuidId2 [Fact] - public void CanCompareDefaults() + public void CanDeserializeFromGuid_WithMultiTemplates_WithNewtonsoftJsonProvider() { - ComparableGuidId original = default; - var other = ComparableGuidId.Empty; - - var compare1 = original.CompareTo(other); - var compare2 = other.CompareTo(original); - Assert.Equal(compare1, -compare2); + var value = Guid.NewGuid(); + var foo = new ConvertersGuidId2(value); + var serializedGuid = NewtonsoftJsonSerializer.SerializeObject(value); + + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedGuid); + + Assert.Equal(foo, deserializedFoo); } [Fact] - public void CanEquateDefaults() + public void CanSerializeToNullable_WithMultiTemplates_WithNewtonsoftJsonProvider() { - EquatableGuidId original = default; - var other = EquatableGuidId.Empty; - - var equals1 = (original as IEquatable).Equals(other); - var equals2 = (other as IEquatable).Equals(original); - - Assert.Equal(equals1, equals2); + var entity = new EntityWithNullableId2 { Id = null }; + + var json = NewtonsoftJsonSerializer.SerializeObject(entity); + var deserialize = NewtonsoftJsonSerializer.DeserializeObject(json); + + Assert.NotNull(deserialize); + Assert.Null(deserialize.Id); } [Fact] - public void ImplementsInterfaces() + public void CanSerializeToGuid_WithMultiTemplates_WithBothJsonConverters() { - Assert.IsAssignableFrom>(BothGuidId.Empty); - Assert.IsAssignableFrom>(BothGuidId.Empty); + var foo = ConvertersGuidId2.New(); + + var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedGuid1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + + var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); + var serializedGuid2 = SystemTextJsonSerializer.Serialize(foo.Value); + + Assert.Equal(serializedFoo1, serializedGuid1); + Assert.Equal(serializedFoo2, serializedGuid2); + } - Assert.IsAssignableFrom>(EquatableGuidId.Empty); - Assert.IsAssignableFrom>(ComparableGuidId.Empty); + [Fact] + public void WhenEfCore_WithMultiTemplates_ValueConverterUsesValueConverter() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + using (var context = new TestDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities2.Add( + new TestEntity2 { Id = ConvertersGuidId2.New() }); + context.SaveChanges(); + } + using (var context = new TestDbContext(options)) + { + var all = context.Entities2.ToList(); + Assert.Single(all); + } + } -#pragma warning disable 184 - Assert.False(GuidId1.Empty is IComparable); - Assert.False(GuidId1.Empty is IEquatable); -#pragma warning restore 184 + [Fact] + public async Task WhenDapperValueConverter_WithMultiTemplates_UsesValueConverter() + { + using var connection = new SqliteConnection("DataSource=:memory:"); + await connection.OpenAsync(); + + var results = await connection.QueryAsync("SELECT '5640dad4-862a-4738-9e3c-c76dc227eb66'"); + + var value = Assert.Single(results); + Assert.Equal(value, new ConvertersGuidId2(Guid.Parse("5640dad4-862a-4738-9e3c-c76dc227eb66"))); } #if NET6_0_OR_GREATER [Fact] - public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() + public void WhenConventionBasedEfCore_WithMultiTemplates_ValueConverterUsesValueConverter() { var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); @@ -286,20 +466,23 @@ public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() using (var context = new ConventionsDbContext(options)) { context.Database.EnsureCreated(); - context.Entities.Add( - new TestEntity { Id = EfCoreGuidId.New() }); + context.Entities2.Add( + new TestEntity2 { Id = ConvertersGuidId2.New() }); context.SaveChanges(); } using (var context = new ConventionsDbContext(options)) { - var all = context.Entities.ToList(); + var all = context.Entities2.ToList(); Assert.Single(all); } } - - public class ConventionsDbContext : DbContext +#endif +#endregion +#if NET6_0_OR_GREATER + internal class ConventionsDbContext : DbContext { public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } public ConventionsDbContext(DbContextOptions options) : base(options) { @@ -308,8 +491,11 @@ public ConventionsDbContext(DbContextOptions options) : base(options) protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder - .Properties() - .HaveConversion(); + .Properties() + .HaveConversion(); + configurationBuilder + .Properties() + .HaveConversion(); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -321,13 +507,21 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .Property(x => x.Id) .ValueGeneratedNever(); }); + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .ValueGeneratedNever(); + }); } } #endif - public class TestDbContext : DbContext + internal class TestDbContext : DbContext { public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } public TestDbContext(DbContextOptions options) : base(options) { @@ -340,20 +534,44 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { builder .Property(x => x.Id) - .HasConversion(new EfCoreGuidId.EfCoreValueConverter()) + .HasConversion(new ConvertersGuidId.EfCoreValueConverter()) + .ValueGeneratedNever(); + }); + + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .HasConversion(new ConvertersGuidId2.EfCoreValueConverter()) .ValueGeneratedNever(); }); } } - public class TestEntity + internal class TestEntity + { + public ConvertersGuidId Id { get; set; } + } + + internal class EntityWithNullableId + { + public ConvertersGuidId? Id { get; set; } + } + + internal class TypeWithDictionaryKeys + { + public Dictionary Values { get; set; } + } + + internal class TestEntity2 { - public EfCoreGuidId Id { get; set; } + public ConvertersGuidId2 Id { get; set; } } - public class EntityWithNullableId + internal class EntityWithNullableId2 { - public NewtonsoftJsonGuidId? Id { get; set; } + public ConvertersGuidId2? Id { get; set; } } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/IntIdTests.cs b/test/StronglyTypedIds.IntegrationTests/IntIdTests.cs index e2c48be64..b930c3120 100644 --- a/test/StronglyTypedIds.IntegrationTests/IntIdTests.cs +++ b/test/StronglyTypedIds.IntegrationTests/IntIdTests.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Dapper; using Microsoft.Data.Sqlite; @@ -10,343 +12,522 @@ using NewtonsoftJsonSerializer = Newtonsoft.Json.JsonConvert; using SystemTextJsonSerializer = System.Text.Json.JsonSerializer; -namespace StronglyTypedIds.IntegrationTests +namespace StronglyTypedIds.IntegrationTests; + +public class IntIdTests { - public class IntIdTests + [Fact] + public void SameValuesAreEqual() { - [Fact] - public void SameValuesAreEqual() - { - var id = 123; - var foo1 = new IntId(id); - var foo2 = new IntId(id); + var id = 123; + var foo1 = new IntId(id); + var foo2 = new IntId(id); - Assert.Equal(foo1, foo2); - } + Assert.Equal(foo1, foo2); + } - [Fact] - public void EmptyValueIsEmpty() - { - Assert.Equal(0, IntId.Empty.Value); - } + [Fact] + public void EmptyValueIsEmpty() + { + Assert.Equal(0, IntId.Empty.Value); + } - [Fact] - public void DifferentValuesAreUnequal() - { - var foo1 = new IntId(1); - var foo2 = new IntId(2); + [Fact] + public void DifferentValuesAreUnequal() + { + var foo1 = new IntId(1); + var foo2 = new IntId(2); - Assert.NotEqual(foo1, foo2); - } + Assert.NotEqual(foo1, foo2); + } - [Fact] - public void OverloadsWorkCorrectly() - { - var id = 12; - var same1 = new IntId(id); - var same2 = new IntId(id); - var different = new IntId(3); - - Assert.True(same1 == same2); - Assert.False(same1 == different); - Assert.False(same1 != same2); - Assert.True(same1 != different); - } + [Fact] + public void OverloadsWorkCorrectly() + { + var id = 12; + var same1 = new IntId(id); + var same2 = new IntId(id); + var different = new IntId(3); + + Assert.True(same1 == same2); + Assert.False(same1 == different); + Assert.False(same1 != same2); + Assert.True(same1 != different); + } - [Fact] - public void DifferentTypesAreUnequal() - { - var bar = GuidId2.New(); - var foo = new IntId(23); + [Fact] + public void DifferentTypesAreUnequal() + { + var bar = GuidId2.New(); + var foo = new IntId(23); - //Assert.NotEqual(bar, foo); // does not compile - Assert.NotEqual((object)bar, (object)foo); - } + //Assert.NotEqual(bar, foo); // does not compile + Assert.NotEqual((object) bar, (object) foo); + } - [Fact] - public void CanSerializeToInt_WithNewtonsoftJsonProvider() - { - var foo = new NewtonsoftJsonIntId(123); + [Fact] + public void CanSerializeToNullableInt_WithNewtonsoftJsonProvider() + { + var entity = new EntityWithNullableId {Id = null}; - var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedInt = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + var json = NewtonsoftJsonSerializer.SerializeObject(entity); + var deserialize = NewtonsoftJsonSerializer.DeserializeObject(json); - Assert.Equal(serializedFoo, serializedInt); - } + Assert.NotNull(deserialize); + Assert.Null(deserialize.Id); + } - [Fact] - public void CanSerializeToNullableInt_WithNewtonsoftJsonProvider() +#if NET6_0_OR_GREATER + [Fact] + public void CanDeserializeDictionaryKeys_WithSystemTextJsonProvider() + { + var value = new TypeWithDictionaryKeys() + { + Values = new() + }; + var key = new IntId(123); + value.Values.Add(key, "My Value"); + var opts = new JsonSerializerOptions { - var entity = new EntityWithNullableId { Id = null }; + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + var serialized = SystemTextJsonSerializer.Serialize(value, opts); + + var expected = $$""" + { + "values": { + "123": "My Value" + } + } + """; + Assert.Equal(serialized, expected); + + var deserialized = SystemTextJsonSerializer.Deserialize(serialized, opts); + + Assert.NotNull(deserialized.Values); + Assert.True(deserialized.Values.ContainsKey(key)); + Assert.Equal("My Value", deserialized.Values[key]); + } +#endif - var json = NewtonsoftJsonSerializer.SerializeObject(entity); - var deserialize = NewtonsoftJsonSerializer.DeserializeObject(json); + [Fact] + public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() + { + var foo = new IntId(123); - Assert.NotNull(deserialize); - Assert.Null(deserialize.Id); - } + var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); - [Fact] - public void CanSerializeToInt_WithSystemTextJsonProvider() - { - var foo = new SystemTextJsonIntId(123); + var expected = $"\"{foo.Value}\""; - var serializedFoo = SystemTextJsonSerializer.Serialize(foo); - var serializedInt = SystemTextJsonSerializer.Serialize(foo.Value); + Assert.Equal(expected, serialized); + } - Assert.Equal(serializedFoo, serializedInt); - } + [Fact] + public void CanCompareDefaults() + { + IntId original = default; + var other = IntId.Empty; - [Fact] - public void CanDeserializeFromInt_WithNewtonsoftJsonProvider() - { - var value = 123; - var foo = new NewtonsoftJsonIntId(value); - var serializedInt = NewtonsoftJsonSerializer.SerializeObject(value); + var compare1 = original.CompareTo(other); + var compare2 = other.CompareTo(original); + Assert.Equal(compare1, -compare2); + } + + [Fact] + public void CanEquateDefaults() + { + IntId original = default; + var other = IntId.Empty; - var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedInt); + var equals1 = (original as IEquatable).Equals(other); + var equals2 = (other as IEquatable).Equals(original); - Assert.Equal(foo, deserializedFoo); - } + Assert.Equal(equals1, equals2); + } - [Fact] - public void CanDeserializeFromInt_WithSystemTextJsonProvider() - { - var value = 123; - var foo = new SystemTextJsonIntId(value); - var serializedInt = SystemTextJsonSerializer.Serialize(value); + [Fact] + public void ImplementsInterfaces() + { + Assert.IsAssignableFrom>(IntId.Empty); + Assert.IsAssignableFrom>(IntId.Empty); + Assert.IsAssignableFrom(IntId.Empty); - var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedInt); +#pragma warning disable CS0183 +#pragma warning disable 184 + Assert.True(IntId.Empty is IComparable); + Assert.True(IntId.Empty is IEquatable); +#pragma warning restore 184 +#pragma warning restore CS0183 + +#if NET6_0_OR_GREATER + Assert.IsAssignableFrom(IntId.Empty); +#endif +#if NET7_0_OR_GREATER + // doesn't compile if doesn't implement it + ParseAs("123"); + ParseSpan("123".AsSpan()); - Assert.Equal(foo, deserializedFoo); + T ParseAs(string s) where T : IParsable + { + return T.Parse(s, null); } - [Fact] - public void CanSerializeToInt_WithBothJsonConverters() + T ParseSpan(ReadOnlySpan s) where T : ISpanParsable { - var foo = new BothJsonIntId(123); + return T.Parse(s, null); + } +#endif + } - var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedInt1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value); +#region ConvertersIntId + [Fact] + public void CanSerializeToInt_WithNewtonsoftJsonProvider() + { + var foo = new ConvertersIntId(123); - var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); - var serializedInt2 = SystemTextJsonSerializer.Serialize(foo.Value); + var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedInt = NewtonsoftJsonSerializer.SerializeObject(foo.Value); - Assert.Equal(serializedFoo1, serializedInt1); - Assert.Equal(serializedFoo2, serializedInt2); - } + Assert.Equal(serializedFoo, serializedInt); + } - [Fact] - public void WhenNoJsonConverter_SystemTextJsonSerializesWithValueProperty() - { - var foo = new NoJsonIntId(123); + [Fact] + public void CanSerializeToInt_WithSystemTextJsonProvider() + { + var foo = new ConvertersIntId(123); - var serialized = SystemTextJsonSerializer.Serialize(foo); + var serializedFoo = SystemTextJsonSerializer.Serialize(foo); + var serializedInt = SystemTextJsonSerializer.Serialize(foo.Value); - var expected = "{\"Value\":" + foo.Value + "}"; + Assert.Equal(serializedFoo, serializedInt); + } - Assert.Equal(expected, serialized); - } + [Fact] + public void CanDeserializeFromInt_WithNewtonsoftJsonProvider() + { + var value = 123; + var foo = new ConvertersIntId(value); + var serializedInt = NewtonsoftJsonSerializer.SerializeObject(value); - [Fact] - public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() - { - var foo = new NoJsonIntId(123); + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedInt); - var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); + Assert.Equal(foo, deserializedFoo); + } - var expected = $"\"{foo.Value}\""; + [Fact] + public void CanDeserializeFromInt_WithSystemTextJsonProvider() + { + var value = 123; + var foo = new ConvertersIntId(value); + var serializedInt = SystemTextJsonSerializer.Serialize(value); - Assert.Equal(expected, serialized); - } + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedInt); - [Fact] - public void WhenNoTypeConverter_SerializesWithValueProperty() - { - var foo = new NoConverterIntId(123); + Assert.Equal(foo, deserializedFoo); + } - var newtonsoft = SystemTextJsonSerializer.Serialize(foo); - var systemText = SystemTextJsonSerializer.Serialize(foo); + [Fact] + public void WhenEfCoreValueConverterUsesValueConverter() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); - var expected = "{\"Value\":" + foo.Value + "}"; + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; - Assert.Equal(expected, newtonsoft); - Assert.Equal(expected, systemText); + var original = new TestEntity {Id = new ConvertersIntId(123)}; + using (var context = new TestDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities.Add(original); + context.SaveChanges(); } - [Fact] - public void WhenEfCoreValueConverterUsesValueConverter() + using (var context = new TestDbContext(options)) { - var connection = new SqliteConnection("DataSource=:memory:"); - connection.Open(); - - var options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - var original = new TestEntity { Id = new EfCoreIntId(123) }; - using (var context = new TestDbContext(options)) - { - context.Database.EnsureCreated(); - context.Entities.Add(original); - context.SaveChanges(); - } - using (var context = new TestDbContext(options)) - { - var all = context.Entities.ToList(); - var retrieved = Assert.Single(all); - Assert.Equal(original.Id, retrieved.Id); - } + var all = context.Entities.ToList(); + var retrieved = Assert.Single(all); + Assert.Equal(original.Id, retrieved.Id); } + } - [Fact] - public async Task WhenDapperValueConverterUsesValueConverter() - { - using var connection = new SqliteConnection("DataSource=:memory:"); - await connection.OpenAsync(); + [Fact] + public async Task WhenDapperValueConverterUsesValueConverter() + { + using var connection = new SqliteConnection("DataSource=:memory:"); + await connection.OpenAsync(); - var results = await connection.QueryAsync("SELECT 123"); + var results = await connection.QueryAsync("SELECT 123"); - var value = Assert.Single(results); - Assert.Equal(new DapperIntId(123), value); - } + var value = Assert.Single(results); + Assert.Equal(new ConvertersIntId(123), value); + } - [Theory] - [InlineData(123)] - [InlineData("123")] - public void TypeConverter_CanConvertToAndFrom(object value) - { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonIntId)); - var id = converter.ConvertFrom(value); - Assert.IsType(id); - Assert.Equal(new NoJsonIntId(123), id); + [Theory] + [InlineData(123)] + [InlineData("123")] + public void TypeConverter_CanConvertToAndFrom(object value) + { + var converter = TypeDescriptor.GetConverter(typeof(ConvertersIntId)); + var id = converter.ConvertFrom(value); + Assert.IsType(id); + Assert.Equal(new ConvertersIntId(123), id); - var reconverted = converter.ConvertTo(id, value.GetType()); - Assert.Equal(value, reconverted); - } + var reconverted = converter.ConvertTo(id, value.GetType()); + Assert.Equal(value, reconverted); + } - [Fact] - public void CanCompareDefaults() - { - ComparableIntId original = default; - var other = ComparableIntId.Empty; +#if NET6_0_OR_GREATER + [Fact] + public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; - var compare1 = original.CompareTo(other); - var compare2 = other.CompareTo(original); - Assert.Equal(compare1, -compare2); + using (var context = new ConventionsDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities.Add( + new TestEntity {Id = new ConvertersIntId(123)}); + context.SaveChanges(); } - [Fact] - public void CanEquateDefaults() + using (var context = new ConventionsDbContext(options)) { - EquatableIntId original = default; - var other = EquatableIntId.Empty; + var all = context.Entities.ToList(); + Assert.Single(all); + } + } +#endif +#endregion + + +#region ConvertersIntId22 + [Fact] + public void CanSerializeToInt_WithMultiTemplates_WithNewtonsoftJsonProvider() + { + var foo = new ConvertersIntId2(123); + + var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedInt = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + + Assert.Equal(serializedFoo, serializedInt); + } + + [Fact] + public void CanSerializeToInt_WithMultiTemplates_WithSystemTextJsonProvider() + { + var foo = new ConvertersIntId2(123); + + var serializedFoo = SystemTextJsonSerializer.Serialize(foo); + var serializedInt = SystemTextJsonSerializer.Serialize(foo.Value); + + Assert.Equal(serializedFoo, serializedInt); + } + + [Fact] + public void CanDeserializeFromInt_WithMultiTemplates_WithNewtonsoftJsonProvider() + { + var value = 123; + var foo = new ConvertersIntId2(value); + var serializedInt = NewtonsoftJsonSerializer.SerializeObject(value); + + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedInt); + + Assert.Equal(foo, deserializedFoo); + } + + [Fact] + public void CanDeserializeFromInt_WithMultiTemplates_WithSystemTextJsonProvider() + { + var value = 123; + var foo = new ConvertersIntId2(value); + var serializedInt = SystemTextJsonSerializer.Serialize(value); - var equals1 = (original as IEquatable).Equals(other); - var equals2 = (other as IEquatable).Equals(original); + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedInt); + + Assert.Equal(foo, deserializedFoo); + } - Assert.Equal(equals1, equals2); + [Fact] + public void WhenEfCoreValueConverter_WithMultiTemplates_UsesValueConverter() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + var original = new TestEntity2 {Id = new ConvertersIntId2(123)}; + using (var context = new TestDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities2.Add(original); + context.SaveChanges(); } - [Fact] - public void ImplementsInterfaces() + using (var context = new TestDbContext(options)) { - Assert.IsAssignableFrom>(BothIntId.Empty); - Assert.IsAssignableFrom>(BothIntId.Empty); + var all = context.Entities2.ToList(); + var retrieved = Assert.Single(all); + Assert.Equal(original.Id, retrieved.Id); + } + } - Assert.IsAssignableFrom>(EquatableIntId.Empty); - Assert.IsAssignableFrom>(ComparableIntId.Empty); + [Fact] + public async Task WhenDapperValueConverter_WithMultiTemplates_UsesValueConverter() + { + using var connection = new SqliteConnection("DataSource=:memory:"); + await connection.OpenAsync(); -#pragma warning disable 184 - Assert.False(IntId.Empty is IComparable); - Assert.False(IntId.Empty is IEquatable); -#pragma warning restore 184 - } + var results = await connection.QueryAsync("SELECT 123"); + + var value = Assert.Single(results); + Assert.Equal(new ConvertersIntId2(123), value); + } + + [Theory] + [InlineData(123)] + [InlineData("123")] + public void TypeConverter_WithMultiTemplates_CanConvertToAndFrom(object value) + { + var converter = TypeDescriptor.GetConverter(typeof(ConvertersIntId2)); + var id = converter.ConvertFrom(value); + Assert.IsType(id); + Assert.Equal(new ConvertersIntId2(123), id); + var reconverted = converter.ConvertTo(id, value.GetType()); + Assert.Equal(value, reconverted); + } #if NET6_0_OR_GREATER - [Fact] - public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() + [Fact] + public void WhenConventionBasedEfCoreValueConverter_WithMultiTemplates_UsesValueConverter() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + using (var context = new ConventionsDbContext(options)) { - var connection = new SqliteConnection("DataSource=:memory:"); - connection.Open(); - - var options = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - - using (var context = new ConventionsDbContext(options)) - { - context.Database.EnsureCreated(); - context.Entities.Add( - new TestEntity { Id = new EfCoreIntId(123) }); - context.SaveChanges(); - } - using (var context = new ConventionsDbContext(options)) - { - var all = context.Entities.ToList(); - Assert.Single(all); - } + context.Database.EnsureCreated(); + context.Entities2.Add( + new TestEntity2 {Id = new ConvertersIntId2(123)}); + context.SaveChanges(); } - public class ConventionsDbContext : DbContext + using (var context = new ConventionsDbContext(options)) { - public DbSet Entities { get; set; } - - public ConventionsDbContext(DbContextOptions options) : base(options) - { - } - - protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) - { - configurationBuilder - .Properties() - .HaveConversion(); - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder - .Entity(builder => - { - builder - .Property(x => x.Id) - .ValueGeneratedNever(); - }); - } + var all = context.Entities2.ToList(); + Assert.Single(all); } + } #endif +#endregion + +#if NET6_0_OR_GREATER + internal class ConventionsDbContext : DbContext + { + public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } + + public ConventionsDbContext(DbContextOptions options) : base(options) + { + } + + protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) + { + configurationBuilder + .Properties() + .HaveConversion(); + configurationBuilder + .Properties() + .HaveConversion(); + } - public class TestDbContext : DbContext + protected override void OnModelCreating(ModelBuilder modelBuilder) { - public DbSet Entities { get; set; } - - public TestDbContext(DbContextOptions options) : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder - .Entity(builder => - { - builder - .Property(x => x.Id) - .HasConversion(new EfCoreIntId.EfCoreValueConverter()) - .ValueGeneratedNever(); - }); - } + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .ValueGeneratedNever(); + }); + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .ValueGeneratedNever(); + }); } + } +#endif - public class TestEntity + internal class TestDbContext : DbContext + { + public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } + + public TestDbContext(DbContextOptions options) : base(options) { - public EfCoreIntId Id { get; set; } } - public class EntityWithNullableId + protected override void OnModelCreating(ModelBuilder modelBuilder) { - public NewtonsoftJsonIntId? Id { get; set; } + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .HasConversion(new ConvertersIntId.EfCoreValueConverter()) + .ValueGeneratedNever(); + }); + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .HasConversion(new ConvertersIntId2.EfCoreValueConverter()) + .ValueGeneratedNever(); + }); } } + + internal class TestEntity + { + public ConvertersIntId Id { get; set; } + } + + internal class EntityWithNullableId + { + public ConvertersIntId? Id { get; set; } + } + + internal class TestEntity2 + { + public ConvertersIntId2 Id { get; set; } + } + + internal class EntityWithNullableId2 + { + public ConvertersIntId2? Id { get; set; } + } + + internal class TypeWithDictionaryKeys + { + public Dictionary Values { get; set; } + } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/LongIdTests.cs b/test/StronglyTypedIds.IntegrationTests/LongIdTests.cs index b2f70dbcb..0c0787312 100644 --- a/test/StronglyTypedIds.IntegrationTests/LongIdTests.cs +++ b/test/StronglyTypedIds.IntegrationTests/LongIdTests.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Dapper; using Microsoft.Data.Sqlite; @@ -30,7 +32,6 @@ public void EmptyValueIsEmpty() Assert.Equal(0, LongId.Empty.Value); } - [Fact] public void DifferentValuesAreUnequal() { @@ -64,17 +65,6 @@ public void DifferentTypesAreUnequal() Assert.NotEqual((object)bar, (object)foo); } - [Fact] - public void CanSerializeToLong_WithNewtonsoftJsonProvider() - { - var foo = new NewtonsoftJsonLongId(123); - - var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedLong = NewtonsoftJsonSerializer.SerializeObject(foo.Value); - - Assert.Equal(serializedFoo, serializedLong); - } - [Fact] public void CanSerializeToNullableInt_WithNewtonsoftJsonProvider() { @@ -87,92 +77,167 @@ public void CanSerializeToNullableInt_WithNewtonsoftJsonProvider() Assert.Null(deserialize.Id); } +#if NET6_0_OR_GREATER [Fact] - public void CanSerializeToLong_WithSystemTextJsonProvider() + public void CanDeserializeDictionaryKeys_WithSystemTextJsonProvider() { - var foo = new SystemTextJsonLongId(123L); + var value = new TypeWithDictionaryKeys() + { + Values = new() + }; + var key = new LongId(123); + value.Values.Add(key, "My Value"); + var opts = new JsonSerializerOptions + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + var serialized = SystemTextJsonSerializer.Serialize(value, opts); + + var expected = $$""" + { + "values": { + "123": "My Value" + } + } + """; + Assert.Equal(serialized, expected); + + var deserialized = SystemTextJsonSerializer.Deserialize(serialized, opts); + + Assert.NotNull(deserialized.Values); + Assert.True(deserialized.Values.ContainsKey(key)); + Assert.Equal("My Value", deserialized.Values[key]); + } +#endif - var serializedFoo = SystemTextJsonSerializer.Serialize(foo); - var serializedLong = SystemTextJsonSerializer.Serialize(foo.Value); + [Fact] + public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() + { + var foo = new LongId(123); - Assert.Equal(serializedFoo, serializedLong); + var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); + + var expected = $"\"{foo.Value}\""; + + Assert.Equal(expected, serialized); } - [Fact] - public void CanDeserializeFromLong_WithNewtonsoftJsonProvider() + [Theory] + [InlineData(123L)] + [InlineData("123")] + public void TypeConverter_CanConvertToAndFrom(object value) { - var value = 123L; - var foo = new NewtonsoftJsonLongId(value); - var serializedLong = NewtonsoftJsonSerializer.SerializeObject(value); + var converter = TypeDescriptor.GetConverter(typeof(LongId)); + var id = converter.ConvertFrom(value); + Assert.IsType(id); + Assert.Equal(new LongId(123), id); + + var reconverted = converter.ConvertTo(id, value.GetType()); + Assert.Equal(value, reconverted); + } - var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedLong); + [Fact] + public void CanCompareDefaults() + { + LongId original = default; + var other = LongId.Empty; - Assert.Equal(foo, deserializedFoo); + var compare1 = original.CompareTo(other); + var compare2 = other.CompareTo(original); + Assert.Equal(compare1, -compare2); } [Fact] - public void CanDeserializeFromLong_WithSystemTextJsonProvider() + public void CanEquateDefaults() { - var value = 123L; - var foo = new SystemTextJsonLongId(value); - var serializedLong = SystemTextJsonSerializer.Serialize(value); + LongId original = default; + var other = LongId.Empty; - var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedLong); + var equals1 = (original as IEquatable).Equals(other); + var equals2 = (other as IEquatable).Equals(original); - Assert.Equal(foo, deserializedFoo); + Assert.Equal(equals1, equals2); } [Fact] - public void CanSerializeToLong_WithBothJsonConverters() + public void ImplementsInterfaces() { - var foo = new BothJsonLongId(123L); + Assert.IsAssignableFrom>(LongId.Empty); + Assert.IsAssignableFrom>(LongId.Empty); - var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedLong1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value); +#pragma warning disable 184 +#pragma warning disable CS0183 + Assert.True(LongId.Empty is IComparable); + Assert.True(LongId.Empty is IEquatable); +#pragma warning restore CS0183 +#pragma warning restore 184 + +#if NET6_0_OR_GREATER + Assert.IsAssignableFrom(LongId.Empty); +#endif +#if NET7_0_OR_GREATER + // doesn't compile if doesn't implement it + ParseAs("123"); + ParseSpan("123".AsSpan()); - var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); - var serializedLong2 = SystemTextJsonSerializer.Serialize(foo.Value); + T ParseAs(string s) where T : IParsable + { + return T.Parse(s, null); + } - Assert.Equal(serializedFoo1, serializedLong1); - Assert.Equal(serializedFoo2, serializedLong2); + T ParseSpan(ReadOnlySpan s) where T : ISpanParsable + { + return T.Parse(s, null); + } +#endif } +#region ConvertersLongId [Fact] - public void WhenNoJsonConverter_SystemTextJsonSerializesWithValueProperty() + public void CanSerializeToLong_WithNewtonsoftJsonProvider() { - var foo = new NoJsonLongId(123); + var foo = new ConvertersLongId(123); - var serialized = SystemTextJsonSerializer.Serialize(foo); - - var expected = "{\"Value\":" + foo.Value + "}"; + var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedLong = NewtonsoftJsonSerializer.SerializeObject(foo.Value); - Assert.Equal(expected, serialized); + Assert.Equal(serializedFoo, serializedLong); } [Fact] - public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() + public void CanSerializeToLong_WithSystemTextJsonProvider() { - var foo = new NoJsonLongId(123); + var foo = new ConvertersLongId(123L); - var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); - - var expected = $"\"{foo.Value}\""; + var serializedFoo = SystemTextJsonSerializer.Serialize(foo); + var serializedLong = SystemTextJsonSerializer.Serialize(foo.Value); - Assert.Equal(expected, serialized); + Assert.Equal(serializedFoo, serializedLong); } [Fact] - public void WhenNoTypeConverter_SerializesWithValueProperty() + public void CanDeserializeFromLong_WithNewtonsoftJsonProvider() { - var foo = new NoConverterLongId(123); + var value = 123L; + var foo = new ConvertersLongId(value); + var serializedLong = NewtonsoftJsonSerializer.SerializeObject(value); - var newtonsoft = SystemTextJsonSerializer.Serialize(foo); - var systemText = SystemTextJsonSerializer.Serialize(foo); + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedLong); + + Assert.Equal(foo, deserializedFoo); + } + + [Fact] + public void CanDeserializeFromLong_WithSystemTextJsonProvider() + { + var value = 123L; + var foo = new ConvertersLongId(value); + var serializedLong = SystemTextJsonSerializer.Serialize(value); - var expected = "{\"Value\":" + foo.Value + "}"; + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedLong); - Assert.Equal(expected, newtonsoft); - Assert.Equal(expected, systemText); + Assert.Equal(foo, deserializedFoo); } [Fact] @@ -185,7 +250,7 @@ public void WhenEfCoreValueConverterUsesValueConverter() .UseSqlite(connection) .Options; - var original = new TestEntity { Id = new EfCoreLongId(123) }; + var original = new TestEntity { Id = new ConvertersLongId(123) }; using (var context = new TestDbContext(options)) { context.Database.EnsureCreated(); @@ -207,68 +272,128 @@ public async Task WhenDapperValueConverterUsesValueConverter() using var connection = new SqliteConnection("DataSource=:memory:"); await connection.OpenAsync(); - var results = await connection.QueryAsync("SELECT 123"); + var results = await connection.QueryAsync("SELECT 123"); var value = Assert.Single(results); - Assert.Equal(value, new DapperLongId(123)); + Assert.Equal(value, new ConvertersLongId(123)); } - [Theory] - [InlineData(123L)] - [InlineData("123")] - public void TypeConverter_CanConvertToAndFrom(object value) +#if NET6_0_OR_GREATER + [Fact] + public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonLongId)); - var id = converter.ConvertFrom(value); - Assert.IsType(id); - Assert.Equal(new NoJsonLongId(123), id); + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); - var reconverted = converter.ConvertTo(id, value.GetType()); - Assert.Equal(value, reconverted); + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + using (var context = new ConventionsDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities.Add( + new TestEntity { Id = new ConvertersLongId(123) }); + context.SaveChanges(); + } + using (var context = new ConventionsDbContext(options)) + { + var all = context.Entities.ToList(); + Assert.Single(all); + } } +#endif +#endregion + +#region ConvertersLongId2 [Fact] - public void CanCompareDefaults() + public void CanSerializeToLong_WithMultiTemplates_WithNewtonsoftJsonProvider() { - ComparableLongId original = default; - var other = ComparableLongId.Empty; + var foo = new ConvertersLongId2(123); - var compare1 = original.CompareTo(other); - var compare2 = other.CompareTo(original); - Assert.Equal(compare1, -compare2); + var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedLong = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + + Assert.Equal(serializedFoo, serializedLong); } [Fact] - public void CanEquateDefaults() + public void CanSerializeToLong_WithMultiTemplates_WithSystemTextJsonProvider() { - EquatableLongId original = default; - var other = EquatableLongId.Empty; + var foo = new ConvertersLongId2(123L); - var equals1 = (original as IEquatable).Equals(other); - var equals2 = (other as IEquatable).Equals(original); + var serializedFoo = SystemTextJsonSerializer.Serialize(foo); + var serializedLong = SystemTextJsonSerializer.Serialize(foo.Value); - Assert.Equal(equals1, equals2); + Assert.Equal(serializedFoo, serializedLong); } [Fact] - public void ImplementsInterfaces() + public void CanDeserializeFromLong_WithMultiTemplates_WithNewtonsoftJsonProvider() { - Assert.IsAssignableFrom>(BothLongId.Empty); - Assert.IsAssignableFrom>(BothLongId.Empty); + var value = 123L; + var foo = new ConvertersLongId2(value); + var serializedLong = NewtonsoftJsonSerializer.SerializeObject(value); - Assert.IsAssignableFrom>(EquatableLongId.Empty); - Assert.IsAssignableFrom>(ComparableLongId.Empty); + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedLong); -#pragma warning disable 184 - Assert.False(LongId.Empty is IComparable); - Assert.False(LongId.Empty is IEquatable); -#pragma warning restore 184 + Assert.Equal(foo, deserializedFoo); + } + + [Fact] + public void CanDeserializeFromLong_WithMultiTemplates_WithSystemTextJsonProvider() + { + var value = 123L; + var foo = new ConvertersLongId2(value); + var serializedLong = SystemTextJsonSerializer.Serialize(value); + + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedLong); + + Assert.Equal(foo, deserializedFoo); } + [Fact] + public void WhenEfCoreValueConverter_WithMultiTemplates_UsesValueConverter() + { + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + var original = new TestEntity2 { Id = new ConvertersLongId2(123) }; + using (var context = new TestDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities2.Add(original); + context.SaveChanges(); + } + + using (var context = new TestDbContext(options)) + { + var all = context.Entities2.ToList(); + var retrieved = Assert.Single(all); + Assert.Equal(original.Id, retrieved.Id); + } + } + + [Fact] + public async Task WhenDapperValueConverter_WithMultiTemplates_UsesValueConverter() + { + using var connection = new SqliteConnection("DataSource=:memory:"); + await connection.OpenAsync(); + + var results = await connection.QueryAsync("SELECT 123"); + + var value = Assert.Single(results); + Assert.Equal(value, new ConvertersLongId2(123)); + } #if NET6_0_OR_GREATER [Fact] - public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() + public void WhenConventionBasedEfCoreValueConverter_WithMultiTemplates_UsesValueConverter() { var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); @@ -280,20 +405,24 @@ public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() using (var context = new ConventionsDbContext(options)) { context.Database.EnsureCreated(); - context.Entities.Add( - new TestEntity { Id = new EfCoreLongId(123) }); + context.Entities2.Add( + new TestEntity2 { Id = new ConvertersLongId2(123) }); context.SaveChanges(); } using (var context = new ConventionsDbContext(options)) { - var all = context.Entities.ToList(); + var all = context.Entities2.ToList(); Assert.Single(all); } } - - public class ConventionsDbContext : DbContext +#endif +#endregion + +#if NET6_0_OR_GREATER + internal class ConventionsDbContext : DbContext { public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } public ConventionsDbContext(DbContextOptions options) : base(options) { @@ -302,8 +431,11 @@ public ConventionsDbContext(DbContextOptions options) : base(options) protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder - .Properties() - .HaveConversion(); + .Properties() + .HaveConversion(); + configurationBuilder + .Properties() + .HaveConversion(); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -315,13 +447,21 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .Property(x => x.Id) .ValueGeneratedNever(); }); + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .ValueGeneratedNever(); + }); } } #endif - public class TestDbContext : DbContext + internal class TestDbContext : DbContext { public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } public TestDbContext(DbContextOptions options) : base(options) { @@ -334,20 +474,43 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { builder .Property(x => x.Id) - .HasConversion(new EfCoreLongId.EfCoreValueConverter()) + .HasConversion(new ConvertersLongId.EfCoreValueConverter()) + .ValueGeneratedNever(); + }); + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .HasConversion(new ConvertersLongId2.EfCoreValueConverter()) .ValueGeneratedNever(); }); } } - public class TestEntity + internal class TestEntity + { + public ConvertersLongId Id { get; set; } + } + + internal class EntityWithNullableId + { + public ConvertersLongId? Id { get; set; } + } + + internal class TestEntity2 + { + public ConvertersLongId2 Id { get; set; } + } + + internal class EntityWithNullableId2 { - public EfCoreLongId Id { get; set; } + public ConvertersLongId2? Id { get; set; } } - public class EntityWithNullableId + internal class TypeWithDictionaryKeys { - public NewtonsoftJsonLongId? Id { get; set; } + public Dictionary Values { get; set; } } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/MassTransitNewIdTests.cs b/test/StronglyTypedIds.IntegrationTests/MassTransitNewIdTests.cs index e6dce6d74..675ecad98 100644 --- a/test/StronglyTypedIds.IntegrationTests/MassTransitNewIdTests.cs +++ b/test/StronglyTypedIds.IntegrationTests/MassTransitNewIdTests.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Dapper; using MassTransit; @@ -76,35 +78,59 @@ public void CantCreateEmptyGeneratedId1() } [Fact] - public void CanSerializeToNewId_WithTypeConverter() + public void CanSerializeToNewId_WithSystemTextJsonProvider() { - var foo = NewtonsoftJsonNewIdId.New(); + var foo = NewIdId1.New(); - var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedNewId = NewtonsoftJsonSerializer.SerializeObject(foo.Value.ToGuid()); + var serializedFoo = SystemTextJsonSerializer.Serialize(foo); + var serializedNewId = SystemTextJsonSerializer.Serialize(foo.Value.ToGuid().ToString()); Assert.Equal(serializedFoo, serializedNewId); } +#if NET6_0_OR_GREATER [Fact] - public void CanSerializeToNewId_WithSystemTextJsonProvider() + public void CanDeserializeDictionaryKeys_WithSystemTextJsonProvider() { - var foo = SystemTextJsonNewIdId.New(); - - var serializedFoo = SystemTextJsonSerializer.Serialize(foo); - var serializedNewId = SystemTextJsonSerializer.Serialize(foo.Value.ToGuid().ToString()); + var value = new TypeWithDictionaryKeys() + { + Values = new() + }; - Assert.Equal(serializedFoo, serializedNewId); + var key = new NewIdId1(NewId.FromGuid(Guid.Parse("78104553-f1cd-41ec-bcb6-d3a8ff8d994d"))); + value.Values.Add(key, "My Value"); + var opts = new JsonSerializerOptions + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + var serialized = SystemTextJsonSerializer.Serialize(value, opts); + + var expected = $$""" + { + "values": { + "78104553-f1cd-41ec-bcb6-d3a8ff8d994d": "My Value" + } + } + """; + Assert.Equal(serialized, expected); + + var deserialized = SystemTextJsonSerializer.Deserialize(serialized, opts); + + Assert.NotNull(deserialized.Values); + Assert.True(deserialized.Values.ContainsKey(key)); + Assert.Equal("My Value", deserialized.Values[key]); } +#endif [Fact] public void CanDeserializeFromNewId_WithNewtonsoftJsonProvider() { var value = NewId.Next(); - var foo = new NewtonsoftJsonNewIdId(value); + var foo = new NewIdId1(value); var serializedNewId = NewtonsoftJsonSerializer.SerializeObject(value.ToGuid()); - var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedNewId); + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedNewId); Assert.Equal(foo, deserializedFoo); } @@ -125,67 +151,14 @@ public void CanSerializeToNullableInt_WithNewtonsoftJsonProvider() public void CanDeserializeFromNewId_WithSystemTextJsonProvider() { var value = NewId.Next(); - var foo = new SystemTextJsonNewIdId(value); + var foo = new NewIdId1(value); var serializedNewId = SystemTextJsonSerializer.Serialize(value.ToGuid()); - var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedNewId); + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedNewId); Assert.Equal(foo, deserializedFoo); } - [Fact] - public void CanSerializeToNewId_WithBothJsonConverters() - { - var foo = BothJsonNewIdId.New(); - - var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedNewId1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value.ToGuid().ToString()); - - var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); - var serializedNewId2 = SystemTextJsonSerializer.Serialize(foo.Value.ToGuid().ToString()); - - Assert.Equal(serializedFoo1, serializedNewId1); - Assert.Equal(serializedFoo2, serializedNewId2); - } - - [Fact] - public void WhenNoJsonConverter_SystemTextJsonSerializesWithValueProperty() - { - var foo = NoJsonNewIdId.New(); - - var serialized = SystemTextJsonSerializer.Serialize(foo); - - var expected = "{\"Value\":" + SystemTextJsonSerializer.Serialize(foo.Value) + "}"; - - Assert.Equal(expected, serialized); - } - - [Fact] - public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() - { - var foo = NoJsonNewIdId.New(); - - var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); - - var expected = $"\"{foo.Value.ToGuid()}\""; - - Assert.Equal(expected, serialized); - } - - [Fact] - public void WhenNoTypeConverter_SerializesWithValueProperty() - { - var foo = NoConverterNewIdId.New(); - - var newtonsoft = SystemTextJsonSerializer.Serialize(foo); - var systemText = SystemTextJsonSerializer.Serialize(foo); - - var expected = "{\"Value\":" + SystemTextJsonSerializer.Serialize(foo.Value) + "}"; - - Assert.Equal(expected, newtonsoft); - Assert.Equal(expected, systemText); - } - [Fact] public void WhenEfCoreValueConverterUsesValueConverter() { @@ -200,7 +173,7 @@ public void WhenEfCoreValueConverterUsesValueConverter() { context.Database.EnsureCreated(); context.Entities.Add( - new TestEntity { Id = EfCoreNewIdId.New() }); + new TestEntity { Id = NewIdId1.New() }); context.SaveChanges(); } using (var context = new TestDbContext(options)) @@ -216,20 +189,20 @@ public async Task WhenDapperValueConverterUsesValueConverter() using var connection = new SqliteConnection("DataSource=:memory:"); await connection.OpenAsync(); - var results = await connection.QueryAsync("SELECT '5640dad4-862a-4738-9e3c-c76dc227eb66'"); + var results = await connection.QueryAsync("SELECT '5640dad4-862a-4738-9e3c-c76dc227eb66'"); var value = Assert.Single(results); - Assert.Equal(new DapperNewIdId(NewId.FromGuid(Guid.Parse("5640dad4-862a-4738-9e3c-c76dc227eb66"))), value); + Assert.Equal(new NewIdId1(NewId.FromGuid(Guid.Parse("5640dad4-862a-4738-9e3c-c76dc227eb66"))), value); } [Theory] [InlineData("78104553-f1cd-41ec-bcb6-d3a8ff8d994d")] public void TypeConverter_CanConvertToAndFrom(string value) { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonNewIdId)); + var converter = TypeDescriptor.GetConverter(typeof(NewIdId1)); var id = converter.ConvertFrom(value); - Assert.IsType(id); - Assert.Equal(new NoJsonNewIdId(NewId.FromGuid(Guid.Parse(value))), id); + Assert.IsType(id); + Assert.Equal(new NewIdId1(NewId.FromGuid(Guid.Parse(value))), id); var reconverted = converter.ConvertTo(id, value.GetType()); Assert.Equal(value, reconverted); @@ -238,8 +211,8 @@ public void TypeConverter_CanConvertToAndFrom(string value) [Fact] public void CanCompareDefaults() { - ComparableNewIdId original = default; - var other = ComparableNewIdId.Empty; + NewIdId1 original = default; + var other = NewIdId1.Empty; var compare1 = original.CompareTo(other); var compare2 = other.CompareTo(original); @@ -249,11 +222,11 @@ public void CanCompareDefaults() [Fact] public void CanEquateDefaults() { - EquatableNewIdId original = default; - var other = EquatableNewIdId.Empty; + NewIdId1 original = default; + var other = NewIdId1.Empty; - var equals1 = (original as IEquatable).Equals(other); - var equals2 = (other as IEquatable).Equals(original); + var equals1 = (original as IEquatable).Equals(other); + var equals2 = (other as IEquatable).Equals(original); Assert.Equal(equals1, equals2); } @@ -261,16 +234,32 @@ public void CanEquateDefaults() [Fact] public void ImplementsInterfaces() { - Assert.IsAssignableFrom>(BothNewIdId.Empty); - Assert.IsAssignableFrom>(BothNewIdId.Empty); - - Assert.IsAssignableFrom>(EquatableNewIdId.Empty); - Assert.IsAssignableFrom>(ComparableNewIdId.Empty); + Assert.IsAssignableFrom>(NewIdId1.Empty); + Assert.IsAssignableFrom>(NewIdId1.Empty); +#pragma warning disable CS0183 #pragma warning disable 184 - Assert.False(NewIdId1.Empty is IComparable); - Assert.False(NewIdId1.Empty is IEquatable); + Assert.True(NewIdId1.Empty is IComparable); + Assert.True(NewIdId1.Empty is IEquatable); #pragma warning restore 184 +#pragma warning restore CS0183 + +#if NET6_0_OR_GREATER + Assert.IsAssignableFrom(NewIdId1.Empty); +#endif +#if NET7_0_OR_GREATER + // doesn't compile if doesn't implement it + ParseAs(Guid.NewGuid().ToString()); + ParseSpan(Guid.NewGuid().ToString().AsSpan()); + + T ParseAs(string s) where T: IParsable { + return T.Parse(s, null); + } + + T ParseSpan(ReadOnlySpan s) where T: ISpanParsable { + return T.Parse(s, null); + } +#endif } @@ -289,7 +278,7 @@ public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() { context.Database.EnsureCreated(); context.Entities.Add( - new TestEntity { Id = EfCoreNewIdId.New() }); + new TestEntity { Id = NewIdId1.New() }); context.SaveChanges(); } using (var context = new ConventionsDbContext(options)) @@ -299,7 +288,7 @@ public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() } } - public class ConventionsDbContext : DbContext + internal class ConventionsDbContext : DbContext { public DbSet Entities { get; set; } @@ -310,8 +299,8 @@ public ConventionsDbContext(DbContextOptions options) : base(options) protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder - .Properties() - .HaveConversion(); + .Properties() + .HaveConversion(); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -327,7 +316,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } #endif - public class TestDbContext : DbContext + internal class TestDbContext : DbContext { public DbSet Entities { get; set; } @@ -342,20 +331,25 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { builder .Property(x => x.Id) - .HasConversion(new EfCoreNewIdId.EfCoreValueConverter()) + .HasConversion(new NewIdId1.EfCoreValueConverter()) .ValueGeneratedNever(); }); } } - public class TestEntity + internal class TestEntity + { + public NewIdId1 Id { get; set; } + } + + internal class EntityWithNullableId { - public EfCoreNewIdId Id { get; set; } + public NewIdId1? Id { get; set; } } - public class EntityWithNullableId + internal class TypeWithDictionaryKeys { - public NewtonsoftJsonNewIdId? Id { get; set; } + public Dictionary Values { get; set; } } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/NullableStringIdTests.cs b/test/StronglyTypedIds.IntegrationTests/NullableStringIdTests.cs index c6835af82..35ab555c3 100644 --- a/test/StronglyTypedIds.IntegrationTests/NullableStringIdTests.cs +++ b/test/StronglyTypedIds.IntegrationTests/NullableStringIdTests.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Dapper; using Microsoft.Data.Sqlite; @@ -14,6 +16,14 @@ namespace StronglyTypedIds.IntegrationTests { public class NullableStringIdTests { + [Fact] + public void CanUseNull() + { + var foo1 = new NullableStringId(null); + + Assert.Null(foo1.Value); + } + [Fact] public void SameValuesAreEqual() { @@ -67,7 +77,7 @@ public void DifferentTypesAreUnequal() [Fact] public void CanSerializeToString_WithNewtonsoftJsonProvider() { - var foo = new NewtonsoftJsonNullableStringId("123"); + var foo = new NullableStringId("123"); var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); var serializedString = NewtonsoftJsonSerializer.SerializeObject(foo.Value); @@ -92,7 +102,7 @@ public void CanSerializeToNullableId_WithNewtonsoftJsonProvider() [Fact] public void CanSerializeToString_WithSystemTextJsonProvider() { - var foo = new SystemTextJsonNullableStringId("123"); + var foo = new NullableStringId("123"); var serializedFoo = SystemTextJsonSerializer.Serialize(foo); var serializedString = SystemTextJsonSerializer.Serialize(foo.Value); @@ -100,14 +110,48 @@ public void CanSerializeToString_WithSystemTextJsonProvider() Assert.Equal(serializedFoo, serializedString); } +#if NET6_0_OR_GREATER + [Fact] + public void CanDeserializeDictionaryKeys_WithSystemTextJsonProvider() + { + var value = new TypeWithDictionaryKeys() + { + Values = new() + }; + + var key = new NullableStringId("78104553-f1cd-41ec-bcb6-d3a8ff8d994d"); + value.Values.Add(key, "My Value"); + var opts = new JsonSerializerOptions + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + var serialized = SystemTextJsonSerializer.Serialize(value, opts); + + var expected = $$""" + { + "values": { + "78104553-f1cd-41ec-bcb6-d3a8ff8d994d": "My Value" + } + } + """; + Assert.Equal(serialized, expected); + + var deserialized = SystemTextJsonSerializer.Deserialize(serialized, opts); + + Assert.NotNull(deserialized.Values); + Assert.True(deserialized.Values.ContainsKey(key)); + Assert.Equal("My Value", deserialized.Values[key]); + } +#endif [Fact] public void CanDeserializeFromString_WithNewtonsoftJsonProvider() { var value = "123"; - var foo = new NewtonsoftJsonNullableStringId(value); + var foo = new NullableStringId(value); var serializedString = NewtonsoftJsonSerializer.SerializeObject(value); - var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedString); + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedString); Assert.Equal(foo, deserializedFoo); } @@ -116,45 +160,18 @@ public void CanDeserializeFromString_WithNewtonsoftJsonProvider() public void CanDeserializeFromString_WithSystemTextJsonProvider() { var value = "123"; - var foo = new SystemTextJsonNullableStringId(value); + var foo = new NullableStringId(value); var serializedString = SystemTextJsonSerializer.Serialize(value); - var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedString); + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedString); Assert.Equal(foo, deserializedFoo); } - [Fact] - public void CanSerializeToString_WithBothJsonConverters() - { - var foo = new BothJsonNullableStringId("123"); - - var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedString1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value); - - var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); - var serializedString2 = SystemTextJsonSerializer.Serialize(foo.Value); - - Assert.Equal(serializedFoo1, serializedString1); - Assert.Equal(serializedFoo2, serializedString2); - } - - [Fact] - public void WhenNoJsonConverter_SystemTextJsonSerializesWithValueProperty() - { - var foo = new NoJsonNullableStringId("123"); - - var serialized = SystemTextJsonSerializer.Serialize(foo); - - var expected = "{\"Value\":\"" + foo.Value + "\"}"; - - Assert.Equal(expected, serialized); - } - [Fact] public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() { - var foo = new NoJsonNullableStringId("123"); + var foo = new NullableStringId("123"); var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); @@ -163,20 +180,6 @@ public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() Assert.Equal(expected, serialized); } - [Fact] - public void WhenNoTypeConverter_SerializesWithValueProperty() - { - var foo = new NoConvertersNullableStringId("123"); - - var newtonsoft = SystemTextJsonSerializer.Serialize(foo); - var systemText = SystemTextJsonSerializer.Serialize(foo); - - var expected = "{\"Value\":\"" + foo.Value + "\"}"; - - Assert.Equal(expected, newtonsoft); - Assert.Equal(expected, systemText); - } - [Fact] public void WhenEfCoreValueConverterUsesValueConverter() { @@ -187,7 +190,7 @@ public void WhenEfCoreValueConverterUsesValueConverter() .UseSqlite(connection) .Options; - var original = new TestEntity { Id = Guid.NewGuid(), Name = new EfCoreNullableStringId("some name") }; + var original = new TestEntity { Id = Guid.NewGuid(), Name = new NullableStringId("some name") }; using (var context = new TestDbContext(options)) { context.Database.EnsureCreated(); @@ -210,10 +213,10 @@ public async Task WhenDapperValueConverterUsesValueConverter() using var connection = new SqliteConnection("DataSource=:memory:"); await connection.OpenAsync(); - var results = await connection.QueryAsync("SELECT 'this is a value'"); + var results = await connection.QueryAsync("SELECT 'this is a value'"); var value = Assert.Single(results); - Assert.Equal(value, new DapperNullableStringId("this is a value")); + Assert.Equal(value, new NullableStringId("this is a value")); } [Theory] @@ -221,10 +224,10 @@ public async Task WhenDapperValueConverterUsesValueConverter() [InlineData("some value")] public void TypeConverter_CanConvertToAndFrom(object value) { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonNullableStringId)); + var converter = TypeDescriptor.GetConverter(typeof(NullableStringId)); var id = converter.ConvertFrom(value); - Assert.IsType(id); - Assert.Equal(new NoJsonNullableStringId(value?.ToString()), id); + Assert.IsType(id); + Assert.Equal(new NullableStringId(value?.ToString()), id); var reconverted = converter.ConvertTo(id, value.GetType()); Assert.Equal(value, reconverted); @@ -233,8 +236,8 @@ public void TypeConverter_CanConvertToAndFrom(object value) [Fact] public void CanCompareDefaults() { - ComparableNullableStringId original = default; - var other = ComparableNullableStringId.Empty; + NullableStringId original = default; + var other = NullableStringId.Empty; var compare1 = original.CompareTo(other); var compare2 = other.CompareTo(original); @@ -244,11 +247,11 @@ public void CanCompareDefaults() [Fact] public void CanEquateDefaults() { - EquatableNullableStringId original = default; - var other = EquatableNullableStringId.Empty; + NullableStringId original = default; + var other = NullableStringId.Empty; - var equals1 = (original as IEquatable).Equals(other); - var equals2 = (other as IEquatable).Equals(original); + var equals1 = (original as IEquatable).Equals(other); + var equals2 = (other as IEquatable).Equals(original); Assert.Equal(equals1, equals2); } @@ -256,16 +259,34 @@ public void CanEquateDefaults() [Fact] public void ImplementsInterfaces() { - Assert.IsAssignableFrom>(BothNullableStringId.Empty); - Assert.IsAssignableFrom>(BothNullableStringId.Empty); - - Assert.IsAssignableFrom>(EquatableNullableStringId.Empty); - Assert.IsAssignableFrom>(ComparableNullableStringId.Empty); + Assert.IsAssignableFrom>(NullableStringId.Empty); + Assert.IsAssignableFrom>(NullableStringId.Empty); #pragma warning disable 184 - Assert.False(NullableStringId.Empty is IComparable); - Assert.False(NullableStringId.Empty is IEquatable); +#pragma warning disable CS0183 + Assert.True(NullableStringId.Empty is IComparable); + Assert.True(NullableStringId.Empty is IEquatable); +#pragma warning restore CS0183 #pragma warning restore 184 + +#if NET6_0_OR_GREATER + Assert.IsAssignableFrom(NullableStringId.Empty); +#endif +#if NET7_0_OR_GREATER + // doesn't compile if doesn't implement it + ParseAs("123"); + ParseSpan("123".AsSpan()); + + T ParseAs(string s) where T : IParsable + { + return T.Parse(s, null); + } + + T ParseSpan(ReadOnlySpan s) where T : ISpanParsable + { + return T.Parse(s, null); + } +#endif } [Fact] @@ -303,23 +324,11 @@ public void NullHashCodes() Assert.NotEqual(value1.GetHashCode(), value4.GetHashCode()); } - [Fact] - public void NullSerializesAsExpectedWithoutConverters() - { - var expected = "{\"Value\":null}"; - var value = new NoConvertersNullableStringId(null); - - var json = SystemTextJsonSerializer.Serialize(value); - var systemText = SystemTextJsonSerializer.Serialize(value); - Assert.Equal(expected, json); - Assert.Equal(expected, systemText); - } - [Fact] public void NullSerializesAsExpectedWithConverters() { var expected = "null"; - var value = new BothJsonNullableStringId(null); + var value = new NullableStringId(null); var json = SystemTextJsonSerializer.Serialize(value); var systemText = SystemTextJsonSerializer.Serialize(value); @@ -330,10 +339,10 @@ public void NullSerializesAsExpectedWithConverters() [Fact] public void TypeConverterConvertsNullAsExpected() { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonNullableStringId)); + var converter = TypeDescriptor.GetConverter(typeof(NullableStringId)); var id = converter.ConvertFrom(null); - Assert.IsType(id); - Assert.Equal(new NoJsonNullableStringId(null), id); + Assert.IsType(id); + Assert.Equal(new NullableStringId(null), id); var reconverted = converter.ConvertTo(id, typeof(string)); Assert.Null(reconverted); @@ -350,7 +359,7 @@ public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() .UseSqlite(connection) .Options; - var original = new TestEntity { Id = Guid.NewGuid(), Name = new EfCoreNullableStringId("some name") }; + var original = new TestEntity { Id = Guid.NewGuid(), Name = new NullableStringId("some name") }; using (var context = new ConventionsDbContext(options)) { context.Database.EnsureCreated(); @@ -367,7 +376,7 @@ public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() } } - public class ConventionsDbContext : DbContext + internal class ConventionsDbContext : DbContext { public DbSet Entities { get; set; } @@ -378,8 +387,8 @@ public ConventionsDbContext(DbContextOptions options) : base(options) protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder - .Properties() - .HaveConversion(); + .Properties() + .HaveConversion(); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -395,7 +404,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } #endif - public class TestDbContext : DbContext + internal class TestDbContext : DbContext { public DbSet Entities { get; set; } @@ -410,22 +419,27 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { builder .Property(x => x.Name) - .HasConversion(new EfCoreNullableStringId.EfCoreValueConverter()) + .HasConversion(new NullableStringId.EfCoreValueConverter()) .ValueGeneratedNever(); }); } } - public class TestEntity + internal class TestEntity { public Guid Id { get; set; } - public EfCoreNullableStringId Name { get; set; } + public NullableStringId Name { get; set; } } - public class EntityWithNullableId + internal class EntityWithNullableId + { + public NullableStringId? Id { get; set; } + } + + internal class TypeWithDictionaryKeys { - public NewtonsoftJsonNullableStringId? Id { get; set; } + public Dictionary Values { get; set; } } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/StringIdTests.cs b/test/StronglyTypedIds.IntegrationTests/StringIdTests.cs index 0cc76b44d..9cc6e3ea0 100644 --- a/test/StronglyTypedIds.IntegrationTests/StringIdTests.cs +++ b/test/StronglyTypedIds.IntegrationTests/StringIdTests.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Text.Json; using System.Threading.Tasks; using Dapper; using Microsoft.Data.Sqlite; @@ -36,7 +38,6 @@ public void EmptyValueIsEmpty() Assert.Equal(StringId.Empty.Value, string.Empty); } - [Fact] public void DifferentValuesAreUnequal() { @@ -70,17 +71,6 @@ public void DifferentTypesAreUnequal() Assert.NotEqual((object)bar, (object)foo); } - [Fact] - public void CanSerializeToString_WithNewtonsoftJsonProvider() - { - var foo = new NewtonsoftJsonStringId("123"); - - var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedString = NewtonsoftJsonSerializer.SerializeObject(foo.Value); - - Assert.Equal(serializedFoo, serializedString); - } - [Fact] public void CanSerializeToNullableId_WithNewtonsoftJsonProvider() { @@ -93,92 +83,168 @@ public void CanSerializeToNullableId_WithNewtonsoftJsonProvider() Assert.Null(deserialize.Id); } +#if NET6_0_OR_GREATER [Fact] - public void CanSerializeToString_WithSystemTextJsonProvider() + public void CanDeserializeDictionaryKeys_WithSystemTextJsonProvider() + { + var value = new TypeWithDictionaryKeys() + { + Values = new() + }; + + var key = new StringId("78104553-f1cd-41ec-bcb6-d3a8ff8d994d"); + value.Values.Add(key, "My Value"); + var opts = new JsonSerializerOptions + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + }; + var serialized = SystemTextJsonSerializer.Serialize(value, opts); + + var expected = $$""" + { + "values": { + "78104553-f1cd-41ec-bcb6-d3a8ff8d994d": "My Value" + } + } + """; + Assert.Equal(serialized, expected); + + var deserialized = SystemTextJsonSerializer.Deserialize(serialized, opts); + + Assert.NotNull(deserialized.Values); + Assert.True(deserialized.Values.ContainsKey(key)); + Assert.Equal("My Value", deserialized.Values[key]); + } +#endif + + [Fact] + public void ImplementsInterfaces() { - var foo = new SystemTextJsonStringId("123"); + Assert.IsAssignableFrom>(StringId.Empty); + Assert.IsAssignableFrom>(StringId.Empty); - var serializedFoo = SystemTextJsonSerializer.Serialize(foo); - var serializedString = SystemTextJsonSerializer.Serialize(foo.Value); +#pragma warning disable 184 +#pragma warning disable CS0183 + Assert.True(StringId.Empty is IComparable); + Assert.True(StringId.Empty is IEquatable); +#pragma warning restore CS0183 +#pragma warning restore 184 - Assert.Equal(serializedFoo, serializedString); +#if NET6_0_OR_GREATER + Assert.IsAssignableFrom(StringId.Empty); +#endif +#if NET7_0_OR_GREATER + // doesn't compile if doesn't implement it + ParseAs("123"); + ParseSpan("123".AsSpan()); + + T ParseAs(string s) where T : IParsable + { + return T.Parse(s, null); + } + + T ParseSpan(ReadOnlySpan s) where T : ISpanParsable + { + return T.Parse(s, null); + } +#endif } - [Fact] - public void CanDeserializeFromString_WithNewtonsoftJsonProvider() + [Theory] + [InlineData("")] + [InlineData("some value")] + public void TypeConverter_CanConvertToAndFrom(object value) { - var value = "123"; - var foo = new NewtonsoftJsonStringId(value); - var serializedString = NewtonsoftJsonSerializer.SerializeObject(value); + var converter = TypeDescriptor.GetConverter(typeof(StringId)); + var id = converter.ConvertFrom(value); + Assert.IsType(id); + Assert.Equal(new StringId(value?.ToString()), id); - var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedString); + var reconverted = converter.ConvertTo(id, value.GetType()); + Assert.Equal(value, reconverted); + } - Assert.Equal(foo, deserializedFoo); + [Fact] + public void CanCompareDefaults() + { + StringId original = default; + var other = StringId.Empty; + + var compare1 = original.CompareTo(other); + var compare2 = other.CompareTo(original); + Assert.Equal(compare1, -compare2); } [Fact] - public void CanDeserializeFromString_WithSystemTextJsonProvider() + public void CanEquateDefaults() { - var value = "123"; - var foo = new SystemTextJsonStringId(value); - var serializedString = SystemTextJsonSerializer.Serialize(value); + StringId original = default; + var other = StringId.Empty; - var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedString); + var equals1 = (original as IEquatable).Equals(other); + var equals2 = (other as IEquatable).Equals(original); - Assert.Equal(foo, deserializedFoo); + Assert.Equal(equals1, equals2); } +#region ConvertersStringId [Fact] - public void CanSerializeToString_WithBothJsonConverters() + public void CanSerializeToString_WithNewtonsoftJsonProvider() { - var foo = new BothJsonStringId("123"); - - var serializedFoo1 = NewtonsoftJsonSerializer.SerializeObject(foo); - var serializedString1 = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + var foo = new ConvertersStringId("123"); - var serializedFoo2 = SystemTextJsonSerializer.Serialize(foo); - var serializedString2 = SystemTextJsonSerializer.Serialize(foo.Value); + var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedString = NewtonsoftJsonSerializer.SerializeObject(foo.Value); - Assert.Equal(serializedFoo1, serializedString1); - Assert.Equal(serializedFoo2, serializedString2); + Assert.Equal(serializedFoo, serializedString); } [Fact] - public void WhenNoJsonConverter_SystemTextJsonSerializesWithValueProperty() + public void CanSerializeToString_WithSystemTextJsonProvider() { - var foo = new NoJsonStringId("123"); + var foo = new ConvertersStringId("123"); - var serialized = SystemTextJsonSerializer.Serialize(foo); - - var expected = "{\"Value\":\"" + foo.Value + "\"}"; + var serializedFoo = SystemTextJsonSerializer.Serialize(foo); + var serializedString = SystemTextJsonSerializer.Serialize(foo.Value); - Assert.Equal(expected, serialized); + Assert.Equal(serializedFoo, serializedString); } [Fact] - public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() + public void CanDeserializeFromString_WithNewtonsoftJsonProvider() { - var foo = new NoJsonStringId("123"); + var value = "123"; + var foo = new ConvertersStringId(value); + var serializedString = NewtonsoftJsonSerializer.SerializeObject(value); - var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedString); - var expected = "\"" + foo.Value + "\""; + Assert.Equal(foo, deserializedFoo); + } - Assert.Equal(expected, serialized); + [Fact] + public void CanDeserializeFromString_WithSystemTextJsonProvider() + { + var value = "123"; + var foo = new ConvertersStringId(value); + var serializedString = SystemTextJsonSerializer.Serialize(value); + + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedString); + + Assert.Equal(foo, deserializedFoo); } [Fact] - public void WhenNoTypeConverter_SerializesWithValueProperty() + public void WhenNoJsonConverter_NewtonsoftSerializesWithoutValueProperty() { - var foo = new NoConvertersStringId("123"); + var foo = new ConvertersStringId("123"); - var newtonsoft = SystemTextJsonSerializer.Serialize(foo); - var systemText = SystemTextJsonSerializer.Serialize(foo); + var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); - var expected = "{\"Value\":\"" + foo.Value + "\"}"; + var expected = "\"" + foo.Value + "\""; - Assert.Equal(expected, newtonsoft); - Assert.Equal(expected, systemText); + Assert.Equal(expected, serialized); } [Fact] @@ -191,7 +257,7 @@ public void WhenEfCoreValueConverterUsesValueConverter() .UseSqlite(connection) .Options; - var original = new TestEntity { Id = Guid.NewGuid(), Name = new EfCoreStringId("some name") }; + var original = new TestEntity { Id = Guid.NewGuid(), Name = new ConvertersStringId("some name") }; using (var context = new TestDbContext(options)) { context.Database.EnsureCreated(); @@ -214,68 +280,143 @@ public async Task WhenDapperValueConverterUsesValueConverter() using var connection = new SqliteConnection("DataSource=:memory:"); await connection.OpenAsync(); - var results = await connection.QueryAsync("SELECT 'this is a value'"); + var results = await connection.QueryAsync("SELECT 'this is a value'"); var value = Assert.Single(results); - Assert.Equal(value, new DapperStringId("this is a value")); + Assert.Equal(value, new ConvertersStringId("this is a value")); } - [Theory] - [InlineData("")] - [InlineData("some value")] - public void TypeConverter_CanConvertToAndFrom(object value) +#if NET6_0_OR_GREATER + [Fact] + public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() { - var converter = TypeDescriptor.GetConverter(typeof(NoJsonStringId)); - var id = converter.ConvertFrom(value); - Assert.IsType(id); - Assert.Equal(new NoJsonStringId(value?.ToString()), id); + var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); - var reconverted = converter.ConvertTo(id, value.GetType()); - Assert.Equal(value, reconverted); + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + var original = new TestEntity { Id = Guid.NewGuid(), Name = new ConvertersStringId("some name") }; + using (var context = new ConventionsDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities.Add(original); + context.SaveChanges(); + } + + using (var context = new ConventionsDbContext(options)) + { + var all = context.Entities.ToList(); + var retrieved = Assert.Single(all); + Assert.Equal(original.Id, retrieved.Id); + Assert.Equal(original.Name, retrieved.Name); + } } +#endif +#endregion +#region ConvertersStringId2 [Fact] - public void CanCompareDefaults() + public void CanSerializeToString_WithMultiTemplates_WithNewtonsoftJsonProvider() { - ComparableStringId original = default; - var other = ComparableStringId.Empty; + var foo = new ConvertersStringId2("123"); - var compare1 = original.CompareTo(other); - var compare2 = other.CompareTo(original); - Assert.Equal(compare1, -compare2); + var serializedFoo = NewtonsoftJsonSerializer.SerializeObject(foo); + var serializedString = NewtonsoftJsonSerializer.SerializeObject(foo.Value); + + Assert.Equal(serializedFoo, serializedString); } [Fact] - public void CanEquateDefaults() + public void CanSerializeToString_WithMultiTemplates_WithSystemTextJsonProvider() { - EquatableStringId original = default; - var other = EquatableStringId.Empty; + var foo = new ConvertersStringId2("123"); - var equals1 = (original as IEquatable).Equals(other); - var equals2 = (other as IEquatable).Equals(original); + var serializedFoo = SystemTextJsonSerializer.Serialize(foo); + var serializedString = SystemTextJsonSerializer.Serialize(foo.Value); - Assert.Equal(equals1, equals2); + Assert.Equal(serializedFoo, serializedString); } [Fact] - public void ImplementsInterfaces() + public void CanDeserializeFromString_WithMultiTemplates_WithNewtonsoftJsonProvider() { - Assert.IsAssignableFrom>(BothStringId.Empty); - Assert.IsAssignableFrom>(BothStringId.Empty); + var value = "123"; + var foo = new ConvertersStringId2(value); + var serializedString = NewtonsoftJsonSerializer.SerializeObject(value); - Assert.IsAssignableFrom>(EquatableStringId.Empty); - Assert.IsAssignableFrom>(ComparableStringId.Empty); + var deserializedFoo = NewtonsoftJsonSerializer.DeserializeObject(serializedString); -#pragma warning disable 184 - Assert.False(StringId.Empty is IComparable); - Assert.False(StringId.Empty is IEquatable); -#pragma warning restore 184 + Assert.Equal(foo, deserializedFoo); + } + + [Fact] + public void CanDeserializeFromString_WithMultiTemplates_WithSystemTextJsonProvider() + { + var value = "123"; + var foo = new ConvertersStringId2(value); + var serializedString = SystemTextJsonSerializer.Serialize(value); + + var deserializedFoo = SystemTextJsonSerializer.Deserialize(serializedString); + + Assert.Equal(foo, deserializedFoo); + } + + [Fact] + public void WhenNoJsonConverter_WithMultiTemplates_NewtonsoftSerializesWithoutValueProperty() + { + var foo = new ConvertersStringId2("123"); + + var serialized = NewtonsoftJsonSerializer.SerializeObject(foo); + + var expected = "\"" + foo.Value + "\""; + + Assert.Equal(expected, serialized); + } + + [Fact] + public void WhenEfCoreValueConverter_WithMultiTemplates_UsesValueConverter() + { + using var connection = new SqliteConnection("DataSource=:memory:"); + connection.Open(); + + var options = new DbContextOptionsBuilder() + .UseSqlite(connection) + .Options; + + var original = new TestEntity2 { Id = Guid.NewGuid(), Name = new ConvertersStringId2("some name") }; + using (var context = new TestDbContext(options)) + { + context.Database.EnsureCreated(); + context.Entities2.Add(original); + context.SaveChanges(); + } + + using (var context = new TestDbContext(options)) + { + var all = context.Entities2.ToList(); + var retrieved = Assert.Single(all); + Assert.Equal(original.Id, retrieved.Id); + Assert.Equal(original.Name, retrieved.Name); + } } + [Fact] + public async Task WhenDapperValueConverter_WithMultiTemplates_UsesValueConverter() + { + using var connection = new SqliteConnection("DataSource=:memory:"); + await connection.OpenAsync(); + + var results = await connection.QueryAsync("SELECT 'this is a value'"); + + var value = Assert.Single(results); + Assert.Equal(value, new ConvertersStringId2("this is a value")); + } #if NET6_0_OR_GREATER [Fact] - public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() + public void WhenConventionBasedEfCoreValueConverter_WithMultiTemplates_UsesValueConverter() { var connection = new SqliteConnection("DataSource=:memory:"); connection.Open(); @@ -284,26 +425,30 @@ public void WhenConventionBasedEfCoreValueConverterUsesValueConverter() .UseSqlite(connection) .Options; - var original = new TestEntity { Id = Guid.NewGuid(), Name = new EfCoreStringId("some name") }; + var original = new TestEntity2 { Id = Guid.NewGuid(), Name = new ConvertersStringId2("some name") }; using (var context = new ConventionsDbContext(options)) { context.Database.EnsureCreated(); - context.Entities.Add(original); + context.Entities2.Add(original); context.SaveChanges(); } using (var context = new ConventionsDbContext(options)) { - var all = context.Entities.ToList(); + var all = context.Entities2.ToList(); var retrieved = Assert.Single(all); Assert.Equal(original.Id, retrieved.Id); Assert.Equal(original.Name, retrieved.Name); } } +#endif +#endregion - public class ConventionsDbContext : DbContext +#if NET6_0_OR_GREATER + internal class ConventionsDbContext : DbContext { public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } public ConventionsDbContext(DbContextOptions options) : base(options) { @@ -312,8 +457,11 @@ public ConventionsDbContext(DbContextOptions options) : base(options) protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder - .Properties() - .HaveConversion(); + .Properties() + .HaveConversion(); + configurationBuilder + .Properties() + .HaveConversion(); } protected override void OnModelCreating(ModelBuilder modelBuilder) @@ -325,13 +473,21 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) .Property(x => x.Id) .ValueGeneratedNever(); }); + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Id) + .ValueGeneratedNever(); + }); } } #endif - public class TestDbContext : DbContext + internal class TestDbContext : DbContext { public DbSet Entities { get; set; } + public DbSet Entities2 { get; set; } public TestDbContext(DbContextOptions options) : base(options) { @@ -344,21 +500,45 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { builder .Property(x => x.Name) - .HasConversion(new EfCoreStringId.EfCoreValueConverter()) + .HasConversion(new ConvertersStringId.EfCoreValueConverter()) + .ValueGeneratedNever(); + }); + modelBuilder + .Entity(builder => + { + builder + .Property(x => x.Name) + .HasConversion(new ConvertersStringId2.EfCoreValueConverter()) .ValueGeneratedNever(); }); } } - public class TestEntity + internal class TestEntity { public Guid Id { get; set; } - public EfCoreStringId Name { get; set; } + public ConvertersStringId Name { get; set; } + } + + internal class EntityWithNullableId + { + public ConvertersStringId? Id { get; set; } + } + + internal class TestEntity2 + { + public Guid Id { get; set; } + public ConvertersStringId2 Name { get; set; } + } + + internal class EntityWithNullableId2 + { + public ConvertersStringId2? Id { get; set; } } - public class EntityWithNullableId + internal class TypeWithDictionaryKeys { - public NewtonsoftJsonStringId? Id { get; set; } + public Dictionary Values { get; set; } } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/StronglyTypedIds.IntegrationTests.csproj b/test/StronglyTypedIds.IntegrationTests/StronglyTypedIds.IntegrationTests.csproj index 2800167d3..ecb695358 100644 --- a/test/StronglyTypedIds.IntegrationTests/StronglyTypedIds.IntegrationTests.csproj +++ b/test/StronglyTypedIds.IntegrationTests/StronglyTypedIds.IntegrationTests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1;net6.0;net7.0 + netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 net48;$(TargetFrameworks) false true @@ -14,6 +14,7 @@ + diff --git a/test/StronglyTypedIds.IntegrationTests/SystemTextJsonSerializerContext.cs b/test/StronglyTypedIds.IntegrationTests/SystemTextJsonSerializerContext.cs new file mode 100644 index 000000000..7a388704c --- /dev/null +++ b/test/StronglyTypedIds.IntegrationTests/SystemTextJsonSerializerContext.cs @@ -0,0 +1,38 @@ +#if NET6_0_OR_GREATER +using System.Text.Json; +using System.Text.Json.Serialization; +using StronglyTypedIds.IntegrationTests.Types; + +namespace StronglyTypedIds.IntegrationTests; + +[JsonSerializable(typeof(GuidId1))] +[JsonSerializable(typeof(ConvertersGuidId))] +[JsonSerializable(typeof(ConvertersGuidId2))] +[JsonSerializable(typeof(GuidIdTests.TypeWithDictionaryKeys))] +internal partial class SystemTextJsonSerializerContext : JsonSerializerContext +{ + internal static SystemTextJsonSerializerContext Custom + => new(new JsonSerializerOptions + { + Converters = + { + new GuidId1.GuidId1SystemTextJsonConverter(), + new ConvertersGuidId.ConvertersGuidIdSystemTextJsonConverter(), + new ConvertersGuidId2.ConvertersGuidId2SystemTextJsonConverter(), + } + }); + + internal static SystemTextJsonSerializerContext Web + => new(new JsonSerializerOptions() + { + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = + { + new GuidId1.GuidId1SystemTextJsonConverter(), + new ConvertersGuidId.ConvertersGuidIdSystemTextJsonConverter(), + new ConvertersGuidId2.ConvertersGuidId2SystemTextJsonConverter(), + } + }); +} +#endif diff --git a/test/StronglyTypedIds.IntegrationTests/Types/DefaultId.cs b/test/StronglyTypedIds.IntegrationTests/Types/DefaultId.cs deleted file mode 100644 index cbe84fe1d..000000000 --- a/test/StronglyTypedIds.IntegrationTests/Types/DefaultId.cs +++ /dev/null @@ -1,41 +0,0 @@ -using StronglyTypedIds; -[assembly: StronglyTypedIdDefaults(converters: StronglyTypedIdConverter.None, implementations: StronglyTypedIdImplementations.None)] - -namespace StronglyTypedIds.IntegrationTests.Types -{ - [StronglyTypedId] - partial struct DefaultId1 { } - - [StronglyTypedId] - public partial struct DefaultId2 { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.None)] - public partial struct NoConverterDefaultId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter)] - public partial struct NoJsonDefaultId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson)] - public partial struct NewtonsoftJsonDefaultId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter | StronglyTypedIdConverter.SystemTextJson)] - public partial struct SystemTextJsonDefaultId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson)] - public partial struct BothJsonDefaultId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.EfCoreValueConverter)] - public partial struct EfCoreDefaultId { } - - public partial class SomeType where T : new() - { - public partial record NestedType - { - public partial struct MoreNesting - { - [StronglyTypedId] - public partial struct VeryNestedId {} - } - } - } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/Types/GuidId.cs b/test/StronglyTypedIds.IntegrationTests/Types/GuidId.cs deleted file mode 100644 index 9ad651d72..000000000 --- a/test/StronglyTypedIds.IntegrationTests/Types/GuidId.cs +++ /dev/null @@ -1,40 +0,0 @@ -using StronglyTypedIds; - -namespace StronglyTypedIds.IntegrationTests.Types -{ - [StronglyTypedId] - partial struct GuidId1 { } - - [StronglyTypedId] - public partial struct GuidId2 { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.None)] - public partial struct NoConverterGuidId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter)] - public partial struct NoJsonGuidId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson)] - public partial struct NewtonsoftJsonGuidId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter | StronglyTypedIdConverter.SystemTextJson)] - public partial struct SystemTextJsonGuidId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson)] - public partial struct BothJsonGuidId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.EfCoreValueConverter)] - public partial struct EfCoreGuidId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.DapperTypeHandler)] - public partial struct DapperGuidId { } - - [StronglyTypedId(implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable)] - public partial struct BothGuidId { } - - [StronglyTypedId(implementations: StronglyTypedIdImplementations.IEquatable)] - public partial struct EquatableGuidId { } - - [StronglyTypedId(implementations: StronglyTypedIdImplementations.IComparable)] - public partial struct ComparableGuidId { } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/Types/IntId.cs b/test/StronglyTypedIds.IntegrationTests/Types/IntId.cs deleted file mode 100644 index 15316b98a..000000000 --- a/test/StronglyTypedIds.IntegrationTests/Types/IntId.cs +++ /dev/null @@ -1,37 +0,0 @@ -using StronglyTypedIds; - -namespace StronglyTypedIds.IntegrationTests.Types -{ - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Int)] - partial struct IntId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.None, backingType: StronglyTypedIdBackingType.Int)] - public partial struct NoConverterIntId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter, backingType: StronglyTypedIdBackingType.Int)] - public partial struct NoJsonIntId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson, backingType: StronglyTypedIdBackingType.Int)] - public partial struct NewtonsoftJsonIntId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.Int)] - public partial struct SystemTextJsonIntId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.Int)] - public partial struct BothJsonIntId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.EfCoreValueConverter, backingType: StronglyTypedIdBackingType.Int)] - public partial struct EfCoreIntId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.DapperTypeHandler, backingType: StronglyTypedIdBackingType.Int)] - public partial struct DapperIntId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Int, implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable)] - public partial struct BothIntId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Int, implementations: StronglyTypedIdImplementations.IEquatable)] - public partial struct EquatableIntId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Int, implementations: StronglyTypedIdImplementations.IComparable)] - public partial struct ComparableIntId { } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/Types/LongId.cs b/test/StronglyTypedIds.IntegrationTests/Types/LongId.cs deleted file mode 100644 index 5a1081bb8..000000000 --- a/test/StronglyTypedIds.IntegrationTests/Types/LongId.cs +++ /dev/null @@ -1,37 +0,0 @@ -using StronglyTypedIds; - -namespace StronglyTypedIds.IntegrationTests.Types -{ - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Long)] - partial struct LongId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.None, backingType: StronglyTypedIdBackingType.Long)] - public partial struct NoConverterLongId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter, backingType: StronglyTypedIdBackingType.Long)] - public partial struct NoJsonLongId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson, backingType: StronglyTypedIdBackingType.Long)] - public partial struct NewtonsoftJsonLongId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.Long)] - public partial struct SystemTextJsonLongId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.Long)] - public partial struct BothJsonLongId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.EfCoreValueConverter, backingType: StronglyTypedIdBackingType.Long)] - public partial struct EfCoreLongId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.DapperTypeHandler, backingType: StronglyTypedIdBackingType.Long)] - public partial struct DapperLongId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Long, implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable)] - public partial struct BothLongId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Long, implementations: StronglyTypedIdImplementations.IEquatable)] - public partial struct EquatableLongId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.Long, implementations: StronglyTypedIdImplementations.IComparable)] - public partial struct ComparableLongId { } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/Types/NewIdId.cs b/test/StronglyTypedIds.IntegrationTests/Types/NewIdId.cs deleted file mode 100644 index 0be4ce4c9..000000000 --- a/test/StronglyTypedIds.IntegrationTests/Types/NewIdId.cs +++ /dev/null @@ -1,40 +0,0 @@ -using StronglyTypedIds; - -namespace StronglyTypedIds.IntegrationTests.Types -{ - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId)] - partial struct NewIdId1 { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId)] - public partial struct NewIdId2 { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, converters: StronglyTypedIdConverter.None)] - public partial struct NoConverterNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, converters: StronglyTypedIdConverter.TypeConverter)] - public partial struct NoJsonNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, converters: StronglyTypedIdConverter.NewtonsoftJson)] - public partial struct NewtonsoftJsonNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, converters: StronglyTypedIdConverter.TypeConverter | StronglyTypedIdConverter.SystemTextJson)] - public partial struct SystemTextJsonNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, converters: StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson)] - public partial struct BothJsonNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, converters: StronglyTypedIdConverter.EfCoreValueConverter)] - public partial struct EfCoreNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, converters: StronglyTypedIdConverter.DapperTypeHandler)] - public partial struct DapperNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable)] - public partial struct BothNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, implementations: StronglyTypedIdImplementations.IEquatable)] - public partial struct EquatableNewIdId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.MassTransitNewId, implementations: StronglyTypedIdImplementations.IComparable)] - public partial struct ComparableNewIdId { } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/Types/NullableStringId.cs b/test/StronglyTypedIds.IntegrationTests/Types/NullableStringId.cs deleted file mode 100644 index d51e901a1..000000000 --- a/test/StronglyTypedIds.IntegrationTests/Types/NullableStringId.cs +++ /dev/null @@ -1,37 +0,0 @@ -using StronglyTypedIds; - -namespace StronglyTypedIds.IntegrationTests.Types -{ - [StronglyTypedId(backingType: StronglyTypedIdBackingType.NullableString)] - partial struct NullableStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.None, backingType: StronglyTypedIdBackingType.NullableString)] - public partial struct NoConvertersNullableStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter, backingType: StronglyTypedIdBackingType.NullableString)] - public partial struct NoJsonNullableStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson, backingType: StronglyTypedIdBackingType.NullableString)] - public partial struct NewtonsoftJsonNullableStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.NullableString)] - public partial struct SystemTextJsonNullableStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.NullableString)] - public partial struct BothJsonNullableStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.EfCoreValueConverter, backingType: StronglyTypedIdBackingType.NullableString)] - public partial struct EfCoreNullableStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.DapperTypeHandler, backingType: StronglyTypedIdBackingType.NullableString)] - public partial struct DapperNullableStringId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.NullableString, implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable)] - public partial struct BothNullableStringId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.NullableString, implementations: StronglyTypedIdImplementations.IEquatable)] - public partial struct EquatableNullableStringId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.NullableString, implementations: StronglyTypedIdImplementations.IComparable)] - public partial struct ComparableNullableStringId { } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.IntegrationTests/Types/StringId.cs b/test/StronglyTypedIds.IntegrationTests/Types/StringId.cs deleted file mode 100644 index 5e7cdfa57..000000000 --- a/test/StronglyTypedIds.IntegrationTests/Types/StringId.cs +++ /dev/null @@ -1,37 +0,0 @@ -using StronglyTypedIds; - -namespace StronglyTypedIds.IntegrationTests.Types -{ - [StronglyTypedId(backingType: StronglyTypedIdBackingType.String)] - partial struct StringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.None, backingType: StronglyTypedIdBackingType.String)] - public partial struct NoConvertersStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.TypeConverter, backingType: StronglyTypedIdBackingType.String)] - public partial struct NoJsonStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson, backingType: StronglyTypedIdBackingType.String)] - public partial struct NewtonsoftJsonStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.String)] - public partial struct SystemTextJsonStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson, backingType: StronglyTypedIdBackingType.String)] - public partial struct BothJsonStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.EfCoreValueConverter, backingType: StronglyTypedIdBackingType.String)] - public partial struct EfCoreStringId { } - - [StronglyTypedId(converters: StronglyTypedIdConverter.DapperTypeHandler, backingType: StronglyTypedIdBackingType.String)] - public partial struct DapperStringId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.String, implementations: StronglyTypedIdImplementations.IEquatable | StronglyTypedIdImplementations.IComparable)] - public partial struct BothStringId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.String, implementations: StronglyTypedIdImplementations.IEquatable)] - public partial struct EquatableStringId { } - - [StronglyTypedId(backingType: StronglyTypedIdBackingType.String, implementations: StronglyTypedIdImplementations.IComparable)] - public partial struct ComparableStringId { } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.Nuget.Attributes.IntegrationTests/StronglyTypedIds.Nuget.Attributes.IntegrationTests.csproj b/test/StronglyTypedIds.Nuget.Attributes.IntegrationTests/StronglyTypedIds.Nuget.Attributes.IntegrationTests.csproj index 16fb810fc..c8c04769c 100644 --- a/test/StronglyTypedIds.Nuget.Attributes.IntegrationTests/StronglyTypedIds.Nuget.Attributes.IntegrationTests.csproj +++ b/test/StronglyTypedIds.Nuget.Attributes.IntegrationTests/StronglyTypedIds.Nuget.Attributes.IntegrationTests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1;net6.0;net7.0 + netcoreapp3.1;net6.0;net7.0;net8.0 net48;$(TargetFrameworks) false STRONGLY_TYPED_ID_EMBED_ATTRIBUTES @@ -9,7 +9,6 @@ - @@ -18,6 +17,7 @@ + diff --git a/test/StronglyTypedIds.Nuget.IntegrationTests/StronglyTypedIds.Nuget.IntegrationTests.csproj b/test/StronglyTypedIds.Nuget.IntegrationTests/StronglyTypedIds.Nuget.IntegrationTests.csproj index 38b3c43f8..06ad863b3 100644 --- a/test/StronglyTypedIds.Nuget.IntegrationTests/StronglyTypedIds.Nuget.IntegrationTests.csproj +++ b/test/StronglyTypedIds.Nuget.IntegrationTests/StronglyTypedIds.Nuget.IntegrationTests.csproj @@ -1,14 +1,13 @@ - netcoreapp3.1;net6.0;net7.0 + netcoreapp3.1;net6.0;net7.0;net8.0 net48;$(TargetFrameworks) false - @@ -17,6 +16,7 @@ + diff --git a/test/StronglyTypedIds.Tests/Diagnostics/InvalidBackingTypeDiagnosticTests.cs b/test/StronglyTypedIds.Tests/Diagnostics/InvalidBackingTypeDiagnosticTests.cs deleted file mode 100644 index ea6c9eff3..000000000 --- a/test/StronglyTypedIds.Tests/Diagnostics/InvalidBackingTypeDiagnosticTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using StronglyTypedIds.Diagnostics; -using Xunit; - -namespace StronglyTypedIds.Tests.Diagnostics -{ - public class InvalidBackingTypeDiagnosticTests - { - [Fact] - public void Create() - { - var diagnostic = InvalidBackingTypeDiagnostic.Create( - SyntaxFactory.ClassDeclaration("A") - .WithMembers(new SyntaxList(SyntaxFactory.StructDeclaration("A")))); - - Assert.Equal(InvalidBackingTypeDiagnostic.Message, diagnostic.GetMessage()); - Assert.Equal(InvalidBackingTypeDiagnostic.Title, diagnostic.Descriptor.Title); - Assert.Equal(InvalidBackingTypeDiagnostic.Id, diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); - Assert.Equal(Constants.Usage, diagnostic.Descriptor.Category); - } - } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Diagnostics/InvalidConverterDiagnosticTests.cs b/test/StronglyTypedIds.Tests/Diagnostics/InvalidConverterDiagnosticTests.cs deleted file mode 100644 index 6fe0eae2a..000000000 --- a/test/StronglyTypedIds.Tests/Diagnostics/InvalidConverterDiagnosticTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using StronglyTypedIds.Diagnostics; -using Xunit; - -namespace StronglyTypedIds.Tests.Diagnostics -{ - public class InvalidConverterDiagnosticTests - { - [Fact] - public void Create() - { - var diagnostic = InvalidConverterDiagnostic.Create( - SyntaxFactory.ClassDeclaration("A") - .WithMembers(new SyntaxList(SyntaxFactory.StructDeclaration("A")))); - - Assert.Equal(InvalidConverterDiagnostic.Message, diagnostic.GetMessage()); - Assert.Equal(InvalidConverterDiagnostic.Title, diagnostic.Descriptor.Title); - Assert.Equal(InvalidConverterDiagnostic.Id, diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); - Assert.Equal(Constants.Usage, diagnostic.Descriptor.Category); - } - } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Diagnostics/NotPartialDiagnosticTests.cs b/test/StronglyTypedIds.Tests/Diagnostics/NotPartialDiagnosticTests.cs deleted file mode 100644 index a92899fc2..000000000 --- a/test/StronglyTypedIds.Tests/Diagnostics/NotPartialDiagnosticTests.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using StronglyTypedIds.Diagnostics; -using Xunit; - -namespace StronglyTypedIds.Tests.Diagnostics -{ - public class NotPartialDiagnosticTests - { - [Fact] - public void Create() - { - var diagnostic = NotPartialDiagnostic.Create( - SyntaxFactory.StructDeclaration("A")); - - Assert.Equal(NotPartialDiagnostic.Message, diagnostic.GetMessage()); - Assert.Equal(NotPartialDiagnostic.Title, diagnostic.Descriptor.Title); - Assert.Equal(NotPartialDiagnostic.Id, diagnostic.Id); - Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity); - Assert.Equal(Constants.Usage, diagnostic.Descriptor.Category); - } - } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/DiagnosticsTests.cs b/test/StronglyTypedIds.Tests/DiagnosticsTests.cs new file mode 100644 index 000000000..b809fb657 --- /dev/null +++ b/test/StronglyTypedIds.Tests/DiagnosticsTests.cs @@ -0,0 +1,79 @@ +using System.Threading.Tasks; +using StronglyTypedIds.Diagnostics; +using VerifyTests; +using VerifyXunit; +using Xunit; + +namespace StronglyTypedIds.Tests.Diagnostics; + +[UsesVerify] +public class DiagnosticsTests +{ + public const string NoIdGenerationSnapshotName = "NoGeneratedIds"; + + [Theory] + [InlineData("\"\"")] + [InlineData("\" \"")] + public void EmptyTemplate_GivesInvalidTemplateNameDiagnostic_AndDoesntGenerate(string template) + { + var input = $$""" + using StronglyTypedIds; + + [StronglyTypedId({{template}})] + public partial struct MyId {} + """; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); + + Assert.Contains(diagnostics, diagnostic => diagnostic.Id == InvalidTemplateNameDiagnostic.Id); + Assert.Empty(output); + } + + [Fact] + public void MultipleAssemblyAttributes_GivesMultipleAttributeDiagnostic_AndDoesntGenerate() + { + const string input = """ + using StronglyTypedIds; + [assembly:StronglyTypedIdDefaults(Template.Int)] + [assembly:StronglyTypedIdDefaults(Template.Long)] + + [StronglyTypedId] + public partial struct MyId {} + """; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); + + Assert.Contains(diagnostics, diagnostic => diagnostic.Id == MultipleAssemblyAttributeDiagnostic.Id); + Assert.Empty(output); + } + + [Fact] + public void InvalidTemplate_GivesDiagnostic_AndDoesntGenerate() + { + const string input = """ + using StronglyTypedIds; + + [StronglyTypedId("some-template")] + public partial struct MyId {} + """; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); + + Assert.Contains(diagnostics, diagnostic => diagnostic.Id == UnknownTemplateDiagnostic.Id); + Assert.Empty(output); + } + + [Fact] + public void InvalidTemplateInDefaultsAttribute_GivesDiagnostic_AndDoesntGenerate() + { + const string input = """ + using StronglyTypedIds; + [assembly:StronglyTypedIdDefaults("some-template")] + + [StronglyTypedId] + public partial struct MyId {} + """; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); + + Assert.Contains(diagnostics, diagnostic => diagnostic.Id == UnknownTemplateDiagnostic.Id); + + Assert.Empty(output); + } +} \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/EmbeddedResourceTests.cs b/test/StronglyTypedIds.Tests/EmbeddedResourceTests.cs index 4a13cec27..fd4aef693 100644 --- a/test/StronglyTypedIds.Tests/EmbeddedResourceTests.cs +++ b/test/StronglyTypedIds.Tests/EmbeddedResourceTests.cs @@ -11,16 +11,14 @@ public class EmbeddedResourceTests { "StronglyTypedIdAttribute", "StronglyTypedIdDefaultsAttribute", - "StronglyTypedIdBackingType", - "StronglyTypedIdConverter", - "StronglyTypedIdImplementations", + "Template", }; [Theory] [MemberData(nameof(EmbeddedResources))] public Task EmittedResourceIsSameAsCompiledResource(string resource) { - var embedded = EmbeddedSources.LoadTemplateForEmitting(resource); + var embedded = EmbeddedSources.LoadAttributeTemplateForEmitting(resource); return Verifier.Verify(embedded) .UseDirectory("Snapshots") diff --git a/test/StronglyTypedIds.Tests/EnumHelper.cs b/test/StronglyTypedIds.Tests/EnumHelper.cs deleted file mode 100644 index ea74cd267..000000000 --- a/test/StronglyTypedIds.Tests/EnumHelper.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; - -namespace StronglyTypedIds.Tests -{ - public class EnumHelper - { - public static IEnumerable AllBackingTypes(bool includeDefault = true) - => Enum.GetValues(typeof(StronglyTypedIdBackingType)) - .Cast() - .Where(value => value != StronglyTypedIdBackingType.Default || includeDefault); - - public static IEnumerable AllConverters(bool includeDefault = true) - => Enum.GetValues(typeof(StronglyTypedIdConverter)) - .Cast() - .Where(value => value != StronglyTypedIdConverter.Default || includeDefault); - - public static IEnumerable AllImplementations(bool includeDefault = true) - => Enum.GetValues(typeof(StronglyTypedIdImplementations)) - .Cast() - .Where(value => value != StronglyTypedIdImplementations.Default || includeDefault); - - public static IEnumerable AllConverterCombinations(bool includeDefault = true, bool includeNone = true) - { - // get highest value - var highestValue = Enum.GetValues(typeof(StronglyTypedIdConverter)) - .Cast() - .Max(); - - var upperBound = highestValue * 2; - for (var i = 0; i < upperBound; i++) - { - var converter = (StronglyTypedIdConverter)i; - if (converter.IsSet(StronglyTypedIdConverter.Default) && !includeDefault - || converter == StronglyTypedIdConverter.None && !includeNone) - { - continue; - } - - yield return converter; - } - } - - public static IEnumerable AllImplementationCombinations(bool includeDefault = true, bool includeNone = true) - { - // get highest value - var highestValue = Enum.GetValues(typeof(StronglyTypedIdImplementations)) - .Cast() - .Max(); - - var upperBound = highestValue * 2; - for (var i = 0; i < upperBound; i++) - { - var implementations = (StronglyTypedIdImplementations)i; - if (implementations.IsSet(StronglyTypedIdImplementations.Default) && !includeDefault - || implementations == StronglyTypedIdImplementations.None && !includeNone) - { - continue; - } - - yield return implementations; - } - } - } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/EqualityTests.cs b/test/StronglyTypedIds.Tests/EqualityTests.cs new file mode 100644 index 000000000..840276066 --- /dev/null +++ b/test/StronglyTypedIds.Tests/EqualityTests.cs @@ -0,0 +1,152 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using StronglyTypedIds.Diagnostics; +using Xunit; + +namespace StronglyTypedIds.Tests; + +public class EqualityTests +{ + private static LocationInfo _templateLocation = new("Some path", new TextSpan(0, 100), new LinePositionSpan(new LinePosition(23, 2), new LinePosition(23, 15))); + + [Fact] + public void ParentClassHasExpectedEqualityBehaviour() + { + var instance1 = GetParentClass(); + var instance2 = GetParentClass(); + + Assert.Equal(instance1, instance2); + Assert.True(instance1.Equals(instance2)); + Assert.True(instance1 == instance2); + + ParentClass GetParentClass() => new(null, "struct", "TestName", "where T : class", null, false); + } + + [Fact] + public void ParentClassWithParentHasExpectedEqualityBehaviour() + { + var instance1 = GetParentClass(); + var instance2 = GetParentClass(); + + Assert.Equal(instance1, instance2); + Assert.True(instance1.Equals(instance2)); + Assert.True(instance1 == instance2); + + ParentClass GetParentClass() => new(null, "struct", "TestName", "where T : class", new ParentClass(null, "class", "b", "", null, false), false); + } + + [Fact] + public void StructToGenerateHasExpectedEqualityBehaviour() + { + var instance1 = GetStruct(); + var instance2 = GetStruct(); + + Assert.Equal(instance1, instance2); + Assert.True(instance1.Equals(instance2)); + Assert.True(instance1 == instance2); + + StructToGenerate GetStruct() => + new( + name: "MyStruct", + nameSpace: "MyNamespace", + template: Template.Guid, + null, + parent: null, + _templateLocation); + } + + [Fact] + public void StructToGenerateWithTemplateAndLocationHasExpectedEqualityBehaviour() + { + var instance1 = GetStruct(); + var instance2 = GetStruct(); + + Assert.Equal(instance1, instance2); + Assert.True(instance1.Equals(instance2)); + Assert.True(instance1 == instance2); + + StructToGenerate GetStruct() => + new( + name: "MyStruct", + nameSpace: "MyNamespace", + template: Template.Int, + templateNames: new[] {"Guid"}, + templateLocation: _templateLocation, + parent: null); + } + + [Fact] + public void StructToGenerateWithParentHasExpectedEqualityBehaviour() + { + var instance1 = GetStruct(); + var instance2 = GetStruct(); + + Assert.Equal(instance1, instance2); + Assert.True(instance1.Equals(instance2)); + Assert.True(instance1 == instance2); + + StructToGenerate GetStruct() + { + return new StructToGenerate( + name: "MyStruct", + nameSpace: "MyNamespace", + template: Template.Guid, + templateNames: null, + parent: new ParentClass(null, "class", "b", "", null, false), + _templateLocation); + } + } + + [Fact] + public void ResultWithoutDiagnosticHasExpectedEqualityBehaviour() + { + var instance1 = GetResult(); + var instance2 = GetResult(); + + Assert.Equal(instance1, instance2); + Assert.True(instance1.Equals(instance2)); + Assert.True(instance1 == instance2); + + static Result<(StructToGenerate, bool)> GetResult() + { + var instance = new StructToGenerate( + name: "MyStruct", + nameSpace: "MyNamespace", + template: Template.Guid, + templateNames: null, + parent: new ParentClass(null, "class", "b", "", null, false), + _templateLocation); + + return new Result<(StructToGenerate, bool)>((instance, true), new EquatableArray()); + } + } + + [Fact] + public void ResultWithDiagnosticHasExpectedEqualityBehaviour() + { + var instance1 = GetResult(); + var instance2 = GetResult(); + + Assert.Equal(instance1, instance2); + Assert.True(instance1.Equals(instance2)); + Assert.True(instance1 == instance2); + + static Result<(StructToGenerate, bool)> GetResult() + { + var instance = new StructToGenerate( + name: "MyStruct", + nameSpace: "MyNamespace", + template: Template.Guid, + templateNames: null, + parent: new ParentClass(null, "class", "b", "", null, false), + _templateLocation); + var diagnostics = new DiagnosticInfo(new DiagnosticDescriptor( + NotPartialDiagnostic.Id, NotPartialDiagnostic.Title, NotPartialDiagnostic.Message, category: Constants.Usage, + defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true), + Location.Create("somepath.cs", new TextSpan(), new LinePositionSpan(LinePosition.Zero, LinePosition.Zero))); + + var errors = new EquatableArray(new[] { diagnostics }); + return new Result<(StructToGenerate, bool)>((instance, true), errors); + } + } +} \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdAttribute.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdAttribute.verified.txt index 58a2c4794..59dc3731d 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdAttribute.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdAttribute.verified.txt @@ -9,54 +9,44 @@ #pragma warning disable 1591 // publicly visible type or member must be documented -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES +#nullable enable -using System; +#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES namespace StronglyTypedIds { /// /// Place on partial structs to make the type a strongly-typed ID /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute + [global::System.AttributeUsage(global::System.AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] + [global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] + internal sealed class StronglyTypedIdAttribute : global::System.Attribute { /// - /// Make the struct a strongly typed ID + /// Make the struct a strongly typed ID. /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) + /// The built-in template to use to generate the ID. + /// The names of additional custom templates to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdAttribute(global::StronglyTypedIds.Template template, params string[] templateNames) { - BackingType = backingType; - Converters = converters; - Implementations = implementations; } /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value + /// Make the struct a strongly typed ID. /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } + /// The names of the template to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// If no templates are provided, the default value is used, as specified by + /// , or alternatively the + /// template. + /// + public StronglyTypedIdAttribute(params string[] templateNames) + { + } } } #endif \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdConverter.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdConverter.verified.txt deleted file mode 100644 index 32b324616..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdConverter.verified.txt +++ /dev/null @@ -1,64 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdDefaultsAttribute.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdDefaultsAttribute.verified.txt index 3df9e2e31..3dd6d36b4 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdDefaultsAttribute.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdDefaultsAttribute.verified.txt @@ -9,52 +9,53 @@ #pragma warning disable 1591 // publicly visible type or member must be documented -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES +#nullable enable -using System; +#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES namespace StronglyTypedIds { /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID + /// Used to control the default strongly typed ID values. Apply to an assembly using + /// [assembly:StronglyTypedIdDefaults(Template.Int)] for example /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute + [global::System.AttributeUsage(global::System.AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] + [global::System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] + internal sealed class StronglyTypedIdDefaultsAttribute : global::System.Attribute { /// - /// Set the default values used for strongly typed ids + /// Set the default template to use for strongly typed IDs /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) + /// The built-in template to use to generate the ID. + /// The names of additional custom templates to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdDefaultsAttribute(global::StronglyTypedIds.Template template, params string[] templateNames) { - BackingType = backingType; - Converters = converters; - Implementations = implementations; } /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. + /// Set the default template to use for strongly typed IDs /// - public StronglyTypedIdConverter Converters { get; } + /// The name of the template to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdDefaultsAttribute(string templateName) + { + } /// - /// Interfaces and patterns the strongly typed id should implement + /// Set the default template to use for strongly typed IDs /// - public StronglyTypedIdImplementations Implementations { get; } + /// The name of the template to use to generate the ID. + /// Templates must be added to the project using the format NAME.typedid, + /// where NAME is the name of the template passed in . + /// + public StronglyTypedIdDefaultsAttribute(string templateName, params string[] templateNames) + { + } } } #endif \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdImplementations.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdImplementations.verified.txt deleted file mode 100644 index 76835ffec..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdImplementations.verified.txt +++ /dev/null @@ -1,51 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdBackingType.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=Template.verified.txt similarity index 59% rename from test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdBackingType.verified.txt rename to test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=Template.verified.txt index 4ea1be319..9de4588cf 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=StronglyTypedIdBackingType.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/EmbeddedResourceTests.EmittedResourceIsSameAsCompiledResource_resource=Template.verified.txt @@ -9,6 +9,8 @@ #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable + #if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES using System; @@ -16,21 +18,14 @@ using System; namespace StronglyTypedIds { /// - /// The to use to store the value of a strongly-typed ID + /// The built-in template to use to generate the strongly-typed ID /// - internal enum StronglyTypedIdBackingType + internal enum Template { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, + Guid, + Int, + String, + Long, } } #endif \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Guid.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Guid.verified.txt deleted file mode 100644 index d7a3ed3e7..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Guid.verified.txt +++ /dev/null @@ -1,143 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - System.Guid guidValue => new MyTestId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - System.Guid guidValue => new MyTestId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || 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 MyTestId idValue) - { - if (destinationType == typeof(System.Guid)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyTestId(guid.Value) : null; - } - } - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Int.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Int.verified.txt deleted file mode 100644 index e7affbacb..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Int.verified.txt +++ /dev/null @@ -1,143 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId : System.IComparable, System.IEquatable - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - int intValue => new MyTestId(intValue), - long longValue when longValue < int.MaxValue => new MyTestId((int)longValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new MyTestId(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - int intValue => new MyTestId(intValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new MyTestId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(int) || 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 MyTestId idValue) - { - if (destinationType == typeof(int)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var result = serializer.Deserialize(reader); - return result.HasValue ? new MyTestId(result.Value) : null; - } - } - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetInt32()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteNumberValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Long.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Long.verified.txt deleted file mode 100644 index 0a464e952..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=Long.verified.txt +++ /dev/null @@ -1,146 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId : System.IComparable, System.IEquatable - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - long longValue => new MyTestId(longValue), - int intValue => new MyTestId(intValue), - short shortValue => new MyTestId(shortValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new MyTestId(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(long) || sourceType == typeof(int) || sourceType == typeof(short) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - long longValue => new MyTestId(longValue), - int intValue => new MyTestId(intValue), - short shortValue => new MyTestId(shortValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new MyTestId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(long) || 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 MyTestId idValue) - { - if (destinationType == typeof(long)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var result = serializer.Deserialize(reader); - return result.HasValue ? new MyTestId(result.Value) : null; - } - } - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetInt64()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteNumberValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=MassTransitNewId.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=MassTransitNewId.verified.txt deleted file mode 100644 index c2c044246..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=MassTransitNewId.verified.txt +++ /dev/null @@ -1,151 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId : System.IComparable, System.IEquatable - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value.ToGuid(), - value => new MyTestId(MassTransit.NewId.FromGuid(value)), - mappingHints - ) { } - } - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value.ToGuid(); - } - - public override MyTestId Parse(object value) - { - return value switch - { - System.Guid guidValue => new MyTestId(MassTransit.NewId.FromGuid(guidValue)), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(MassTransit.NewId.FromGuid(result)), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) || - sourceType == typeof(string) || base.CanConvertFrom - (context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - MassTransit.NewId newIdValue => new MyTestId(newIdValue), - System.Guid guidValue => new MyTestId(MassTransit.NewId.FromGuid(guidValue)), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(MassTransit.NewId.FromGuid(result)), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) || 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 MyTestId idValue) - { - if (destinationType == typeof(MassTransit.NewId)) - { - return idValue.Value; - } - - if (destinationType == typeof(System.Guid)) - { - return idValue.Value.ToGuid(); - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToGuid().ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value.ToGuid()); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyTestId(MassTransit.NewId.FromGuid(guid.Value)) : null; - } - } - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(MassTransit.NewId.FromGuid(reader.GetGuid())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value.ToGuid()); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=NullableString.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=NullableString.verified.txt deleted file mode 100644 index 975c29ade..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=NullableString.verified.txt +++ /dev/null @@ -1,175 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId : System.IComparable, System.IEquatable - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => 0, - (null, _) => -1, - (_, null) => 1, - (_, _) => Value.CompareTo(other.Value), - }; - } - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) - : base( - id => id.Value!, - value => new MyTestId(value), - mappingHints - ) { } - } - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - null => new MyTestId(null), - System.DBNull => new MyTestId(null), - string stringValue => new MyTestId(stringValue), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object? ConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object value) - { - if (value is null) - { - return new MyTestId(null); - } - - var stringValue = value as string; - if (stringValue is not null) - { - return new MyTestId(stringValue); - } - - return base.ConvertFrom(context, culture, value); - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Type? sourceType) - { - return 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 MyTestId idValue) - { - if (destinationType == typeof(string)) - { - return idValue.Value; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object? value, Newtonsoft.Json.JsonSerializer serializer) - { - if (value is null) - { - serializer.Serialize(writer, null); - } - else - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object? existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - return new MyTestId(serializer.Deserialize(reader)); - } - } - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetString()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - if (value.Value is null) - { - writer.WriteNullValue(); - } - else - { - writer.WriteStringValue(value.Value); - } - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=String.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=String.verified.txt deleted file mode 100644 index 3e93ee6b2..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesFullIdCorrectly_type=String.verified.txt +++ /dev/null @@ -1,161 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId : System.IComparable, System.IEquatable - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => 0, - (null, _) => -1, - (_, null) => 1, - (_, _) => Value.CompareTo(other.Value), - }; - } - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - string stringValue => new MyTestId(stringValue), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - var stringValue = value as string; - if (stringValue is not null) - { - return new MyTestId(stringValue); - } - - return base.ConvertFrom(context, culture, value); - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return 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 MyTestId idValue) - { - if (destinationType == typeof(string)) - { - return idValue.Value; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - if (objectType == typeof(MyTestId?)) - { - var value = serializer.Deserialize(reader); - - return value is null ? null : new MyTestId(value); - } - - return new MyTestId(serializer.Deserialize(reader)); - } - } - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetString()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=DapperTypeHandler_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=DapperTypeHandler_i=None.verified.txt deleted file mode 100644 index bb6b344ab..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=DapperTypeHandler_i=None.verified.txt +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - System.Guid guidValue => new MyTestId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=EfCoreValueConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=EfCoreValueConverter_i=None.verified.txt deleted file mode 100644 index 508208c37..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=EfCoreValueConverter_i=None.verified.txt +++ /dev/null @@ -1,47 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=NewtonsoftJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=NewtonsoftJson_i=None.verified.txt deleted file mode 100644 index db59f66c1..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=NewtonsoftJson_i=None.verified.txt +++ /dev/null @@ -1,57 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyTestId(guid.Value) : null; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IComparable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IComparable.verified.txt deleted file mode 100644 index bef90429e..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IComparable.verified.txt +++ /dev/null @@ -1,37 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IComparable - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IEquatable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IEquatable.verified.txt deleted file mode 100644 index a13e9bec6..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=IEquatable.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IEquatable - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=None.verified.txt deleted file mode 100644 index fad5ea0b5..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=None_i=None.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=SystemTextJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=SystemTextJson_i=None.verified.txt deleted file mode 100644 index d6d801a99..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=SystemTextJson_i=None.verified.txt +++ /dev/null @@ -1,50 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=TypeConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=TypeConverter_i=None.verified.txt deleted file mode 100644 index 295e92baf..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Guid_c=TypeConverter_i=None.verified.txt +++ /dev/null @@ -1,78 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - System.Guid guidValue => new MyTestId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || 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 MyTestId idValue) - { - if (destinationType == typeof(System.Guid)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=DapperTypeHandler_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=DapperTypeHandler_i=None.verified.txt deleted file mode 100644 index f8d24bbf5..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=DapperTypeHandler_i=None.verified.txt +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - int intValue => new MyTestId(intValue), - long longValue when longValue < int.MaxValue => new MyTestId((int)longValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new MyTestId(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=EfCoreValueConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=EfCoreValueConverter_i=None.verified.txt deleted file mode 100644 index d3e50467b..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=EfCoreValueConverter_i=None.verified.txt +++ /dev/null @@ -1,46 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=NewtonsoftJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=NewtonsoftJson_i=None.verified.txt deleted file mode 100644 index b4d9738e7..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=NewtonsoftJson_i=None.verified.txt +++ /dev/null @@ -1,56 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - readonly partial struct MyTestId - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var result = serializer.Deserialize(reader); - return result.HasValue ? new MyTestId(result.Value) : null; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IComparable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IComparable.verified.txt deleted file mode 100644 index d76d3afd2..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IComparable.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IComparable - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IEquatable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IEquatable.verified.txt deleted file mode 100644 index 5d23b64a1..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=IEquatable.verified.txt +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IEquatable - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=None.verified.txt deleted file mode 100644 index 45272d34a..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=None_i=None.verified.txt +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=SystemTextJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=SystemTextJson_i=None.verified.txt deleted file mode 100644 index 7c016c3be..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=SystemTextJson_i=None.verified.txt +++ /dev/null @@ -1,49 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetInt32()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteNumberValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=TypeConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=TypeConverter_i=None.verified.txt deleted file mode 100644 index 39f1e9331..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Int_c=TypeConverter_i=None.verified.txt +++ /dev/null @@ -1,77 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId - { - public int Value { get; } - - public MyTestId(int value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - int intValue => new MyTestId(intValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new MyTestId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(int) || 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 MyTestId idValue) - { - if (destinationType == typeof(int)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=DapperTypeHandler_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=DapperTypeHandler_i=None.verified.txt deleted file mode 100644 index 35fd482b5..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=DapperTypeHandler_i=None.verified.txt +++ /dev/null @@ -1,55 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - long longValue => new MyTestId(longValue), - int intValue => new MyTestId(intValue), - short shortValue => new MyTestId(shortValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new MyTestId(result), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=EfCoreValueConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=EfCoreValueConverter_i=None.verified.txt deleted file mode 100644 index cb5754863..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=EfCoreValueConverter_i=None.verified.txt +++ /dev/null @@ -1,46 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=NewtonsoftJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=NewtonsoftJson_i=None.verified.txt deleted file mode 100644 index 7052a3b27..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=NewtonsoftJson_i=None.verified.txt +++ /dev/null @@ -1,56 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - readonly partial struct MyTestId - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var result = serializer.Deserialize(reader); - return result.HasValue ? new MyTestId(result.Value) : null; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IComparable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IComparable.verified.txt deleted file mode 100644 index c38fa63f6..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IComparable.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IComparable - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IEquatable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IEquatable.verified.txt deleted file mode 100644 index 13b9b1ac7..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=IEquatable.verified.txt +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IEquatable - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=None.verified.txt deleted file mode 100644 index af1658c35..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=None_i=None.verified.txt +++ /dev/null @@ -1,35 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=SystemTextJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=SystemTextJson_i=None.verified.txt deleted file mode 100644 index 17a45333f..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=SystemTextJson_i=None.verified.txt +++ /dev/null @@ -1,49 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetInt64()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteNumberValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=TypeConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=TypeConverter_i=None.verified.txt deleted file mode 100644 index e22d0478c..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=Long_c=TypeConverter_i=None.verified.txt +++ /dev/null @@ -1,79 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId - { - public long Value { get; } - - public MyTestId(long value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(0); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(long) || sourceType == typeof(int) || sourceType == typeof(short) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - long longValue => new MyTestId(longValue), - int intValue => new MyTestId(intValue), - short shortValue => new MyTestId(shortValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new MyTestId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(long) || 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 MyTestId idValue) - { - if (destinationType == typeof(long)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=DapperTypeHandler_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=DapperTypeHandler_i=None.verified.txt deleted file mode 100644 index 23efe4b09..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=DapperTypeHandler_i=None.verified.txt +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value.ToGuid(); - } - - public override MyTestId Parse(object value) - { - return value switch - { - System.Guid guidValue => new MyTestId(MassTransit.NewId.FromGuid(guidValue)), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(MassTransit.NewId.FromGuid(result)), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=EfCoreValueConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=EfCoreValueConverter_i=None.verified.txt deleted file mode 100644 index 9114f2d54..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=EfCoreValueConverter_i=None.verified.txt +++ /dev/null @@ -1,47 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value.ToGuid(), - value => new MyTestId(MassTransit.NewId.FromGuid(value)), - mappingHints - ) { } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=NewtonsoftJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=NewtonsoftJson_i=None.verified.txt deleted file mode 100644 index 181d85e44..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=NewtonsoftJson_i=None.verified.txt +++ /dev/null @@ -1,57 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - readonly partial struct MyTestId - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value.ToGuid()); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyTestId(MassTransit.NewId.FromGuid(guid.Value)) : null; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IComparable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IComparable.verified.txt deleted file mode 100644 index 3a19fc65e..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IComparable.verified.txt +++ /dev/null @@ -1,37 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IComparable - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) => Value.CompareTo(other.Value); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IEquatable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IEquatable.verified.txt deleted file mode 100644 index b4c2d5867..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=IEquatable.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IEquatable - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=None.verified.txt deleted file mode 100644 index 7e4892f41..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=None_i=None.verified.txt +++ /dev/null @@ -1,36 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=SystemTextJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=SystemTextJson_i=None.verified.txt deleted file mode 100644 index 3de0600ab..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=SystemTextJson_i=None.verified.txt +++ /dev/null @@ -1,50 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(MassTransit.NewId.FromGuid(reader.GetGuid())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value.ToGuid()); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=TypeConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=TypeConverter_i=None.verified.txt deleted file mode 100644 index 757eb4ebb..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=MassTransitNewId_c=TypeConverter_i=None.verified.txt +++ /dev/null @@ -1,86 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId - { - public MassTransit.NewId Value { get; } - - public MyTestId(MassTransit.NewId value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(MassTransit.NewId.Next()); - public static readonly MyTestId Empty = new MyTestId(MassTransit.NewId.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) || - sourceType == typeof(string) || base.CanConvertFrom - (context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - MassTransit.NewId newIdValue => new MyTestId(newIdValue), - System.Guid guidValue => new MyTestId(MassTransit.NewId.FromGuid(guidValue)), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyTestId(MassTransit.NewId.FromGuid(result)), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(MassTransit.NewId) || 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 MyTestId idValue) - { - if (destinationType == typeof(MassTransit.NewId)) - { - return idValue.Value; - } - - if (destinationType == typeof(System.Guid)) - { - return idValue.Value.ToGuid(); - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToGuid().ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=DapperTypeHandler_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=DapperTypeHandler_i=None.verified.txt deleted file mode 100644 index c96f1e168..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=DapperTypeHandler_i=None.verified.txt +++ /dev/null @@ -1,63 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - readonly partial struct MyTestId - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - null => new MyTestId(null), - System.DBNull => new MyTestId(null), - string stringValue => new MyTestId(stringValue), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=EfCoreValueConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=EfCoreValueConverter_i=None.verified.txt deleted file mode 100644 index e1a174104..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=EfCoreValueConverter_i=None.verified.txt +++ /dev/null @@ -1,55 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - readonly partial struct MyTestId - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) - : base( - id => id.Value!, - value => new MyTestId(value), - mappingHints - ) { } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=NewtonsoftJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=NewtonsoftJson_i=None.verified.txt deleted file mode 100644 index 9660c1fc0..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=NewtonsoftJson_i=None.verified.txt +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - readonly partial struct MyTestId - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object? value, Newtonsoft.Json.JsonSerializer serializer) - { - if (value is null) - { - serializer.Serialize(writer, null); - } - else - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object? existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - return new MyTestId(serializer.Deserialize(reader)); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IComparable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IComparable.verified.txt deleted file mode 100644 index d779d1af4..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IComparable.verified.txt +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - readonly partial struct MyTestId : System.IComparable - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => 0, - (null, _) => -1, - (_, null) => 1, - (_, _) => Value.CompareTo(other.Value), - }; - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IEquatable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IEquatable.verified.txt deleted file mode 100644 index bb2e2c7d2..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=IEquatable.verified.txt +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - readonly partial struct MyTestId : System.IEquatable - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=None.verified.txt deleted file mode 100644 index fe1e43665..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=None_i=None.verified.txt +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - readonly partial struct MyTestId - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=SystemTextJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=SystemTextJson_i=None.verified.txt deleted file mode 100644 index c049fb7f5..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=SystemTextJson_i=None.verified.txt +++ /dev/null @@ -1,65 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetString()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - if (value.Value is null) - { - writer.WriteNullValue(); - } - else - { - writer.WriteStringValue(value.Value); - } - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=TypeConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=TypeConverter_i=None.verified.txt deleted file mode 100644 index 50b3c0585..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=NullableString_c=TypeConverter_i=None.verified.txt +++ /dev/null @@ -1,87 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -#nullable enable - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId - { - public string? Value { get; } - - public MyTestId(string? value) - { - Value = value; - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object? obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value?.GetHashCode() ?? 0; - public override string? ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object? ConvertFrom(System.ComponentModel.ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object value) - { - if (value is null) - { - return new MyTestId(null); - } - - var stringValue = value as string; - if (stringValue is not null) - { - return new MyTestId(stringValue); - } - - return base.ConvertFrom(context, culture, value); - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext? context, System.Type? sourceType) - { - return 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 MyTestId idValue) - { - if (destinationType == typeof(string)) - { - return idValue.Value; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=DapperTypeHandler_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=DapperTypeHandler_i=None.verified.txt deleted file mode 100644 index 749dd1dbd..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=DapperTypeHandler_i=None.verified.txt +++ /dev/null @@ -1,61 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class DapperTypeHandler : Dapper.SqlMapper.TypeHandler - { - public override void SetValue(System.Data.IDbDataParameter parameter, MyTestId value) - { - parameter.Value = value.Value; - } - - public override MyTestId Parse(object value) - { - return value switch - { - string stringValue => new MyTestId(stringValue), - _ => throw new System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyTestId"), - }; - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=EfCoreValueConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=EfCoreValueConverter_i=None.verified.txt deleted file mode 100644 index 05700f78d..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=EfCoreValueConverter_i=None.verified.txt +++ /dev/null @@ -1,55 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - public class EfCoreValueConverter : Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter - { - public EfCoreValueConverter() : this(null) { } - public EfCoreValueConverter(Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints mappingHints = null) - : base( - id => id.Value, - value => new MyTestId(value), - mappingHints - ) { } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=NewtonsoftJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=NewtonsoftJson_i=None.verified.txt deleted file mode 100644 index d7596bf2b..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=NewtonsoftJson_i=None.verified.txt +++ /dev/null @@ -1,71 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [Newtonsoft.Json.JsonConverter(typeof(MyTestIdNewtonsoftJsonConverter))] - readonly partial struct MyTestId - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyTestId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyTestId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - if (objectType == typeof(MyTestId?)) - { - var value = serializer.Deserialize(reader); - - return value is null ? null : new MyTestId(value); - } - - return new MyTestId(serializer.Deserialize(reader)); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IComparable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IComparable.verified.txt deleted file mode 100644 index 4fae5139a..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IComparable.verified.txt +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IComparable - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - public int CompareTo(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => 0, - (null, _) => -1, - (_, null) => 1, - (_, _) => Value.CompareTo(other.Value), - }; - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IEquatable.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IEquatable.verified.txt deleted file mode 100644 index 050bcc20b..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=IEquatable.verified.txt +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId : System.IEquatable - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=None.verified.txt deleted file mode 100644 index 0987c7d64..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=None_i=None.verified.txt +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyTestId - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=SystemTextJson_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=SystemTextJson_i=None.verified.txt deleted file mode 100644 index 1396ccae3..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=SystemTextJson_i=None.verified.txt +++ /dev/null @@ -1,58 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(reader.GetString()); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=TypeConverter_i=None.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=TypeConverter_i=None.verified.txt deleted file mode 100644 index d35ac20a3..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdCorrectly_type=String_c=TypeConverter_i=None.verified.txt +++ /dev/null @@ -1,82 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - [System.ComponentModel.TypeConverter(typeof(MyTestIdTypeConverter))] - readonly partial struct MyTestId - { - public string Value { get; } - - public MyTestId(string value) - { - Value = value ?? throw new System.ArgumentNullException(nameof(value)); - } - - public static readonly MyTestId Empty = new MyTestId(string.Empty); - - public bool Equals(MyTestId other) - { - return (Value, other.Value) switch - { - (null, null) => true, - (null, _) => false, - (_, null) => false, - (_, _) => Value.Equals(other.Value), - }; - } - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value; - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - var stringValue = value as string; - if (stringValue is not null) - { - return new MyTestId(stringValue); - } - - return base.ConvertFrom(context, culture, value); - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return 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 MyTestId idValue) - { - if (destinationType == typeof(string)) - { - return idValue.Value; - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=0.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=0.verified.txt deleted file mode 100644 index ff61cdde7..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=0.verified.txt +++ /dev/null @@ -1,56 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTestNamespace -{ - partial record InnerMost - { - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=1.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=1.verified.txt deleted file mode 100644 index dacf3158c..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=1.verified.txt +++ /dev/null @@ -1,59 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTestNamespace -{ - partial class OuterLayer0 - { - partial record InnerMost - { - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=2.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=2.verified.txt deleted file mode 100644 index b71458e7e..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/SourceGenerationHelperSnapshotTests.GeneratesIdWithNestedClassCorrectly_nestedClassCount=2.verified.txt +++ /dev/null @@ -1,62 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTestNamespace -{ - partial class OuterLayer1 - { - partial class OuterLayer0 - { - partial record InnerMost - { - [System.Text.Json.Serialization.JsonConverter(typeof(MyTestIdSystemTextJsonConverter))] - readonly partial struct MyTestId - { - public System.Guid Value { get; } - - public MyTestId(System.Guid value) - { - Value = value; - } - - public static MyTestId New() => new MyTestId(System.Guid.NewGuid()); - public static readonly MyTestId Empty = new MyTestId(System.Guid.Empty); - - public bool Equals(MyTestId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyTestId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyTestId a, MyTestId b) => a.Equals(b); - public static bool operator !=(MyTestId a, MyTestId b) => !(a == b); - - class MyTestIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyTestId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyTestId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyTestId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateDefaultIdInGlobalNamespace.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateDefaultIdInGlobalNamespace.verified.txt index e397007be..4986c71ff 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateDefaultIdInGlobalNamespace.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateDefaultIdInGlobalNamespace.verified.txt @@ -1,222 +1,4 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by the StronglyTypedId source generator // @@ -227,22 +9,31 @@ namespace StronglyTypedIds #pragma warning disable 1591 // publicly visible type or member must be documented - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable +#nullable enable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable { - public System.Guid Value { get; } + public global::System.Guid Value { get; } - public MyId(System.Guid value) + public MyId(global::System.Guid value) { Value = value; } - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + /// public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); @@ -251,37 +42,44 @@ namespace StronglyTypedIds public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); + public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); - class MyIdTypeConverter : System.ComponentModel.TypeConverter + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) { return value switch { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), _ => base.ConvertFrom(context, culture, value), }; } - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); } - public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) { if (value is MyId idValue) { - if (destinationType == typeof(System.Guid)) + if (destinationType == typeof(global::System.Guid)) { return idValue.Value; } @@ -296,23 +94,124 @@ namespace StronglyTypedIds } } - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) { - public override bool CanConvert(System.Type objectType) + if (input is null) { - return objectType == typeof(MyId); + result = default; + return false; } - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); + result = default; + return false; } + } +#endif - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + else { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; + result = default; + return false; } } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateForCustomTemplate.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateForCustomTemplate.verified.txt new file mode 100644 index 000000000..b09689aaf --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateForCustomTemplate.verified.txt @@ -0,0 +1,272 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable +namespace SomeNamespace +{ + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::MassTransit.NewId Value { get; } + + public MyId(global::MassTransit.NewId value) + { + Value = value; + } + + public static MyId New() => new MyId(global::MassTransit.NewId.Next()); + public static readonly MyId Empty = new MyId(global::MassTransit.NewId.Empty); + + /// + public bool Equals(MyId other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MyId other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(MyId a, MyId b) => a.Equals(b); + public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(MyId other) => Value.CompareTo(other.Value); + + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId) + || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::MassTransit.NewId newIdValue => new MyId(newIdValue), + global::System.Guid guidValue => new MyId(global::MassTransit.NewId.FromGuid(guidValue)), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(global::MassTransit.NewId.FromGuid(result)), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId) + || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is MyId idValue) + { + if (destinationType == typeof(global::MassTransit.NewId)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value.ToGuid(); + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToGuid().ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(string) || typeToConvert == typeof(global::System.Guid) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (global::MassTransit.NewId.FromGuid(reader.GetGuid())); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value.ToGuid()); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null")))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToGuid().ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider))); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(global::MassTransit.NewId.FromGuid(guid)); + return true; + } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString(string? format, global::System.IFormatProvider? formatProvider) + => Value.ToGuid().ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider))); +#else + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(global::MassTransit.NewId.FromGuid(guid)); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.ToGuid().TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.ToGuid().TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, MyId value) + { + parameter.Value = value.Value.ToGuid(); + } + + public override MyId Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new MyId(global::MassTransit.NewId.FromGuid(guidValue)), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(global::MassTransit.NewId.FromGuid(result)), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyId"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value.ToGuid(), + value => new MyId(global::MassTransit.NewId.FromGuid(value)), + mappingHints + ) { } + } + + public partial class MyIdNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(MyId); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is MyId id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var guid = serializer.Deserialize(reader); + return guid.HasValue ? new MyId(global::MassTransit.NewId.FromGuid(guid.Value)) : null; + } + } + } +} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateGenericVeryNestedIdInFileScopeNamespace.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateGenericVeryNestedIdInFileScopeNamespace.verified.txt new file mode 100644 index 000000000..c55e78c8f --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateGenericVeryNestedIdInFileScopeNamespace.verified.txt @@ -0,0 +1,227 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable +namespace SomeNamespace +{ + public partial class ParentClass where T: new() + { + internal partial record InnerClass + { + public partial struct InnerStruct + { + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::System.Guid Value { get; } + + public MyId(global::System.Guid value) + { + Value = value; + } + + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + + /// + public bool Equals(MyId other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MyId other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(MyId a, MyId b) => a.Equals(b); + public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(MyId other) => Value.CompareTo(other.Value); + + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is MyId idValue) + { + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + } + } + } + } +} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInFileScopedNamespace.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInFileScopedNamespace.verified.txt index 0b021b89a..8a8530375 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInFileScopedNamespace.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInFileScopedNamespace.verified.txt @@ -1,222 +1,4 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by the StronglyTypedId source generator // @@ -227,24 +9,33 @@ namespace StronglyTypedIds #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable namespace SomeNamespace { - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable { - public System.Guid Value { get; } + public global::System.Guid Value { get; } - public MyId(System.Guid value) + public MyId(global::System.Guid value) { Value = value; } - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + /// public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); @@ -253,37 +44,44 @@ namespace SomeNamespace public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); + public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); - class MyIdTypeConverter : System.ComponentModel.TypeConverter + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) { return value switch { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), _ => base.ConvertFrom(context, culture, value), }; } - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); } - public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) { if (value is MyId idValue) { - if (destinationType == typeof(System.Guid)) + if (destinationType == typeof(global::System.Guid)) { return idValue.Value; } @@ -298,24 +96,125 @@ namespace SomeNamespace } } - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { - public override bool CanConvert(System.Type objectType) + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) { - return objectType == typeof(MyId); + result = default; + return false; } - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + if (global::System.Guid.TryParse(input, provider, out var guid)) { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); + result = new(guid); + return true; } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; + result = new(guid); + return true; + } + else + { + result = default; + return false; } } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif } } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInNamespace.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInNamespace.verified.txt index 0b021b89a..8a8530375 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInNamespace.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdInNamespace.verified.txt @@ -1,222 +1,4 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by the StronglyTypedId source generator // @@ -227,24 +9,33 @@ namespace StronglyTypedIds #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable namespace SomeNamespace { - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable { - public System.Guid Value { get; } + public global::System.Guid Value { get; } - public MyId(System.Guid value) + public MyId(global::System.Guid value) { Value = value; } - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + /// public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); @@ -253,37 +44,44 @@ namespace SomeNamespace public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); + public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); - class MyIdTypeConverter : System.ComponentModel.TypeConverter + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) { return value switch { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), _ => base.ConvertFrom(context, culture, value), }; } - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); } - public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) { if (value is MyId idValue) { - if (destinationType == typeof(System.Guid)) + if (destinationType == typeof(global::System.Guid)) { return idValue.Value; } @@ -298,24 +96,125 @@ namespace SomeNamespace } } - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { - public override bool CanConvert(System.Type objectType) + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) { - return objectType == typeof(MyId); + result = default; + return false; } - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + if (global::System.Guid.TryParse(input, provider, out var guid)) { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); + result = new(guid); + return true; } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; + result = new(guid); + return true; + } + else + { + result = default; + return false; } } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif } } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt deleted file mode 100644 index 1be7dd3cb..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt +++ /dev/null @@ -1,293 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; - } - } - - class MyIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt deleted file mode 100644 index a7e3384bc..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt +++ /dev/null @@ -1,279 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=SystemTextJson.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=SystemTextJson.verified.txt deleted file mode 100644 index e8ca99b42..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=SystemTextJson.verified.txt +++ /dev/null @@ -1,272 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=TypeConverter.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=TypeConverter.verified.txt deleted file mode 100644 index 62ccb4765..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=TypeConverter.verified.txt +++ /dev/null @@ -1,300 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || 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 MyId idValue) - { - if (destinationType == typeof(System.Guid)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=null.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=null.verified.txt deleted file mode 100644 index af074ad91..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithNamedParameters_backingType=Guid_converter=null.verified.txt +++ /dev/null @@ -1,321 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || 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 MyId idValue) - { - if (destinationType == typeof(System.Guid)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt deleted file mode 100644 index 1be7dd3cb..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson, SystemTextJson.verified.txt +++ /dev/null @@ -1,293 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; - } - } - - class MyIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt deleted file mode 100644 index a7e3384bc..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=NewtonsoftJson.verified.txt +++ /dev/null @@ -1,279 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=SystemTextJson.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=SystemTextJson.verified.txt deleted file mode 100644 index e8ca99b42..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=SystemTextJson.verified.txt +++ /dev/null @@ -1,272 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdSystemTextJsonConverter : System.Text.Json.Serialization.JsonConverter - { - public override MyId Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options) - { - return new MyId(System.Guid.Parse(reader.GetString())); - } - - public override void Write(System.Text.Json.Utf8JsonWriter writer, MyId value, System.Text.Json.JsonSerializerOptions options) - { - writer.WriteStringValue(value.Value); - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=TypeConverter.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=TypeConverter.verified.txt deleted file mode 100644 index 62ccb4765..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=TypeConverter.verified.txt +++ /dev/null @@ -1,300 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || 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 MyId idValue) - { - if (destinationType == typeof(System.Guid)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=null.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=null.verified.txt deleted file mode 100644 index af074ad91..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateIdWithPositionalParameters_backingType=Guid_converter=null.verified.txt +++ /dev/null @@ -1,321 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - -namespace MyTests.TestNameSpace -{ - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public System.Guid Value { get; } - - public MyId(System.Guid value) - { - Value = value; - } - - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - - class MyIdTypeConverter : System.ComponentModel.TypeConverter - { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) - { - return value switch - { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), - _ => base.ConvertFrom(context, culture, value), - }; - } - - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) - { - return sourceType == typeof(System.Guid) || 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 MyId idValue) - { - if (destinationType == typeof(System.Guid)) - { - return idValue.Value; - } - - if (destinationType == typeof(string)) - { - return idValue.Value.ToString(); - } - } - - return base.ConvertTo(context, culture, value, destinationType); - } - } - - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter - { - public override bool CanConvert(System.Type objectType) - { - return objectType == typeof(MyId); - } - - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) - { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); - } - - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) - { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; - } - } - } -} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleIdsWithSameName.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleIdsWithSameName.verified.txt index 7e73d73fe..9da3f1057 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleIdsWithSameName.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleIdsWithSameName.verified.txt @@ -1,222 +1,4 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by the StronglyTypedId source generator // @@ -227,24 +9,33 @@ namespace StronglyTypedIds #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable namespace MyContracts.V1 { - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable { - public System.Guid Value { get; } + public global::System.Guid Value { get; } - public MyId(System.Guid value) + public MyId(global::System.Guid value) { Value = value; } - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + /// public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); @@ -253,37 +44,44 @@ namespace MyContracts.V1 public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); + public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); - class MyIdTypeConverter : System.ComponentModel.TypeConverter + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) { return value switch { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), _ => base.ConvertFrom(context, culture, value), }; } - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); } - public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) { if (value is MyId idValue) { - if (destinationType == typeof(System.Guid)) + if (destinationType == typeof(global::System.Guid)) { return idValue.Value; } @@ -298,25 +96,126 @@ namespace MyContracts.V1 } } - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { - public override bool CanConvert(System.Type objectType) + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) { - return objectType == typeof(MyId); + result = default; + return false; } - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); + result = default; + return false; } + } +#endif - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + else { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; + result = default; + return false; } } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif } } @@ -331,24 +230,33 @@ namespace MyContracts.V1 #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable namespace MyContracts.V2 { - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable { - public System.Guid Value { get; } + public global::System.Guid Value { get; } - public MyId(System.Guid value) + public MyId(global::System.Guid value) { Value = value; } - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + /// public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); @@ -357,37 +265,44 @@ namespace MyContracts.V2 public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); + public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); - class MyIdTypeConverter : System.ComponentModel.TypeConverter + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) { return value switch { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), _ => base.ConvertFrom(context, culture, value), }; } - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); } - public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) { if (value is MyId idValue) { - if (destinationType == typeof(System.Guid)) + if (destinationType == typeof(global::System.Guid)) { return idValue.Value; } @@ -402,24 +317,125 @@ namespace MyContracts.V2 } } - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { - public override bool CanConvert(System.Type objectType) + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) { - return objectType == typeof(MyId); + result = default; + return false; } - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); + result = default; + return false; } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + else { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; + result = default; + return false; } } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif } } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt new file mode 100644 index 000000000..ddcee0c20 --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithBuiltIn.verified.txt @@ -0,0 +1,276 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + partial struct MyId + { + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new MyId(value), + mappingHints + ) { } + } + } + +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + partial struct MyId + { + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, MyId value) + { + parameter.Value = value.Value; + } + + public override MyId Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyId"), + }; + } + } + } + +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::System.Guid Value { get; } + + public MyId(global::System.Guid value) + { + Value = value; + } + + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + + /// + public bool Equals(MyId other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MyId other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(MyId a, MyId b) => a.Equals(b); + public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(MyId other) => Value.CompareTo(other.Value); + + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is MyId idValue) + { + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithoutBuiltIn.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithoutBuiltIn.verified.txt new file mode 100644 index 000000000..0b77f220b --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateMultipleTemplatesWithoutBuiltIn.verified.txt @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + partial struct MyId + { + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new MyId(value), + mappingHints + ) { } + } + } + +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + partial struct MyId + { + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, MyId value) + { + parameter.Value = value.Value; + } + + public override MyId Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyId"), + }; + } + } + } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNestedIdInFileScopeNamespace.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNestedIdInFileScopeNamespace.verified.txt index c259d55ac..c2b59d42e 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNestedIdInFileScopeNamespace.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNestedIdInFileScopeNamespace.verified.txt @@ -1,222 +1,4 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by the StronglyTypedId source generator // @@ -227,26 +9,35 @@ namespace StronglyTypedIds #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable namespace SomeNamespace { - partial class ParentClass + public partial class ParentClass { - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable { - public System.Guid Value { get; } + public global::System.Guid Value { get; } - public MyId(System.Guid value) + public MyId(global::System.Guid value) { Value = value; } - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + /// public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); @@ -255,37 +46,44 @@ namespace SomeNamespace public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); + public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); - class MyIdTypeConverter : System.ComponentModel.TypeConverter + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) { return value switch { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), _ => base.ConvertFrom(context, culture, value), }; } - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); } - public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) { if (value is MyId idValue) { - if (destinationType == typeof(System.Guid)) + if (destinationType == typeof(global::System.Guid)) { return idValue.Value; } @@ -300,25 +98,126 @@ namespace SomeNamespace } } - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { - public override bool CanConvert(System.Type objectType) + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) { - return objectType == typeof(MyId); + result = default; + return false; } - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + if (global::System.Guid.TryParse(input, provider, out var guid)) { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); + result = new(guid); + return true; } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; + result = new(guid); + return true; + } + else + { + result = default; + return false; } } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif } } } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNonDefaultIdInNamespace.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNonDefaultIdInNamespace.verified.txt new file mode 100644 index 000000000..db87dacf0 --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateNonDefaultIdInNamespace.verified.txt @@ -0,0 +1,215 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable +namespace SomeNamespace +{ + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public int Value { get; } + + public MyId(int value) + { + Value = value; + } + + public static readonly MyId Empty = new MyId(0); + + /// + public bool Equals(MyId other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MyId other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(MyId a, MyId b) => a.Equals(b); + public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(MyId other) => Value.CompareTo(other.Value); + + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + int intValue => new MyId(intValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new MyId(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is MyId idValue) + { + if (destinationType == typeof(int)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(int) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt32()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(int.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); +#endif + } + + public static MyId Parse(string input) + => new(int.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(int.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) + { + result = default; + return false; + } + + if (int.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.NumericFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(int.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(int.Parse(input, provider)); +#else + => new(int.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (int.TryParse(input, provider, out var value)) +#else + if (int.TryParse(input, out var value)) +#endif + { + result = new(value); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + } +} diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateVeryNestedIdInFileScopeNamespace.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateVeryNestedIdInFileScopeNamespace.verified.txt index ebcdb6716..776fbf1d3 100644 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateVeryNestedIdInFileScopeNamespace.verified.txt +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanGenerateVeryNestedIdInFileScopeNamespace.verified.txt @@ -1,222 +1,4 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by the StronglyTypedId source generator // @@ -227,30 +9,39 @@ namespace StronglyTypedIds #pragma warning disable 1591 // publicly visible type or member must be documented +#nullable enable namespace SomeNamespace { - partial class ParentClass where T: new() + public partial class ParentClass { - partial record InnerClass + internal partial record InnerClass { - partial struct InnerStruct + public readonly partial record struct InnerStruct { - [Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] - [System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] - readonly partial struct MyId : System.IComparable, System.IEquatable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable { - public System.Guid Value { get; } + public global::System.Guid Value { get; } - public MyId(System.Guid value) + public MyId(global::System.Guid value) { Value = value; } - public static MyId New() => new MyId(System.Guid.NewGuid()); - public static readonly MyId Empty = new MyId(System.Guid.Empty); + public static MyId New() => new MyId(global::System.Guid.NewGuid()); + public static readonly MyId Empty = new MyId(global::System.Guid.Empty); + /// public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; return obj is MyId other && Equals(other); @@ -259,37 +50,44 @@ namespace SomeNamespace public override int GetHashCode() => Value.GetHashCode(); public override string ToString() => Value.ToString(); + public static bool operator ==(MyId a, MyId b) => a.Equals(b); public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// public int CompareTo(MyId other) => Value.CompareTo(other.Value); - class MyIdTypeConverter : System.ComponentModel.TypeConverter + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter { - public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } - - public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) { return value switch { - System.Guid guidValue => new MyId(guidValue), - string stringValue when !string.IsNullOrEmpty(stringValue) && System.Guid.TryParse(stringValue, out var result) => new MyId(result), + global::System.Guid guidValue => new MyId(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(result), _ => base.ConvertFrom(context, culture, value), }; } - public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType) + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) { - return sourceType == typeof(System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); } - public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) { if (value is MyId idValue) { - if (destinationType == typeof(System.Guid)) + if (destinationType == typeof(global::System.Guid)) { return idValue.Value; } @@ -304,25 +102,126 @@ namespace SomeNamespace } } - class MyIdNewtonsoftJsonConverter : Newtonsoft.Json.JsonConverter + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter { - public override bool CanConvert(System.Type objectType) + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) { - return objectType == typeof(MyId); + result = default; + return false; } - public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + if (global::System.Guid.TryParse(input, provider, out var guid)) { - var id = (MyId)value; - serializer.Serialize(writer, id.Value); + result = new(guid); + return true; } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); - public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif { - var guid = serializer.Deserialize(reader); - return guid.HasValue ? new MyId(guid.Value) : null; + result = new(guid); + return true; + } + else + { + result = default; + return false; } } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif } } } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsUsingGlobalAttribute.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsUsingGlobalAttribute.verified.txt deleted file mode 100644 index 02e7314d4..000000000 --- a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsUsingGlobalAttribute.verified.txt +++ /dev/null @@ -1,254 +0,0 @@ -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdAttribute : Attribute - { - /// - /// Make the struct a strongly typed ID - /// - /// The to use to store the strongly-typed ID value. - /// If not set, uses , which defaults to - /// Converters to create for serializing/deserializing the strongly-typed ID value. - /// If not set, uses , which defaults to - /// and - /// Interfaces and patterns the strongly typed id should implement - /// If not set, uses , which defaults to - /// and - public StronglyTypedIdAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The to use to store the strongly-typed ID value - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// JSON library used to serialize/deserialize strongly-typed ID value - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Used to control the default Place on partial structs to make the type a strongly-typed ID - /// - [AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)] - [System.Diagnostics.Conditional("STRONGLY_TYPED_ID_USAGES")] - internal sealed class StronglyTypedIdDefaultsAttribute : Attribute - { - /// - /// Set the default values used for strongly typed ids - /// - /// The to use to store the strongly-typed ID value. - /// Defaults to - /// JSON library used to serialize/deserialize strongly-typed ID value. - /// Defaults to and - /// Interfaces and patterns the strongly typed id should implement - /// Defaults to and - public StronglyTypedIdDefaultsAttribute( - StronglyTypedIdBackingType backingType = StronglyTypedIdBackingType.Default, - StronglyTypedIdConverter converters = StronglyTypedIdConverter.Default, - StronglyTypedIdImplementations implementations = StronglyTypedIdImplementations.Default) - { - BackingType = backingType; - Converters = converters; - Implementations = implementations; - } - - /// - /// The default to use to store the strongly-typed ID values. - /// - public StronglyTypedIdBackingType BackingType { get; } - - /// - /// The default converters to create for serializing/deserializing strongly-typed ID values. - /// - public StronglyTypedIdConverter Converters { get; } - - /// - /// Interfaces and patterns the strongly typed id should implement - /// - public StronglyTypedIdImplementations Implementations { get; } - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// The to use to store the value of a strongly-typed ID - /// - internal enum StronglyTypedIdBackingType - { - /// - /// Use the default backing type (either the globally configured default, or Guid) - /// - Default = 0, - - Guid = 1, - Int = 2, - String = 3, - Long = 4, - NullableString = 5, - MassTransitNewId = 6, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Converters used to to serialize/deserialize strongly-typed ID values - /// - [Flags] - internal enum StronglyTypedIdConverter - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't create any converters for the strongly typed ID - /// - None = 0, - - /// - /// Use the default converters for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - /// - /// Creates a for converting from the strongly typed ID to and from a string - /// - TypeConverter = 2, - - /// - /// Creates a Newtonsoft.Json.JsonConverter for serializing the strongly typed id to its primitive value - /// - NewtonsoftJson = 4, - - /// - /// Creates a System.Text.Json.Serialization.JsonConverter for serializing the strongly typed id to its primitive value - /// - SystemTextJson = 8, - - /// - /// Creates an EF Core Value Converter for extracting the primitive value - /// - EfCoreValueConverter = 16, - - /// - /// Creates a Dapper TypeHandler for converting to and from the type - /// - DapperTypeHandler = 32, - } -} -#endif -#if STRONGLY_TYPED_ID_EMBED_ATTRIBUTES - -using System; - -namespace StronglyTypedIds -{ - /// - /// Interfaces and patterns the strongly typed id should implement - /// - [Flags] - internal enum StronglyTypedIdImplementations - { - // Used with HasFlag, so needs to be 1, 2, 4 etc - - /// - /// Don't implement any additional members for the strongly typed ID - /// - None = 0, - - /// - /// Use the default implementations for the strongly typed Id. - /// This will be the value provided in the , which falls back to - /// and - /// - Default = 1, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IEquatable = 2, - - // ReSharper disable once InconsistentNaming - /// - /// Implement the interface - /// - IComparable = 4, - } -} -#endif -//------------------------------------------------------------------------------ -// -// This code was generated by the StronglyTypedId source generator -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -#pragma warning disable 1591 // publicly visible type or member must be documented - - readonly partial struct MyId : System.IComparable, System.IEquatable - { - public int Value { get; } - - public MyId(int value) - { - Value = value; - } - - public static readonly MyId Empty = new MyId(0); - - public bool Equals(MyId other) => this.Value.Equals(other.Value); - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - return obj is MyId other && Equals(other); - } - - public override int GetHashCode() => Value.GetHashCode(); - - public override string ToString() => Value.ToString(); - public static bool operator ==(MyId a, MyId b) => a.Equals(b); - public static bool operator !=(MyId a, MyId b) => !(a == b); - public int CompareTo(MyId other) => Value.CompareTo(other.Value); - } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithCustomTemplateUsingGlobalAttribute.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithCustomTemplateUsingGlobalAttribute.verified.txt new file mode 100644 index 000000000..ed0410a74 --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithCustomTemplateUsingGlobalAttribute.verified.txt @@ -0,0 +1,269 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(MyIdNewtonsoftJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::MassTransit.NewId Value { get; } + + public MyId(global::MassTransit.NewId value) + { + Value = value; + } + + public static MyId New() => new MyId(global::MassTransit.NewId.Next()); + public static readonly MyId Empty = new MyId(global::MassTransit.NewId.Empty); + + /// + public bool Equals(MyId other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MyId other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(MyId a, MyId b) => a.Equals(b); + public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(MyId other) => Value.CompareTo(other.Value); + + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId) + || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::MassTransit.NewId newIdValue => new MyId(newIdValue), + global::System.Guid guidValue => new MyId(global::MassTransit.NewId.FromGuid(guidValue)), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(global::MassTransit.NewId.FromGuid(result)), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(System.Guid) || sourceType == typeof(global::MassTransit.NewId) + || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is MyId idValue) + { + if (destinationType == typeof(global::MassTransit.NewId)) + { + return idValue.Value; + } + + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value.ToGuid(); + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToGuid().ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(string) || typeToConvert == typeof(global::System.Guid) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (global::MassTransit.NewId.FromGuid(reader.GetGuid())); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value.ToGuid()); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null")))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToGuid().ToString()); +#endif + } + + public static MyId Parse(string input) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider))); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(global::MassTransit.NewId.FromGuid(guid)); + return true; + } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString(string? format, global::System.IFormatProvider? formatProvider) + => Value.ToGuid().ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input, provider))); +#else + => new(global::MassTransit.NewId.FromGuid(global::System.Guid.Parse(input))); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(global::MassTransit.NewId.FromGuid(guid)); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.ToGuid().TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.ToGuid().TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, MyId value) + { + parameter.Value = value.Value.ToGuid(); + } + + public override MyId Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new MyId(global::MassTransit.NewId.FromGuid(guidValue)), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new MyId(global::MassTransit.NewId.FromGuid(result)), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to MyId"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value.ToGuid(), + value => new MyId(global::MassTransit.NewId.FromGuid(value)), + mappingHints + ) { } + } + + public partial class MyIdNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(MyId); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is MyId id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var guid = serializer.Deserialize(reader); + return guid.HasValue ? new MyId(global::MassTransit.NewId.FromGuid(guid.Value)) : null; + } + } + } diff --git a/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithTemplateUsingGlobalAttribute.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithTemplateUsingGlobalAttribute.verified.txt new file mode 100644 index 000000000..6e458d2ff --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/StronglyTypedIdGeneratorTests.CanOverrideDefaultsWithTemplateUsingGlobalAttribute.verified.txt @@ -0,0 +1,212 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by the StronglyTypedId source generator +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable 1591 // publicly visible type or member must be documented + +#nullable enable + [global::System.ComponentModel.TypeConverter(typeof(MyIdTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(MyIdSystemTextJsonConverter))] + partial struct MyId : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public int Value { get; } + + public MyId(int value) + { + Value = value; + } + + public static readonly MyId Empty = new MyId(0); + + /// + public bool Equals(MyId other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is MyId other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(MyId a, MyId b) => a.Equals(b); + public static bool operator !=(MyId a, MyId b) => !(a == b); + public static bool operator > (MyId a, MyId b) => a.CompareTo(b) > 0; + public static bool operator < (MyId a, MyId b) => a.CompareTo(b) < 0; + public static bool operator >= (MyId a, MyId b) => a.CompareTo(b) >= 0; + public static bool operator <= (MyId a, MyId b) => a.CompareTo(b) <= 0; + + /// + public int CompareTo(MyId other) => Value.CompareTo(other.Value); + + public partial class MyIdTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + int intValue => new MyId(intValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new MyId(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is MyId idValue) + { + if (destinationType == typeof(int)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class MyIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(int) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override MyId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt32()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + +#if NET6_0_OR_GREATER + public override MyId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(int.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the MyId property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, MyId value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); +#endif + } + + public static MyId Parse(string input) + => new(int.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static MyId Parse(string input, global::System.IFormatProvider? provider) + => new(int.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out MyId result) + { + if (input is null) + { + result = default; + return false; + } + + if (int.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.NumericFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static MyId Parse(global::System.ReadOnlySpan input) + => new(int.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static MyId Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(int.Parse(input, provider)); +#else + => new(int.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out MyId result) + { +#if NET7_0_OR_GREATER + if (int.TryParse(input, provider, out var value)) +#else + if (int.TryParse(input, out var value)) +#endif + { + result = new(value); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + } diff --git a/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Guid.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Guid.verified.txt new file mode 100644 index 000000000..b71fddfb9 --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Guid.verified.txt @@ -0,0 +1,264 @@ +// ACTION REQUIRED: This file was automatically added to your project, but it +// will not take effect until additional steps are taken to enable it. See +// https://github.com/dotnet/roslyn/issues/4655 for more details. +// +// To enable the template, in Visual Studio 2017, 2019, and 2022: +// 1. Select the file in Solution Explorer. +// 2. In the 'Properties' window, set the value for 'Build Action' +// to one of the following (whichever is available): +// - For .NET Core and .NET Standard projects: 'C# analyzer additional file' +// - For other projects: 'AdditionalFiles' +// +// Any instances of PLACEHOLDERID will be replaced with the target ID name +// when generating code from this template. + + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public global::System.Guid Value { get; } + + public PLACEHOLDERID(global::System.Guid value) + { + Value = value; + } + + public static PLACEHOLDERID New() => new PLACEHOLDERID(global::System.Guid.NewGuid()); + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(global::System.Guid.Empty); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + global::System.Guid guidValue => new PLACEHOLDERID(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(global::System.Guid) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(global::System.Guid)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(global::System.Guid) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetGuid()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(global::System.Guid.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString()); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(global::System.Guid.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(global::System.Guid.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (global::System.Guid.TryParse(input, provider, out var guid)) + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(global::System.Guid.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(global::System.Guid.Parse(input, provider)); +#else + => new(global::System.Guid.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { +#if NET7_0_OR_GREATER + if (global::System.Guid.TryParse(input, provider, out var guid)) +#else + if (global::System.Guid.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + else + { + result = default; + return false; + } + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + global::System.Guid guidValue => new PLACEHOLDERID(guidValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && global::System.Guid.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var guid = serializer.Deserialize(reader); + return guid.HasValue ? new PLACEHOLDERID(guid.Value) : null; + } + } + } \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Int.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Int.verified.txt new file mode 100644 index 000000000..fd1dcc935 --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Int.verified.txt @@ -0,0 +1,260 @@ +// ACTION REQUIRED: This file was automatically added to your project, but it +// will not take effect until additional steps are taken to enable it. See +// https://github.com/dotnet/roslyn/issues/4655 for more details. +// +// To enable the template, in Visual Studio 2017, 2019, and 2022: +// 1. Select the file in Solution Explorer. +// 2. In the 'Properties' window, set the value for 'Build Action' +// to one of the following (whichever is available): +// - For .NET Core and .NET Standard projects: 'C# analyzer additional file' +// - For other projects: 'AdditionalFiles' +// +// Any instances of PLACEHOLDERID will be replaced with the target ID name +// when generating code from this template. + + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public int Value { get; } + + public PLACEHOLDERID(int value) + { + Value = value; + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + int intValue => new PLACEHOLDERID(intValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(int) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(int)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(int) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt32()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(int.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(int.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(int.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (int.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(int.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(int.Parse(input, provider)); +#else + => new(int.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { +#if NET7_0_OR_GREATER + if (int.TryParse(input, provider, out var guid)) +#else + if (int.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + int intValue => new PLACEHOLDERID(intValue), + long longValue when longValue < int.MaxValue => new PLACEHOLDERID((int)longValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && int.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var result = serializer.Deserialize(reader); + return result.HasValue ? new PLACEHOLDERID(result.Value) : null; + } + } + } \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Long.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Long.verified.txt new file mode 100644 index 000000000..46805531d --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_Long.verified.txt @@ -0,0 +1,261 @@ +// ACTION REQUIRED: This file was automatically added to your project, but it +// will not take effect until additional steps are taken to enable it. See +// https://github.com/dotnet/roslyn/issues/4655 for more details. +// +// To enable the template, in Visual Studio 2017, 2019, and 2022: +// 1. Select the file in Solution Explorer. +// 2. In the 'Properties' window, set the value for 'Build Action' +// to one of the following (whichever is available): +// - For .NET Core and .NET Standard projects: 'C# analyzer additional file' +// - For other projects: 'AdditionalFiles' +// +// Any instances of PLACEHOLDERID will be replaced with the target ID name +// when generating code from this template. + + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public long Value { get; } + + public PLACEHOLDERID(long value) + { + Value = value; + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(0); + + /// + public bool Equals(PLACEHOLDERID other) => this.Value.Equals(other.Value); + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + + /// + public int CompareTo(PLACEHOLDERID other) => Value.CompareTo(other.Value); + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + return value switch + { + long intValue => new PLACEHOLDERID(intValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => base.ConvertFrom(context, culture, value), + }; + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(long) || sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(long)) + { + return idValue.Value; + } + + if (destinationType == typeof(string)) + { + return idValue.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture); + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(long) || typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetInt32()); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteNumberValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(long.Parse(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null"))); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture)); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(long.Parse(input)); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(long.Parse(input, provider)); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + if (long.TryParse(input, provider, out var value)) + { + result = new(value); + return true; + } + + result = default; + return false; + } +#endif + + /// + public string ToString( +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + string? format, + global::System.IFormatProvider? formatProvider) + => Value.ToString(format, formatProvider); + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(long.Parse(input)); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) +#if NET7_0_OR_GREATER + => new(long.Parse(input, provider)); +#else + => new(long.Parse(input)); +#endif + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { +#if NET7_0_OR_GREATER + if (long.TryParse(input, provider, out var guid)) +#else + if (long.TryParse(input, out var guid)) +#endif + { + result = new(guid); + return true; + } + + result = default; + return false; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => Value.TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, +#if NET7_0_OR_GREATER + [global::System.Diagnostics.CodeAnalysis.StringSyntax(global::System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.GuidFormat)] +#endif + global::System.ReadOnlySpan format = default) + => Value.TryFormat(destination, out charsWritten, format); +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + long longValue => new PLACEHOLDERID(longValue), + int intValue => new PLACEHOLDERID(intValue), + short shortValue => new PLACEHOLDERID(shortValue), + string stringValue when !string.IsNullOrEmpty(stringValue) && long.TryParse(stringValue, out var result) => new PLACEHOLDERID(result), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + var result = serializer.Deserialize(reader); + return result.HasValue ? new PLACEHOLDERID(result.Value) : null; + } + } + } \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_String.verified.txt b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_String.verified.txt new file mode 100644 index 000000000..b17b95140 --- /dev/null +++ b/test/StronglyTypedIds.Tests/Snapshots/UnknownTemplateCodeFixProviderUnitTests.UsesBuiltInTemplates_String.verified.txt @@ -0,0 +1,253 @@ +// ACTION REQUIRED: This file was automatically added to your project, but it +// will not take effect until additional steps are taken to enable it. See +// https://github.com/dotnet/roslyn/issues/4655 for more details. +// +// To enable the template, in Visual Studio 2017, 2019, and 2022: +// 1. Select the file in Solution Explorer. +// 2. In the 'Properties' window, set the value for 'Build Action' +// to one of the following (whichever is available): +// - For .NET Core and .NET Standard projects: 'C# analyzer additional file' +// - For other projects: 'AdditionalFiles' +// +// Any instances of PLACEHOLDERID will be replaced with the target ID name +// when generating code from this template. + + [global::System.ComponentModel.TypeConverter(typeof(PLACEHOLDERIDTypeConverter))] + [global::System.Text.Json.Serialization.JsonConverter(typeof(PLACEHOLDERIDSystemTextJsonConverter))] + [global::Newtonsoft.Json.JsonConverter(typeof(PLACEHOLDERIDNewtonsoftJsonConverter))] + partial struct PLACEHOLDERID : +#if NET6_0_OR_GREATER + global::System.ISpanFormattable, +#endif +#if NET7_0_OR_GREATER + global::System.IParsable, global::System.ISpanParsable, +#endif + global::System.IComparable, global::System.IEquatable, global::System.IFormattable + { + public string Value { get; } + + public PLACEHOLDERID(string value) + { + Value = value ?? throw new global::System.ArgumentNullException(nameof(value)); + } + + public static readonly PLACEHOLDERID Empty = new PLACEHOLDERID(string.Empty); + + /// + public bool Equals(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => true, + (null, _) => false, + (_, null) => false, + (_, _) => Value.Equals(other.Value), + }; + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + return obj is PLACEHOLDERID other && Equals(other); + } + + public override int GetHashCode() => Value.GetHashCode(); + + public override string ToString() => Value; + + public static bool operator ==(PLACEHOLDERID a, PLACEHOLDERID b) => a.Equals(b); + public static bool operator !=(PLACEHOLDERID a, PLACEHOLDERID b) => !(a == b); + + /// + public int CompareTo(PLACEHOLDERID other) + => (Value, other.Value) switch + { + (null, null) => 0, + (null, _) => -1, + (_, null) => 1, + (_, _) => Value.CompareTo(other.Value), + }; + + public partial class PLACEHOLDERIDTypeConverter : global::System.ComponentModel.TypeConverter + { + public override bool CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + public override object? ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object value) + { + if (value is string stringValue) + { + return new PLACEHOLDERID(stringValue); + } + + return base.ConvertFrom(context, culture, value); + } + + public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Type? sourceType) + { + return sourceType == typeof(string) || base.CanConvertTo(context, sourceType); + } + + public override object? ConvertTo(global::System.ComponentModel.ITypeDescriptorContext? context, global::System.Globalization.CultureInfo? culture, object? value, global::System.Type destinationType) + { + if (value is PLACEHOLDERID idValue) + { + if (destinationType == typeof(string)) + { + return idValue.Value; + } + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public partial class PLACEHOLDERIDSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter + { + public override bool CanConvert(global::System.Type typeToConvert) + => typeToConvert == typeof(string) || base.CanConvert(typeToConvert); + + public override PLACEHOLDERID Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new (reader.GetString()!); + + public override void Write(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WriteStringValue(value.Value); + +#if NET6_0_OR_GREATER + public override PLACEHOLDERID ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options) + => new(reader.GetString() ?? throw new global::System.FormatException("The string for the PLACEHOLDERID property was null")); + + public override void WriteAsPropertyName(global::System.Text.Json.Utf8JsonWriter writer, PLACEHOLDERID value, global::System.Text.Json.JsonSerializerOptions options) + => writer.WritePropertyName(value.Value); +#endif + } + + public static PLACEHOLDERID Parse(string input) + => new(input); + +#if NET7_0_OR_GREATER + /// + public static PLACEHOLDERID Parse(string input, global::System.IFormatProvider? provider) + => new(input); + + /// + public static bool TryParse( + [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? input, + global::System.IFormatProvider? provider, + out PLACEHOLDERID result) + { + if (input is null) + { + result = default; + return false; + } + + result = new(input); + return true; + } +#endif + + /// + public string ToString(string? format, global::System.IFormatProvider? formatProvider) + => Value; + +#if NETCOREAPP2_1_OR_GREATER + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input) + => new(input.ToString()); +#endif + +#if NET6_0_OR_GREATER +#if NET7_0_OR_GREATER + /// +#endif + public static PLACEHOLDERID Parse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider) + => new(input.ToString()); + +#if NET7_0_OR_GREATER + /// +#endif + public static bool TryParse(global::System.ReadOnlySpan input, global::System.IFormatProvider? provider, out PLACEHOLDERID result) + { + result = new(input.ToString()); + return true; + } + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format, + global::System.IFormatProvider? provider) + => TryFormat(destination, out charsWritten, format); + + /// + public bool TryFormat( + global::System.Span destination, + out int charsWritten, + global::System.ReadOnlySpan format = default) + { + if (destination.Length > Value.Length) + { + global::System.MemoryExtensions.AsSpan(Value).CopyTo(destination); + charsWritten = Value.Length; + return true; + } + + charsWritten = default; + return false; + } +#endif + + public partial class DapperTypeHandler : global::Dapper.SqlMapper.TypeHandler + { + public override void SetValue(global::System.Data.IDbDataParameter parameter, PLACEHOLDERID value) + { + parameter.Value = value.Value; + } + + public override PLACEHOLDERID Parse(object value) + { + return value switch + { + string stringValue => new PLACEHOLDERID(stringValue), + _ => throw new global::System.InvalidCastException($"Unable to cast object of type {value.GetType()} to PLACEHOLDERID"), + }; + } + } + + public partial class EfCoreValueConverter : global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter + { + public EfCoreValueConverter() : this(null) { } + public EfCoreValueConverter(global::Microsoft.EntityFrameworkCore.Storage.ValueConversion.ConverterMappingHints? mappingHints = null) + : base( + id => id.Value, + value => new PLACEHOLDERID(value), + mappingHints + ) { } + } + + public partial class PLACEHOLDERIDNewtonsoftJsonConverter : global::Newtonsoft.Json.JsonConverter + { + public override bool CanConvert(global::System.Type objectType) + { + return objectType == typeof(PLACEHOLDERID); + } + + public override void WriteJson(global::Newtonsoft.Json.JsonWriter writer, object? value, global::Newtonsoft.Json.JsonSerializer serializer) + { + serializer.Serialize(writer, value is PLACEHOLDERID id ? id.Value : null); + } + + public override object? ReadJson(global::Newtonsoft.Json.JsonReader reader, global::System.Type objectType, object? existingValue, global::Newtonsoft.Json.JsonSerializer serializer) + { + if (objectType == typeof(PLACEHOLDERID?)) + { + var value = serializer.Deserialize(reader); + + return value is null ? null : new PLACEHOLDERID(value); + } + + return new PLACEHOLDERID(serializer.Deserialize(reader)!); + } + } + } \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/SourceGenerationHelperSnapshotTests.cs b/test/StronglyTypedIds.Tests/SourceGenerationHelperSnapshotTests.cs index 383b9a129..8f04986b6 100644 --- a/test/StronglyTypedIds.Tests/SourceGenerationHelperSnapshotTests.cs +++ b/test/StronglyTypedIds.Tests/SourceGenerationHelperSnapshotTests.cs @@ -1,167 +1,131 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using VerifyXunit; -using Xunit; - -namespace StronglyTypedIds.Tests -{ - [UsesVerify] - public class SourceGenerationHelperSnapshotTests - { - private const string IdNamespace = "Some.Namespace"; - - [Theory] - [InlineData(null)] - [InlineData("")] - public void ThrowsWhenClassNameIsNullOrEmpty(string idName) - { - Assert.Throws(() => SourceGenerationHelper.CreateId( - idName: idName, - idNamespace: IdNamespace, - parentClass: null, - converters: StronglyTypedIdConverter.None, - backingType: StronglyTypedIdBackingType.Guid, - implementations: StronglyTypedIdImplementations.None - )); - } - - [Fact] - public void ThrowsWhenDefaultConverterIsUsed() - { - Assert.Throws(() => SourceGenerationHelper.CreateId( - idName: "MyTestId", - idNamespace: IdNamespace, - parentClass: null, - converters: StronglyTypedIdConverter.Default, - backingType: StronglyTypedIdBackingType.Guid, - implementations: StronglyTypedIdImplementations.None - )); - } - - [Fact] - public void ThrowsWhenDefaultBackingTypeIsUsed() - { - Assert.Throws(() => SourceGenerationHelper.CreateId( - idName: "MyTestId", - idNamespace: IdNamespace, - parentClass: null, - converters: StronglyTypedIdConverter.None, - backingType: StronglyTypedIdBackingType.Default, - implementations: StronglyTypedIdImplementations.None - )); - } - - [Fact] - public void ThrowsWhenDefaultImplementationsIsUsed() - { - Assert.Throws(() => SourceGenerationHelper.CreateId( - idName: "MyTestId", - idNamespace: IdNamespace, - parentClass: null, - converters: StronglyTypedIdConverter.None, - backingType: StronglyTypedIdBackingType.Guid, - implementations: StronglyTypedIdImplementations.Default - )); - } - - [Theory] - [MemberData(nameof(Parameters))] - public Task GeneratesIdCorrectly( - StronglyTypedIdBackingType type, - StronglyTypedIdConverter c, - StronglyTypedIdImplementations i) - { - const string idName = "MyTestId"; - var result = SourceGenerationHelper.CreateId( - idName: idName, - idNamespace: "", - parentClass: null, - converters: c, - backingType: type, - implementations: i - ); - - return Verifier.Verify(result) - .UseDirectory("Snapshots") - .UseParameters(type, c, i); - } - - [Theory] - [MemberData(nameof(BackingTypes))] - public Task GeneratesFullIdCorrectly(StronglyTypedIdBackingType type) - { - // combine them all - var combinedConverter = EnumHelper.AllConverters(includeDefault: false) - .Aggregate(StronglyTypedIdConverter.None, (prev, current) => prev | current); - - // combine them all - var combinedImplementation = EnumHelper.AllImplementations(includeDefault: false) - .Aggregate(StronglyTypedIdImplementations.None, (prev, current) => prev | current); - - const string idName = "MyTestId"; - - var result = SourceGenerationHelper.CreateId( - idName: idName, - idNamespace: "", - parentClass: null, - converters: combinedConverter, - backingType: type, - implementations: combinedImplementation - ); - - return Verifier.Verify(result) - .UseDirectory("Snapshots") - .UseParameters(type); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public Task GeneratesIdWithNestedClassCorrectly(int nestedClassCount) - { - var parent = new ParentClass("record", "InnerMost", string.Empty, child: null); - for (int i = 0; i < nestedClassCount; i++) - { - parent = new ParentClass("class", "OuterLayer" + i, string.Empty, parent); - } - - var result = SourceGenerationHelper.CreateId( - idName: "MyTestId", - idNamespace: "MyTestNamespace", - parentClass: parent, - converters: StronglyTypedIdConverter.SystemTextJson, - backingType: StronglyTypedIdBackingType.Guid, - implementations: StronglyTypedIdImplementations.None - ); - - return Verifier.Verify(result) - .UseDirectory("Snapshots") - .UseParameters(nestedClassCount); - } - - public static IEnumerable BackingTypes() - => EnumHelper.AllBackingTypes(includeDefault: false) - .Select(x => new object[] { x }); - - public static IEnumerable Parameters() - { - foreach (var backingType in EnumHelper.AllBackingTypes(includeDefault: false)) - { - // All individual convert types - foreach (var converter in EnumHelper.AllConverters(includeDefault: false)) - { - yield return new object[] { backingType, converter, StronglyTypedIdImplementations.None }; - } - - // All individual implementations - foreach (var implementation in EnumHelper.AllImplementations(includeDefault: false)) - { - yield return new object[] { backingType, StronglyTypedIdConverter.None, implementation }; - } - } - } - } -} \ No newline at end of file +// using System; +// using System.Collections.Generic; +// using System.Linq; +// using System.Threading.Tasks; +// using VerifyXunit; +// using Xunit; +// +// namespace StronglyTypedIds.Tests +// { +// [UsesVerify] +// public class SourceGenerationHelperSnapshotTests +// { +// private const string IdNamespace = "Some.Namespace"; +// +// [Theory] +// [InlineData(null)] +// [InlineData("")] +// public void ThrowsWhenClassNameIsNullOrEmpty(string idName) +// { +// Assert.Throws(() => SourceGenerationHelper.CreateId( +// idName: idName, +// idNamespace: IdNamespace, +// parentClass: null, +// template: "N/A" +// )); +// } +// +// [Theory] +// [MemberData(nameof(Parameters))] +// public Task GeneratesIdCorrectly( +// StronglyTypedIdBackingType type, +// StronglyTypedIdConverter c, +// StronglyTypedIdImplementations i) +// { +// const string idName = "MyTestId"; +// var result = SourceGenerationHelper.CreateId( +// idName: idName, +// idNamespace: "", +// parentClass: null, +// converters: c, +// backingType: type, +// implementations: i +// ); +// +// return Verifier.Verify(result) +// .UseDirectory("Snapshots") +// .UseParameters(type, c, i); +// } +// +// [Theory] +// [MemberData(nameof(BackingTypes))] +// public Task GeneratesFullIdCorrectly(StronglyTypedIdBackingType type) +// { +// // combine them all +// var combinedConverter = EnumHelper.AllConverters(includeDefault: false) +// .Aggregate(StronglyTypedIdConverter.None, (prev, current) => prev | current); +// +// // combine them all +// var combinedImplementation = EnumHelper.AllImplementations(includeDefault: false) +// .Aggregate(StronglyTypedIdImplementations.None, (prev, current) => prev | current); +// +// const string idName = "MyTestId"; +// +// var result = SourceGenerationHelper.CreateId( +// idName: idName, +// idNamespace: "", +// parentClass: null, +// converters: combinedConverter, +// backingType: type, +// implementations: combinedImplementation +// ); +// +// return Verifier.Verify(result) +// .UseDirectory("Snapshots") +// .UseParameters(type); +// } +// +// [Theory] +// [InlineData(0)] +// [InlineData(1)] +// [InlineData(2)] +// public Task GeneratesIdWithNestedClassCorrectly(int nestedClassCount) +// { +// var parent = new ParentClass("record", "InnerMost", string.Empty, child: null); +// for (int i = 0; i < nestedClassCount; i++) +// { +// parent = new ParentClass("class", "OuterLayer" + i, string.Empty, parent); +// } +// +// var result = SourceGenerationHelper.CreateId( +// idName: "MyTestId", +// idNamespace: "MyTestNamespace", +// parentClass: parent, +// converters: StronglyTypedIdConverter.SystemTextJson, +// backingType: StronglyTypedIdBackingType.Guid, +// implementations: StronglyTypedIdImplementations.None +// ); +// +// return Verifier.Verify(result) +// .UseDirectory("Snapshots") +// .UseParameters(nestedClassCount); +// } +// +// public static IEnumerable BackingTypes() +// => EnumHelper.AllBackingTypes(includeDefault: false) +// .Select(x => new object[] { x }); +// +// public static IEnumerable Parameters() +// { +// foreach (var backingType in EnumHelper.AllBackingTypes(includeDefault: false)) +// { +// // All individual convert types +// foreach (var converter in EnumHelper.AllConverters(includeDefault: false)) +// { +// yield return new object[] { backingType, converter, StronglyTypedIdImplementations.None }; +// } +// +// // All individual implementations +// foreach (var implementation in EnumHelper.AllImplementations(includeDefault: false)) +// { +// if (implementation is StronglyTypedIdImplementations.None) +// { +// // We've already covered this one in the previous loop +// continue; +// } +// yield return new object[] { backingType, StronglyTypedIdConverter.None, implementation }; +// } +// } +// } +// } +// } \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/StronglyTypedIdConfiguration.cs b/test/StronglyTypedIds.Tests/StronglyTypedIdConfiguration.cs deleted file mode 100644 index a667c3caa..000000000 --- a/test/StronglyTypedIds.Tests/StronglyTypedIdConfiguration.cs +++ /dev/null @@ -1,211 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Xunit; - -namespace StronglyTypedIds.Tests -{ - public class StronglyTypedIdConfigurationTests - { - [Theory] - [MemberData(nameof(ExpectedBackingTypes))] - public void ReturnsCorrectBackingType_WhenNoDefaultAttribute(StronglyTypedIdBackingType attributeValue, StronglyTypedIdBackingType expected) - { - var attributeValues = new StronglyTypedIdConfiguration(attributeValue, StronglyTypedIdConverter.Default, StronglyTypedIdImplementations.Default); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, null); - - Assert.Equal(expected, result.BackingType); - } - - [Theory] - [MemberData(nameof(ExpectedBackingTypes))] - public void ReturnsCorrectBackingType_WhenHaveDefaultAttributeThatUsesDefault(StronglyTypedIdBackingType attributeValue, StronglyTypedIdBackingType expected) - { - var defaultAttribute = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, StronglyTypedIdConverter.Default, StronglyTypedIdImplementations.Default); - var attributeValues = new StronglyTypedIdConfiguration(attributeValue, StronglyTypedIdConverter.Default, StronglyTypedIdImplementations.Default); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, defaultAttribute); - - Assert.Equal(expected, result.BackingType); - } - - [Theory] - [MemberData(nameof(ExpectedBackingTypesWithDefault))] - public void ReturnsCorrectBackingType_WhenHaveDefaultAttribute(StronglyTypedIdBackingType attributeValue, StronglyTypedIdBackingType defaultValue, StronglyTypedIdBackingType expected) - { - var defaultAttribute = new StronglyTypedIdConfiguration(defaultValue, StronglyTypedIdConverter.Default, StronglyTypedIdImplementations.Default); - var attributeValues = new StronglyTypedIdConfiguration(attributeValue, StronglyTypedIdConverter.Default, StronglyTypedIdImplementations.Default); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, defaultAttribute); - - Assert.Equal(expected, result.BackingType); - } - - [Theory] - [MemberData(nameof(ExpectedConverters))] - public void ReturnsCorrectConverters_WhenNoDefaultAttribute(StronglyTypedIdConverter attributeValue, StronglyTypedIdConverter expected) - { - var attributeValues = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, attributeValue, StronglyTypedIdImplementations.Default); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, null); - - Assert.Equal(expected, result.Converters); - } - - [Theory] - [MemberData(nameof(ExpectedConverters))] - public void ReturnsCorrectConverters_WhenHaveDefaultAttributeThatUsesDefault(StronglyTypedIdConverter attributeValue, StronglyTypedIdConverter expected) - { - var defaultAttribute = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, StronglyTypedIdConverter.Default, StronglyTypedIdImplementations.Default); - var attributeValues = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, attributeValue, StronglyTypedIdImplementations.Default); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, defaultAttribute); - - Assert.Equal(expected, result.Converters); - } - - [Theory] - [MemberData(nameof(ExpectedConvertersWithDefault))] - public void ReturnsCorrectConverters_WhenHaveDefaultAttribute(StronglyTypedIdConverter attributeValue, StronglyTypedIdConverter defaultValue, StronglyTypedIdConverter expected) - { - var defaultAttribute = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, defaultValue, StronglyTypedIdImplementations.Default); - var attributeValues = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, attributeValue, StronglyTypedIdImplementations.Default); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, defaultAttribute); - - Assert.Equal(expected, result.Converters); - } - - [Theory] - [MemberData(nameof(ExpectedImplementations))] - public void ReturnsCorrectImplementations_WhenNoDefaultAttribute(StronglyTypedIdImplementations attributeValue, StronglyTypedIdImplementations expected) - { - var attributeValues = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, StronglyTypedIdConverter.Default, attributeValue); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, null); - - Assert.Equal(expected, result.Implementations); - } - - [Theory] - [MemberData(nameof(ExpectedImplementations))] - public void ReturnsCorrectImplementations_WhenHaveDefaultAttributeThatUsesDefault(StronglyTypedIdImplementations attributeValue, StronglyTypedIdImplementations expected) - { - var defaultAttribute = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, StronglyTypedIdConverter.Default, StronglyTypedIdImplementations.Default); - var attributeValues = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, StronglyTypedIdConverter.Default, attributeValue); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, defaultAttribute); - - Assert.Equal(expected, result.Implementations); - } - - [Theory] - [MemberData(nameof(ExpectedImplementationsWithDefault))] - public void ReturnsCorrectImplementations_WhenHaveDefaultAttribute(StronglyTypedIdImplementations attributeValue, StronglyTypedIdImplementations defaultValue, StronglyTypedIdImplementations expected) - { - var defaultAttribute = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, StronglyTypedIdConverter.Default, defaultValue); - var attributeValues = new StronglyTypedIdConfiguration(StronglyTypedIdBackingType.Default, StronglyTypedIdConverter.Default, attributeValue); - - var result = StronglyTypedIdConfiguration.Combine(attributeValues, defaultAttribute); - - Assert.Equal(expected, result.Implementations); - } - - public static IEnumerable ExpectedBackingTypes() - { - foreach (var backingType in EnumHelper.AllBackingTypes(includeDefault: false)) - { - // attribute, expected - yield return new object[] { backingType, backingType }; - } - - yield return new object[] { StronglyTypedIdBackingType.Default, StronglyTypedIdConfiguration.Defaults.BackingType }; - } - - public static IEnumerable ExpectedBackingTypesWithDefault() - { - foreach (var attributeType in EnumHelper.AllBackingTypes(includeDefault: false)) - { - foreach (var defaultType in EnumHelper.AllBackingTypes(includeDefault: true)) - { - // attribute, default, expected - yield return new object[] { attributeType, defaultType, attributeType }; - } - } - - foreach (var defaultType in EnumHelper.AllBackingTypes(includeDefault: false)) - { - // attribute, default, expected - yield return new object[] { StronglyTypedIdBackingType.Default, defaultType, defaultType }; - } - - yield return new object[] { StronglyTypedIdBackingType.Default, StronglyTypedIdBackingType.Default, StronglyTypedIdConfiguration.Defaults.BackingType }; - } - - - public static IEnumerable ExpectedConverters() - { - foreach (var backingType in EnumHelper.AllConverterCombinations(includeDefault: false, includeNone: false)) - { - // attribute, expected - yield return new object[] { backingType, backingType }; - } - - yield return new object[] { StronglyTypedIdConverter.None, StronglyTypedIdConverter.None }; - yield return new object[] { StronglyTypedIdConverter.Default, StronglyTypedIdConfiguration.Defaults.Converters }; - } - - public static IEnumerable ExpectedConvertersWithDefault() - { - foreach (var attributeType in EnumHelper.AllConverterCombinations(includeDefault: false)) - { - foreach (var defaultType in EnumHelper.AllConverterCombinations(includeDefault: true)) - { - // attribute, default, expected - yield return new object[] { attributeType, defaultType, attributeType }; - } - } - - foreach (var defaultType in EnumHelper.AllConverterCombinations(includeDefault: false)) - { - // attribute, default, expected - yield return new object[] { StronglyTypedIdConverter.Default, defaultType, defaultType }; - } - - yield return new object[] { StronglyTypedIdConverter.Default, StronglyTypedIdConverter.Default, StronglyTypedIdConfiguration.Defaults.Converters }; - } - - public static IEnumerable ExpectedImplementations() - { - foreach (var backingType in EnumHelper.AllImplementationCombinations(includeDefault: false, includeNone: false)) - { - // attribute, expected - yield return new object[] { backingType, backingType }; - } - - yield return new object[] { StronglyTypedIdImplementations.None, StronglyTypedIdImplementations.None }; - yield return new object[] { StronglyTypedIdImplementations.Default, StronglyTypedIdConfiguration.Defaults.Implementations }; - } - - public static IEnumerable ExpectedImplementationsWithDefault() - { - foreach (var attributeType in EnumHelper.AllImplementations(includeDefault: false)) - { - foreach (var defaultType in EnumHelper.AllImplementations(includeDefault: true)) - { - // attribute, default, expected - yield return new object[] { attributeType, defaultType, attributeType }; - } - } - - foreach (var defaultType in EnumHelper.AllImplementations(includeDefault: false)) - { - // attribute, default, expected - yield return new object[] { StronglyTypedIdImplementations.Default, defaultType, defaultType }; - } - - yield return new object[] { StronglyTypedIdImplementations.Default, StronglyTypedIdImplementations.Default, StronglyTypedIdConfiguration.Defaults.Implementations }; - } - } -} \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/StronglyTypedIdGeneratorTests.cs b/test/StronglyTypedIds.Tests/StronglyTypedIdGeneratorTests.cs index db399a465..4a4746d04 100644 --- a/test/StronglyTypedIds.Tests/StronglyTypedIdGeneratorTests.cs +++ b/test/StronglyTypedIds.Tests/StronglyTypedIdGeneratorTests.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using StronglyTypedIds.Diagnostics; using VerifyXunit; using Xunit; using Xunit.Abstractions; @@ -23,7 +24,7 @@ public Task CanGenerateDefaultIdInGlobalNamespace() [StronglyTypedId] public partial struct MyId {}"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); @@ -31,21 +32,70 @@ public partial struct MyId {}"; .UseDirectory("Snapshots"); } - [Fact] - public Task CanGenerateIdInNamespace() + [Theory] + [InlineData("")] + [InlineData("Template.Guid")] + [InlineData("template: Template.Guid")] + public Task CanGenerateIdInNamespace(string template) { - const string input = @"using StronglyTypedIds; + var input = $$""" + using StronglyTypedIds; + namespace SomeNamespace + { + [StronglyTypedId({{template}})] + public partial struct MyId {} + } + """; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); -namespace SomeNamespace -{ - [StronglyTypedId] - public partial struct MyId {} -}"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + Assert.Empty(diagnostics); + + return Verifier.Verify(output) + .DisableRequireUniquePrefix() + .UseDirectory("Snapshots"); + } + + [Theory] + [InlineData("Template.Int")] + [InlineData("template: Template.Int")] + public Task CanGenerateNonDefaultIdInNamespace(string template) + { + var input = $$""" + using StronglyTypedIds; + namespace SomeNamespace + { + [StronglyTypedId({{template}})] + public partial struct MyId {} + } + """; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); return Verifier.Verify(output) + .DisableRequireUniquePrefix() + .UseDirectory("Snapshots"); + } + + [Theory] + [InlineData("\"newid-full\"")] + [InlineData("templateNames: \"newid-full\"")] + public Task CanGenerateForCustomTemplate(string templateName) + { + var input = $$""" + using StronglyTypedIds; + namespace SomeNamespace + { + [StronglyTypedId({{templateName}})] + public partial struct MyId {} + } + """; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); + + Assert.Empty(diagnostics); + + return Verifier.Verify(output) + .DisableRequireUniquePrefix() .UseDirectory("Snapshots"); } @@ -57,7 +107,7 @@ public Task CanGenerateIdInFileScopedNamespace() namespace SomeNamespace; [StronglyTypedId] public partial struct MyId {}"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); @@ -77,7 +127,7 @@ public class ParentClass [StronglyTypedId] public partial struct MyId {} }"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); @@ -92,19 +142,18 @@ public Task CanGenerateVeryNestedIdInFileScopeNamespace() namespace SomeNamespace; -public class ParentClass - where T: new() +public partial class ParentClass { - internal record InnerClass + internal partial record InnerClass { - public struct InnerStruct + public readonly partial record struct InnerStruct { [StronglyTypedId] - public partial struct MyId {} + public readonly partial struct MyId {} } } }"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); @@ -113,14 +162,25 @@ public partial struct MyId {} } [Fact] - public Task CanOverrideDefaultsUsingGlobalAttribute() + public Task CanGenerateGenericVeryNestedIdInFileScopeNamespace() { const string input = @"using StronglyTypedIds; -[assembly:StronglyTypedIdDefaults(backingType: StronglyTypedIdBackingType.Int, converters: StronglyTypedIdConverter.None)] -[StronglyTypedId] -public partial struct MyId {}"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); +namespace SomeNamespace; + +public class ParentClass + where T: new() +{ + internal record InnerClass + { + public struct InnerStruct + { + [StronglyTypedId] + public partial struct MyId {} + } + } +}"; + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); @@ -129,56 +189,46 @@ public partial struct MyId {}"; } [Theory] - [MemberData(nameof(GetData))] - public Task CanGenerateIdWithNamedParameters(StronglyTypedIdBackingType backingType, StronglyTypedIdConverter? converter) + [InlineData("Template.Int")] + [InlineData("template: Template.Int")] + public Task CanOverrideDefaultsWithTemplateUsingGlobalAttribute(string template) { - var type = $"backingType: {nameof(StronglyTypedIdBackingType)}.{backingType.ToString()}"; - var converters = converter.HasValue - ? $", converters: {ToArgument(converter.Value)}" - : string.Empty; - var attribute = $"[StronglyTypedId({type}{converters})]"; - - _output.WriteLine(attribute); + var input = $$""" + using StronglyTypedIds; + [assembly:StronglyTypedIdDefaults({{template}})] + + [StronglyTypedId] + public partial struct MyId {} + """; - var input = @"using StronglyTypedIds; - -namespace MyTests.TestNameSpace -{ - " + attribute + @" - public partial struct MyId {} -}"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); return Verifier.Verify(output) - .UseParameters(backingType, converter) + .DisableRequireUniquePrefix() .UseDirectory("Snapshots"); } [Theory] - [MemberData(nameof(GetData))] - public Task CanGenerateIdWithPositionalParameters(StronglyTypedIdBackingType backingType, StronglyTypedIdConverter? converter) + [InlineData("\"newid-full\"")] + [InlineData("templateName: \"newid-full\"")] + public Task CanOverrideDefaultsWithCustomTemplateUsingGlobalAttribute(string templateNames) { - var type = $"{nameof(StronglyTypedIdBackingType)}.{backingType.ToString()}"; - var args = converter.HasValue ? $"{type}, {ToArgument(converter.Value)}" : $"{type}"; - var attribute = $"[StronglyTypedId({args})]"; - - _output.WriteLine(attribute); + var input = $$""" + using StronglyTypedIds; + [assembly:StronglyTypedIdDefaults({{templateNames}})] + + [StronglyTypedId] + public partial struct MyId {} + """; - var input = @"using StronglyTypedIds; - -namespace MyTests.TestNameSpace -{ - " + attribute + @" - public partial struct MyId {} -}"; - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); return Verifier.Verify(output) - .UseParameters(backingType, converter) + .DisableRequireUniquePrefix() .UseDirectory("Snapshots"); } @@ -201,7 +251,7 @@ public partial struct MyId {} }"; // This only includes the last ID but that's good enough for this - var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input); + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); Assert.Empty(diagnostics); @@ -209,25 +259,70 @@ public partial struct MyId {} .UseDirectory("Snapshots"); } - public static TheoryData GetData => new() - { - {StronglyTypedIdBackingType.Guid, null}, - {StronglyTypedIdBackingType.Guid, StronglyTypedIdConverter.NewtonsoftJson}, - {StronglyTypedIdBackingType.Guid, StronglyTypedIdConverter.SystemTextJson}, - {StronglyTypedIdBackingType.Guid, StronglyTypedIdConverter.TypeConverter}, - {StronglyTypedIdBackingType.Guid, StronglyTypedIdConverter.SystemTextJson | StronglyTypedIdConverter.NewtonsoftJson}, - }; - - public static string ToArgument(StronglyTypedIdConverter converter) => - converter switch - { - StronglyTypedIdConverter.NewtonsoftJson => "StronglyTypedIdConverter.NewtonsoftJson", - StronglyTypedIdConverter.SystemTextJson => "StronglyTypedIdConverter.SystemTextJson", - StronglyTypedIdConverter.TypeConverter => "StronglyTypedIdConverter.TypeConverter", - _ when converter.HasFlag(StronglyTypedIdConverter.NewtonsoftJson) && - converter.HasFlag(StronglyTypedIdConverter.SystemTextJson) => - "StronglyTypedIdConverter.NewtonsoftJson | StronglyTypedIdConverter.SystemTextJson", - _ => throw new InvalidOperationException("Unknown converter " + converter), - }; + [Theory] + [InlineData(false, "Template.Guid, \"guid-efcore\", \"guid-dapper\"")] + [InlineData(false, "template: Template.Guid, \"guid-efcore\", \"guid-dapper\"")] + [InlineData(false, "Template.Guid, templateNames: new [] {\"guid-efcore\", \"guid-dapper\"}")] + [InlineData(true, "Template.Guid, \"guid-efcore\", \"guid-dapper\"")] + [InlineData(true, "template: Template.Guid, \"guid-efcore\", \"guid-dapper\"")] + [InlineData(true, "Template.Guid, templateNames: new [] {\"guid-efcore\", \"guid-dapper\"}")] + public Task CanGenerateMultipleTemplatesWithBuiltIn(bool useDefault, string template) + { + var defaultAttr = useDefault + ? $"[assembly:StronglyTypedIdDefaults({template})]" + : string.Empty; + + var templateAttr = useDefault ? string.Empty : template; + + var input = $$""" + using StronglyTypedIds; + {{defaultAttr}} + + [StronglyTypedId({{templateAttr}})] + public partial struct MyId {} + """; + + // This only includes the last ID but that's good enough for this + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); + + Assert.Empty(diagnostics); + + return Verifier.Verify(output) + .DisableRequireUniquePrefix() + .UseDirectory("Snapshots"); + } + + [Theory] + [InlineData(false, "\"guid-efcore\", \"guid-dapper\"")] + [InlineData(false, "templateNames: new [] {\"guid-efcore\", \"guid-dapper\"}")] + [InlineData(true, "\"guid-dapper\", \"guid-efcore\"")] + [InlineData(true, "\"guid-dapper\", new [] {\"guid-efcore\"}")] + [InlineData(true, "\"guid-dapper\", templateNames: new [] {\"guid-efcore\"}")] + [InlineData(true, "templateName: \"guid-dapper\", templateNames: new [] {\"guid-efcore\"}")] + public Task CanGenerateMultipleTemplatesWithoutBuiltIn(bool useDefault, string template) + { + var defaultAttr = useDefault + ? $"[assembly:StronglyTypedIdDefaults({template})]" + : string.Empty; + + var templateAttr = useDefault ? string.Empty : template; + + var input = $$""" + using StronglyTypedIds; + {{defaultAttr}} + + [StronglyTypedId({{templateAttr}})] + public partial struct MyId {} + """; + + // This only includes the last ID but that's good enough for this + var (diagnostics, output) = TestHelpers.GetGeneratedOutput(input, includeAttributes: false); + + Assert.Empty(diagnostics); + + return Verifier.Verify(output) + .DisableRequireUniquePrefix() + .UseDirectory("Snapshots"); + } } } \ No newline at end of file diff --git a/test/StronglyTypedIds.Tests/StronglyTypedIds.Tests.csproj b/test/StronglyTypedIds.Tests/StronglyTypedIds.Tests.csproj index 4fc7f0fb2..4ef5fe171 100644 --- a/test/StronglyTypedIds.Tests/StronglyTypedIds.Tests.csproj +++ b/test/StronglyTypedIds.Tests/StronglyTypedIds.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;net6.0;net7.0 + netcoreapp3.1;net6.0;net7.0;net8.0 net48;$(TargetFrameworks) false latest @@ -18,9 +18,23 @@ + + + + + + + + + + + + + + diff --git a/test/StronglyTypedIds.Tests/TestHelpers.cs b/test/StronglyTypedIds.Tests/TestHelpers.cs index 7b99488a6..f7e1e3894 100644 --- a/test/StronglyTypedIds.Tests/TestHelpers.cs +++ b/test/StronglyTypedIds.Tests/TestHelpers.cs @@ -1,16 +1,20 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Reflection; using System.Text; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; namespace StronglyTypedIds.Tests { internal static class TestHelpers { - public static (ImmutableArray Diagnostics, string Output) GetGeneratedOutput(string source) + public static (ImmutableArray Diagnostics, string Output) GetGeneratedOutput(string source, bool includeAttributes = true) where T : IIncrementalGenerator, new() { var syntaxTree = CSharpSyntaxTree.ParseText(source); @@ -28,15 +32,33 @@ public static (ImmutableArray Diagnostics, string Output) GetGenerat CSharpGeneratorDriver .Create(new T()) + .AddAdditionalTexts(LoadEmbeddedResourcesAsAdditionalText()) .RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var diagnostics); - var output = string.Join("\n", outputCompilation.SyntaxTrees.Skip(originalTreeCount).Select(t => t.ToString())); + + // If we don't want the attributes, we try to get all the potential resource streams and exclude them + var countsToExclude = includeAttributes + ? originalTreeCount + : originalTreeCount + typeof(T).Assembly.GetManifestResourceNames().Count(x => x.StartsWith("StronglyTypedIds.Templates.Sources.")); + + var output = string.Join("\n", outputCompilation.SyntaxTrees.Skip(countsToExclude).Select(t => t.ToString())); return (diagnostics, output); } - internal static string LoadEmbeddedResource(string resourceName) + private static ImmutableArray LoadEmbeddedResourcesAsAdditionalText() { + var texts = ImmutableArray.CreateBuilder(); var assembly = typeof(TestHelpers).Assembly; + + texts.AddRange(assembly.GetManifestResourceNames() + .Select(name => new TestAdditionalText( + text: LoadEmbeddedResource(assembly, name), + path: Path.Combine("c:", "test", "Templates", Path.GetExtension(Path.GetFileNameWithoutExtension(name)).Substring(1) + ".typedid")))); + + return texts.ToImmutable(); + } + private static string LoadEmbeddedResource(Assembly assembly, string resourceName) + { var resourceStream = assembly.GetManifestResourceStream(resourceName); if (resourceStream is null) { @@ -48,5 +70,111 @@ internal static string LoadEmbeddedResource(string resourceName) return reader.ReadToEnd(); } + + private sealed class TestAdditionalText : AdditionalText + { + private readonly SourceText _text; + + public TestAdditionalText(string path, SourceText text) + { + Path = path; + _text = text; + } + + public TestAdditionalText(string text = "", Encoding encoding = null, string path = "dummy", SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithm.Sha1) + : this(path, new StringText(text, encoding, checksumAlgorithm: checksumAlgorithm)) + { + } + + public override string Path { get; } + + public override SourceText GetText(CancellationToken cancellationToken = default) => _text; + } + + /// + /// Implementation of SourceText based on a input + /// + internal sealed class StringText : SourceText + { + private readonly string _source; + private readonly Encoding _encodingOpt; + + internal StringText( + string source, + Encoding encodingOpt, + ImmutableArray checksum = default(ImmutableArray), + SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithm.Sha1) + : base(checksum, checksumAlgorithm) + { + _source = source; + _encodingOpt = encodingOpt; + } + + public override Encoding Encoding => _encodingOpt; + + /// + /// Underlying string which is the source of this instance + /// + public string Source => _source; + + /// + /// The length of the text represented by . + /// + public override int Length => _source.Length; + + /// + /// Returns a character at given position. + /// + /// The position to get the character from. + /// The character. + /// When position is negative or + /// greater than . + public override char this[int position] + { + get + { + // NOTE: we are not validating position here as that would not + // add any value to the range check that string accessor performs anyways. + + return _source[position]; + } + } + + /// + /// Provides a string representation of the StringText located within given span. + /// + /// When given span is outside of the text range. + public override string ToString(TextSpan span) + { + if (span.End > this.Source.Length) + { + throw new ArgumentOutOfRangeException(nameof(span)); + } + + if (span.Start == 0 && span.Length == this.Length) + { + return this.Source; + } + + return this.Source.Substring(span.Start, span.Length); + } + + public override void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) + { + this.Source.CopyTo(sourceIndex, destination, destinationIndex, count); + } + + public override void Write(TextWriter textWriter, TextSpan span, CancellationToken cancellationToken = default(CancellationToken)) + { + if (span.Start == 0 && span.End == this.Length) + { + textWriter.Write(this.Source); + } + else + { + base.Write(textWriter, span, cancellationToken); + } + } + } } } \ No newline at end of file